Full Code of adrienpoly/rubyvideo for AI

main e6cdb725d6ad cached
3709 files
15.1 MB
4.1M tokens
3552 symbols
1 requests
Copy disabled (too large) Download .txt
Showing preview only (16,718K chars total). Download the full file to get everything.
Repository: adrienpoly/rubyvideo
Branch: main
Commit: e6cdb725d6ad
Files: 3709
Total size: 15.1 MB

Directory structure:
gitextract_xohe3ehl/

├── .annotaterb.yml
├── .cursor/
│   ├── commands/
│   │   └── plan_commands.md
│   └── rules/
│       ├── cursorrules.mdc
│       └── viewcomponents.mdc
├── .devcontainer/
│   ├── Dockerfile
│   ├── devcontainer.json
│   └── docker-compose.yml
├── .dockerignore
├── .erb_lint.yml
├── .eslintignore
├── .eslintrc
├── .gitattributes
├── .github/
│   ├── pull_request_template.md
│   ├── skills/
│   │   └── event-data/
│   │       └── SKILL.md
│   └── workflows/
│       ├── ci.yml
│       ├── copilot-setup-steps.yml
│       ├── deploy-staging.yml
│       ├── migrate-production.yml
│       ├── migrate-staging.yml
│       ├── release-lock-production.yml
│       ├── release-lock-staging.yml
│       ├── seed-production.yml
│       └── seed-staging.yml
├── .gitignore
├── .herb.yml
├── .kamal/
│   ├── hooks/
│   │   ├── docker-setup.sample
│   │   ├── post-deploy.sample
│   │   ├── post-proxy-reboot.sample
│   │   ├── pre-build.sample
│   │   ├── pre-connect.sample
│   │   ├── pre-deploy.sample
│   │   └── pre-proxy-reboot.sample
│   ├── secrets
│   └── secrets.staging
├── .mcp.json
├── .node-version
├── .prettierignore
├── .ruby-version
├── .standard.yml
├── .vscode/
│   ├── extensions.json
│   └── settings.json
├── CLAUDE.md
├── CONTRIBUTING.md
├── Dockerfile
├── Gemfile
├── Guardfile
├── Procfile.dev
├── README.md
├── Rakefile
├── app/
│   ├── assets/
│   │   ├── builds/
│   │   │   └── .keep
│   │   └── stylesheets/
│   │       ├── application.css
│   │       ├── bridge/
│   │       │   └── components.css
│   │       └── components/
│   │           ├── button.css
│   │           ├── diff.css
│   │           ├── dropdown.css
│   │           ├── event.css
│   │           ├── form.css
│   │           ├── hotwire-combobox.css
│   │           ├── iframe.css
│   │           ├── markdown.css
│   │           ├── modal.css
│   │           ├── nav.css
│   │           ├── pagination.css
│   │           ├── skeleton.css
│   │           ├── spotlight.css
│   │           ├── tabs.css
│   │           ├── transition.css
│   │           ├── typography.css
│   │           └── video.css
│   ├── avo/
│   │   ├── actions/
│   │   │   ├── approve_topic.rb
│   │   │   ├── assign_canonical_event.rb
│   │   │   ├── assign_canonical_speaker.rb
│   │   │   ├── assign_canonical_topic.rb
│   │   │   ├── assign_canonical_user.rb
│   │   │   ├── clear_user.rb
│   │   │   ├── enhance_transcript.rb
│   │   │   ├── extract_topics.rb
│   │   │   ├── fetch_duration.rb
│   │   │   ├── find_topic_talks.rb
│   │   │   ├── geocode_record.rb
│   │   │   ├── reject_topic.rb
│   │   │   ├── summarize.rb
│   │   │   ├── talk_index.rb
│   │   │   ├── talk_ingest.rb
│   │   │   ├── transcript.rb
│   │   │   ├── update_from_yml.rb
│   │   │   └── user_fetch_github.rb
│   │   ├── cards/
│   │   │   ├── duplicates_summary.rb
│   │   │   ├── reversed_name_duplicates_list.rb
│   │   │   ├── reversed_name_duplicates_metric.rb
│   │   │   ├── same_name_duplicates_list.rb
│   │   │   ├── same_name_duplicates_metric.rb
│   │   │   ├── suspicious_signals_breakdown.rb
│   │   │   ├── suspicious_summary.rb
│   │   │   ├── suspicious_users_list.rb
│   │   │   ├── suspicious_users_metric.rb
│   │   │   ├── unavailable_videos_by_event.rb
│   │   │   ├── unavailable_videos_list.rb
│   │   │   ├── unavailable_videos_metric.rb
│   │   │   └── unavailable_videos_summary.rb
│   │   ├── dashboards/
│   │   │   ├── default.rb
│   │   │   ├── duplicates.rb
│   │   │   ├── suspicious.rb
│   │   │   └── unavailable_videos.rb
│   │   ├── filters/
│   │   │   ├── aliasable_type.rb
│   │   │   ├── attended_as.rb
│   │   │   ├── bio.rb
│   │   │   ├── bio_presence.rb
│   │   │   ├── canonical.rb
│   │   │   ├── enhanced_transcript.rb
│   │   │   ├── geocoded_presence.rb
│   │   │   ├── github.rb
│   │   │   ├── github_handle.rb
│   │   │   ├── github_handle_presence.rb
│   │   │   ├── has_duplicate.rb
│   │   │   ├── involvement_role.rb
│   │   │   ├── language.rb
│   │   │   ├── location_presence.rb
│   │   │   ├── name.rb
│   │   │   ├── provider.rb
│   │   │   ├── published.rb
│   │   │   ├── raw_transcript.rb
│   │   │   ├── slug.rb
│   │   │   ├── summary.rb
│   │   │   ├── suspicious.rb
│   │   │   ├── talk_event.rb
│   │   │   ├── title.rb
│   │   │   ├── topic_talks.rb
│   │   │   ├── topics.rb
│   │   │   ├── video_availability.rb
│   │   │   ├── video_provider.rb
│   │   │   └── without_talks.rb
│   │   └── resources/
│   │       ├── alias.rb
│   │       ├── city.rb
│   │       ├── connected_account.rb
│   │       ├── contributor.rb
│   │       ├── event.rb
│   │       ├── event_involvement.rb
│   │       ├── event_participation.rb
│   │       ├── event_series.rb
│   │       ├── favorite_user.rb
│   │       ├── geocode_result.rb
│   │       ├── organization.rb
│   │       ├── session.rb
│   │       ├── sponsor.rb
│   │       ├── suggestion.rb
│   │       ├── talk.rb
│   │       ├── talk_topic.rb
│   │       ├── talk_transcript.rb
│   │       ├── topic.rb
│   │       ├── topic_gem.rb
│   │       ├── user.rb
│   │       ├── user_talk.rb
│   │       ├── watch_list.rb
│   │       └── watch_list_talk.rb
│   ├── channels/
│   │   └── application_cable/
│   │       ├── channel.rb
│   │       └── connection.rb
│   ├── clients/
│   │   ├── application_client.rb
│   │   ├── blue_sky.rb
│   │   ├── github/
│   │   │   ├── client.rb
│   │   │   ├── contributors_client.rb
│   │   │   └── user_client.rb
│   │   ├── ruby_conferences/
│   │   │   └── client.rb
│   │   ├── speakerdeck/
│   │   │   └── client.rb
│   │   └── youtube/
│   │       ├── channels.rb
│   │       ├── client.rb
│   │       ├── playlist_items.rb
│   │       ├── playlists.rb
│   │       ├── thumbnail.rb
│   │       ├── transcript.rb
│   │       └── video.rb
│   ├── components/
│   │   ├── application_component.rb
│   │   ├── events/
│   │   │   ├── upcoming_event_banner_component.html.erb
│   │   │   └── upcoming_event_banner_component.rb
│   │   ├── hover_card/
│   │   │   ├── base_component.html.erb
│   │   │   ├── base_component.rb
│   │   │   ├── event_component.rb
│   │   │   └── user_component.rb
│   │   ├── tito/
│   │   │   ├── button_component.html.erb
│   │   │   ├── button_component.rb
│   │   │   ├── widget_component.html.erb
│   │   │   └── widget_component.rb
│   │   └── ui/
│   │       ├── avatar_component.html.erb
│   │       ├── avatar_component.rb
│   │       ├── avatar_group_component.html.erb
│   │       ├── avatar_group_component.rb
│   │       ├── badge_component.rb
│   │       ├── button_component.rb
│   │       ├── divider_component.rb
│   │       ├── dropdown_component.html.erb
│   │       ├── dropdown_component.rb
│   │       ├── modal_component.html.erb
│   │       ├── modal_component.rb
│   │       ├── stamp_component.html.erb
│   │       └── stamp_component.rb
│   ├── controllers/
│   │   ├── admin/
│   │   │   └── suggestions_controller.rb
│   │   ├── analytics/
│   │   │   └── dashboards_controller.rb
│   │   ├── announcements_controller.rb
│   │   ├── api/
│   │   │   └── v1/
│   │   │       └── embed/
│   │   │           ├── base_controller.rb
│   │   │           ├── events_controller.rb
│   │   │           ├── profiles_controller.rb
│   │   │           ├── speakers_controller.rb
│   │   │           ├── stamps_controller.rb
│   │   │           ├── stickers_controller.rb
│   │   │           ├── talks_controller.rb
│   │   │           └── topics_controller.rb
│   │   ├── application_controller.rb
│   │   ├── avo/
│   │   │   ├── aliases_controller.rb
│   │   │   ├── cities_controller.rb
│   │   │   ├── connected_accounts_controller.rb
│   │   │   ├── contributors_controller.rb
│   │   │   ├── event_involvements_controller.rb
│   │   │   ├── event_participations_controller.rb
│   │   │   ├── event_series_controller.rb
│   │   │   ├── events_controller.rb
│   │   │   ├── favorite_users_controller.rb
│   │   │   ├── geocode_results_controller.rb
│   │   │   ├── organizations_controller.rb
│   │   │   ├── sessions_controller.rb
│   │   │   ├── speaker_talks_controller.rb
│   │   │   ├── speakers_controller.rb
│   │   │   ├── sponsors_controller.rb
│   │   │   ├── suggestions_controller.rb
│   │   │   ├── talk_topics_controller.rb
│   │   │   ├── talk_transcripts_controller.rb
│   │   │   ├── talks_controller.rb
│   │   │   ├── topic_gems_controller.rb
│   │   │   ├── topics_controller.rb
│   │   │   ├── user_talks_controller.rb
│   │   │   ├── users_controller.rb
│   │   │   ├── watch_list_talks_controller.rb
│   │   │   └── watch_lists_controller.rb
│   │   ├── browse_controller.rb
│   │   ├── cfp_controller.rb
│   │   ├── cities_controller.rb
│   │   ├── concerns/
│   │   │   ├── analytics.rb
│   │   │   ├── authenticable.rb
│   │   │   ├── event_data.rb
│   │   │   ├── event_map_markers.rb
│   │   │   ├── favorite_users.rb
│   │   │   ├── geo_map_layers.rb
│   │   │   ├── location_events.rb
│   │   │   ├── metadata.rb
│   │   │   ├── profile_data.rb
│   │   │   ├── remote_modal.rb
│   │   │   ├── spotlight_search.rb
│   │   │   ├── turbo/
│   │   │   │   └── force_response.rb
│   │   │   └── watched_talks.rb
│   │   ├── continents/
│   │   │   ├── base_controller.rb
│   │   │   └── countries_controller.rb
│   │   ├── continents_controller.rb
│   │   ├── contributions_controller.rb
│   │   ├── coordinates_controller.rb
│   │   ├── countries/
│   │   │   ├── base_controller.rb
│   │   │   └── cities_controller.rb
│   │   ├── countries_controller.rb
│   │   ├── event_participations_controller.rb
│   │   ├── events/
│   │   │   ├── archive_controller.rb
│   │   │   ├── attendances_controller.rb
│   │   │   ├── cfp_controller.rb
│   │   │   ├── collectibles_controller.rb
│   │   │   ├── events_controller.rb
│   │   │   ├── involvements_controller.rb
│   │   │   ├── meetups_controller.rb
│   │   │   ├── participants_controller.rb
│   │   │   ├── past_controller.rb
│   │   │   ├── related_talks_controller.rb
│   │   │   ├── schedules_controller.rb
│   │   │   ├── series_controller.rb
│   │   │   ├── speakers_controller.rb
│   │   │   ├── sponsors_controller.rb
│   │   │   ├── talks_controller.rb
│   │   │   ├── tickets_controller.rb
│   │   │   ├── todos_controller.rb
│   │   │   ├── upcoming_controller.rb
│   │   │   ├── venues_controller.rb
│   │   │   ├── videos_controller.rb
│   │   │   └── years_controller.rb
│   │   ├── events_controller.rb
│   │   ├── favorite_users_controller.rb
│   │   ├── gems_controller.rb
│   │   ├── hotwire/
│   │   │   └── native/
│   │   │       └── v1/
│   │   │           ├── android/
│   │   │           │   └── path_configurations_controller.rb
│   │   │           └── ios/
│   │   │               └── path_configurations_controller.rb
│   │   ├── hover_cards/
│   │   │   ├── events_controller.rb
│   │   │   └── users_controller.rb
│   │   ├── leaderboard_controller.rb
│   │   ├── locations/
│   │   │   ├── base_controller.rb
│   │   │   ├── map_controller.rb
│   │   │   ├── meetups_controller.rb
│   │   │   ├── past_controller.rb
│   │   │   ├── stamps_controller.rb
│   │   │   └── users_controller.rb
│   │   ├── online_controller.rb
│   │   ├── organizations/
│   │   │   ├── logos_controller.rb
│   │   │   └── wrapped_controller.rb
│   │   ├── organizations_controller.rb
│   │   ├── page_controller.rb
│   │   ├── profiles/
│   │   │   ├── aliases_controller.rb
│   │   │   ├── claims_controller.rb
│   │   │   ├── connect_controller.rb
│   │   │   ├── enhance_controller.rb
│   │   │   ├── events_controller.rb
│   │   │   ├── involvements_controller.rb
│   │   │   ├── map_controller.rb
│   │   │   ├── mutual_events_controller.rb
│   │   │   ├── notes_controller.rb
│   │   │   ├── stamps_controller.rb
│   │   │   ├── stickers_controller.rb
│   │   │   ├── talks_controller.rb
│   │   │   └── wrapped_controller.rb
│   │   ├── profiles_controller.rb
│   │   ├── recommendations_controller.rb
│   │   ├── sessions/
│   │   │   └── omniauth_controller.rb
│   │   ├── sessions_controller.rb
│   │   ├── settings_controller.rb
│   │   ├── sitemaps_controller.rb
│   │   ├── speakers_controller.rb
│   │   ├── sponsors/
│   │   │   └── missing_controller.rb
│   │   ├── spotlight/
│   │   │   ├── events_controller.rb
│   │   │   ├── kinds_controller.rb
│   │   │   ├── languages_controller.rb
│   │   │   ├── locations_controller.rb
│   │   │   ├── organizations_controller.rb
│   │   │   ├── series_controller.rb
│   │   │   ├── speakers_controller.rb
│   │   │   ├── talks_controller.rb
│   │   │   └── topics_controller.rb
│   │   ├── stamps_controller.rb
│   │   ├── states/
│   │   │   ├── base_controller.rb
│   │   │   └── cities_controller.rb
│   │   ├── states_controller.rb
│   │   ├── talks/
│   │   │   ├── recommendations_controller.rb
│   │   │   ├── slides_controller.rb
│   │   │   └── watched_talks_controller.rb
│   │   ├── talks_controller.rb
│   │   ├── templates_controller.rb
│   │   ├── todos_controller.rb
│   │   ├── topics_controller.rb
│   │   ├── watch_list_talks_controller.rb
│   │   ├── watch_lists_controller.rb
│   │   ├── watched_talks_controller.rb
│   │   └── wrapped_controller.rb
│   ├── helpers/
│   │   ├── application_helper.rb
│   │   ├── events/
│   │   │   └── talks_helper.rb
│   │   ├── events_helper.rb
│   │   ├── icon_helper.rb
│   │   ├── language_helper.rb
│   │   ├── location_helper.rb
│   │   ├── markdown_helper.rb
│   │   ├── page_helper.rb
│   │   ├── speakers/
│   │   │   └── enhance_helper.rb
│   │   ├── speakers_helper.rb
│   │   ├── spotlight_helper.rb
│   │   ├── suggestions_helper.rb
│   │   ├── talks_helper.rb
│   │   └── view_component_helper.rb
│   ├── javascript/
│   │   ├── controllers/
│   │   │   ├── application.js
│   │   │   ├── auto-click_controller.js
│   │   │   ├── auto_submit_controller.js
│   │   │   ├── bridge/
│   │   │   │   └── button_controller.js
│   │   │   ├── collapsible_controller.js
│   │   │   ├── content_row_controller.js
│   │   │   ├── copy_to_clipboard_controller.js
│   │   │   ├── dropdown_controller.js
│   │   │   ├── event_controller.js
│   │   │   ├── event_list_controller.js
│   │   │   ├── events_filter_controller.js
│   │   │   ├── events_view_switcher_controller.js
│   │   │   ├── geolocation_controller.js
│   │   │   ├── hover_card_controller.js
│   │   │   ├── index.js
│   │   │   ├── lazy_loading_controller.js
│   │   │   ├── map_controller.js
│   │   │   ├── modal_controller.js
│   │   │   ├── preserve_scroll_controller.js
│   │   │   ├── pronouns_select_controller.js
│   │   │   ├── scroll_controller.js
│   │   │   ├── scroll_into_view_controller.js
│   │   │   ├── splide_controller.js
│   │   │   ├── spotlight_search_controller.js
│   │   │   ├── tabs_controller.js
│   │   │   ├── talks_filter_controller.js
│   │   │   ├── talks_filter_pill_controller.js
│   │   │   ├── talks_navigation_controller.js
│   │   │   ├── toggable_controller.js
│   │   │   ├── tooltip_controller.js
│   │   │   ├── top_banner_controller.js
│   │   │   ├── transition_controller.js
│   │   │   ├── video_player_controller.js
│   │   │   ├── watched_talk_form_controller.js
│   │   │   └── wrapped_stories_controller.js
│   │   ├── entrypoints/
│   │   │   ├── application.css
│   │   │   ├── application.js
│   │   │   └── chartkick.js
│   │   ├── helpers/
│   │   │   └── timing_helpers.js
│   │   └── support/
│   │       └── appsignal.js
│   ├── jobs/
│   │   ├── application_job.rb
│   │   ├── generate_wrapped_screenshot_job.rb
│   │   ├── geocode_record_job.rb
│   │   ├── recurring/
│   │   │   ├── fetch_contributors_job.rb
│   │   │   ├── mark_suspicious_users_job.rb
│   │   │   ├── rollup_job.rb
│   │   │   ├── youtube_thumbnail_validation_job.rb
│   │   │   ├── youtube_video_availability_job.rb
│   │   │   ├── youtube_video_duration_job.rb
│   │   │   └── youtube_video_statistics_job.rb
│   │   └── typesense_index_job.rb
│   ├── lib/
│   │   ├── command.rb
│   │   ├── download_sponsors.rb
│   │   ├── duration.rb
│   │   └── router.rb
│   ├── mailers/
│   │   └── application_mailer.rb
│   ├── models/
│   │   ├── active_record/
│   │   │   └── sqlite/
│   │   │       └── index.rb
│   │   ├── ahoy/
│   │   │   ├── event.rb
│   │   │   └── visit.rb
│   │   ├── alias.rb
│   │   ├── announcement.rb
│   │   ├── application_record.rb
│   │   ├── cfp.rb
│   │   ├── city.rb
│   │   ├── concerns/
│   │   │   ├── appsignal/
│   │   │   │   └── admin_namespace.rb
│   │   │   ├── geocodeable.rb
│   │   │   ├── locatable.rb
│   │   │   ├── rollupable.rb
│   │   │   ├── sluggable.rb
│   │   │   ├── suggestable.rb
│   │   │   ├── todoable.rb
│   │   │   ├── url_normalizable.rb
│   │   │   ├── watchable.rb
│   │   │   └── yaml_file.rb
│   │   ├── connected_account.rb
│   │   ├── continent.rb
│   │   ├── contributor.rb
│   │   ├── coordinate_location.rb
│   │   ├── country.rb
│   │   ├── cue.rb
│   │   ├── current.rb
│   │   ├── email_verification_token.rb
│   │   ├── event/
│   │   │   ├── assets.rb
│   │   │   ├── cfp_file.rb
│   │   │   ├── involvements_file.rb
│   │   │   ├── schedule.rb
│   │   │   ├── sponsors_file.rb
│   │   │   ├── static_metadata.rb
│   │   │   ├── tickets.rb
│   │   │   ├── transcripts_file.rb
│   │   │   ├── typesense_searchable.rb
│   │   │   ├── venue.rb
│   │   │   └── videos_file.rb
│   │   ├── event.rb
│   │   ├── event_involvement.rb
│   │   ├── event_participation.rb
│   │   ├── event_series/
│   │   │   ├── static_metadata.rb
│   │   │   └── typesense_searchable.rb
│   │   ├── event_series.rb
│   │   ├── favorite_user.rb
│   │   ├── geocode_result.rb
│   │   ├── language.rb
│   │   ├── llm/
│   │   │   ├── client.rb
│   │   │   └── request.rb
│   │   ├── location.rb
│   │   ├── online_location.rb
│   │   ├── organization/
│   │   │   ├── typesense_searchable.rb
│   │   │   └── wrapped_screenshot_generator.rb
│   │   ├── organization.rb
│   │   ├── password_reset_token.rb
│   │   ├── prompts/
│   │   │   ├── base.rb
│   │   │   ├── talk/
│   │   │   │   ├── enhance_transcript.rb
│   │   │   │   ├── summary.rb
│   │   │   │   └── topics.rb
│   │   │   └── topic/
│   │   │       ├── match_talks.rb
│   │   │       └── suggest_gems.rb
│   │   ├── rollup.rb
│   │   ├── search/
│   │   │   ├── backend/
│   │   │   │   ├── sqlite_fts/
│   │   │   │   │   └── indexer.rb
│   │   │   │   ├── sqlite_fts.rb
│   │   │   │   ├── typesense/
│   │   │   │   │   ├── circuit_breaker.rb
│   │   │   │   │   ├── indexer.rb
│   │   │   │   │   ├── kind_indexer.rb
│   │   │   │   │   ├── language_indexer.rb
│   │   │   │   │   └── location_indexer.rb
│   │   │   │   └── typesense.rb
│   │   │   └── backend.rb
│   │   ├── session.rb
│   │   ├── speaker.rb
│   │   ├── sponsor.rb
│   │   ├── stamp.rb
│   │   ├── state.rb
│   │   ├── static/
│   │   │   ├── backends/
│   │   │   │   ├── array_backend.rb
│   │   │   │   ├── file_backend.rb
│   │   │   │   └── multi_file_backend.rb
│   │   │   ├── city.rb
│   │   │   ├── event.rb
│   │   │   ├── event_series.rb
│   │   │   ├── speaker.rb
│   │   │   ├── sponsor.rb
│   │   │   ├── topic.rb
│   │   │   ├── transcript.rb
│   │   │   └── video.rb
│   │   ├── sticker.rb
│   │   ├── suggestion.rb
│   │   ├── talk/
│   │   │   ├── agents.rb
│   │   │   ├── downloader.rb
│   │   │   ├── index.rb
│   │   │   ├── similar_recommender.rb
│   │   │   ├── sqlite_fts_searchable.rb
│   │   │   ├── thumbnails.rb
│   │   │   ├── transcript.rb
│   │   │   └── typesense_searchable.rb
│   │   ├── talk.rb
│   │   ├── talk_topic.rb
│   │   ├── template.rb
│   │   ├── todo.rb
│   │   ├── topic/
│   │   │   ├── agents.rb
│   │   │   ├── gem_info.rb
│   │   │   └── typesense_searchable.rb
│   │   ├── topic.rb
│   │   ├── topic_gem.rb
│   │   ├── transcript.rb
│   │   ├── uk_nation.rb
│   │   ├── user/
│   │   │   ├── duplicate_detector.rb
│   │   │   ├── index.rb
│   │   │   ├── profiles.rb
│   │   │   ├── speakerdeck_feed.rb
│   │   │   ├── sqlite_fts_searchable.rb
│   │   │   ├── suspicion_detector.rb
│   │   │   ├── talk_recommender.rb
│   │   │   ├── typesense_searchable.rb
│   │   │   ├── watched_talk_seeder.rb
│   │   │   ├── wrapped_image_generator.rb
│   │   │   └── wrapped_screenshot_generator.rb
│   │   ├── user.rb
│   │   ├── user_talk.rb
│   │   ├── watch_list.rb
│   │   ├── watch_list_talk.rb
│   │   ├── watched_talk.rb
│   │   └── youtube/
│   │       ├── null_parser.rb
│   │       ├── video_metadata.rb
│   │       ├── video_metadata_baltic_ruby_2024.rb
│   │       ├── video_metadata_kaigi_on_rails.rb
│   │       └── video_metadata_rails_world.rb
│   ├── schemas/
│   │   ├── address_schema.rb
│   │   ├── cfp_schema.rb
│   │   ├── coordinates_schema.rb
│   │   ├── event_schema.rb
│   │   ├── featured_city_schema.rb
│   │   ├── hotel_schema.rb
│   │   ├── involvement_schema.rb
│   │   ├── location_schema.rb
│   │   ├── maps_schema.rb
│   │   ├── schedule_schema.rb
│   │   ├── series_schema.rb
│   │   ├── speaker_schema.rb
│   │   ├── sponsors_schema.rb
│   │   ├── transcript_schema.rb
│   │   ├── venue_schema.rb
│   │   └── video_schema.rb
│   ├── serializers/
│   │   └── transcript_serializer.rb
│   ├── tools/
│   │   ├── cfp_create_tool.rb
│   │   ├── cfp_info_tool.rb
│   │   ├── cfp_update_tool.rb
│   │   ├── event_create_tool.rb
│   │   ├── event_lookup_tool.rb
│   │   ├── event_series_create_tool.rb
│   │   ├── event_series_events_tool.rb
│   │   ├── event_series_lookup_tool.rb
│   │   ├── event_talks_tool.rb
│   │   ├── geocode_tool.rb
│   │   ├── github_profile_tool.rb
│   │   ├── speaker_lookup_tool.rb
│   │   ├── speaker_talks_tool.rb
│   │   ├── speakerdeck_deck_tool.rb
│   │   ├── speakerdeck_user_decks_tool.rb
│   │   ├── venue_create_tool.rb
│   │   ├── vimeo_video_tool.rb
│   │   ├── youtube_channel_videos_tool.rb
│   │   ├── youtube_playlist_items_tool.rb
│   │   ├── youtube_playlist_tool.rb
│   │   ├── youtube_video_tool.rb
│   │   └── youtube_videos_tool.rb
│   └── views/
│       ├── admin/
│       │   └── suggestions/
│       │       ├── _suggestion.html.erb
│       │       └── index.html.erb
│       ├── analytics/
│       │   └── dashboards/
│       │       ├── daily_page_views.html.erb
│       │       ├── daily_visits.html.erb
│       │       ├── monthly_page_views.html.erb
│       │       ├── monthly_visits.html.erb
│       │       ├── show.html.erb
│       │       ├── top_landing_pages.html.erb
│       │       ├── top_referrers.html.erb
│       │       ├── top_searches.html.erb
│       │       ├── yearly_conferences.html.erb
│       │       └── yearly_talks.html.erb
│       ├── announcements/
│       │   ├── feed.rss.builder
│       │   ├── index.html.erb
│       │   └── show.html.erb
│       ├── avo/
│       │   └── cards/
│       │       ├── _duplicates_summary.html.erb
│       │       ├── _reversed_name_duplicates_list.html.erb
│       │       ├── _same_name_duplicates_list.html.erb
│       │       ├── _suspicious_signals_breakdown.html.erb
│       │       ├── _suspicious_summary.html.erb
│       │       ├── _suspicious_users_list.html.erb
│       │       ├── _unavailable_videos_by_event.html.erb
│       │       ├── _unavailable_videos_list.html.erb
│       │       └── _unavailable_videos_summary.html.erb
│       ├── browse/
│       │   ├── _content_row.html.erb
│       │   ├── _content_row_skeleton.html.erb
│       │   ├── _featured_events.html.erb
│       │   ├── _kind_row.html.erb
│       │   ├── _topic_row.html.erb
│       │   ├── index.html.erb
│       │   └── sections/
│       │       ├── _beginner_friendly.html.erb
│       │       ├── _continue_watching.html.erb
│       │       ├── _deep_dives.html.erb
│       │       ├── _event_rows.html.erb
│       │       ├── _events_attended.html.erb
│       │       ├── _evergreen.html.erb
│       │       ├── _favorite_rubyists.html.erb
│       │       ├── _favorite_speakers.html.erb
│       │       ├── _featured_events.html.erb
│       │       ├── _for_you.html.erb
│       │       ├── _from_bookmarks.html.erb
│       │       ├── _hidden_gems.html.erb
│       │       ├── _inspiring.html.erb
│       │       ├── _language_rows.html.erb
│       │       ├── _mind_blowing.html.erb
│       │       ├── _most_bookmarked.html.erb
│       │       ├── _most_liked.html.erb
│       │       ├── _newest_talks.html.erb
│       │       ├── _popular.html.erb
│       │       ├── _popular_topics.html.erb
│       │       ├── _popular_youtube.html.erb
│       │       ├── _quick_watches.html.erb
│       │       ├── _recently_published.html.erb
│       │       ├── _recommended_community.html.erb
│       │       ├── _talk_kinds.html.erb
│       │       ├── _topic_rows.html.erb
│       │       ├── _trending.html.erb
│       │       └── _unwatched_attended.html.erb
│       ├── cfp/
│       │   ├── _event_list.html.erb
│       │   └── index.html.erb
│       ├── cities/
│       │   ├── index.html.erb
│       │   ├── map/
│       │   │   └── index.html.erb
│       │   ├── meetups/
│       │   │   └── index.html.erb
│       │   ├── past/
│       │   │   └── index.html.erb
│       │   ├── show.html.erb
│       │   ├── stamps/
│       │   │   └── index.html.erb
│       │   └── users/
│       │       └── index.html.erb
│       ├── continents/
│       │   ├── countries/
│       │   │   └── index.html.erb
│       │   ├── index.html.erb
│       │   ├── map/
│       │   │   └── index.html.erb
│       │   ├── past/
│       │   │   └── index.html.erb
│       │   ├── show.html.erb
│       │   ├── stamps/
│       │   │   └── index.html.erb
│       │   └── users/
│       │       └── index.html.erb
│       ├── contributions/
│       │   ├── _events_without_dates.html.erb
│       │   ├── _events_without_location.html.erb
│       │   ├── _events_without_videos.html.erb
│       │   ├── _introduction.html.erb
│       │   ├── _missing_videos_cue.html.erb
│       │   ├── _speakers_without_github.html.erb
│       │   ├── _talks_dates_out_of_bounds.html.erb
│       │   ├── _talks_without_slides.html.erb
│       │   ├── index.html.erb
│       │   └── show.html.erb
│       ├── coordinates/
│       │   ├── index.html.erb
│       │   ├── map/
│       │   │   └── index.html.erb
│       │   ├── past/
│       │   │   └── index.html.erb
│       │   ├── show.html.erb
│       │   └── users/
│       │       └── index.html.erb
│       ├── countries/
│       │   ├── cities/
│       │   │   └── index.html.erb
│       │   ├── index.html.erb
│       │   ├── map/
│       │   │   └── index.html.erb
│       │   ├── meetups/
│       │   │   └── index.html.erb
│       │   ├── past/
│       │   │   └── index.html.erb
│       │   ├── show.html.erb
│       │   ├── stamps/
│       │   │   └── index.html.erb
│       │   ├── state.html.erb
│       │   └── users/
│       │       └── index.html.erb
│       ├── event_participations/
│       │   ├── create.turbo_stream.erb
│       │   └── destroy.turbo_stream.erb
│       ├── events/
│       │   ├── _card.html.erb
│       │   ├── _event.html.erb
│       │   ├── _event_list.html.erb
│       │   ├── _featured.html.erb
│       │   ├── _featured_card.html.erb
│       │   ├── _featured_card_list.html.erb
│       │   ├── _featured_home.html.erb
│       │   ├── _form.html.erb
│       │   ├── _header.html.erb
│       │   ├── _my_attendance.html.erb
│       │   ├── _my_attendance_day.html.erb
│       │   ├── _my_attendance_talk.html.erb
│       │   ├── _navigation.html.erb
│       │   ├── _participation_button.html.erb
│       │   ├── _plain_list.html.erb
│       │   ├── archive/
│       │   │   └── index.html.erb
│       │   ├── attendances/
│       │   │   ├── index.html.erb
│       │   │   └── show.html.erb
│       │   ├── cfp/
│       │   │   └── index.html.erb
│       │   ├── collectibles/
│       │   │   └── index.html.erb
│       │   ├── edit.html.erb
│       │   ├── events/
│       │   │   ├── index.html.erb
│       │   │   └── show.html.erb
│       │   ├── index.html.erb
│       │   ├── involvements/
│       │   │   ├── _list.html.erb
│       │   │   └── index.html.erb
│       │   ├── meetups/
│       │   │   └── index.html.erb
│       │   ├── new.html.erb
│       │   ├── participants/
│       │   │   ├── _list.html.erb
│       │   │   └── index.html.erb
│       │   ├── past/
│       │   │   └── index.html.erb
│       │   ├── related_talks/
│       │   │   ├── _list.html.erb
│       │   │   └── index.html.erb
│       │   ├── schedules/
│       │   │   ├── _day.html.erb
│       │   │   ├── _schedule.html.erb
│       │   │   ├── index.html.erb
│       │   │   ├── missing_schedule.html.erb
│       │   │   └── show.html.erb
│       │   ├── series/
│       │   │   ├── _card.html.erb
│       │   │   ├── index.html.erb
│       │   │   └── show.html.erb
│       │   ├── show.html.erb
│       │   ├── speakers/
│       │   │   └── index.html.erb
│       │   ├── sponsors/
│       │   │   └── index.html.erb
│       │   ├── talks/
│       │   │   └── index.html.erb
│       │   ├── tickets/
│       │   │   └── show.html.erb
│       │   ├── todos/
│       │   │   └── index.html.erb
│       │   ├── venues/
│       │   │   ├── missing_venue.html.erb
│       │   │   └── show.html.erb
│       │   ├── videos/
│       │   │   └── index.html.erb
│       │   └── years/
│       │       ├── _desktop_calendar.html.erb
│       │       ├── _event_hover_card.html.erb
│       │       ├── _header.html.erb
│       │       ├── _mobile_calendar.html.erb
│       │       ├── _yearly_events.html.erb
│       │       └── index.html.erb
│       ├── favorite_users/
│       │   ├── _favorite_user.html.erb
│       │   ├── _form.html.erb
│       │   ├── _list.html.erb
│       │   ├── _no_favorites.html.erb
│       │   └── index.html.erb
│       ├── gems/
│       │   ├── _gem_card.html.erb
│       │   ├── index.html.erb
│       │   ├── index.turbo_stream.erb
│       │   ├── show.html.erb
│       │   ├── talks.html.erb
│       │   └── talks.turbo_stream.erb
│       ├── home/
│       │   └── index.html.erb
│       ├── hover_cards/
│       │   ├── events/
│       │   │   ├── _content.html.erb
│       │   │   └── show.html.erb
│       │   └── users/
│       │       ├── _content.html.erb
│       │       └── show.html.erb
│       ├── identity/
│       │   ├── emails/
│       │   │   └── edit.html.erb
│       │   └── password_resets/
│       │       ├── edit.html.erb
│       │       └── new.html.erb
│       ├── layouts/
│       │   ├── application.html.erb
│       │   ├── application.turbo_stream.erb
│       │   ├── mailer.html.erb
│       │   ├── mailer.text.erb
│       │   ├── modal.html.erb
│       │   ├── turbo_rails/
│       │   │   └── frame.turbo_stream.erb
│       │   └── wrapped.html.erb
│       ├── leaderboard/
│       │   ├── _speaker.html.erb
│       │   └── index.html.erb
│       ├── online/
│       │   ├── past/
│       │   │   └── index.html.erb
│       │   └── show.html.erb
│       ├── organizations/
│       │   ├── _card.html.erb
│       │   ├── _compact_card.html.erb
│       │   ├── _header.html.erb
│       │   ├── _navigation.html.erb
│       │   ├── _organization.html.erb
│       │   ├── index.html.erb
│       │   ├── logos/
│       │   │   └── show.html.erb
│       │   ├── show.html.erb
│       │   └── wrapped/
│       │       ├── index.html.erb
│       │       └── pages/
│       │           └── _summary_card_horizontal.html.erb
│       ├── page/
│       │   ├── about.md
│       │   ├── assets.html.erb
│       │   ├── components/
│       │   │   ├── _avatars.html.erb
│       │   │   ├── _buttons.html.erb
│       │   │   ├── _dropdowns.html.erb
│       │   │   ├── _links.html.erb
│       │   │   ├── _modals.html.erb
│       │   │   ├── _stamps.html.erb
│       │   │   ├── _tabs.html.erb
│       │   │   └── _tooltips.html.erb
│       │   ├── components.html.erb
│       │   ├── contributors.html.erb
│       │   ├── featured.html.erb
│       │   ├── home.html.erb
│       │   ├── privacy.md
│       │   ├── stickers.html.erb
│       │   └── uses.md
│       ├── profiles/
│       │   ├── _actions.html.erb
│       │   ├── _aliases.html.erb
│       │   ├── _events.html.erb
│       │   ├── _form.html.erb
│       │   ├── _header.html.erb
│       │   ├── _header_content.html.erb
│       │   ├── _involvements.html.erb
│       │   ├── _map.html.erb
│       │   ├── _mutual_events.html.erb
│       │   ├── _navigation.html.erb
│       │   ├── _notes.html.erb
│       │   ├── _socials.html.erb
│       │   ├── _stamps.html.erb
│       │   ├── _stickers.html.erb
│       │   ├── _tab_layout.html.erb
│       │   ├── _talks.html.erb
│       │   ├── _topics.html.erb
│       │   ├── actions/
│       │   │   ├── _admin.html.erb
│       │   │   ├── _anonymous.html.erb
│       │   │   ├── _owner.html.erb
│       │   │   └── _signed_in.html.erb
│       │   ├── aliases/
│       │   │   └── index.html.erb
│       │   ├── connect/
│       │   │   ├── _claim_profile.html.erb
│       │   │   ├── _friend_prompt.html.erb
│       │   │   ├── _no_profile_found.html.erb
│       │   │   └── show.html.erb
│       │   ├── edit.html.erb
│       │   ├── enhance/
│       │   │   └── update.turbo_stream.erb
│       │   ├── events/
│       │   │   └── index.html.erb
│       │   ├── involvements/
│       │   │   └── index.html.erb
│       │   ├── map/
│       │   │   └── index.html.erb
│       │   ├── mutual_events/
│       │   │   └── index.html.erb
│       │   ├── notes/
│       │   │   ├── edit.html.erb
│       │   │   └── show.html.erb
│       │   ├── show.html.erb
│       │   ├── stamps/
│       │   │   └── index.html.erb
│       │   ├── stickers/
│       │   │   └── index.html.erb
│       │   ├── talks/
│       │   │   └── index.html.erb
│       │   └── wrapped/
│       │       ├── _share.html.erb
│       │       ├── card.html.erb
│       │       ├── index.html.erb
│       │       ├── pages/
│       │       │   ├── _bookends.html.erb
│       │       │   ├── _closing.html.erb
│       │       │   ├── _conference_buddies.html.erb
│       │       │   ├── _content_mix.html.erb
│       │       │   ├── _contributor.html.erb
│       │       │   ├── _cover.html.erb
│       │       │   ├── _event_map.html.erb
│       │       │   ├── _events_attended.html.erb
│       │       │   ├── _fun_facts.html.erb
│       │       │   ├── _involvements.html.erb
│       │       │   ├── _languages.html.erb
│       │       │   ├── _og_image.html.erb
│       │       │   ├── _passport_holder.html.erb
│       │       │   ├── _speaker_journey.html.erb
│       │       │   ├── _speaking_calendar.html.erb
│       │       │   ├── _stamps.html.erb
│       │       │   ├── _stickers.html.erb
│       │       │   ├── _summary_card.html.erb
│       │       │   ├── _summary_card_horizontal.html.erb
│       │       │   ├── _top_events.html.erb
│       │       │   ├── _top_speakers.html.erb
│       │       │   ├── _top_topics.html.erb
│       │       │   ├── _watch_twin.html.erb
│       │       │   ├── _watching_calendar.html.erb
│       │       │   └── _watching_journey.html.erb
│       │       └── private.html.erb
│       ├── recommendations/
│       │   └── index.html.erb
│       ├── sessions/
│       │   └── new.html.erb
│       ├── settings/
│       │   └── show.html.erb
│       ├── shared/
│       │   ├── _breakpoints.html.erb
│       │   ├── _cfp_countdown_badge.html.erb
│       │   ├── _city_sidebar.html.erb
│       │   ├── _country_card.html.erb
│       │   ├── _date_grouped_events.html.erb
│       │   ├── _event_countdown_badge.html.erb
│       │   ├── _event_row.html.erb
│       │   ├── _events_section.html.erb
│       │   ├── _filter_buttons.html.erb
│       │   ├── _flashes.html.erb
│       │   ├── _footer.html.erb
│       │   ├── _location_header.html.erb
│       │   ├── _location_map.html.erb
│       │   ├── _location_meetups.html.erb
│       │   ├── _location_navigation.html.erb
│       │   ├── _location_past.html.erb
│       │   ├── _location_show.html.erb
│       │   ├── _location_sidebar.html.erb
│       │   ├── _location_stamps.html.erb
│       │   ├── _location_users.html.erb
│       │   ├── _map_layer_controls.html.erb
│       │   ├── _map_time_filter.html.erb
│       │   ├── _meta_talk_card.html.erb
│       │   ├── _month_grouped_events.html.erb
│       │   ├── _navbar.html.erb
│       │   ├── _nearby_events_section.html.erb
│       │   ├── _rubyists_preview.html.erb
│       │   ├── _spotlight_search.html.erb
│       │   ├── _stamps_grid.html.erb
│       │   ├── _stickers_display.html.erb
│       │   ├── _toast.html.erb
│       │   ├── _top_banner.html.erb
│       │   ├── _user_dropdown.html.erb
│       │   ├── _user_mobile_dropdown.html.erb
│       │   └── navbar/
│       │       ├── _link.html.erb
│       │       └── _search_bar.html.erb
│       ├── speakers/
│       │   ├── _card.html.erb
│       │   ├── _speaker.html.erb
│       │   ├── _speaker.json.jbuilder
│       │   ├── index.html.erb
│       │   ├── index.json.jbuilder
│       │   ├── index.turbo_stream.erb
│       │   └── show.html.erb
│       ├── sponsors/
│       │   └── missing/
│       │       └── index.html.erb
│       ├── spotlight/
│       │   ├── events/
│       │   │   ├── _event.html.erb
│       │   │   └── index.turbo_stream.erb
│       │   ├── kinds/
│       │   │   └── index.turbo_stream.erb
│       │   ├── languages/
│       │   │   └── index.turbo_stream.erb
│       │   ├── locations/
│       │   │   └── index.turbo_stream.erb
│       │   ├── organizations/
│       │   │   └── index.turbo_stream.erb
│       │   ├── series/
│       │   │   └── index.turbo_stream.erb
│       │   ├── speakers/
│       │   │   ├── _speaker.html.erb
│       │   │   └── index.turbo_stream.erb
│       │   ├── talks/
│       │   │   ├── _talk.html.erb
│       │   │   └── index.turbo_stream.erb
│       │   └── topics/
│       │       └── index.turbo_stream.erb
│       ├── stamps/
│       │   └── index.html.erb
│       ├── states/
│       │   ├── cities/
│       │   │   └── index.html.erb
│       │   ├── country_index.html.erb
│       │   ├── index.html.erb
│       │   ├── map/
│       │   │   └── index.html.erb
│       │   ├── meetups/
│       │   │   └── index.html.erb
│       │   ├── past/
│       │   │   └── index.html.erb
│       │   ├── show.html.erb
│       │   ├── stamps/
│       │   │   └── index.html.erb
│       │   └── users/
│       │       └── index.html.erb
│       ├── talks/
│       │   ├── _card.html.erb
│       │   ├── _card_horizontal.html.erb
│       │   ├── _card_thumbnail.html.erb
│       │   ├── _event.html.erb
│       │   ├── _event_tab.html.erb
│       │   ├── _explore_event.html.erb
│       │   ├── _form.html.erb
│       │   ├── _schedule_tab.html.erb
│       │   ├── _sections.html.erb
│       │   ├── _similar_talks_tab.html.erb
│       │   ├── _speaker_tab.html.erb
│       │   ├── _talk.html.erb
│       │   ├── _talk_filter.html.erb
│       │   ├── _transcript.html.erb
│       │   ├── _video_player.html.erb
│       │   ├── edit.html.erb
│       │   ├── index.html.erb
│       │   ├── index.json.jbuilder
│       │   ├── new.html.erb
│       │   ├── recommendations/
│       │   │   └── index.html.erb
│       │   ├── show.html.erb
│       │   ├── show.json.jbuilder
│       │   ├── slides/
│       │   │   └── show.html.erb
│       │   ├── video_providers/
│       │   │   ├── _children.html.erb
│       │   │   ├── _mp4.html.erb
│       │   │   ├── _not_published.html.erb
│       │   │   ├── _not_recorded.html.erb
│       │   │   ├── _scheduled.html.erb
│       │   │   ├── _video_unavailable.html.erb
│       │   │   ├── _vimeo.html.erb
│       │   │   └── _youtube.html.erb
│       │   └── watched_talks/
│       │       ├── _button.html.erb
│       │       ├── _feedback_banner.html.erb
│       │       ├── _feedback_questions.html.erb
│       │       ├── _form.html.erb
│       │       ├── _watched_overlay.html.erb
│       │       ├── _where_watched.html.erb
│       │       ├── create.turbo_stream.erb
│       │       ├── destroy.turbo_stream.erb
│       │       ├── new.html.erb
│       │       ├── toggle_attendance.turbo_stream.erb
│       │       └── update.turbo_stream.erb
│       ├── templates/
│       │   ├── _talk_fields.html.erb
│       │   ├── create.turbo_stream.erb
│       │   ├── delete_child.turbo_stream.erb
│       │   ├── new.html.erb
│       │   ├── new_child.turbo_stream.erb
│       │   └── speakers_search.turbo_stream.erb
│       ├── todos/
│       │   ├── _by_event.html.erb
│       │   ├── _by_type.html.erb
│       │   └── index.html.erb
│       ├── topics/
│       │   ├── _badge.html.erb
│       │   ├── _badge_list.html.erb
│       │   ├── _gem_info.html.erb
│       │   ├── _talks_cursor.html.erb
│       │   ├── _topic.html.erb
│       │   ├── index.html.erb
│       │   ├── index.turbo_stream.erb
│       │   ├── show.html.erb
│       │   └── show.turbo_stream.erb
│       ├── users/
│       │   └── _card.html.erb
│       ├── watch_lists/
│       │   ├── _watch_list.html.erb
│       │   ├── edit.html.erb
│       │   ├── index.html.erb
│       │   ├── new.html.erb
│       │   └── show.html.erb
│       ├── watched_talks/
│       │   └── index.html.erb
│       └── wrapped/
│           ├── _card.html.erb
│           ├── _featured.html.erb
│           └── index.html.erb
├── bin/
│   ├── brakeman
│   ├── bundle
│   ├── bundler-audit
│   ├── ci
│   ├── dev
│   ├── docker-entrypoint
│   ├── dump_prod.sh
│   ├── jobs
│   ├── lint
│   ├── mcp_server
│   ├── rails
│   ├── rake
│   ├── rubocop
│   ├── setup
│   ├── thrust
│   ├── update_lrug_meetups
│   └── vite
├── config/
│   ├── application.rb
│   ├── appsignal.yml
│   ├── boot.rb
│   ├── bundler-audit.yml
│   ├── cable.yml
│   ├── cache.yml
│   ├── ci.rb
│   ├── credentials/
│   │   ├── development.key
│   │   ├── development.yml.enc
│   │   ├── production.yml.enc
│   │   ├── staging.yml.enc
│   │   ├── test.key
│   │   └── test.yml.enc
│   ├── database.yml
│   ├── deploy.staging.yml
│   ├── deploy.yml
│   ├── environment.rb
│   ├── environments/
│   │   ├── development.rb
│   │   ├── production.rb
│   │   ├── staging.rb
│   │   └── test.rb
│   ├── initializers/
│   │   ├── active_genie.rb
│   │   ├── ahoy.rb
│   │   ├── assets.rb
│   │   ├── avo.rb
│   │   ├── content_security_policy.rb
│   │   ├── filter_parameter_logging.rb
│   │   ├── geocoder.rb
│   │   ├── groupe_date.rb
│   │   ├── inflections.rb
│   │   ├── locale.rb
│   │   ├── markdown.rb
│   │   ├── meta_tags.rb
│   │   ├── omniauth.rb
│   │   ├── openai.rb
│   │   ├── pagy.rb
│   │   ├── permissions_policy.rb
│   │   ├── reactionview.rb
│   │   ├── ruby_llm.rb
│   │   ├── typesense.rb
│   │   ├── yjit.rb
│   │   └── yt.rb
│   ├── litestream.staging.yml
│   ├── litestream.yml
│   ├── locales/
│   │   ├── en.yml
│   │   ├── models/
│   │   │   └── event_participation.en.yml
│   │   └── transliterate.en.yml
│   ├── puma.rb
│   ├── queue.yml
│   ├── recurring.yml
│   ├── routes.rb
│   ├── storage.yml
│   └── vite.json
├── config.ru
├── content/
│   └── announcements/
│       ├── 2026-01-01-happy-new-year-2026.md
│       ├── 2026-01-21-introducing-web-components.md
│       ├── 2026-01-22-announcements-and-news.md
│       ├── 2026-03-01-february-newsletter.md
│       └── 2026-04-01-march-newsletter.md
├── data/
│   ├── acts-as-conference/
│   │   ├── acts-as-conference-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── acts-as-conference-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── african-ruby-community/
│   │   ├── african-ruby-mini-conference-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── akashi-rb/
│   │   ├── akashi-rb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── aloha-on-rails/
│   │   ├── aloha-on-rails-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── aloha-rubyconf/
│   │   ├── aloha-rubyconf-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── amsterdam-rb/
│   │   ├── amsterdam-rb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ancient-city-ruby/
│   │   ├── ancient-city-ruby-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ancient-city-ruby-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ancient-city-ruby-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ancient-city-ruby-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ancient-city-ruby-2019/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── arrrrcamp/
│   │   ├── arrrrcamp-2009-may/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── arrrrcamp-2009-october/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── arrrrcamp-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── arrrrcamp-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── arrrrcamp-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── arrrrcamp-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── arrrrcamp-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── arrrrcamp-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── artificialruby/
│   │   ├── artificialruby/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── austinrb/
│   │   ├── austinrb/
│   │   │   ├── cfp.yml
│   │   │   └── event.yml
│   │   └── series.yml
│   ├── balkanruby/
│   │   ├── balkanruby-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── balkanruby-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── balkanruby-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── balkanruby-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── balkanruby-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── balkanruby-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── balticruby/
│   │   ├── balticruby-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── balticruby-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── balticruby-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── bangkok-rb/
│   │   ├── ruby-tuesday/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── barcelona-rb/
│   │   ├── barcelona-rb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── baruco/
│   │   ├── barcelona-ruby-conf-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── barcelona-ruby-conf-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── barcelona-ruby-conf-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── barcelona-ruby-conf-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── bathruby/
│   │   ├── bathruby-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── bathruby-2016/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── bathruby-2018/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── belfastruby/
│   │   ├── belfast-rubyfest-2026/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── belfastruby-meetup/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── big-ruby/
│   │   ├── big-ruby-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── big-ruby-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── birmingham-on-rails/
│   │   ├── birmingham-on-rails-2020/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── blastoffrails/
│   │   ├── blastoffrails-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── blue-ridge-ruby/
│   │   ├── blue-ridge-ruby-2023/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── blue-ridge-ruby-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── blue-ridge-ruby-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── bluegrass-ruby/
│   │   ├── bluegrass-ruby/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── bridgetownconf/
│   │   ├── bridgetownconf-2022/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── brightonruby/
│   │   ├── brightonruby-2014/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2015/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2016/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2017/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2018/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2019/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2020/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2022/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2023/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── burlington-ruby-conference/
│   │   ├── burlington-ruby-conference-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── burlington-ruby-conference-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── burlington-ruby-conference-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── burlington-ruby-conference-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── cascadia-ruby/
│   │   ├── cascadia-ruby-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── cascadia-ruby-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── cascadia-ruby-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ceru-camp/
│   │   ├── ceru-camp-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── chicagoruby/
│   │   ├── chicagoruby/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── conferencia-rails/
│   │   ├── conferencia-rails-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── conferencia-rails-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── conferencia-rails-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── deccan-queen-on-rails/
│   │   ├── deccan-queen-on-rails-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── deccanrubyconf/
│   │   ├── deccanrubyconf-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── deccanrubyconf-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── deccanrubyconf-2016/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   └── videos.yml
│   │   ├── deccanrubyconf-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── deccanrubyconf-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── deccanrubyconf-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── dotrb/
│   │   ├── dotrb-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── dresden-rb/
│   │   ├── dresden-rb-meetup/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── emea-on-rails/
│   │   ├── emea-on-rails-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── erubycon/
│   │   ├── erubycon-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── eurucamp/
│   │   ├── eurucamp-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── eurucamp-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── euruko/
│   │   ├── euruko-2003/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2004/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2005/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2006/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2007/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2019/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2022/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2023/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2024/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2026/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── noruko-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── featured_cities.yml
│   ├── fosdem/
│   │   ├── ruby-devroom-at-fosdem-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-devroom-at-fosdem-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-devroom-at-fosdem-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-devroom-at-fosdem-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── friendly-rb/
│   │   ├── friendly-rb-2023/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── friendly-rb-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── friendly-rb-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── frozen-rails/
│   │   ├── frozen-rails-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── frozen-rails-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── frozen-rails-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── frozen-rails-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── fukuoka-rubyistkaigi/
│   │   ├── fukuoka-rubyistkaigi-03/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── fukuoka-rubyistkaigi-04/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── fukuoka-rubyistkaigi-05/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── fukuoka-rubykaigi-01/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── fukuoka-rubykaigi-02/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── garden-city-ruby/
│   │   ├── garden-city-ruby-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── garden-city-ruby-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── geneva-rb/
│   │   ├── geneva-rb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── gogaruco/
│   │   ├── gogaruco-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── gogaruco-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── gogaruco-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── gogaruco-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── gogaruco-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── gogaruco-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── goruco/
│   │   ├── goruco-2007/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2010/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2011/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── grill-rb/
│   │   ├── grill-rb-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── grill-rb-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── grill-rb-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── grill-rb-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── guru-pr/
│   │   ├── series.yml
│   │   └── tech-day-by-guru-pr-2016/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── haggis-ruby/
│   │   ├── haggis-ruby-2024/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── haggis-ruby-2026/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── helsinki-ruby/
│   │   ├── helsinki-ruby-brigade/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── helveticruby/
│   │   ├── helveticruby-2023/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── helveticruby-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── helveticruby-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── helveticruby-2026/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── hirakatarb/
│   │   ├── hirakatarb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── hokuriku-rubykaigi/
│   │   ├── hokuriku-rubykaigi-01/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── isle-of-ruby/
│   │   ├── isle-of-ruby-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── jrubyconf-eu/
│   │   ├── jrubyconf-eu-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── jrubyconf-eu-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── jrubyconf-eu-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── jrubyconf-eu-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── kaigi-on-rails/
│   │   ├── kaigi-on-rails-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── kaigi-on-rails-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── kaigi-on-rails-2022/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── kaigi-on-rails-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── kaigi-on-rails-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── kaigi-on-rails-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── kaigi-on-rails-2026/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── kansai-rubykaigi/
│   │   ├── kansai-rubykaigi-08/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── kansai-rubykaigi-09/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── kashiwarb/
│   │   ├── kashiwarb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── keeprubyweird/
│   │   ├── keep-ruby-weird-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── keep-ruby-weird-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── keep-ruby-weird-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── keep-ruby-weird-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── keep-ruby-weird-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── kiwi-ruby/
│   │   ├── kiwi-ruby-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── kiwi-ruby-2019/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── koberb/
│   │   ├── koberb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── krk-rb/
│   │   ├── krk-rb-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── kyobashirb/
│   │   ├── kyobashirb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── kyotorb/
│   │   ├── kyotorb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── la-conf/
│   │   └── series.yml
│   ├── la-rubyconf/
│   │   ├── la-rubyconf-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── la-rubyconf-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── la-rubyconf-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── la-rubyconf-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── la-rubyconf-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── la-rubyconf-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── la-rubyconf-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── latvian-ruby-community/
│   │   ├── latviarb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── london-ruby-unconference/
│   │   ├── london-ruby-unconference-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── london-ruby-unconference-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── london-ruby-unconference-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── lone-star-ruby-conf/
│   │   ├── lone-star-ruby-conf-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── lone-star-ruby-conf-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── lone-star-ruby-conf-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── lone-star-ruby-conf-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── lone-star-ruby-conf-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── lone-star-ruby-conf-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── lone-star-ruby-conf-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── lrug/
│   │   ├── lrug-meetup/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── lyon-rb/
│   │   ├── lyon-rb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── madison-ruby/
│   │   ├── madison-ruby-2011/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── madison-ruby-2012/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── madison-ruby-2013/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── madison-ruby-2014/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── madison-ruby-2015/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── madison-ruby-2016/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── madison-ruby-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── madison-ruby-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── madrid-rb/
│   │   ├── madrid-rb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── magic-ruby/
│   │   ├── magic-ruby-2011/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── magic-ruby-2012/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── matsue-rubykaigi/
│   │   ├── matsue-rubykaigi-01/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-02/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-03/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-04/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-05/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-06/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-07/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-08/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-09/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-10/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-11/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-12/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── merseyrails/
│   │   ├── merseyrails/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── montreal-rb/
│   │   ├── montreal-rb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── mountainwest-rubyconf/
│   │   ├── mountainwest-rubyconf-2007/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── mountainwest-rubyconf-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── mountainwest-rubyconf-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── mountainwest-rubyconf-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── mountainwest-rubyconf-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── mountainwest-rubyconf-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── mountainwest-rubyconf-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── mountainwest-rubyconf-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── mountainwest-rubyconf-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── mountainwest-rubyconf-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── munich-rubyshift/
│   │   ├── munich-rubyshift/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── nairuby/
│   │   ├── rubyconf-kenya-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-kenya-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-kenya-2017/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-kenya-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-kenya-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── naniwarb/
│   │   ├── naniwarb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── picorubyoverflowkaigi-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── nantes-rb/
│   │   ├── nantes-rb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── nepal-ruby/
│   │   ├── nepal-ruby-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── nickel-city-ruby/
│   │   ├── nickel-city-ruby-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── nickel-city-ruby-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── nordicruby/
│   │   ├── nordicruby-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── nordicruby-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── nordicruby-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── nordicruby-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── nordicruby-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── oedo-rubykaigi/
│   │   ├── oedo-rubykaigi-01/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── oedo-rubykaigi-02/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── oedo-rubykaigi-03/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── oedo-rubykaigi-04/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── osaka-rubykaigi/
│   │   ├── osaka-rubykaigi-01/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── osaka-rubykaigi-02/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── osaka-rubykaigi-03/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── osaka-rubykaigi-04/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── oxente-rails/
│   │   ├── oxente-rails-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── paris-rb/
│   │   ├── paris-rb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── paris-rb-conf/
│   │   ├── paris-rb-conf-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── paris-rb-conf-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── philly-rb/
│   │   ├── philly-rb/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── pivorak/
│   │   ├── pivorak-conf-1/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── pivorak-conf-2/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── pivorak-conf-3/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── pivorak-conf-4/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── pivorak-conf-5/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── polishrubyusergroup/
│   │   ├── ruby-warsaw-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── poznanrubyusergroup/
│   │   ├── poznan-ruby-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-at-scale-summit/
│   │   ├── rails-at-scale-summit-2025/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rails-at-scale-summit-2026/
│   │   │   └── event.yml
│   │   └── series.yml
│   ├── rails-camp-south/
│   │   ├── rails-camp-south-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-camp-uk/
│   │   ├── rails-camp-uk-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-camp-us/
│   │   ├── rails-camp-us-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-camp-west/
│   │   ├── rails-camp-west-2022/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rails-camp-west-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rails-camp-west-2024/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rails-camp-west-2025/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rails-camp-west-2026/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── venue.yml
│   │   └── series.yml
│   ├── rails-girls-sao-paulo/
│   │   ├── rails-girls-sao-paulo-evolution-2026/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   └── venue.yml
│   │   └── series.yml
│   ├── rails-hackathon/
│   │   ├── rails-hackathon-community/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rails-hackathon-hotwire/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-israel/
│   │   ├── rails-israel-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rails-israel-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rails-israel-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rails-israel-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-konferenz/
│   │   ├── rails-konferenz-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-outreach-workshop/
│   │   ├── rails-outreach-workshop-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-pacific/
│   │   ├── rails-pacific-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rails-pacific-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-remote-conf/
│   │   ├── rails-remote-conf-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-saas-conference/
│   │   ├── rails-saas-conference-2022/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rails-saas-conference-2023/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-studio/
│   │   ├── rails-studio-2006-pasadena/
│   │   │   └── event.yml
│   │   ├── rails-studio-portland/
│   │   │   └── event.yml
│   │   └── series.yml
│   ├── rails-summit-latin-america/
│   │   ├── rails-summit-latin-america-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-to-italy/
│   │   └── series.yml
│   ├── rails-underground/
│   │   ├── rails-underground-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-world/
│   │   ├── rails-world-2023/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rails-world-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rails-world-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rails-world-2026/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── railsberry/
│   │   ├── railsberry-2012/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── railsclub/
│   │   ├── railsclub-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsclub-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsclub-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsclub-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── railsconf/
│   │   ├── railsconf-2006/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2007/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2022/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2023/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── railsconf-europe/
│   │   ├── railsconf-europe-2006/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-europe-2007/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-europe-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── railswaycon/
│   │   ├── railswaycon-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railswaycon-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railswaycon-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railswaycon-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rbqconf/
│   │   ├── rbqconf-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── red-dirt-rubyconf/
│   │   ├── red-dirt-rubyconf-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── red-dirt-rubyconf-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── red-dot-ruby-conference/
│   │   ├── red-dot-ruby-conference-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── red-dot-ruby-conference-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── red-dot-ruby-conference-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── red-dot-ruby-conference-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── red-dot-ruby-conference-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── red-dot-ruby-conference-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── red-dot-ruby-conference-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── red-dot-ruby-conference-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── redfrogconf/
│   │   ├── redfrogconf-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rocky-mountain-ruby/
│   │   ├── rocky-mountain-ruby-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2026/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── venue.yml
│   │   └── series.yml
│   ├── rossconf/
│   │   ├── rossconf-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rossconf-2015-berlin/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rossconf-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rossconf-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rs-on-rails/
│   │   ├── rs-on-rails-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-argentina/
│   │   ├── rubysur-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-australia/
│   │   ├── ruby-australia-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-banitsa/
│   │   ├── ruby-banitsa-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-banitsa-conf/
│   │   ├── ruby-banitsa-conf-2024/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-community-conference/
│   │   ├── ruby-community-conference-summer-edition-2023/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── ruby-community-conference-summer-edition-2024/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── ruby-community-conference-winter-edition-2024/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── ruby-community-conference-winter-edition-2025/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── ruby-community-conference-winter-edition-2026/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-cwb/
│   │   ├── ruby-cwb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-dcamp/
│   │   ├── ruby-dcamp-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-dev-summit/
│   │   ├── ruby-dev-summit-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-df/
│   │   ├── ruby-df-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-foo/
│   │   ├── ruby-foo-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-for-good/
│   │   ├── ruby-for-good-2016/
│   │   │   └── event.yml
│   │   ├── ruby-for-good-2020/
│   │   │   └── event.yml
│   │   ├── ruby-for-good-2023/
│   │   │   └── event.yml
│   │   ├── ruby-for-good-2024/
│   │   │   ├── event.yml
│   │   │   └── venue.yml
│   │   ├── ruby-for-good-2025/
│   │   │   └── event.yml
│   │   ├── ruby-for-good-belgium-2025/
│   │   │   └── event.yml
│   │   ├── ruby-for-good-belgium-2026/
│   │   │   ├── event.yml
│   │   │   └── venue.yml
│   │   └── series.yml
│   ├── ruby-frankfurt/
│   │   ├── ruby-frankfurt/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-fringe/
│   │   ├── futureruby-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyfringe-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-galaxy/
│   │   ├── ruby-galaxy-v01/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-galaxy-v02/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-galaxy-v03/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-galaxy-v04/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-galaxy-v05/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-galaxy-v06/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-hoedown/
│   │   ├── nuby-hoedown-2010/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── ruby-hoedown-2007/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── ruby-hoedown-2008/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── ruby-hoedown-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-hoedown-2010/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-in-common/
│   │   ├── ruby-in-common-2024/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-in-london/
│   │   ├── ruby-in-london-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-india/
│   │   ├── pune-ruby-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-maizuru/
│   │   ├── ruby-maizuru-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-manor/
│   │   ├── ruby-manor-1/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   ├── ruby-manor-2/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   ├── ruby-manor-3/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   ├── ruby-manor-4/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-midwest/
│   │   ├── ruby-midwest-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-midwest-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-montevideo/
│   │   ├── ruby-montevideo/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-on-ales/
│   │   ├── ruby-on-ales-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-on-ales-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-on-ales-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-on-ales-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-on-ales-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-on-ales-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-on-ice/
│   │   ├── ruby-on-ice-2018/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   └── videos.yml
│   │   ├── ruby-on-ice-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-on-rails-global-summit/
│   │   ├── ruby-on-rails-global-summit-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-on-rails-switzerland/
│   │   ├── railshock/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-on-waves/
│   │   ├── ruby-on-waves-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-phil/
│   │   ├── ruby-phil/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-retreat-au/
│   │   ├── rails-camp-au-1-2007/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-10-2012/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-11-2012/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-12-2012/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-13-2013/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-14-2013/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-15-2014/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-16-2014/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-17-2015/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-18-2015/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-19-2016/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-2-2007/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-20-2016/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-21-2017/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-22-2017/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-23-2018/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-24-2018/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-25-2019/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-26-2019/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-27-2022/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-3-2008/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-4-2008/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-5-2009/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-6-2009/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-7-2010/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-8-2010/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-9-2011/
│   │   │   └── event.yml
│   │   ├── ruby-retreat-au-2024/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── ruby-retreat-au-2025/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-retreat-nz/
│   │   ├── ruby-retreat-nz-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-retreat-nz-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-retreat-nz-2025/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-romania/
│   │   ├── ruby-romania-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-summit-china/
│   │   ├── ruby-summit-china-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-tuesday/
│   │   ├── ruby-tuesday-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-turkiye/
│   │   ├── ruby-turkiye/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-web-conference/
│   │   ├── ruby-web-conference-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-wine/
│   │   ├── ruby-wine-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-wine-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubybelgium/
│   │   ├── rubybelgium-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyc/
│   │   ├── rubyc-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyc-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyc-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyc-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyc-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyc-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyc-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubycon/
│   │   ├── rubycon-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf/
│   │   ├── rubyconf-2001/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2002/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2003/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2004/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2005/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2006/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2007/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2016/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2022/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2022-mini/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2023/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-africa/
│   │   ├── rubyconf-africa-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-africa-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-africa-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-argentina/
│   │   ├── rubyconf-argentina-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-argentina-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-argentina-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-argentina-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-au/
│   │   ├── rubyconf-au-2013/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-au-2014/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-au-2015/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-au-2016/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-au-2017/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-au-2018/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-au-2019/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-au-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-au-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-au-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-austria/
│   │   ├── rubyconf-austria-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-brazil/
│   │   ├── rubyconf-brazil-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-brazil-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-brazil-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-brazil-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-brazil-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-brazil-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-by/
│   │   ├── rubyconfby-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconfby-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconfby-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconfby-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconfby-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-china/
│   │   ├── rubyconf-china-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-china-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-china-2024/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-colombia/
│   │   ├── rubyconf-colombia-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-colombia-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-colombia-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-colombia-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-india/
│   │   ├── rubyconf-india-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2019/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2022/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-indonesia/
│   │   ├── rubyconf-indonesia-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-jakarta/
│   │   ├── rubyconf-jakarta-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-lt/
│   │   ├── rubyconf-lt-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-lt-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-lt-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-my/
│   │   ├── rubyconf-kl-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-my-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-my-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-philippines/
│   │   ├── rubyconf-philippines-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-philippines-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-philippines-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-philippines-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-philippines-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-portugal/
│   │   ├── rubyconf-portugal-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-portugal-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-portugal-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-taiwan/
│   │   ├── rubyconf-taiwan-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-taiwan-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-taiwan-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-taiwan-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-taiwan-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-taiwan-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-taiwan-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-taiwan-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-uruguay/
│   │   ├── rubyconf-uruguay-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-uruguay-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconfth/
│   │   ├── rubyconf-th-2020/
│   │   │   └── event.yml
│   │   ├── rubyconfth-2019/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyconfth-2022/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyconfth-2023/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyconfth-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyday/
│   │   ├── rubyday-2011/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyday-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyday-2015/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyday-2016/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyday-2019/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyday-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyday-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyday-2023/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyday-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyenrails/
│   │   ├── rubyandrails-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyenrails-2006/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyenrails-2007/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyenrails-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyenrails-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyeurope/
│   │   ├── rubyeurope-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyevents/
│   │   ├── rubyevents/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyfuza/
│   │   ├── rubyfuza-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyfuza-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyfuza-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyfuza-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyfuza-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyfuza-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyfuza-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyfuza-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyhack/
│   │   ├── rubyhack-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyhack-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyhack-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyhiroba/
│   │   ├── rubyhiroba-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyhiroba-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubykaigi/
│   │   ├── rubykaigi-2006/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2007/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2019/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2022/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2023/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubykansai/
│   │   ├── rubykansai-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubymotion-inspect/
│   │   ├── rubymotion-inspect-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubymotion-inspect-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubymx/
│   │   ├── rubymx-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubynation/
│   │   ├── rubynation-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubynation-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubynation-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubynation-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubynation-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyness/
│   │   ├── rubyness-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyrussia/
│   │   ├── rubyrussia-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyrussia-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyrussia-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyrussia-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyrussia-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyrussia-2024/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyrx/
│   │   ├── rubyrx-2009-philadelphia/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyrx-2009-washington-dc/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubysauna/
│   │   ├── rubysauna-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyunconf/
│   │   ├── rubyunconf-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyunconf-2019/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyunconf-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyunconf-2023/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyunconf-2024/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyworld/
│   │   ├── rubyworld-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2019/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2023/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2024/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rulu/
│   │   ├── rulu-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rulu-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rulu-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rulu-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rupy/
│   │   ├── rupy-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── saint-p-rubyconf/
│   │   ├── saint-p-rubyconf-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── saint-p-rubyconf-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── saint-p-rubyconf-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── saint-p-rubyconf-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── scotlandonrails/
│   │   ├── scotlandonrails-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── scotlandonrails-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── scottish-ruby-conf/
│   │   ├── scottish-ruby-conf-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── scottish-ruby-conf-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── scottish-ruby-conf-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── scottish-ruby-conf-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── scottish-ruby-conf-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── sekigahara-rubykaigi/
│   │   ├── sekigahara-rubykaigi-01/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── venue.yml
│   │   └── series.yml
│   ├── sf-bay-area-ruby/
│   │   ├── series.yml
│   │   └── sf-bay-area-ruby-meetup/
│   │       ├── cfp.yml
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── sfruby/
│   │   ├── series.yml
│   │   └── sfruby-2025/
│   │       ├── cfp.yml
│   │       ├── event.yml
│   │       ├── involvements.yml
│   │       ├── schedule.yml
│   │       ├── sponsors.yml
│   │       ├── venue.yml
│   │       └── videos.yml
│   ├── shinosakarb/
│   │   ├── series.yml
│   │   └── shinosakarb-meetup/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── shrug/
│   │   ├── series.yml
│   │   └── shrug-meetup/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── sin-city-ruby/
│   │   ├── series.yml
│   │   ├── sin-city-ruby-2022/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── sin-city-ruby-2024/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── sin-city-ruby-2025/
│   │       ├── event.yml
│   │       ├── schedule.yml
│   │       ├── sponsors.yml
│   │       ├── venue.yml
│   │       └── videos.yml
│   ├── solidusconf/
│   │   ├── series.yml
│   │   ├── solidusconf-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── solidusconf-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── solidusconf-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── solidusconf-2019/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── solidusconf-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── solidusconf-2022/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── southeast-ruby/
│   │   ├── series.yml
│   │   ├── southeast-ruby-2017/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── southeast-ruby-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── southeast-ruby-2019/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── speakers.yml
│   ├── steelcityruby/
│   │   ├── series.yml
│   │   ├── steelcityruby-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── steelcityruby-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── steelcityruby-2014/
│   │       ├── event.yml
│   │       ├── sponsors.yml
│   │       └── videos.yml
│   ├── the-rails-edge/
│   │   ├── series.yml
│   │   └── the-rails-edge-2007/
│   │       ├── event.yml
│   │       ├── venue.yml
│   │       └── videos.yml
│   ├── thoughtbot-open-summit/
│   │   ├── series.yml
│   │   ├── thoughtbot-open-summit-2024/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── thoughtbot-open-summit-2025/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── tiny-ruby-conf/
│   │   ├── series.yml
│   │   ├── tiny-ruby-conf-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── tiny-ruby-conf-2026/
│   │       ├── cfp.yml
│   │       ├── event.yml
│   │       └── venue.yml
│   ├── tokyo-rubykaigi/
│   │   ├── series.yml
│   │   ├── tokyo-rubykaigi-10/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── tokyo-rubykaigi-11/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── tokyo-rubykaigi-12/
│   │       ├── event.yml
│   │       ├── schedule.yml
│   │       ├── sponsors.yml
│   │       └── videos.yml
│   ├── topics.yml
│   ├── toronto-ruby/
│   │   ├── series.yml
│   │   └── toronto-ruby-meetup/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── tropicalrb/
│   │   ├── abril-pro-ruby-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── abril-pro-ruby-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── abril-pro-ruby-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── series.yml
│   │   ├── tropical-on-rails-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── tropical-on-rails-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── tropicalrb-2015/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── tropicalrb-2024/
│   │       ├── cfp.yml
│   │       ├── event.yml
│   │       ├── involvements.yml
│   │       ├── schedule.yml
│   │       ├── sponsors.yml
│   │       ├── venue.yml
│   │       └── videos.yml
│   ├── umedarb/
│   │   ├── series.yml
│   │   └── umedarb-meetup/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── valencia-rb/
│   │   ├── series.yml
│   │   └── valencia-rb-meetup/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── vienna-rb/
│   │   ├── series.yml
│   │   └── vienna-rb-meetup/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── wakayama-rb/
│   │   ├── series.yml
│   │   └── wakayama-rb-meetup/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── windycityrails/
│   │   ├── series.yml
│   │   ├── windycityrails-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── windycityrails-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── windycityrails-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── windycityrails-2016/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── winnipeg-rb/
│   │   ├── series.yml
│   │   └── winnipeg-rb-meetup/
│   │       ├── event.yml
│   │       ├── involvements.yml
│   │       ├── sponsors.yml
│   │       ├── venue.yml
│   │       └── videos.yml
│   ├── wnb-rb/
│   │   ├── series.yml
│   │   └── wnb-rb-meetup/
│   │       ├── event.yml
│   │       ├── sponsors.yml
│   │       └── videos.yml
│   ├── wroclove-rb/
│   │   ├── series.yml
│   │   ├── wroclove-rb-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2019/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2022/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2023/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── wroclove-rb-2026/
│   │       ├── cfp.yml
│   │       ├── event.yml
│   │       ├── schedule.yml
│   │       ├── sponsors.yml
│   │       ├── venue.yml
│   │       └── videos.yml
│   └── xoruby/
│       ├── series.yml
│       ├── xoruby-atlanta-2025/
│       │   ├── cfp.yml
│       │   ├── event.yml
│       │   ├── involvements.yml
│       │   ├── schedule.yml
│       │   ├── sponsors.yml
│       │   ├── venue.yml
│       │   └── videos.yml
│       ├── xoruby-austin-2025/
│       │   ├── event.yml
│       │   ├── involvements.yml
│       │   ├── sponsors.yml
│       │   ├── venue.yml
│       │   └── videos.yml
│       ├── xoruby-chicago-2025/
│       │   ├── cfp.yml
│       │   ├── event.yml
│       │   ├── involvements.yml
│       │   ├── schedule.yml
│       │   ├── sponsors.yml
│       │   ├── venue.yml
│       │   └── videos.yml
│       ├── xoruby-new-orleans-2025/
│       │   ├── cfp.yml
│       │   ├── event.yml
│       │   ├── involvements.yml
│       │   ├── schedule.yml
│       │   ├── sponsors.yml
│       │   ├── venue.yml
│       │   └── videos.yml
│       ├── xoruby-portland-2025/
│       │   ├── event.yml
│       │   ├── involvements.yml
│       │   ├── schedule.yml
│       │   ├── sponsors.yml
│       │   ├── venue.yml
│       │   └── videos.yml
│       └── xoruby-san-diego-2025/
│           ├── event.yml
│           ├── involvements.yml
│           ├── schedule.yml
│           ├── sponsors.yml
│           ├── venue.yml
│           └── videos.yml
├── db/
│   ├── cache_migrate/
│   │   ├── 20240516085648_create_solid_cache_entries.solid_cache.rb
│   │   ├── 20240516085649_add_key_hash_and_byte_size_to_solid_cache_entries.solid_cache.rb
│   │   ├── 20240516085650_add_key_hash_and_byte_size_indexes_and_null_constraints_to_solid_cache_entries.solid_cache.rb
│   │   └── 20240516085651_remove_key_index_from_solid_cache_entries.solid_cache.rb
│   ├── cache_schema.rb
│   ├── migrate/
│   │   ├── 20230512050041_create_speakers.rb
│   │   ├── 20230512051225_create_talks.rb
│   │   ├── 20230521202931_create_join_table_speakers_talks.rb
│   │   ├── 20230521211825_add_talks_count_to_speaker.rb
│   │   ├── 20230522051939_create_suggestions.rb
│   │   ├── 20230522133312_create_users.rb
│   │   ├── 20230522133313_create_sessions.rb
│   │   ├── 20230522133314_create_password_reset_tokens.rb
│   │   ├── 20230522133315_create_email_verification_tokens.rb
│   │   ├── 20230522212710_create_events.rb
│   │   ├── 20230522213244_add_event_references_to_talk.rb
│   │   ├── 20230525132507_add_index_slug_to_speaker.rb
│   │   ├── 20230604215247_create_ahoy_visits_and_events.rb
│   │   ├── 20230614230539_rename_event_table_to_organisation.rb
│   │   ├── 20230614231651_create_new_events.rb
│   │   ├── 20230614232412_add_youtube_channel_id_to_organisation.rb
│   │   ├── 20230614233712_add_slug_to_organisation.rb
│   │   ├── 20230614234246_add_name_to_event.rb
│   │   ├── 20230615053959_add_slug_to_event.rb
│   │   ├── 20230615055319_add_thumbnails_to_talk.rb
│   │   ├── 20230615055800_fix_foreign_constrain.rb
│   │   ├── 20230615105716_add_date_to_talk.rb
│   │   ├── 20230622202051_add_upvotes_and_views_to_talks.rb
│   │   ├── 20230625215935_add_twitter_to_organisation.rb
│   │   ├── 20230720104208_add_uniq_index_speaker_talk.rb
│   │   ├── 20230720151537_add_primary_key_to_speaker_talks.rb
│   │   ├── 20240611113918_add_transcript_to_talk.rb
│   │   ├── 20240614060121_add_service_name_to_active_storage_blobs.active_storage.rb
│   │   ├── 20240614060122_create_active_storage_variant_records.active_storage.rb
│   │   ├── 20240614060123_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb
│   │   ├── 20240709194147_add_enhanced_transcript_to_talk.rb
│   │   ├── 20240709200506_rename_transcript_in_talk.rb
│   │   ├── 20240718202658_add_summary_to_talk.rb
│   │   ├── 20240811121204_create_topics.rb
│   │   ├── 20240811122145_create_talk_topics.rb
│   │   ├── 20240815155647_add_uniq_index_on_talk_topic.rb
│   │   ├── 20240816074626_add_status_to_topic.rb
│   │   ├── 20240817083428_add_canonical_reference_to_topic.rb
│   │   ├── 20240818212042_add_language_to_talk.rb
│   │   ├── 20240819134138_drop_year_from_talk.rb
│   │   ├── 20240821191208_add_talks_count_to_event.rb
│   │   ├── 20240823221832_add_slides_url_to_talks.rb
│   │   ├── 20240901163900_add_canonical_reference_to_speaker.rb
│   │   ├── 20240902204752_add_canonical_reference_to_event.rb
│   │   ├── 20240908072757_create_watch_list_talks.rb
│   │   ├── 20240908072819_create_watch_lists.rb
│   │   ├── 20240909194059_create_connected_accounts.rb
│   │   ├── 20240912163015_add_name_to_user.rb
│   │   ├── 20240912163159_encrypt_user_fields.rb
│   │   ├── 20240912164120_encrypt_connected_account_field.rb
│   │   ├── 20240914162252_add_github_handle_to_user.rb
│   │   ├── 20240918050951_add_approved_by_to_suggestion.rb
│   │   ├── 20240918215740_add_suggestor_to_suggestions.rb
│   │   ├── 20240919193323_add_index_on_updated_at_for_talks.rb
│   │   ├── 20240920054416_add_talks_count_to_topic.rb
│   │   ├── 20240920154237_add_talks_count_to_watch_list.rb
│   │   ├── 20241019135118_create_talk_fts.rb
│   │   ├── 20241020174649_add_speakerdeck_to_speaker.rb
│   │   ├── 20241022012631_add_summarized_using_ai_to_talk.rb
│   │   ├── 20241023093844_add_pronouns_to_speaker.rb
│   │   ├── 20241023150341_remove_index_talk_topics_on_talk_id.rb
│   │   ├── 20241023154126_recreate_talk_topic_indexes.rb
│   │   ├── 20241029112719_add_mastodown_bluesky_linkedin_to_speaker.rb
│   │   ├── 20241031112333_add_kind_to_talk.rb
│   │   ├── 20241101185604_add_external_player_to_talk.rb
│   │   ├── 20241105143943_add_website_to_events.rb
│   │   ├── 20241105151601_create_watched_talks.rb
│   │   ├── 20241108215612_add_indexes_speaker_talks.rb
│   │   ├── 20241122155013_add_index_on_slug_for_topics.rb
│   │   ├── 20241122163052_add_index_on_kind_for_talks.rb
│   │   ├── 20241128073415_add_bsky_metadata_to_speaker.rb
│   │   ├── 20241130095835_add_parent_talk_to_talk.rb
│   │   ├── 20241203001515_add_github_metadata_to_speaker.rb
│   │   ├── 20241227192232_add_duration_to_talk.rb
│   │   ├── 20250102175230_create_speaker_full_text_search.rb
│   │   ├── 20250104095544_create_talk_transcript.rb
│   │   ├── 20250104230927_create_rollups.rb
│   │   ├── 20250108221813_set_view_count_default_on_talk.rb
│   │   ├── 20250115215944_add_index_video_provider_to_talk.rb
│   │   ├── 20250124210823_add_discarded_at_speaker_talk.rb
│   │   ├── 20250127012711_add_published_at_and_announced_at_to_talk.rb
│   │   ├── 20250128070756_add_unique_index_on_github_in_speaker.rb
│   │   ├── 20250128085252_remove_github_of_speaker_with_canonical.rb
│   │   ├── 20250218073648_normalize_github_handle.rb
│   │   ├── 20250426063312_add_llm_requests.rb
│   │   ├── 20250427062021_add_success_to_llm_requests.rb
│   │   ├── 20250521011731_add_original_title_to_talks.rb
│   │   ├── 20250524174213_normalize_speaker_website.rb
│   │   ├── 20250605203429_add_start_and_end_date_to_event.rb
│   │   ├── 20250609072113_remove_talk_parent_id_self.rb
│   │   ├── 20250614131810_add_kind_to_event.rb
│   │   ├── 20250617115359_add_date_precision_to_events.rb
│   │   ├── 20250618000304_add_call_for_papers_to_events.rb
│   │   ├── 20250719180249_create_sponsors.rb
│   │   ├── 20250719190411_add_slug_to_sponsors.rb
│   │   ├── 20250719200918_create_event_sponsors.rb
│   │   ├── 20250719204509_add_banner_url_to_sponsors.rb
│   │   ├── 20250719205313_add_main_location_to_sponsors.rb
│   │   ├── 20250719205756_remove_url_fields_from_sponsors.rb
│   │   ├── 20250719225634_add_tier_to_event_sponsors.rb
│   │   ├── 20250719231642_add_logo_url_to_sponsors.rb
│   │   ├── 20250808095915_add_logo_urls_to_sponsors.rb
│   │   ├── 20250808192916_clean_sponsor_website_urls.rb
│   │   ├── 20250809194302_add_badge_to_event_sponsors.rb
│   │   ├── 20250813211012_decrypt_user_name.rb
│   │   ├── 20250814214127_add_speaker_attributes_to_users.rb
│   │   ├── 20250814214146_create_user_talks.rb
│   │   ├── 20250814214412_create_users_search_index.rb
│   │   ├── 20250817060410_set_users_email_null_true.rb
│   │   ├── 20250817223427_update_user_indexes.rb
│   │   ├── 20250819022348_create_cfps.rb
│   │   ├── 20250820183955_add_progress_seconds_to_watched_talks.rb
│   │   ├── 20250820225005_add_watched_talks_count_to_users.rb
│   │   ├── 20250822175423_add_unique_index_to_event_sponsors.rb
│   │   ├── 20250823020826_remove_cfp_fields_from_events.rb
│   │   ├── 20250901185702_update_suggestions_suggestable.rb
│   │   ├── 20250903125458_create_event_participations.rb
│   │   ├── 20250920194438_add_country_code_to_event.rb
│   │   ├── 20250930165602_add_location_to_user.rb
│   │   ├── 20251010092526_create_event_involvements.rb
│   │   ├── 20251012114916_create_contributors.rb
│   │   ├── 20251019071129_add_case_insensitive_github_handle_index_to_users.rb
│   │   ├── 20251019212653_remove_badge_awards_table.rb
│   │   ├── 20251028143012_create_aliases.rb
│   │   ├── 20251028143916_add_marked_for_deletion_to_users.rb
│   │   ├── 20251028143917_migrate_canonical_users_to_aliases.rb
│   │   ├── 20251029032709_rename_organisation_to_event_series.rb
│   │   ├── 20251126171800_rename_sponsor_to_organization.rb
│   │   ├── 20251126171948_rename_event_sponsor_to_sponsor.rb
│   │   ├── 20251126203734_add_coordinates_to_events.rb
│   │   ├── 20251201143109_add_event_names_to_talks_search_index.rb
│   │   ├── 20251201144052_change_slug_to_optional_in_aliases.rb
│   │   ├── 20251203110611_change_youtube_channel_id_nullable_on_event_series.rb
│   │   ├── 20251203110659_change_youtube_channel_name_nullable_on_event_series.rb
│   │   ├── 20251204145850_add_static_id_to_talks.rb
│   │   ├── 20251204195048_change_static_id_null_constraint_on_talks.rb
│   │   ├── 20251206194409_add_additional_resources_to_talks.rb
│   │   ├── 20260101090225_add_wrapped_public_to_users.rb
│   │   ├── 20260101125732_create_active_storage_tables.active_storage.rb
│   │   ├── 20260103114901_add_feedback_to_watched_talks.rb
│   │   ├── 20260103122047_add_feedback_shared_at_to_watched_talks.rb
│   │   ├── 20260103125129_backfill_watched_at_on_watched_talks.rb
│   │   ├── 20260103130348_add_watched_to_watched_talks.rb
│   │   ├── 20260103134407_add_feedback_enabled_to_users.rb
│   │   ├── 20260103210603_add_settings_to_users.rb
│   │   ├── 20260103232220_create_topic_gems.rb
│   │   ├── 20260104181518_create_favorite_users.rb
│   │   ├── 20260105100000_add_indexes_to_ahoy_visits_for_cleanup.rb
│   │   ├── 20260105120000_add_video_provider_to_talks_search_index.rb
│   │   ├── 20260106092124_add_geocoding_to_users.rb
│   │   ├── 20260106121436_add_state_to_events.rb
│   │   ├── 20260106121459_create_featured_cities.rb
│   │   ├── 20260106135053_create_geocode_results.rb
│   │   ├── 20260106141308_add_location_to_events.rb
│   │   ├── 20260106232656_add_marked_suspicious_at_to_users.rb
│   │   ├── 20260109095858_add_geocode_metadata_to_events.rb
│   │   ├── 20260109152525_change_aliases_slug_index.rb
│   │   ├── 20260110193214_rename_featured_cities_to_cities.rb
│   │   ├── 20260110194925_rename_state_to_state_code_on_events_and_users.rb
│   │   ├── 20260110201634_remove_city_column_from_cities.rb
│   │   ├── 20260112065507_add_youtube_thumbnail_checked_at_to_talks.rb
│   │   ├── 20260112071922_add_video_availability_fields_to_talks.rb
│   │   ├── 20260301182003_add_notes_to_favorite_user.rb
│   │   └── 20260306110802_add_level_to_sponsors.rb
│   ├── queue_migrate/
│   │   ├── 20240516090838_create_solid_queue_tables.solid_queue.rb
│   │   ├── 20240516090839_add_missing_index_to_blocked_executions.solid_queue.rb
│   │   ├── 20240516090840_create_recurring_executions.solid_queue.rb
│   │   ├── 20240814230055_create_recurring_tasks.solid_queue.rb
│   │   ├── 20240908182634_add_name_to_processes.solid_queue.rb
│   │   ├── 20240908191029_make_name_not_null.solid_queue.rb
│   │   └── 20240908191030_change_solid_queue_recurring_tasks_static_to_not_null.solid_queue.rb
│   ├── queue_schema.rb
│   ├── schema.rb
│   └── seeds.rb
├── docker-compose.typesense.yml
├── docs/
│   ├── ADDING_CFPS.md
│   ├── ADDING_EVENTS.md
│   ├── ADDING_INVOLVEMENTS.md
│   ├── ADDING_MEETUPS.md
│   ├── ADDING_SCHEDULES.md
│   ├── ADDING_SPONSORS.md
│   ├── ADDING_UNPUBLISHED_TALKS.md
│   ├── ADDING_VENUES.md
│   ├── ADDING_VIDEOS.md
│   ├── ADDING_VISUAL_ASSETS.md
│   └── FIXING_PROFILE_NAMES.md
├── lib/
│   ├── assets/
│   │   └── .keep
│   ├── authenticator.rb
│   ├── generators/
│   │   ├── cfp/
│   │   │   ├── USAGE
│   │   │   ├── cfp_generator.rb
│   │   │   └── templates/
│   │   │       ├── cfp.yml.tt
│   │   │       └── header.yml.tt
│   │   ├── event/
│   │   │   ├── USAGE
│   │   │   ├── event_generator.rb
│   │   │   └── templates/
│   │   │       └── event.yml.tt
│   │   ├── event_base.rb
│   │   ├── schedule/
│   │   │   ├── USAGE
│   │   │   ├── schedule_generator.rb
│   │   │   └── templates/
│   │   │       └── schedule.yml.tt
│   │   ├── sponsors/
│   │   │   ├── USAGE
│   │   │   ├── sponsors_generator.rb
│   │   │   └── templates/
│   │   │       └── sponsors.yml.tt
│   │   ├── talk/
│   │   │   ├── USAGE
│   │   │   ├── talk_generator.rb
│   │   │   └── templates/
│   │   │       ├── lightning_talks.yml.tt
│   │   │       ├── talk.yml.tt
│   │   │       └── videos.yml.tt
│   │   └── venue/
│   │       ├── USAGE
│   │       ├── templates/
│   │       │   ├── location.yml.tt
│   │       │   └── venue.yml.tt
│   │       └── venue_generator.rb
│   ├── guard/
│   │   └── data_import.rb
│   ├── protobuf/
│   │   └── message_type.rb
│   ├── schemas/
│   │   ├── address_schema.json
│   │   ├── cfp_schema.json
│   │   ├── cfps_schema.json
│   │   ├── coordinates_schema.json
│   │   ├── event_schema.json
│   │   ├── featured_city_schema.json
│   │   ├── hotel_schema.json
│   │   ├── involvement_schema.json
│   │   ├── location_schema.json
│   │   ├── maps_schema.json
│   │   ├── schedule_schema.json
│   │   ├── series_schema.json
│   │   ├── speaker_schema.json
│   │   ├── sponsors_schema.json
│   │   ├── tiers_sponsors_schema.json
│   │   ├── transcript_schema.json
│   │   ├── venue_schema.json
│   │   ├── video_schema.json
│   │   └── videos_schema.json
│   ├── tasks/
│   │   ├── annotate_rb.rake
│   │   ├── assets.rake
│   │   ├── backfill_event_involvements.rake
│   │   ├── backfill_speaker_participation.rake
│   │   ├── cities.rake
│   │   ├── cleanup_ahoy_visits.rake
│   │   ├── contributors.rake
│   │   ├── db.rake
│   │   ├── download.rake
│   │   ├── dump.rake
│   │   ├── event_assets.rake
│   │   ├── geolocate.thor
│   │   ├── schema.rake
│   │   ├── search.rake
│   │   ├── seed.rake
│   │   ├── speakerdeck.rake
│   │   ├── speakers.rake
│   │   ├── thumbnails.rake
│   │   ├── topics.rake
│   │   ├── transcripts.rake
│   │   ├── update_video_statistics.rake
│   │   ├── users.rake
│   │   └── validate.rake
│   └── templates/
│       └── erb/
│           └── scaffold/
│               ├── _form.html.erb.tt
│               ├── edit.html.erb.tt
│               ├── index.html.erb.tt
│               ├── new.html.erb.tt
│               ├── partial.html.erb.tt
│               └── show.html.erb.tt
├── log/
│   └── .keep
├── package.json
├── postcss.config.js
├── public/
│   ├── 400.html
│   ├── 404.html
│   ├── 406-unsupported-browser.html
│   ├── 422.html
│   ├── 500.html
│   └── robots.txt
├── scripts/
│   ├── create_events.rb
│   ├── create_videos_yml.rb
│   ├── dump_speakers.rb
│   ├── dump_talks.rb
│   ├── extract_videos.rb
│   ├── import_event.rb
│   ├── prepare_series.rb
│   └── sort_speakers.rb
├── storage/
│   └── .keep
├── tailwind.config.js
├── test/
│   ├── application_system_test_case.rb
│   ├── channels/
│   │   └── application_cable/
│   │       └── connection_test.rb
│   ├── clients/
│   │   └── youtube/
│   │       ├── channels_test.rb
│   │       ├── playlist_items_test.rb
│   │       ├── playlists_test.rb
│   │       ├── transcript_test.rb
│   │       └── video_test.rb
│   ├── components/
│   │   ├── application_component_test.rb
│   │   ├── events/
│   │   │   ├── upcoming_event_banner_component/
│   │   │   │   └── helper_methods_test.rb
│   │   │   └── upcoming_event_banner_component_test.rb
│   │   ├── tito/
│   │   │   ├── button_component_test.rb
│   │   │   └── widget_component_test.rb
│   │   └── ui/
│   │       ├── avatar_component_test.rb
│   │       ├── badge_component_test.rb
│   │       ├── button_component_test.rb
│   │       └── stamp_component_test.rb
│   ├── controllers/
│   │   ├── analytics/
│   │   │   └── dashboards_controller_test.rb
│   │   ├── announcements_controller_test.rb
│   │   ├── cfp_controller_test.rb
│   │   ├── countries_controller_test.rb
│   │   ├── events/
│   │   │   ├── archive_controller_test.rb
│   │   │   ├── meetups_controller_test.rb
│   │   │   ├── participations_controller_test.rb
│   │   │   ├── related_talks_controller_test.rb
│   │   │   ├── schedule_controller_test.rb
│   │   │   ├── series_controller_test.rb
│   │   │   └── sponsors_controller_test.rb
│   │   ├── events_controller_test.rb
│   │   ├── favorite_users_controller_test.rb
│   │   ├── locations/
│   │   │   └── users_controller_test.rb
│   │   ├── organizations/
│   │   │   ├── logos_controller_test.rb
│   │   │   └── wrapped_controller_test.rb
│   │   ├── organizations_controller_test.rb
│   │   ├── page_controller_test.rb
│   │   ├── profiles/
│   │   │   ├── connect_controller_test.rb
│   │   │   ├── enhance_controller_test.rb
│   │   │   ├── involvements_controller_test.rb
│   │   │   ├── map_controller_test.rb
│   │   │   ├── notes_controller_test.rb
│   │   │   └── wrapped_controller_test.rb
│   │   ├── profiles_controller_test.rb
│   │   ├── recommendations_controller_test.rb
│   │   ├── sessions/
│   │   │   ├── omniauth_controller_test copy.rb
│   │   │   └── omniauth_controller_test.rb
│   │   ├── sessions_controller_test.rb
│   │   ├── speakers_controller_test.rb
│   │   ├── sponsors/
│   │   │   └── missing_controller_test.rb
│   │   ├── spotlight/
│   │   │   ├── events_controller_test.rb
│   │   │   ├── languages_controller_test.rb
│   │   │   ├── locations_controller_test.rb
│   │   │   ├── organizations_controller_test.rb
│   │   │   ├── series_controller_test.rb
│   │   │   ├── speakers_controller_test.rb
│   │   │   ├── talks_controller_test.rb
│   │   │   └── topics_controller_test.rb
│   │   ├── suggestions_controller_test.rb
│   │   ├── talks/
│   │   │   ├── recommendations_controller_test.rb
│   │   │   ├── slides_controller_test.rb
│   │   │   └── watched_talks_controller_test.rb
│   │   ├── talks_controller_test.rb
│   │   ├── topics_controller_test.rb
│   │   ├── watch_list_talks_controller_test.rb
│   │   ├── watch_lists_controller_test.rb
│   │   ├── watched_talks_controller_test.rb
│   │   └── wrapped_controller_test.rb
│   ├── fixtures/
│   │   ├── cfps.yml
│   │   ├── cities.yml
│   │   ├── connected_accounts.yml
│   │   ├── contributors.yml
│   │   ├── event_series.yml
│   │   ├── events.yml
│   │   ├── favorite_users.yml
│   │   ├── files/
│   │   │   └── .keep
│   │   ├── organizations.yml
│   │   ├── sponsors.yml
│   │   ├── suggestions.yml
│   │   ├── talk/
│   │   │   └── transcripts.yml
│   │   ├── talk_topics.yml
│   │   ├── talks.yml
│   │   ├── topics.yml
│   │   ├── user_talks.yml
│   │   ├── users.yml
│   │   ├── watch_lists.yml
│   │   └── watched_talks.yml
│   ├── helpers/
│   │   ├── event_tracking_helper.rb
│   │   └── icon_helper_test.rb
│   ├── integration/
│   │   └── .keep
│   ├── jobs/
│   │   ├── geocode_record_job_test.rb
│   │   └── recurring/
│   │       ├── rollup_job_test.rb
│   │       ├── youtube_thumbnail_validation_job_test.rb
│   │       ├── youtube_video_availability_job_test.rb
│   │       └── youtube_video_statistics_job_test.rb
│   ├── lib/
│   │   ├── download_sponsors_test.rb
│   │   ├── generators/
│   │   │   ├── cfp_generator_test.rb
│   │   │   ├── event_generator_test.rb
│   │   │   ├── schedule_generator_test.rb
│   │   │   ├── sponsors_generator_test.rb
│   │   │   ├── talk_generator_test.rb
│   │   │   └── venue_generator_test.rb
│   │   └── schema_export_test.rb
│   ├── models/
│   │   ├── ahoy/
│   │   │   └── visit_test.rb
│   │   ├── alias_test.rb
│   │   ├── announcement_test.rb
│   │   ├── cfp_test.rb
│   │   ├── city_test.rb
│   │   ├── concerns/
│   │   │   └── geocodeable_test.rb
│   │   ├── connected_account_test.rb
│   │   ├── continent_test.rb
│   │   ├── contributor_test.rb
│   │   ├── country_test.rb
│   │   ├── event/
│   │   │   ├── assets_test.rb
│   │   │   ├── static_metadata_test.rb
│   │   │   ├── tickets/
│   │   │   │   └── provider_detection_test.rb
│   │   │   ├── tickets_test.rb
│   │   │   └── videos_file_test.rb
│   │   ├── event_geocoding_test.rb
│   │   ├── event_participation_test.rb
│   │   ├── event_series_test.rb
│   │   ├── event_test.rb
│   │   ├── favorite_user_test.rb
│   │   ├── language_test.rb
│   │   ├── location_test.rb
│   │   ├── online_location_test.rb
│   │   ├── organization_test.rb
│   │   ├── rollup_test.rb
│   │   ├── search/
│   │   │   ├── backend/
│   │   │   │   ├── sqlite_fts/
│   │   │   │   │   └── indexer_test.rb
│   │   │   │   ├── sqlite_fts_test.rb
│   │   │   │   ├── typesense/
│   │   │   │   │   ├── indexer_test.rb
│   │   │   │   │   ├── language_indexer_test.rb
│   │   │   │   │   └── location_indexer_test.rb
│   │   │   │   └── typesense_test.rb
│   │   │   └── backend_test.rb
│   │   ├── sponsor_test.rb
│   │   ├── state_test.rb
│   │   ├── static/
│   │   │   ├── city_test.rb
│   │   │   └── event_test.rb
│   │   ├── suggestion_test.rb
│   │   ├── talk_test.rb
│   │   ├── talk_topic_test.rb
│   │   ├── template_test.rb
│   │   ├── topic_test.rb
│   │   ├── uk_nation_test.rb
│   │   ├── user/
│   │   │   ├── duplicate_detector_test.rb
│   │   │   ├── profiles_test.rb
│   │   │   ├── suspicion_detector_test.rb
│   │   │   └── talk_recommendations_test.rb
│   │   ├── user_geocoding_test.rb
│   │   ├── user_talk_test.rb
│   │   ├── user_test.rb
│   │   └── youtube/
│   │       ├── video_metadata_rails_worldtest.rb
│   │       └── video_metadata_test.rb
│   ├── system/
│   │   ├── call_for_papers_test.rb
│   │   ├── events_test.rb
│   │   ├── sessions_test.rb
│   │   ├── speakers_test.rb
│   │   ├── sponsors_test.rb
│   │   ├── spotlight_search_test.rb
│   │   └── talks_test.rb
│   ├── tasks/
│   │   ├── db_seed_test.rb
│   │   └── seed_test.rb
│   ├── test_helper.rb
│   ├── tools/
│   │   ├── cfp_create_tool_test.rb
│   │   ├── cfp_info_tool_test.rb
│   │   └── cfp_update_tool_test.rb
│   └── vcr_cassettes/
│       ├── profiles/
│       │   └── enhance_controller_test/
│       │       └── patch.yml
│       ├── recurring_youtube_statistics_job.yml
│       ├── sessions/
│       │   └── omniauth_controller_test/
│       │       └── creates_a_new_user_if_not_exists_github.yml
│       ├── talks/
│       │   ├── extract_topics.yml
│       │   ├── summarize.yml
│       │   └── transcript-enhancement.yml
│       ├── user/
│       │   └── enhance_profile_job_test.yml
│       ├── youtube/
│       │   ├── channels-scrapping.yml
│       │   ├── channels.yml
│       │   ├── playlist_items/
│       │   │   └── all.yml
│       │   ├── playlists/
│       │   │   └── all.yml
│       │   ├── transcript.yml
│       │   └── transcript_not_available.yml
│       ├── youtube_duration.yml
│       ├── youtube_statistics.yml
│       ├── youtube_statistics_invalid.yml
│       └── youtube_video_transcript.yml
├── tmp/
│   └── .keep
├── vendor/
│   └── .keep
├── vite.config.mjs
└── yaml/
    ├── enforce_strings.mjs
    └── formatter.mjs

================================================
FILE CONTENTS
================================================

================================================
FILE: .annotaterb.yml
================================================
---
:position: before
:position_in_additional_file_patterns: before
:position_in_class: before
:position_in_factory: before
:position_in_fixture: before
:position_in_routes: before
:position_in_serializer: before
:position_in_test: before
:classified_sort: true
:exclude_controllers: true
:exclude_factories: false
:exclude_fixtures: false
:exclude_helpers: true
:exclude_scaffolds: true
:exclude_serializers: false
:exclude_sti_subclasses: false
:exclude_tests: true
:force: false
:format_markdown: false
:format_rdoc: false
:format_yard: false
:frozen: false
:ignore_model_sub_dir: false
:ignore_unknown_models: false
:include_version: false
:show_check_constraints: false
:show_complete_foreign_keys: false
:show_foreign_keys: true
:show_indexes: true
:simple_indexes: true
:sort: true
:timestamp: false
:trace: false
:with_comment: true
:with_column_comments: true
:with_table_comments: true
:active_admin: false
:command:
:debug: false
:hide_default_column_types: ""
:hide_limit_column_types: ""
:ignore_columns:
:ignore_routes:
:models: true
:routes: false
:skip_on_db_migrate: false
:target_action: :do_annotations
:wrapper:
:wrapper_close:
:wrapper_open:
:classes_default_to_s: []
:additional_file_patterns: []
:model_dir:
  - app/models
:require: []
:root_dir:
  - ""


================================================
FILE: .cursor/commands/plan_commands.md
================================================
The user will provide a feature description. Your job is to:

1. Create a technical plan that concisely describes the feature the user wants to build.
2. Research the files and functions that need to be changed to implement the feature
3. Avoid any product manager style sections (no success criteria, timeline, migration, etc)
4. Avoid writing any actual code in the plan.
5. Include specific and verbatim details from the user's prompt to ensure the plan is accurate.

This is strictly a technical requirements document that should:

1. Include a brief description to set context at the top
2. Point to all the relevant files and functions that need to be changed or created
3. Explain any algorithms that are used step-by-step
4. If necessary, breaks up the work into logical phases. Ideally this should be done in a way that has an initial "data layer" phase that defines the types and db changes that need to run, followed by N phases that can be done in parallel (eg. Phase 2A - routes, Phase 2B - UI, etc). Only include phases if it's a REALLY big feature.

If the user's requirements are unclear, especially after researching the relevant files, you may ask up to 5 clarifying questions before writing the plan. If you do so, incorporate the user's answers into the plan.

Prioritize being concise and precise. Make the plan as tight as possible without losing any of the critical details from the user's requirements.

Write the plan into an <N>\_PLAN.md file with the next available feature number


================================================
FILE: .cursor/rules/cursorrules.mdc
================================================
---
alwaysApply: true
---

# RubyVideo Rails 8 Project - Cursor Rules

You are working on RubyVideo, a modern Ruby on Rails 8 application that aggregates and curates Ruby conference videos. This is a sophisticated video platform with AI-powered features, search, analytics, and social features.

## Project Overview

**Tech Stack:**

- Rails 8.0 with SQLite database
- Frontend: Vite + Tailwind CSS + daisyUI + Stimulus controllers
- Background Jobs: Solid Queue
- Caching: Solid Cache
- Authentication: Custom session-based auth with GitHub OAuth
- Admin: Avo admin panel
- Deployment: Kamal on Hetzner VPS
- Analytics: Ahoy for page tracking
- AI Features: OpenAI integration for summarization and topic extraction

**Architecture:**

- ViewComponent pattern for reusable UI components
- Concerns for shared model behavior
- Associated Objects pattern using `active_record-associated_object`
- Slug-based routing for SEO
- Background jobs for data processing
- YAML-based conference data structure

## Development Standards

### Ruby/Rails Code

**General Rails Conventions:**

- Follow Rails 8 conventions and modern Rails patterns
- Use `standardrb` for Ruby formatting (never `rubocop`)
- Models include concerns: `Suggestable`, `Sluggable`, `Rollupable`, `Searchable`, `Watchable`
- Prefer `belongs_to` with `optional: true` when appropriate
- Use `has_many` with `dependent: :destroy` for cascade deletes

**Model Patterns:**

```ruby
class Talk < ApplicationRecord
  include Rollupable
  include Sluggable
  include Suggestable
  include Searchable
  include Watchable
  configure_slug(attribute: :title, auto_suffix_on_collision: true)

  belongs_to :event, optional: true, counter_cache: :talks_count, touch: true
  has_many :speaker_talks, dependent: :destroy
  has_many :speakers, through: :speaker_talks

  validates :title, presence: true
  enum :kind, ["talk", "keynote", "panel"].index_by(&:itself), default: "talk"

  scope :watchable, -> { where(external_player: false) }
  scope :canonical, -> { where(canonical_id: nil) }
end
```

**Controller Patterns:**

- Inherit from `ApplicationController` which includes:
  - `Authenticable` - session-based authentication
  - `Metadata` - SEO meta tags
  - `Analytics` - page view tracking
- Use `skip_before_action :authenticate_user!` for public pages
- Follow RESTful routing patterns
- Use `Current.user` for current user access
- Implement pagination with `pagy` gem

```ruby
class TalksController < ApplicationController
  skip_before_action :authenticate_user!, only: [:index, :show]

  def show
    @talk = Talk.includes(:speakers, :topics).find_by(slug: params[:slug])
    return redirect_to(root_path, status: :moved_permanently) unless @talk

    @pagy, @related_talks = pagy(@talk.related_talks, limit: 6)
  end
end
```

**Authentication Patterns:**

- Session-based authentication, not JWT
- Use `Current.user` to access current user
- GitHub OAuth integration available
- Admin users have `admin: true` boolean
- Route constraints use `Authenticator` module

### ViewComponent Architecture

> **Detailed UI Component Rules**: See [viewcomponents.mdc](./viewcomponents.mdc) for comprehensive UI component guidelines.

**Component Structure:**

- All components inherit from `ApplicationComponent`
- Components located in `app/components/`
- UI components in `app/components/ui/` namespace

```ruby
class Ui::ButtonComponent < ApplicationComponent
  option :kind, type: Dry::Types["coercible.symbol"].enum(:primary, :secondary), default: proc { :primary }
  option :size, type: Dry::Types["coercible.symbol"].enum(:sm, :md, :lg), default: proc { :md }

  private

  def component_classes
    class_names(
      "btn",
      KIND_MAPPING[kind],
      SIZE_MAPPING[size]
    )
  end
end
```

**Component Conventions:**

- Use mapping constants for CSS class variants
- Implement `component_classes` method for dynamic styling
- Use `class_names` helper for conditional classes
- Support both `param` and `option` for parameters
- Include `display` option for conditional rendering

### Frontend Development

**Stimulus Controllers:**

- Located in `app/javascript/controllers/`
- Follow Stimulus conventions with kebab-case names
- Use Stimulus actions for interactive components

**CSS/Styling:**

- Tailwind CSS with daisyUI components
- Follow utility-first approach
- Use CSS variables for theming
- Responsive design with mobile-first approach

**Assets:**

- Vite for asset bundling
- Images in `app/assets/images/`
- Use WebP format for optimized images

### Database & Models

**Schema Patterns:**

- Use `annotaterb` gem for model annotations
- SQLite database with proper indexing
- Use foreign key constraints
- Counter cache patterns: `counter_cache: :talks_count`

**Data Validation:**

- Validate presence of required fields
- Use Rails enum for status fields
- Normalize data with `normalizes` callback
- Encrypt sensitive data: `encrypts :email, deterministic: true`

**Associations:**

- Use `inverse_of` for bidirectional associations
- `strict_loading: false` where needed for performance
- Scoped associations: `has_many :approved_topics, -> { approved }`

### Background Jobs & Processing

**Job Patterns:**

- Use Solid Queue for background processing
- Jobs in `app/jobs/` directory
- Process video metadata, transcripts, AI summaries
- Handle external API calls asynchronously

**Queue Configuration:**

```ruby
config.active_job.queue_adapter = :solid_queue
config.solid_queue.connects_to = {database: {writing: :queue}}
```

### Search & Data

**Data Structure:**

- Conference data stored in YAML files under `data/`
- Organizations, speakers, events, and videos defined in YAML
- Rake tasks process and import data

### Testing Standards

**Test Structure:**

- Use Minitest (not RSpec)
- Parallel test execution enabled
- VCR for API mocking
- Fixtures for test data
- System tests with Capybara + Selenium

**Test Patterns:**

```ruby
class TalkTest < ActiveSupport::TestCase
  test "creates slug from title" do
    talk = talks(:ruby_conf_talk)
    assert_equal "awesome-ruby-talk", talk.slug
  end

  test "belongs to event" do
    talk = talks(:ruby_conf_talk)
    assert_equal events(:ruby_conf_2023), talk.event
  end
end
```

**Test Helper Setup:**

- Search reindexing in setup
- Sign in helper: `sign_in_as(user)`
- VCR cassettes for external API calls

### API & Integrations

**External APIs:**

- YouTube API for video metadata
- GitHub API for user authentication
- OpenAI API for AI features
- All API clients in `app/clients/` directory

**AI Features:**

- Transcript enhancement
- Topic extraction
- Talk summarization
- All AI prompts stored in `app/models/prompts/`

### Development Commands

**Common Commands:**

- `bin/setup` - Full setup including Docker and database seeding
- `bin/dev` - Start Rails server, jobs, and Vite
- `bin/lint` - Run all linters and formatters
- `bin/rails test` - Run full test suite
- `bundle exec standardrb --fix` - Fix Ruby formatting
- `yarn format` - Fix JavaScript formatting

**Data Management:**

- `bin/rails db:seed:all` - Seed database from YAML files
- YAML files define conference structure and video metadata

### Deployment & Production

**Kamal Deployment:**

- Use Kamal for containerized deployment
- Dockerfile included for production builds
- Environment-specific configurations

**Monitoring:**

- AppSignal for error tracking and performance monitoring
- Ahoy for user analytics
- Mission Control for job monitoring

## Code Quality Standards

1. **Always run `standardrb --fix` for Ruby formatting**
2. **Use `yarn format` for JavaScript formatting**
3. **Include tests for new functionality**
4. **Follow Rails naming conventions**
5. **Use ViewComponents for reusable UI elements**
6. **Implement proper error handling**
7. **Add appropriate database indexes**
8. **Use background jobs for long-running tasks**
9. **Follow security best practices**
10. **Write clear, descriptive commit messages**

## Common Patterns to Follow

- Models use concerns for shared behavior
- Controllers are slim with business logic in models/services
- ViewComponents for reusable UI with design system consistency
- Background jobs for external API calls and heavy processing
- Proper caching strategies with Solid Cache
- SEO-friendly URLs with slugs
- Responsive design with Tailwind CSS
- Session-based authentication
- Comprehensive test coverage

When implementing features, always consider performance, security, accessibility, and maintainability. Follow Rails conventions and this project's established patterns.


================================================
FILE: .cursor/rules/viewcomponents.mdc
================================================
---
alwaysApply: false
---

# RubyVideo ViewComponents - UI Component Rules

> **Main Project Rules**: See [cursorrules.mdc](./cursorrules.mdc) for complete RubyVideo project guidelines.

## UI Component Architecture

This document defines specific rules for creating and maintaining UI components in the `Ui::` namespace within RubyVideo's ViewComponent architecture.

## Component Structure & Inheritance

### Base Component Pattern

All UI components MUST inherit from `ApplicationComponent`:

```ruby
class Ui::ComponentNameComponent < ApplicationComponent
  # Component implementation
end
```

### ApplicationComponent Features

The base `ApplicationComponent` provides:

- `Dry::Initializer` integration for type-safe parameters
- Automatic `attributes` handling for HTML attributes
- `display` option for conditional rendering
- `render?` method that respects the `display` option

## UI Component Conventions

### 1. Component Naming

- **File naming**: `snake_case_component.rb` (e.g., `button_component.rb`)
- **Class naming**: `Ui::PascalCaseComponent` (e.g., `Ui::ButtonComponent`)
- **Template naming**: `snake_case_component.html.erb` (e.g., `button_component.html.erb`)

### 2. Parameter Definition

Use `Dry::Types` for type-safe parameters with proper defaults:

```ruby
class Ui::ButtonComponent < ApplicationComponent
  # Required parameter
  param :text, default: proc {}

  # Optional parameter with type constraint
  option :url, Dry::Types["coercible.string"], optional: true

  # Enum parameter with default
  option :kind, type: Dry::Types["coercible.symbol"].enum(:primary, :secondary), default: proc { :primary }

  # Boolean parameter
  option :disabled, type: Dry::Types["strict.bool"], default: proc { false }
end
```

### 3. CSS Class Management

#### Mapping Constants Pattern

Define mapping constants for CSS class variants:

```ruby
class Ui::ButtonComponent < ApplicationComponent
  KIND_MAPPING = {
    primary: "btn-primary",
    secondary: "btn-secondary",
    neutral: "btn-neutral btn-outline",
    ghost: "btn-ghost"
  }.freeze

  SIZE_MAPPING = {
    sm: "btn-sm",
    md: "",
    lg: "btn-lg"
  }.freeze
end
```

#### Component Classes Method

Implement `component_classes` method for dynamic styling:

```ruby
private

def component_classes
  class_names(
    "btn",                    # Base class
    KIND_MAPPING[kind],       # Variant class
    SIZE_MAPPING[size],       # Size class
    "btn-outline": outline,   # Conditional class
    "btn-disabled": disabled  # State class
  )
end
```

#### Final Classes Method

Combine component classes with user-provided classes:

```ruby
private

def classes
  [component_classes, attributes[:class]].join(" ")
end
```

### 4. Content Handling

#### Content Method Pattern

Handle both parameter content and block content:

```ruby
private

def content
  text.presence || super  # Use param if provided, otherwise use block content
end
```

#### Call Method for Complex Rendering

Use `call` method for complex rendering logic:

```ruby
def call
  case button_kind
  when :link
    link_to(url, class: classes, **attributes.except(:class)) { content }
  when :button
    tag.button(type: type, class: classes, **attributes.except(:class)) { content }
  end
end
```

### 5. Stimulus Integration

#### Before Render Hook

Use `before_render` for Stimulus controller setup:

```ruby
def before_render
  attributes[:data] = {
    controller: "modal",
    modal_open_value: open,
    action: "keydown.esc->modal#close"
  }.merge(attributes[:data] || {})
end
```

#### Data Attributes

Pass Stimulus values through data attributes:

```ruby
attributes[:data] = {
  controller: "dropdown",
  dropdown_open_value: open,
  action: "click->dropdown#toggle"
}
```

## Common UI Component Patterns

### Button Component

```ruby
class Ui::ButtonComponent < ApplicationComponent
  KIND_MAPPING = {
    primary: "btn-primary",
    secondary: "btn-secondary",
    ghost: "btn-ghost"
  }.freeze

  SIZE_MAPPING = {
    sm: "btn-sm",
    md: "",
    lg: "btn-lg"
  }.freeze

  param :text, default: proc {}
  option :url, Dry::Types["coercible.string"], optional: true
  option :kind, type: Dry::Types["coercible.symbol"].enum(*KIND_MAPPING.keys), default: proc { :primary }
  option :size, type: Dry::Types["coercible.symbol"].enum(*SIZE_MAPPING.keys), default: proc { :md }
  option :disabled, type: Dry::Types["strict.bool"], default: proc { false }

  def call
    if url.present?
      link_to(url, class: classes, **attributes.except(:class)) { content }
    else
      tag.button(type: :button, class: classes, **attributes.except(:class)) { content }
    end
  end

  private

  def classes
    [component_classes, attributes[:class]].join(" ")
  end

  def component_classes
    class_names(
      "btn",
      KIND_MAPPING[kind],
      SIZE_MAPPING[size],
      "btn-disabled": disabled
    )
  end

  def content
    text.presence || super
  end
end
```

### Badge Component

```ruby
class Ui::BadgeComponent < ApplicationComponent
  KIND_MAPPING = {
    primary: "badge-primary",
    secondary: "badge-secondary",
    neutral: "badge-neutral"
  }.freeze

  SIZE_MAPPING = {
    xs: "badge-xs",
    sm: "badge-sm",
    md: "badge-md",
    lg: "badge-lg"
  }.freeze

  param :text, optional: true
  option :kind, type: Dry::Types["coercible.symbol"].enum(*KIND_MAPPING.keys), default: proc { :primary }
  option :size, type: Dry::Types["coercible.symbol"].enum(*SIZE_MAPPING.keys), default: proc { :md }

  def call
    content_tag(:span, class: classes, **attributes.except(:class)) do
      content
    end
  end

  private

  def classes
    [component_classes, attributes[:class]].join(" ")
  end

  def component_classes
    class_names(
      "badge",
      KIND_MAPPING[kind],
      SIZE_MAPPING[size]
    )
  end

  def content
    text.presence || super
  end
end
```

### Modal Component

```ruby
class Ui::ModalComponent < ApplicationComponent
  POSITION_MAPPING = {
    top: "modal-top",
    middle: "modal-middle",
    bottom: "modal-bottom",
    responsive: "modal-bottom sm:modal-middle"
  }.freeze

  SIZE_MAPPING = {
    md: "",
    lg: "!max-w-[800px]"
  }.freeze

  option :open, type: Dry::Types["strict.bool"], default: proc { false }
  option :position, type: Dry::Types["coercible.symbol"].enum(*POSITION_MAPPING.keys), default: proc { :responsive }
  option :size, type: Dry::Types["coercible.symbol"].enum(*SIZE_MAPPING.keys), default: proc { :md }

  def before_render
    attributes[:data] = {
      controller: "modal",
      modal_open_value: open,
      action: "keydown.esc->modal#close"
    }.merge(attributes[:data] || {})
  end

  private

  def classes
    [component_classes, attributes.delete(:class)].compact_blank.join(" ")
  end

  def component_classes
    class_names(
      "modal",
      POSITION_MAPPING[position]
    )
  end

  def size_class
    SIZE_MAPPING[size]
  end
end
```

## Template Patterns

### Basic Template Structure

```erb
<!-- button_component.html.erb -->
<%= call %>
```

### Complex Template with Slots

```erb
<!-- modal_component.html.erb -->
<div class="<%= classes %>" <%= tag.attributes(attributes) %>>
  <div class="modal-box <%= size_class %>">
    <% if close_button %>
      <form method="dialog">
        <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
      </form>
    <% end %>
    <%= content %>
  </div>
  <form method="dialog" class="modal-backdrop">
    <button>close</button>
  </form>
</div>
```

## Testing UI Components

### Component Test Structure

```ruby
class Ui::ButtonComponentTest < ViewComponent::TestCase
  test "renders primary button" do
    render_inline(Ui::ButtonComponent.new("Click me", kind: :primary))

    assert_selector("button.btn.btn-primary", text: "Click me")
  end

  test "renders as link when url provided" do
    render_inline(Ui::ButtonComponent.new("Click me", url: "/test"))

    assert_selector("a.btn", text: "Click me", href: "/test")
  end

  test "applies custom classes" do
    render_inline(Ui::ButtonComponent.new("Click me", class: "custom-class"))

    assert_selector("button.custom-class")
  end
end
```

## Best Practices

### 1. Type Safety

- Always use `Dry::Types` for parameter validation
- Define enum constraints for variant options
- Use `optional: true` for non-required parameters

### 2. CSS Architecture

- Use mapping constants for variant classes
- Implement `component_classes` method for dynamic styling
- Support custom classes through `attributes[:class]`

### 3. Content Flexibility

- Support both parameter content and block content
- Use `content` method to handle both cases
- Implement `call` method for complex rendering logic

### 4. Stimulus Integration

- Use `before_render` for controller setup
- Pass values through data attributes
- Support custom actions and controllers

### 5. Accessibility

- Include proper ARIA attributes
- Support keyboard navigation
- Ensure proper semantic HTML

### 6. Performance

- Use `freeze` on mapping constants
- Minimize method calls in templates
- Cache computed values when appropriate

## Common Mistakes to Avoid

1. **Don't** hardcode CSS classes in templates
2. **Don't** forget to handle both parameter and block content
3. **Don't** skip type validation for parameters
4. **Don't** forget to merge custom attributes
5. **Don't** ignore accessibility requirements
6. **Don't** create components without proper mapping constants

## Component Checklist

When creating a new UI component, ensure:

- [ ] Inherits from `ApplicationComponent`
- [ ] Uses proper naming convention (`Ui::NameComponent`)
- [ ] Defines mapping constants for variants
- [ ] Implements `component_classes` method
- [ ] Handles both parameter and block content
- [ ] Supports custom CSS classes
- [ ] Includes proper type validation
- [ ] Has corresponding template file
- [ ] Includes comprehensive tests
- [ ] Follows accessibility guidelines
- [ ] Documents all options and parameters

This ensures consistency across all UI components and maintains the design system's integrity.


================================================
FILE: .devcontainer/Dockerfile
================================================
ARG RUBY_VERSION=4.0.1
FROM docker.io/library/ruby:$RUBY_VERSION

# Rails app lives here
WORKDIR /rails

# Install base packages
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y \
    build-essential \
    # curl \
    # git \
    # imagemagick \ # Generate Assets
    libjemalloc2 \
    libvips \
    # libyaml-dev \
    node-gyp \
    pkg-config \
    python-is-python3 \
    # sqlite3 \
    chromium chromium-driver \
    && rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Copy lockfiles and setup script
# COPY Gemfile Gemfile.lock package.json .env.sample .ruby-version ./
# COPY bin ./bin

# Copy the whole application so we don't stumble on setting up the database
COPY . ./

# Install JavaScript dependencies
ARG NODE_VERSION=22.15.1
ARG YARN_VERSION=1.22.22
ENV PATH=/usr/local/node/bin:$PATH
RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
    /tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
    npm install -g yarn@$YARN_VERSION && \
    rm -rf /tmp/node-build-master

# Setup dependencies
RUN bin/setup --skip-server

# Default command
CMD ["sleep", "infinity"]


================================================
FILE: .devcontainer/devcontainer.json
================================================
{
  "name": "RubyEvents Dev",
  "dockerComposeFile": "./docker-compose.yml",
  "service": "rails-app",
  "workspaceFolder": "/rails",
  "overrideCommand": true,
  "customizations": {
    "vscode": {
      "settings": {
        "git.terminalGitEditor": true
      },
      "extensions": [
        "dbaeumer.vscode-eslint",
        "esbenp.prettier-vscode",
        "bradlc.vscode-tailwindcss",
        "testdouble.vscode-standard-ruby",
        "marcoroth.herb-lsp",
        "redhat.vscode-yaml"
      ]
    }
  },
  "features": {
    "ghcr.io/devcontainers/features/git:1": {},
    "ghcr.io/devcontainers/features/github-cli:1": {},
    "ghcr.io/devcontainers/features/sshd:1": {}
  },
  "portsAttributes": {
    "3000": {
      "label": "Ruby Events Rails Server",
      "onAutoForward": "notify"
    },
    "3036": {
      "label": "Vite Server",
      "onAutoForward": "silent"
    }
  },
  "mounts": [
    "source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached"
  ]
}

================================================
FILE: .devcontainer/docker-compose.yml
================================================
name: "RubyEvents"

services:
  rails-app:
    build:
      context: ..
      dockerfile: .devcontainer/Dockerfile
    command: sleep infinity
    depends_on:
      - typesense
    environment:
      - RAILS_ENV=development
      - NODE_ENV=development
      - TYPESENSE_HOST=typesense
      - TYPESENSE_PORT=8108
    ports:
      - "3000:3000"
    volumes:
      - ..:/rails:cached # Mounts the local project directory
      - node_modules:/rails/node_modules # Prevents overwriting node_modules so yarn install works correctly
    stdin_open: true
    tty: true

  typesense:
    image: typesense/typesense:29.0
    container_name: rubyevents-typesense
    restart: unless-stopped
    ports:
      - "8108:8108"
    volumes:
      - typesense-data:/data
    environment:
      - TYPESENSE_DATA_DIR=/data
      - TYPESENSE_ENABLE_CORS=true
    command: ["--data-dir", "/data", "--api-key", "xyz", "--enable-cors", "true"]
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8108/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s

volumes:
  node_modules:
  typesense-data:
    driver: local


================================================
FILE: .dockerignore
================================================
# See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files.

# Ignore git directory.
/.git/

# Ignore bundler config.
/.bundle

# Ignore all default key files.
/config/master.key
/config/credentials/*.key

# Ignore all environment files.
/.env*
!/.env.sample

# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep

# Ignore pidfiles, but keep the directory.
/tmp/pids/*
!/tmp/pids/
!/tmp/pids/.keep

# Ignore storage (uploaded files in development and any SQLite databases).
/storage/*
!/storage/.keep
/tmp/storage/*
!/tmp/storage/
!/tmp/storage/.keep

# Ignore assets.
/node_modules/
/app/assets/builds/*
!/app/assets/builds/.keep
/public/assets
/scripts/*

/docs/*
/load_testing/*
/test/*


================================================
FILE: .erb_lint.yml
================================================
---
EnableDefaultLinters: true
glob: "**/*.{html}{+*,}.erb"
exclude:
  - vendor/bundle/**/*
  - node_modules/**/*
  - tmp/**/*
  - log/**/*
  - app/views/profiles/wrapped/**/*

linters:
  ErbSafety:
    enabled: true
  PartialInstanceVariable:
    enabled: true
    exclude:
      - app/views/contributions/_events_without_dates.html.erb
      - app/views/contributions/_events_without_location.html.erb
      - app/views/contributions/_events_without_videos.html.erb
      - app/views/contributions/_missing_videos_cue.html.erb
      - app/views/contributions/_speakers_without_github.html.erb
      - app/views/contributions/_talks_dates_out_of_bounds.html.erb
      - app/views/contributions/_talks_without_slides.html.erb
      - app/views/events/_my_attendance_day.html.erb
      - app/views/profiles/wrapped/_share.html.erb

  Rubocop:
    enabled: true
    rubocop_config:
      require: standard
      inherit_gem:
        standard: config/base.yml
      Layout/InitialIndentation:
        Enabled: false
      Layout/TrailingEmptyLines:
        Enabled: false
      Lint/UselessAssignment:
        Enabled: false
      Lint/ItWithoutArgumentsInBlock:
        Enabled: false


================================================
FILE: .eslintignore
================================================
app/javascript/controllers/index.js


================================================
FILE: .eslintrc
================================================
{ "extends": "standard" }


================================================
FILE: .gitattributes
================================================
# See https://git-scm.com/docs/gitattributes for more about git attribute files.

# Mark the database schema as having been generated.
db/schema.rb linguist-generated

# Mark any vendored files as having been vendored.
vendor/* linguist-vendored
config/credentials/*.yml.enc diff=rails_credentials
config/credentials.yml.enc diff=rails_credentials


================================================
FILE: .github/pull_request_template.md
================================================
## Description
<!-- Please describe your changes. -->

## Screenshots
<!-- Add screenshots or GIFs if applicable. -->

## Testing Steps
<!-- List steps to test your changes. -->
<!-- If this is a content PR, link to the affected pages -->

## References
<!-- Link to related issues, discussions, other PRs, or references you used to write the PR. -->
- closes #<!-- issue number -->


================================================
FILE: .github/skills/event-data/SKILL.md
================================================
---
name: event-data
description: Guide for handling event data. Use when asked to update event data such as CFPs, Talks, Schedule, Sponsors, Involvements, or Videos. Use when updating any file in the /data/ directory.
---

# Important Notes
If something is unclear, use the AskUserTool to ask for clarification.
**Always use the generators if possible.**
The generators will create a file with the correct structure, and will help you avoid formatting errors.
If you do not have a paramter for the generator, do not pass it as a parameter.
The generaator will create a reasonable fault or TODO for someone else to fill out later.
`bin/lint` must be called before commiting any changes to confirm the structure of the file is correct.

# Adding a talk

Review documentation in docs/ADDING_UNPUBLISHED_TALKS.md.

Review the available parameters for the TalkGenerator.

```bash
bin/rails g talk --help
```

Create a command to reproduce the talk.

For example, if the user says "Create a lightning talk from Chris Hasiński, the title is Doom, and it's for the Ruby Community Conference".

```bash
bin/rails g talk --event ruby-community-conference-winter-edition-2026 --speaker "Chris Hasiński" --title "Doom" --kind lightning_talk
```

Exclude any missing parameters, and let the generator create TODOs for someone else to fill out later.

If the rubyevents MCP is available, and the user did not provide an event series slug and event, use the EventLookupTool to find the correct event.

Call the generator once per talk, and do not attempt to create multiple talks in one command.

Run `bin/lint` once all talks are added to confirm the structure.

# Generating a Schedule

Load Documentation from docs/ADDING_SCHEDULES.md into context.

Call the help command and review the available parameters for the ScheduleGenerator.

```bash
bin/rails g schedule --help
```

Create a command to approximate the schedule provided by the user.

Modify the yaml file to match the schedule exactly.

Run `bin/lint` to confirm the schedule structure.

# Generating a Sponsors file

Load Documentation from docs/ADDING_SPONSORS.md into context.

Review the available parameters for the SponsorGenerator.

```bash
bin/rails g sponsor --help
```

Generate the sponsor file with appropriate tiers and sponsor names. 

# Speakers

When updating speakers.yml, the structure is:

```yaml
- name: "Speaker Name"
  github: "github_handle"
  slug: "speaker-slug"
```

Other fields are permitted, but these are the fields I want you to focus on.
The GitHub handle is how we deduplicate speakers, and populate their profile, so the key should always be present.
These speakers are used for talks and involvements, so if a speaker is missing, you need to create a new record for them here.

If the GitHub is unknown:

```yaml
- name: "Speaker Name"
  github: ""
  slug: "speaker-slug"
```

If the speaker has multiple aliases, they'll be included as aliases.

```yaml
- name: "Speaker Name"
  github: "github_handle"
  slug: "speaker-slug"
  aliases:
    - name: "Other Name"
      slug: "other-slug"
```

================================================
FILE: .github/workflows/ci.yml
================================================
name: CI

on:
  pull_request:
    branches: ["*"]
  push:
    branches: [main]

concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true

jobs:
  lint:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    env:
      RAILS_ENV: test
      RUBOCOP_CACHE_ROOT: tmp/rubocop
    steps:
      - uses: actions/checkout@v5

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true

      - name: Setup Node
        uses: actions/setup-node@v6
        with:
          node-version-file: ".node-version"
          cache: yarn

      - name: Install dependencies
        run: yarn install --frozen-lockfile

      - name: Prepare RuboCop cache
        uses: actions/cache@v4
        env:
          DEPENDENCIES_HASH: ${{ hashFiles('**/.rubocop.yml', 'Gemfile.lock') }}
        with:
          path: ${{ env.RUBOCOP_CACHE_ROOT }}
          key: rubocop-${{ runner.os }}-${{ env.RUBY_VERSION }}-${{ env.DEPENDENCIES_HASH }}-${{ github.ref_name == github.event.repository.default_branch && github.run_id || 'default' }}
          restore-keys: |
            rubocop-${{ runner.os }}-${{ env.RUBY_VERSION }}-${{ env.DEPENDENCIES_HASH }}-

      - name: StandardRB Check
        run: bundle exec standardrb --format github --format "Standard::Formatter"

      - name: StandardJS Check
        run: yarn lint

      - name: Lint YAML data files
        run: yarn lint:yml

      - name: Validate YAML data schemas
        run: bin/rails validate:all

      - name: erb-lint Check
        run: bundle exec erb_lint --lint-all

      - name: Herb Linter Check
        run: npx @herb-tools/linter

      - name: Herb Analyze (parse/compile)
        run: bundle exec herb analyze app/

  test:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    env:
      RAILS_ENV: test
    steps:
      - uses: actions/checkout@v5

      - name: Install ImageMagick
        run: sudo apt-get update && sudo apt-get install -y imagemagick

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true

      - name: Setup Node
        uses: actions/setup-node@v6
        with:
          node-version-file: ".node-version"
          cache: yarn

      - name: Install dependencies
        run: yarn install --frozen-lockfile

      - name: Build assets
        run: bin/vite build --clear --mode=test

      - name: Prepare database
        run: |
          bin/rails db:create
          bin/rails db:schema:load

      - name: Run tests
        run: |
          bin/rails test
          bin/rails test:system

  seed_smoke_test:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    env:
      RAILS_ENV: test
      SEED_SMOKE_TEST: true
    steps:
      - uses: actions/checkout@v5

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true

      - name: Setup Node
        uses: actions/setup-node@v6
        with:
          node-version-file: ".node-version"
          cache: yarn

      - name: Install dependencies
        run: yarn install --frozen-lockfile

      - name: Build assets
        run: bin/vite build --clear --mode=test

      - name: Prepare database
        run: |
          bin/rails db:create
          bin/rails db:schema:load

      - name: Run Seed Smoke Test
        run: bin/rails test test/tasks/seed_test.rb

      - name: Verify all thumbnails for child talks are present
        run: bin/rails verify_thumbnails

      - name: Validate no duplicated speakers in database
        run: bin/rails validate:speaker_duplicates

  build:
    name: Build Docker Image
    runs-on: ubuntu-24.04-arm

    permissions:
      contents: read
      packages: write
      attestations: write
      id-token: write
    timeout-minutes: 20

    env:
      DOCKER_BUILDKIT: 1
      RAILS_ENV: production

    steps:
      - name: Checkout code
        uses: actions/checkout@v5

      - name: Set up Docker Buildx for cache
        uses: docker/setup-buildx-action@v3

      - name: Expose GitHub Runtime for cache
        uses: crazy-max/ghaction-github-runtime@v3

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true

      - name: Log in to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build Docker image (PR)
        if: ${{ github.event_name == 'pull_request' }}
        run: docker build .
        env:
          DOCKER_BUILDKIT: 1

      - name: Build and push Docker image
        if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
        run: bundle exec kamal build push
        env:
          KAMAL_RAILS_MASTER_KEY: ${{ secrets.KAMAL_RAILS_MASTER_KEY }}
          KAMAL_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}

  deploy:
    needs: [lint, test, seed_smoke_test, build]
    name: Deploy
    if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
    runs-on: ubuntu-latest
    timeout-minutes: 20

    steps:
      - name: Checkout code
        uses: actions/checkout@v5

      - name: Setup SSH
        uses: webfactory/ssh-agent@v0.9.0
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true

      - name: Deploy with Kamal
        run: bundle exec kamal deploy --skip-push
        env:
          KAMAL_RAILS_MASTER_KEY: ${{ secrets.KAMAL_RAILS_MASTER_KEY }}
          KAMAL_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
          GEOLOCATE_API_KEY: ${{ secrets.GEOLOCATE_API_KEY }}
          MAPBOX_ACCESS_TOKEN: ${{ secrets.MAPBOX_ACCESS_TOKEN }}
          TYPESENSE_API_KEY: ${{ secrets.TYPESENSE_API_KEY }}
          TYPESENSE_NODES: ${{ secrets.TYPESENSE_NODES }}
          TYPESENSE_NEAREST_NODE: ${{ secrets.TYPESENSE_NEAREST_NODE }}

      - name: Cleanup on cancellation
        if: always() && steps.deploy.conclusion == 'cancelled'
        run: bundle exec kamal lock release


================================================
FILE: .github/workflows/copilot-setup-steps.yml
================================================
name: Setup Development Environment for GitHub Copilot


# Automatically run the setup steps when they are changed to allow for easy validation, and
# allow manual testing through the repository's "Actions" tab
on:
  workflow_dispatch:
  push:
    paths:
      - .github/workflows/copilot-setup-steps.yml
  pull_request:
    paths:
      - .github/workflows/copilot-setup-steps.yml

jobs:
  # The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.
  copilot-setup-steps:
    runs-on: ubuntu-latest

    # Only let github read the repository contents
    permissions:
      contents: read

    steps:
      - name: Checkout repository
        uses: actions/checkout@v5
        with:
          fetch-depth: 30 # Fetch past 30 commits, so reasonable amount of commit context is included

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true
      
      - name: Run bin/setup
        run: bin/setup --skip-server

      - name: Validate setup
        run: |
          echo "Testing database connectivity..."
          bundle exec rails runner \
            "puts 'Database connection: OK'; \
            puts 'User count: ' + User.count.to_s"

          echo "Running code style validation..."
          bundle exec standardrb


================================================
FILE: .github/workflows/deploy-staging.yml
================================================
name: Deploy to Staging

on: workflow_dispatch

jobs:
  deploy-staging:
    name: Deploy to Staging
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    timeout-minutes: 20
    env:
      DOCKER_BUILDKIT: 1
    steps:
      - name: Checkout code
        uses: actions/checkout@v5

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Setup SSH
        uses: webfactory/ssh-agent@v0.9.0
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true

      - name: Log in to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Deploy to Staging
        env:
          VERSION: ${{ github.sha }}
          KAMAL_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
          KAMAL_RAILS_MASTER_KEY: ${{ secrets.KAMAL_RAILS_MASTER_KEY }}
          GEOLOCATE_API_KEY: ${{ secrets.GEOLOCATE_API_KEY }}
          MAPBOX_ACCESS_TOKEN: ${{ secrets.MAPBOX_ACCESS_TOKEN }}
        run: bundle exec kamal deploy -d staging

      - name: Cleanup on cancellation
        if: always() && steps.deploy.conclusion == 'cancelled'
        run: bundle exec kamal lock release


================================================
FILE: .github/workflows/migrate-production.yml
================================================
name: Migrate Production

on: workflow_dispatch

jobs:
  migrate-production:
    name: Migrate Production
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - name: Checkout code
        uses: actions/checkout@v5

      - name: Setup SSH
        uses: webfactory/ssh-agent@v0.9.0
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true

      - name: Run db:migrate on Production
        run: bundle exec kamal app exec --reuse "bin/rails db:migrate"


================================================
FILE: .github/workflows/migrate-staging.yml
================================================
name: Migrate Staging

on: workflow_dispatch

jobs:
  migrate-staging:
    name: Migrate Staging
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - name: Checkout code
        uses: actions/checkout@v5

      - name: Setup SSH
        uses: webfactory/ssh-agent@v0.9.0
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true

      - name: Run db:migrate on Staging
        run: bundle exec kamal app exec --reuse "bin/rails db:migrate" -d staging


================================================
FILE: .github/workflows/release-lock-production.yml
================================================
name: Release Lock Production

on: workflow_dispatch

jobs:
  release-lock-production:
    name: Release Lock Production
    runs-on: ubuntu-latest
    timeout-minutes: 2
    steps:
      - name: Checkout code
        uses: actions/checkout@v5
      - name: Setup SSH
        uses: webfactory/ssh-agent@v0.9.0
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true
      - name: Deploy to Production
        run: bundle exec kamal lock release


================================================
FILE: .github/workflows/release-lock-staging.yml
================================================
name: Release Lock Staging

on: workflow_dispatch

jobs:
  release-lock-staging:
    name: Release Lock Staging
    runs-on: ubuntu-latest
    timeout-minutes: 2
    steps:
      - name: Checkout code
        uses: actions/checkout@v5
      - name: Setup SSH
        uses: webfactory/ssh-agent@v0.9.0
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true
      - name: Release lock in staging
        run: bundle exec kamal lock release -d staging


================================================
FILE: .github/workflows/seed-production.yml
================================================
name: Seed Production

on: workflow_dispatch

jobs:
  seed-production:
    name: Seed Production
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - name: Checkout code
        uses: actions/checkout@v5

      - name: Setup SSH
        uses: webfactory/ssh-agent@v0.9.0
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true

      - name: Run db:seed:all on Production
        run: bundle exec kamal app exec --reuse "bin/rails db:seed:all"


================================================
FILE: .github/workflows/seed-staging.yml
================================================
name: Seed Staging

on: workflow_dispatch

jobs:
  seed-staging:
    name: Seed Staging
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - name: Checkout code
        uses: actions/checkout@v5

      - name: Setup SSH
        uses: webfactory/ssh-agent@v0.9.0
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true

      - name: Run db:seed:all on Staging
        run: bundle exec kamal app exec --reuse "bin/rails db:seed:all" -d staging


================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
#   git config --global core.excludesfile '~/.gitignore_global'

# Ignore bundler config and cache
/.bundle
vendor/bundle/

# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep

# Ignore pidfiles, but keep the directory.
/tmp/pids/*
!/tmp/pids/
!/tmp/pids/.keep

# Ignore storage (uploaded files in development and any SQLite databases).
/storage/*
!/storage/.keep
/tmp/storage/*
!/tmp/storage/
!/tmp/storage/.keep

/public/assets

# Ignore master key for decrypting credentials and more.
/config/master.key
/config/credentials/production.key
/config/credentials/staging.key


/app/assets/builds/*
!/app/assets/builds/.keep

/node_modules

/script_tmp
.env
.byebug_history

# Vite Ruby
/public/vite*
# Vite uses dotenv and suggests to ignore local-only env files. See
# https://vitejs.dev/guide/env-and-mode.html#env-files
*.local

/data.ms*
/data_tmp
data/talks_slugs.yml

/config/credentials/production.key
/config/credentials/staging.key

test-run-report*

# Ignore SQLite databases create by Litestack for action cable to be removed once we are able to move them to storage
db/*.db
db/*.db-*

# Vite Ruby
/public/vite*
node_modules
# Vite uses dotenv and suggests to ignore local-only env files. See
# https://vitejs.dev/guide/env-and-mode.html#env-files
*.local

# ignore doc folder
doc/*

service_account.json
/.cache

# asdf
.tool-versions

.DS_Store

.ssh-keys/

# IDE files
/.idea


================================================
FILE: .herb.yml
================================================
# This file configures Herb for your project and team.
# Settings here take precedence over individual editor preferences.
#
# Herb is a suite of tools for HTML+ERB templates including:
# - Linter: Validates templates and enforces best practices
# - Formatter: Auto-formats templates with intelligent indentation
# - Language Server: Provides IDE support (VS Code, Zed, Neovim, etc.)
#
# Website: https://herb-tools.dev
# Configuration: https://herb-tools.dev/configuration
# GitHub Repo: https://github.com/marcoroth/herb
#

version: 0.9.2

linter:
  enabled: true

  rules:
    erb-no-interpolated-class-names:
      enabled: false


formatter:
  enabled: false


================================================
FILE: .kamal/hooks/docker-setup.sample
================================================
#!/bin/sh

echo "Docker set up on $KAMAL_HOSTS..."


================================================
FILE: .kamal/hooks/post-deploy.sample
================================================
#!/bin/sh

# A sample post-deploy hook
#
# These environment variables are available:
# KAMAL_RECORDED_AT
# KAMAL_PERFORMER
# KAMAL_VERSION
# KAMAL_HOSTS
# KAMAL_ROLE (if set)
# KAMAL_DESTINATION (if set)
# KAMAL_RUNTIME

echo "$KAMAL_PERFORMER deployed $KAMAL_VERSION to $KAMAL_DESTINATION in $KAMAL_RUNTIME seconds"


================================================
FILE: .kamal/hooks/post-proxy-reboot.sample
================================================
#!/bin/sh

echo "Rebooted kamal-proxy on $KAMAL_HOSTS"


================================================
FILE: .kamal/hooks/pre-build.sample
================================================
#!/bin/sh

# A sample pre-build hook
#
# Checks:
# 1. We have a clean checkout
# 2. A remote is configured
# 3. The branch has been pushed to the remote
# 4. The version we are deploying matches the remote
#
# These environment variables are available:
# KAMAL_RECORDED_AT
# KAMAL_PERFORMER
# KAMAL_VERSION
# KAMAL_HOSTS
# KAMAL_ROLE (if set)
# KAMAL_DESTINATION (if set)

if [ -n "$(git status --porcelain)" ]; then
  echo "Git checkout is not clean, aborting..." >&2
  git status --porcelain >&2
  exit 1
fi

first_remote=$(git remote)

if [ -z "$first_remote" ]; then
  echo "No git remote set, aborting..." >&2
  exit 1
fi

current_branch=$(git branch --show-current)

if [ -z "$current_branch" ]; then
  echo "Not on a git branch, aborting..." >&2
  exit 1
fi

remote_head=$(git ls-remote $first_remote --tags $current_branch | cut -f1)

if [ -z "$remote_head" ]; then
  echo "Branch not pushed to remote, aborting..." >&2
  exit 1
fi

if [ "$KAMAL_VERSION" != "$remote_head" ]; then
  echo "Version ($KAMAL_VERSION) does not match remote HEAD ($remote_head), aborting..." >&2
  exit 1
fi

exit 0


================================================
FILE: .kamal/hooks/pre-connect.sample
================================================
#!/usr/bin/env ruby

# A sample pre-connect check
#
# Warms DNS before connecting to hosts in parallel
#
# These environment variables are available:
# KAMAL_RECORDED_AT
# KAMAL_PERFORMER
# KAMAL_VERSION
# KAMAL_HOSTS
# KAMAL_ROLE (if set)
# KAMAL_DESTINATION (if set)
# KAMAL_RUNTIME

hosts = ENV["KAMAL_HOSTS"].split(",")
results = nil
max = 3

elapsed = Benchmark.realtime do
  results = hosts.map do |host|
    Thread.new do
      tries = 1

      begin
        Socket.getaddrinfo(host, 0, Socket::AF_UNSPEC, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME)
      rescue SocketError
        if tries < max
          puts "Retrying DNS warmup: #{host}"
          tries += 1
          sleep rand
          retry
        else
          puts "DNS warmup failed: #{host}"
          host
        end
      end

      tries
    end
  end.map(&:value)
end

retries = results.sum - hosts.size
nopes = results.count { |r| r == max }

puts "Prewarmed %d DNS lookups in %.2f sec: %d retries, %d failures" % [ hosts.size, elapsed, retries, nopes ]


================================================
FILE: .kamal/hooks/pre-deploy.sample
================================================
#!/usr/bin/env ruby

# A sample pre-deploy hook
#
# Checks the Github status of the build, waiting for a pending build to complete for up to 720 seconds.
#
# Fails unless the combined status is "success"
#
# These environment variables are available:
# KAMAL_RECORDED_AT
# KAMAL_PERFORMER
# KAMAL_VERSION
# KAMAL_HOSTS
# KAMAL_COMMAND
# KAMAL_SUBCOMMAND
# KAMAL_ROLE (if set)
# KAMAL_DESTINATION (if set)

# Only check the build status for production deployments
if ENV["KAMAL_COMMAND"] == "rollback" || ENV["KAMAL_DESTINATION"] != "production"
  exit 0
end

require "bundler/inline"

# true = install gems so this is fast on repeat invocations
gemfile(true, quiet: true) do
  source "https://rubygems.org"

  gem "octokit"
  gem "faraday-retry"
end

MAX_ATTEMPTS = 72
ATTEMPTS_GAP = 10

def exit_with_error(message)
  $stderr.puts message
  exit 1
end

class GithubStatusChecks
  attr_reader :remote_url, :git_sha, :github_client, :combined_status

  def initialize
    @remote_url = `git config --get remote.origin.url`.strip.delete_prefix("https://github.com/")
    @git_sha = `git rev-parse HEAD`.strip
    @github_client = Octokit::Client.new(access_token: ENV["GITHUB_TOKEN"])
    refresh!
  end

  def refresh!
    @combined_status = github_client.combined_status(remote_url, git_sha)
  end

  def state
    combined_status[:state]
  end

  def first_status_url
    first_status = combined_status[:statuses].find { |status| status[:state] == state }
    first_status && first_status[:target_url]
  end

  def complete_count
    combined_status[:statuses].count { |status| status[:state] != "pending"}
  end

  def total_count
    combined_status[:statuses].count
  end

  def current_status
    if total_count > 0
      "Completed #{complete_count}/#{total_count} checks, see #{first_status_url} ..."
    else
      "Build not started..."
    end
  end
end


$stdout.sync = true

puts "Checking build status..."
attempts = 0
checks = GithubStatusChecks.new

begin
  loop do
    case checks.state
    when "success"
      puts "Checks passed, see #{checks.first_status_url}"
      exit 0
    when "failure"
      exit_with_error "Checks failed, see #{checks.first_status_url}"
    when "pending"
      attempts += 1
    end

    exit_with_error "Checks are still pending, gave up after #{MAX_ATTEMPTS * ATTEMPTS_GAP} seconds" if attempts == MAX_ATTEMPTS

    puts checks.current_status
    sleep(ATTEMPTS_GAP)
    checks.refresh!
  end
rescue Octokit::NotFound
  exit_with_error "Build status could not be found"
end


================================================
FILE: .kamal/hooks/pre-proxy-reboot.sample
================================================
#!/bin/sh

echo "Rebooting kamal-proxy on $KAMAL_HOSTS..."


================================================
FILE: .kamal/secrets
================================================
# Secrets defined here are available for reference under registry/password, env/secret, builder/secrets,
# and accessories/*/env/secret in config/deploy.yml. All secrets should be pulled from either
# password manager, ENV, or a file. DO NOT ENTER RAW CREDENTIALS HERE! This file needs to be safe for git.

# Option 1: Read secrets from the environment
KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
RAILS_MASTER_KEY=$KAMAL_RAILS_MASTER_KEY

LITESTREAM_ACCESS_KEY_ID=$LITESTREAM_ACCESS_KEY_ID
LITESTREAM_SECRET_ACCESS_KEY=$LITESTREAM_SECRET_ACCESS_KEY
LITESTREAM_ENDPOINT=$LITESTREAM_ENDPOINT
GEOLOCATE_API_KEY=$GEOLOCATE_API_KEY
MAPBOX_ACCESS_TOKEN=$MAPBOX_ACCESS_TOKEN

TYPESENSE_HOST=$TYPESENSE_HOST
TYPESENSE_PORT=$TYPESENSE_PORT
TYPESENSE_PROTOCOL=$TYPESENSE_PROTOCOL
TYPESENSE_API_KEY=$TYPESENSE_API_KEY
TYPESENSE_NODES=$TYPESENSE_NODES
TYPESENSE_NEAREST_NODE=$TYPESENSE_NEAREST_NODE

# Option 2: Read secrets via a command
# RAILS_MASTER_KEY=$(cat config/master.key)

# Option 3: Read secrets via kamal secrets helpers
# These will handle logging in and fetching the secrets in as few calls as possible
# There are adapters for 1Password, LastPass + Bitwarden
#


================================================
FILE: .kamal/secrets.staging
================================================
# Secrets defined here are available for reference under registry/password, env/secret, builder/secrets,
# and accessories/*/env/secret in config/deploy.yml. All secrets should be pulled from either
# password manager, ENV, or a file. DO NOT ENTER RAW CREDENTIALS HERE! This file needs to be safe for git.

# Option 1: Read secrets from the environment
KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
RAILS_MASTER_KEY=$KAMAL_RAILS_MASTER_KEY

LITESTREAM_ACCESS_KEY_ID=$LITESTREAM_ACCESS_KEY_ID
LITESTREAM_SECRET_ACCESS_KEY=$LITESTREAM_SECRET_ACCESS_KEY
LITESTREAM_ENDPOINT=$LITESTREAM_ENDPOINT
GEOLOCATE_API_KEY=$GEOLOCATE_API_KEY
MAPBOX_ACCESS_TOKEN=$MAPBOX_ACCESS_TOKEN

TYPESENSE_HOST=$TYPESENSE_HOST
TYPESENSE_PORT=$TYPESENSE_PORT
TYPESENSE_PROTOCOL=$TYPESENSE_PROTOCOL
TYPESENSE_API_KEY=$TYPESENSE_API_KEY

# Option 2: Read secrets via a command
# RAILS_MASTER_KEY=$(cat config/master.key)

# Option 3: Read secrets via kamal secrets helpers
# These will handle logging in and fetching the secrets in as few calls as possible
# There are adapters for 1Password, LastPass + Bitwarden
#


================================================
FILE: .mcp.json
================================================
{
  "mcpServers": {
    "rubyevents": {
      "command": "bin/mcp_server",
      "args": [],
      "tools": ["*"]
    }
  }
}


================================================
FILE: .node-version
================================================
22.15.1


================================================
FILE: .prettierignore
================================================
transcripts.yml


================================================
FILE: .ruby-version
================================================
4.0.1


================================================
FILE: .standard.yml
================================================


================================================
FILE: .vscode/extensions.json
================================================
{
  "recommendations": [
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
    "bradlc.vscode-tailwindcss",
    "testdouble.vscode-standard-ruby",
    "marcoroth.herb-lsp",
    "redhat.vscode-yaml"
  ]
}

================================================
FILE: .vscode/settings.json
================================================
{
  "editor.detectIndentation": false,
  "editor.formatOnPaste": true,
  "editor.formatOnSave": true,
  "editor.minimap.enabled": false,
  "editor.multiCursorModifier": "ctrlCmd",
  "editor.insertSpaces": true,
  "editor.tabSize": 2,
  "editor.rulers": [
    80,
    120
  ],
  "editor.renderControlCharacters": true,
  "editor.snippetSuggestions": "top",
  "editor.trimAutoWhitespace": true,
  "editor.useTabStops": true,
  "editor.scrollBeyondLastLine": true,
  "editor.showFoldingControls": "always",
  "emmet.triggerExpansionOnTab": true,
  "emmet.includeLanguages": {
    "html.erb": "html",
    "erb": "html"
  },
  "files.associations": {
    "*.html.erb": "erb"
  },
  "[ruby]": {
    "editor.defaultFormatter": "Shopify.ruby-lsp"
  },
  "rubyLsp.enabledFeatures": {
    "diagnostics": false
  },
  "[javascript]": {
    "editor.defaultFormatter": "dbaeumer.vscode-eslint",
    "editor.codeActionsOnSave": {
      "source.fixAll.eslint": "explicit"
    }
  },
  "tailwindCSS.includeLanguages": {
    "erb": "html"
  },
  "tailwindCSS.emmetCompletions": true,
  "tailwindCSS.validate": true,
  "yaml.schemas": {
    "lib/schemas/cfps_schema.json": "data/**/cfp.yml",
    "lib/schemas/event_schema.json": "data/**/event.yml",
    "lib/schemas/schedule_schema.json": "data/**/schedule.yml",
    "lib/schemas/tiers_sponsors_schema.json": "data/**/sponsors.yml",
    "lib/schemas/venue_schema.json": "data/**/venue.yml",
    "lib/schemas/videos_schema.json": "**/videos.yml",
  }
}

================================================
FILE: CLAUDE.md
================================================
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Common Development Commands

### Setup & Development

- `bin/setup` - Full setup including database seeding via docker-compose
- `bin/dev` - Start Rails server, SolidQueue jobs, and Vite (for CSS/JS)
- `bin/lint` - Run all formatters and linters (StandardRB, JS Standard, ERB lint, YAML prettier)
- `bin/rails db:seed` - Seed database with conference data manually
- `bin/rails db:seed:all` - Seed database with all conference data manually

### Testing

- `bin/rails test` - Run the full test suite (uses Minitest)
- `bin/rails test test/system/` - Run system tests
- `bin/rails test test/models/speaker_test.rb` - Run specific test file

### Linting & Formatting

- `bundle exec standardrb --fix` - Fix Ruby formatting issues
- `yarn format` - Fix JavaScript formatting
- `bundle exec erb_lint --lint-all --autocorrect` - Fix ERB templates
- `yarn format:yml` - Format YAML files in data/ directory

### Jobs & Search

- `bin/jobs` - Start SolidQueue job worker
- Search reindexing happens automatically in test setup

## Architecture Overview

### Core Models & Relationships

- **Event**: Ruby conferences/meetups (belongs_to EventSeries)
- **Talk**: Conference presentations (belongs_to Event, has_many SpeakerTalks)
- **Speaker**: Presenters (has_many SpeakerTalks, has social media fields)
- **EventSeries**: Conference series/organizers (has_many Events)
- **Topic**: AI-extracted talk topics (has_many TalkTopics)
- **WatchList**: User-curated lists (belongs_to User, has_many WatchListTalks)

### Data Structure

Conference data is stored in YAML files under `/data/`:

- `data/speakers.yml` - Global speaker database
- `data/{series-slug}/series.yml` - Event series metadata (conference organizers/series)
- `data/{series-slug}/{event-name}/event.yml` - Event metadata (dates, location, colors, etc.)
- `data/{series-slug}/{event-name}/videos.yml` - Individual talk data
- `data/{series-slug}/{event-name}/schedule.yml` - Event schedules

### Technology Stack

- **Backend**: Rails 8.0, SQLite, Solid Queue, Solid Cache
- **Frontend**: Vite, Tailwind CSS, daisyUI, Stimulus
- **Admin**: Avo admin panel at `/admin`
- **Authentication**: Custom session-based auth with GitHub OAuth
- **Deployment**: Kamal on Hetzner VPS

### Key Components

- **View Components**: Located in `app/components/`, follows ViewComponent pattern
- **Clients**: API clients for YouTube, GitHub, BlueSky in `app/clients/`
- **Search**: Full-text search for Talks and Speakers using Sqlite virtual tables
- **Jobs**: Background processing for video statistics, transcripts, AI summarization
- **Analytics**: Page view tracking with Ahoy

### Authentication & Authorization

- Custom `Authenticator` module provides role-based route constraints
- Admin access required for Avo admin panel and Mission Control Jobs
- GitHub OAuth integration for user registration
- Session-based authentication (not JWT)

### Notable Conventions

- Uses slug-based routing for SEO-friendly URLs
- Talks support multiple video providers (YouTube, Vimeo, etc.)
- AI-powered features: transcript enhancement, topic extraction, summarization
- Responsive design with mobile-first approach
- Canonical references to deduplicate speakers/events/topics

### Testing Setup

- Uses Minitest (not RSpec)
- VCR for API mocking
- Parallel test execution
- Search indexes are reset in test setup
- System tests use Capybara with Selenium

### Data Import Flow

1. YAML files define conference structure
2. Rake tasks process video metadata
3. Background jobs fetch additional data (transcripts, statistics)
4. AI services enhance content (summaries, topics)


================================================
FILE: CONTRIBUTING.md
================================================
# Welcome to RubyEvents.org!

Welcome to RubyEvents.org, and thank you for contributing your time and energy to improving the platform.
We're on a mission to index all ruby events and video talks, and we need your help to do it!

A great way to get started is adding new events and content.
We have a page on the deployed site that has up-to-date information with the remaining known TODOs.
Check out the ["Getting Started: Ways to Contribute" page on RubyEvents.org](https://www.rubyevents.org/contributions) and feel free to start working on any of the remaining TODOs.
Any help is greatly appreciated.

All contributors are expected to abide by the [Code of Conduct](/CODE_OF_CONDUCT.md).

## Getting Started

We have tried to make the setup process as simple as possible so that in a few commands you can have the project with real data running locally.

### Devcontainers

In addition to the local development flow described below, we support [devcontainers](https://containers.dev) and [codespaces](https://github.com/features/codespaces).
If you open this project in VS Code and you have the [dev containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) installed, it will prompt you and ask if you want to reopen in a dev container.
This will set up the dev environment for you in docker, and reopen your editor from within the context of the rails container, so you can run commands and work with the project as if it was local.
All file changes will be present locally when you close the container.

- Clone RubyEvents with https, it tends to behave better, and new `gh auth login` commands won't generate new ssh keys.
- If you cannot fetch or push, use `gh auth login` to auth with GitHub.
- After the container is set up, run `bin/dev` in the terminal to start the development server. The application will be forwarded to [localhost:3000](localhost:3000).
- To run system tests, use `HEADLESS=true bin/rails test`. The HEADLESS=true environment variable ensures Chrome runs in headless mode, which is required in the container environment.

If the ruby version is updated, or you start running into issues, feel free to toss and rebuild the container.

### Local Dev Setup

#### Requirements

- Ruby 4.0.1
- Node.js 22.15.1

#### Setup

To install dependencies and prepare the database run:

```
bin/setup
```

This will seed the database with all speakers, meetups, the last 6 months of events, and all future events.

To load all historical data, run:

```
bin/rails db:seed:all
```

### Environment Variables

You can use the `.env.sample` file as a guide for the environment variables required for the project.
However, there are currently no environment variables necessary for simple app exploration.

### Starting the Application

The following command will start Rails, SolidQueue and Vite (for CSS and JS).

```
bin/dev
```

## Linter

The CI performs these checks:

- erblint
- standardrb
- standard (js)
- prettier (yaml)

Before committing your code you can run `bin/lint` to detect and potentially autocorrect lint errors and validate schemas.

To follow Tailwind CSS's recommended order of classes, you can use [Prettier](https://prettier.io/) along with the [prettier-plugin-tailwindcss](https://github.com/tailwindlabs/prettier-plugin-tailwindcss), both of which are included as devDependencies. This formatting is not yet enforced by the CI.

### Typesense (Optional)

The application uses [Typesense](https://typesense.org/) for enhanced search functionality (spotlight search). Typesense is **optional** for local development. The app works without it, falling back to SQLite FTS5 for search.

**Devcontainers / Docker Compose:** Typesense is included and starts automatically.

**Local development:** Run Typesense with Docker:

```bash
docker compose -f docker-compose.typesense.yml up -d
```

Check the status of the search backends and if you can connect.

```bash
bundle exec rake search:status
```

Once running, you can reindex the data:

```bash
bin/rails search:reindex
```

Useful search commands:

```bash
bin/rails search:status       # Show status of all search backends
bin/rails typesense:health    # Check if Typesense is running
bin/rails typesense:stats     # Show Typesense index statistics
bin/rails typesense:reindex   # Full reindex of Typesense collections
bin/rails sqlite_fts:reindex  # Rebuild SQLite FTS indexes
```

#### Environment Variables

Configure Typesense via environment variables in your `.env` file:

**Local development (single node):**

| Variable | Default | Description |
|----------|---------|-------------|
| `TYPESENSE_HOST` | `localhost` | Typesense server host |
| `TYPESENSE_PORT` | `8108` | Typesense server port |
| `TYPESENSE_PROTOCOL` | `http` | Protocol to use |
| `TYPESENSE_API_KEY` | `xyz` | Your Typesense API key |

**Typesense Cloud with Search Delivery Network (SDN):**

| Variable | Default | Description |
|----------|---------|-------------|
| `TYPESENSE_NODES` | - | Comma-separated list of node hosts (e.g., `xxx-1.a1.typesense.net,xxx-2.a1.typesense.net,xxx-3.a1.typesense.net`) |
| `TYPESENSE_NEAREST_NODE` | - | SDN nearest node hostname (e.g., `xxx.a1.typesense.net`) |
| `TYPESENSE_PORT` | `443` | Typesense server port |
| `TYPESENSE_PROTOCOL` | `https` | Protocol to use |
| `TYPESENSE_API_KEY` | - | Your Typesense Admin API key |

**Other options:**

| Variable | Default | Description |
|----------|---------|-------------|
| `SEARCH_INDEX_ON_IMPORT` | `true` | Whether to update search indexes when importing data from YAML files. Set to `false` to skip indexing during imports (useful for bulk imports followed by a full reindex) |

For local development with Docker, the defaults work out of the box. For production with Typesense Cloud, set `TYPESENSE_NODES` and `TYPESENSE_NEAREST_NODE` to enable the SDN configuration.

## Running the Database Seeds

After adding or modifying data, seed the database to see your changes.
If you are running the dev server, Guard will attempt to import for you on modification.
But if you are not running the dev server, or run into issues - use the seeds.

This will seed the last 6 months of conferences, and all future events and meetups.

```bash
bin/rails db:seed
```

This will seed all data and is what we use in production.

```bash
bin/rails db:seed:all
```

Import one event series and all included events.

```bash
bin/rails db:seed:event_series[blue-ridge-ruby]
```

You can also seed one event series with a script.
This will let you search and select the series.

```bash
rails runner scripts/import_event.rb blue-ridge-ruby
# Search for a series
rails runner scripts/import_event.rb
```

Import all events and event data (but not the series or anything else).
This one is good if you're updating a lot of events at once and backfilling data.
For example, adding coordinates, venues, involvements, sponsors, etc.
It will error if there's a new series (or old one because you haven't run `db:seed:all` yet).

```bash
bin/rails db:seed:events
```

Import all speakers. Great for testing profile changes.

```bash
bin/rails db:seed:speakers
```

### Troubleshooting

If you encounter a ** Process memory map: ** error, close the dev server, run seeds, and restart.

## Running Tests

We use minitest for all our testing.

Run the full test suite with:

```bash
rails test
```

Run just one test using:

```bash
rails test test/models/talk_test.rb
```

Run just one example using:

```bash
rails test test/models/talk_test.rb:6
```

## UI

For the front-end, we use [Vite](https://vite.dev/), [Tailwind CSS](https://tailwindcss.com/) with [Daisyui](https://daisyui.com/) components, [Hotwire](https://hotwired.dev/), and [Stimulus](https://stimulus.hotwired.dev/).

You can find existing RubyEvents components in our [component library](https://www.rubyevents.org/components).

## Queue

We use SolidQueue!

Open the rails console and run the following to clear the queue.

```
SolidQueue::Queue.new("default").clear
```

Get a count of enqueued jobs.

```
SolidQueue::Queue.new("default").size
```

## Contributing new events

Discovering and documenting new Ruby events is an ongoing effort, and a fantastic way to get familiar with the codebase!

All conference data is stored in the `/data` folder with the following structure:

```
data/
├── speakers.yml                    # Global speaker database
├── railsconf/                      # Series folder
│   ├── series.yml                  # Series metadata
│   ├── railsconf-2023/             # Event folder
│   │   ├── event.yml               # Event metadata
│   │   ├── videos.yml              # Talk data
│   │   ├── schedule.yml            # Optional schedule
│   │   ├── sponsors.yml            # Optional sponsors data
│   │   └── venue.yml               # Optional venue
│   └── railsconf-2024/
│       ├── event.yml
│       └── videos.yml
└── rubyconf/
    ├── series.yml
    └── ...
```

A conference series (`series.yml`) describes a series of events.
Each folder represents a different instance of that event, and must contain an `event.yml`.

The schema for each file is located in `/app/schemas`.

If the YouTube videos for an event are available, you can [create events with a script](docs/ADDING_VIDEOS.md).
Otherwise, you can [create the event or event series manually](docs/ADDING_EVENTS.md).

There are additional guides for adding optional information:

- [visual assets](/docs/ADDING_VISUAL_ASSETS.md)
- [videos](/docs/ADDING_VIDEOS.md)
- [schedules](/docs/ADDING_SCHEDULES.md)
- [sponsors](/docs/ADDING_SPONSORS.md)
- [venues](/docs/ADDING_VENUES.md)

If you have questions about contributing events:

- Open an issue on GitHub
- Check existing event files for examples
- Reference this documentation

Your contributions help make RubyEvents a comprehensive resource for the Ruby community!


================================================
FILE: Dockerfile
================================================
# syntax=docker/dockerfile:1
# check=error=true

# This Dockerfile is designed for production, not development. Use with Kamal or build'n'run by hand:
# docker build -t rubyevents .
# docker run -d -p 80:80 -e RAILS_MASTER_KEY=<value from config/master.key> --name rubyevents rubyevents

# For a containerized dev environment, see Dev Containers: https://guides.rubyonrails.org/getting_started_with_devcontainer.html

# Make sure RUBY_VERSION matches the Ruby version in .ruby-version
ARG RUBY_VERSION=4.0.1
FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base

# Rails app lives here
WORKDIR /rails

# Install base packages
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y curl imagemagick libjemalloc2 libvips sqlite3 && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Set production environment
ENV RAILS_ENV="production" \
    BUNDLE_DEPLOYMENT="1" \
    BUNDLE_PATH="/usr/local/bundle" \
    BUNDLE_WITHOUT="development"

# Throw-away build stage to reduce size of final image
FROM base AS build

# Install packages needed to build gems and node modules
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y build-essential git node-gyp pkg-config libyaml-dev python-is-python3 && \
    rm -rf /var/lib/apt/lists /var/cache/apt/archives

# Install JavaScript dependencies
ARG NODE_VERSION=22.15.1
ARG YARN_VERSION=1.22.22
ENV PATH=/usr/local/node/bin:$PATH
RUN curl -sL https://github.com/nodenv/node-build/archive/master.tar.gz | tar xz -C /tmp/ && \
    /tmp/node-build-master/bin/node-build "${NODE_VERSION}" /usr/local/node && \
    npm install -g yarn@$YARN_VERSION && \
    rm -rf /tmp/node-build-master

# Install application gems
COPY Gemfile Gemfile.lock .ruby-version ./
RUN bundle install && \
    rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
    bundle exec bootsnap precompile --gemfile

# Install node modules
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile

# Copy application code
COPY . .

# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile app/ lib/

# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile


RUN rm -rf node_modules


# Final stage for app image
FROM base

# Copy built artifacts: gems, application
COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
COPY --from=build /rails /rails

# Run and own only the runtime files as a non-root user for security
RUN groupadd --system --gid 1000 rails && \
    useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \
    chown -R rails:rails db log storage tmp
USER 1000:1000

# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]

# Start server via Thruster by default, this can be overwritten at runtime
EXPOSE 80
CMD ["./bin/thrust", "./bin/rails", "server"]


================================================
FILE: Gemfile
================================================
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby file: ".ruby-version"

# Use Rails edge
gem "rails", github: "rails/rails"

# The modern asset pipeline for Rails [https://github.com/rails/propshaft]
gem "propshaft"

# Use sqlite3 as the database for Active Record
gem "sqlite3", ">= 2.1.0"

# Use the Puma web server [https://github.com/puma/puma]
gem "puma"

# use jbuilder for the api
gem "jbuilder"

# Bundle and transpile JavaScript [https://github.com/rails/jsbundling-rails]
# gem "jsbundling-rails"

# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]
gem "turbo-rails"

# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
# gem "stimulus-rails"

# Bundle and process CSS [https://github.com/rails/cssbundling-rails]
# gem "cssbundling-rails"

# Use Redis adapter to run Action Cable in production
# gem "redis", ">= 4.0.1"

# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis]
# gem "kredis"

# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
gem "bcrypt", "~> 3.1.7"

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem "tzinfo-data", platforms: %i[windows jruby]

# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", require: false

# Deploy this application anywhere as a Docker container [https://kamal-deploy.org]
gem "kamal", "2.7.0", require: false

# Add HTTP asset caching/compression and X-Sendfile acceleration to Puma [https://github.com/basecamp/thruster/]
gem "thruster", require: false

# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
gem "image_processing", "~> 1.2"

# Image processing for event asset generation
gem "mini_magick"

# All sorts of useful information about every country packaged as convenient little country objects
gem "countries"

# ISO 639-1 and ISO 639-2 language code entries and convenience methods
gem "iso-639"

# A minimal client of Bluesky/ATProto API
gem "minisky", "~> 0.4.0"

# Extract Collaborator Objects from your Active Records, a new concept called Associated Objects
gem "active_record-associated_object"

# Headless Chrome driver for Capybara
gem "cuprite"

# Reusable modules for tasks like data extraction, scoring, and ranking
gem "active_genie"

# A single delightful Ruby way to work with AI.
gem "ruby_llm", "~> 1.9.1"

# A simple and clean Ruby DSL for creating JSON schemas.
gem "ruby_llm-schema"

# JSON Schema validator
gem "json_schemer"

# YouTube V3 API client.
gem "yt"

# Family of libraries that support various formats of XML "feeds".
gem "rss", "~> 0.3.1"

# Powerful and seamless HTML-aware ERB parsing and tooling.
gem "herb", "~> 0.9"

# An ActionView-compatible ERB engine with modern DX - re-imagined with Herb.
gem "reactionview", "~> 0.3"

# Agnostic pagination in plain ruby.
gem "pagy"

# gem "activerecord-enhancedsqlite3-adapter"
gem "solid_cache"

# Database-backed Active Job backend.
gem "solid_queue", github: "joshleblanc/solid_queue", branch: "async-mode"

# Operational controls for Active Job
gem "mission_control-jobs"

# Simple, powerful, first-party analytics for Rails
gem "ahoy_matey"

# The simplest way to group temporal data
gem "groupdate"

# Create beautiful JavaScript charts with one line of Ruby
gem "chartkick", "~> 5.0"

# Use Vite in Rails and bring joy to your JavaScript experience
gem "vite_rails"

# Collection of SEO helpers for Ruby on Rails.
gem "meta-tags"

# Logs performance and exception data from your app to appsignal.com
gem "appsignal"

# Autoload dotenv in Rails.
gem "dotenv-rails"

# Automatic generation of html links in texts
gem "rails_autolink", "~> 1.1"

# Easily generate XML Sitemaps
gem "sitemap_generator", "~> 6.3"

# A framework for building reusable, testable & encapsulated view components
gem "view_component"

# Adds ActiveRecord-specific methods to Dry::Initializer
gem "dry-initializer-rails"

# Type system for Ruby supporting coercions, constraints and complex types
gem "dry-types", "~> 1.7"

# Protocol Buffers are Google's data interchange format.
gem "google-protobuf", require: false

# ActiveJob::Performs adds the `performs` macro to set up jobs by convention.
gem "active_job-performs"

# Use the OpenAI API with Ruby!
gem "ruby-openai"

# Repairs broken JSON strings.
gem "json-repair", "~> 0.2.0"

# Markdown that smells nice
gem "redcarpet", "~> 3.6"

# Syntax highlighting
gem "rouge", "~> 4.4"

# Country Select Plugin
gem "country_select"

# Admin panel framework and Content Management System for Ruby on Rails.
gem "avo"

group :avo, optional: true do
  gem "avo-pro", source: "https://packager.dev/avo-hq/"
end

# Marksmith is a GitHub-style markdown editor for Ruby on Rails applications.
gem "marksmith"

# A fast, safe, extensible parser for CommonMark. This wraps the comrak Rust crate.
gem "commonmarker", ">= 2.6.1"

# ActiveRecord like interface to read only access and query static YAML files
gem "frozen_record", "~> 0.27.2"

# A convenient way to diff string in ruby
gem "diffy"

# ActiveRecord soft-deletes done right
gem "discard"

# Makes consuming restful web services dead easy.
gem "httparty"

# Use OmniAuth to support multi-provider authentication [https://github.com/omniauth/omniauth]
gem "omniauth"

# Official OmniAuth strategy for GitHub.
gem "omniauth-github"

# Provides a mitigation against CVE-2015-9284 [https://github.com/cookpad/omniauth-rails_csrf_protection]
gem "omniauth-rails_csrf_protection"

# An accessible autocomplete for Ruby on Rails apps using Hotwire.
gem "hotwire_combobox", "~> 0.4.0"

# Common locale data and translations for Rails i18n.
gem "rails-i18n", "~> 8.0"

# Ruby standards gems
gem "openssl" # https://github.com/ruby/openssl/issues/949

# Class to build custom data structures, similar to a Hash.
gem "ostruct"

# Complete geocoding solution for Ruby.
gem "geocoder", github: "alexreisner/geocoder" # Use latest geocoder with Nominatim improvements until next release

# RubyGems.org API wrapper for gem information
gem "gems"

# A glamorous CLI toolkit for Ruby
gem "gum", "~> 0.3.1"

# Regex pattern searching in files
gem "grepfruit"

# Create beautiful JavaScript maps with one line of Ruby
gem "mapkick-rb", "~> 0.2.0"

# Typesense Ruby client
gem "typesense", "~> 4.1"

# Typesense integration to your favorite ORM
gem "typesense-rails", "~> 1.0.0.rc4"

group :development, :test do
  # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
  gem "bundler-audit", require: false
  gem "debug", platforms: %i[mri windows]
  gem "byebug"
  gem "minitest-difftastic", "~> 0.2"
end

group :development do
  # A gem for generating annotations for Rails projects.
  gem "annotaterb"

  # Use console on exceptions pages [https://github.com/rails/web-console]
  gem "web-console"

  # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler]
  gem "rack-mini-profiler"

  # For call-stack profiling flamegraphs
  gem "stackprof"

  # Speed up commands on slow machines / big apps [https://github.com/rails/spring]
  # gem "spring"

  # Use listen to watch files for changes [https://github.com/guard/listen]
  gem "listen", "~> 3.5"

  # Guard for watching file changes and auto-importing [https://github.com/guard/guard]
  gem "guard"

  gem "ruby-lsp-rails", require: false
  gem "standardrb", "~> 1.0", require: false
  gem "erb_lint", require: false
  gem "authentication-zero", require: false
end

group :test do
  # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
  gem "capybara"
  gem "rails-controller-testing"
  gem "selenium-webdriver"
  gem "vcr", "~> 6.1"
  gem "webmock"
end


================================================
FILE: Guardfile
================================================
# Guardfile for watching YAML files in data/ and auto-importing them

require_relative "lib/guard/data_import"

guard :data_import, wait_for_delay: 2 do
  watch(%r{^data/speakers\.yml$})
  watch(%r{^data/topics\.yml$})
  watch(%r{^data/featured_cities\.yml$})
  watch(%r{^data/[^/]+/series\.yml$})
  watch(%r{^data/[^/]+/[^/]+/event\.yml$})
  watch(%r{^data/[^/]+/[^/]+/videos\.yml$})
  watch(%r{^data/[^/]+/[^/]+/cfp\.yml$})
  watch(%r{^data/[^/]+/[^/]+/sponsors\.yml$})
  watch(%r{^data/[^/]+/[^/]+/schedule\.yml$})
end


================================================
FILE: Procfile.dev
================================================
web: bin/rails server -b 0.0.0.0
vite: bin/vite dev
jobs: bin/jobs
# guard: bundle exec guard --no-interactions


================================================
FILE: README.md
================================================
# RubyEvents.org (formerly RubyVideo.dev)

[RubyEvents.org](https://www.rubyevents.org) (formerly RubyVideo.dev), inspired by [pyvideo.org](https://pyvideo.org/), is designed to index all Ruby-related events and videos from conferences and meetups around the world. At the time of writing, the project has 6000+ videos indexed from 200+ events and 3000+ speakers.

Technically the project is built using the latest [Ruby](https://www.ruby-lang.org/) and [Rails](https://rubyonrails.org/) goodies such as [Hotwire](https://hotwired.dev/), [Solid Queue](https://github.com/rails/solid_queue), [Solid Cache](https://github.com/rails/solid_cache).

For the front end part we use [Vite](https://vite.dev/), [Tailwind](https://tailwindcss.com/) with [daisyUI](https://daisyUI.com/) components and [Stimulus](https://stimulus.hotwire.dev/).

It is deployed on an [Hetzner](https://hetzner.cloud/?ref=gyPLk7XJthjg) VPS with [Kamal](https://kamal-deploy.org/) using [SQLite](https://www.sqlite.org/) as the main database.

For compatible browsers it tries to demonstrate some of the possibilities of [Page View Transition API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API).

## Contributing

This project is open source, and contributions are greatly appreciated. One of the most direct ways to contribute at this time is by adding more content.

We also have a page on the deployed site that has up-to-date information with the remaining known TODOs. Check out the ["Getting Started: Ways to Contribute" page on RubyEvents.org](https://www.rubyevents.org/contributions) and feel free to start working on any of the remaining TODOs. Any help is greatly appreciated.

For more information on contributing, see the [Contributing Guide](/CONTRIBUTING.md).

## Code of Conduct

Please note that this project is released with a Contributor Code of Conduct. By participating in this project, you agree to abide by its terms. More details can be found in the [Code of Conduct](/CODE_OF_CONDUCT.md) document.

## Credits

Thank you [AppSignal](https://appsignal.com/r/eeab047472) for providing the APM tool that helps us monitor the application.

Thank you [Typesense](https://typesense.org/) for sponsoring our [Typesense Cloud](https://cloud.typesense.org/) instance that powers the search functionality.

## License

RubyEvents.org is open source and available under the MIT License. For more information, please see the [License](/LICENSE.md) file.


================================================
FILE: Rakefile
================================================
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.

require_relative "config/application"

Rails.application.load_tasks


================================================
FILE: app/assets/builds/.keep
================================================


================================================
FILE: app/assets/stylesheets/application.css
================================================
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

@import "components/button.css";
@import "components/diff.css";
@import "components/dropdown.css";
@import "components/event.css";
@import "components/form.css";
@import "components/hotwire-combobox.css";
@import "components/markdown.css";
@import "components/modal.css";
@import "components/nav.css";
@import "components/pagination.css";
@import "components/tabs.css";
@import "components/skeleton.css";
@import "components/spotlight.css";
@import "components/transition.css";
@import "components/typography.css";
@import "components/video.css";
@import "components/iframe.css";

@import "vlitejs/vlite.css";

@import "bridge/components";
@import "flag-icons/css/flag-icons.min.css";

turbo-frame[id^="browse-"][complete] {
  display: contents;
}


================================================
FILE: app/assets/stylesheets/bridge/components.css
================================================
html[data-bridge-platform] {
  user-select: none;
}

[data-bridge-components~="button"] [data-controller~="bridge--button"] {
  display: none;
}


================================================
FILE: app/assets/stylesheets/components/button.css
================================================
@layer components {
  .btn {
    @apply fill-current;
  }

  .btn:not(.btn-sm) {
    height: 2.5rem;
    min-height: 2.5rem;
  }

  .btn-rounded {
    @apply btn-outline rounded-full border border-gray-400 bg-white hover:border-gray-500 hover:bg-gray-100 hover:text-base-content/80;
  }

  .btn-circle {
    @apply btn-rounded;
    @apply h-10 w-10;
  }

  /* for the toolbar buttons */
  .btn.btn-pill {
    @apply btn-rounded btn-outline;
    @apply flex-nowrap whitespace-nowrap;

    /* for the watched button */
    &.active {
      @apply border-primary bg-primary text-primary-content;
    }

    &.btn-sm {
      @apply text-sm font-normal;
    }
  }

  .btn.btn-secondary {
    @apply whitespace-nowrap border-primary bg-white fill-primary text-primary hover:bg-gray-100 hover:text-primary/90;
  }

  .btn.btn-neutral {
    @apply bg-white hover:fill-neutral/80 hover:text-neutral/80;
  }
}


================================================
FILE: app/assets/stylesheets/components/diff.css
================================================
@layer components {
  .diff {
    del {
      @apply text-error;
    }

    ins {
      @apply text-success;
    }
  }
}


================================================
FILE: app/assets/stylesheets/components/dropdown.css
================================================
@layer components {
  details > summary {
    list-style: none;
  }

  /* fix the dropdown button to links, by default daisyui adds padding to the form element */
  /* therefore the inner button does not fill the dropdown item */
  /* and only the text of the button is clickable */
  .menu li form.button_to {
    padding: 0;
    display: block;
  }

  .menu li form.button_to button {
    display: block;
    width: 100%;
    text-align: start;
    padding: 0.5rem 1rem;
  }
}


================================================
FILE: app/assets/stylesheets/components/event.css
================================================
@layer components {
  .event-card.cancelled,
  .card.cancelled {
    opacity: 0.5;
  }
}


================================================
FILE: app/assets/stylesheets/components/form.css
================================================
@layer components {
  label {
    @apply font-semibold;
  }

  /* because setting --rounded-btn to 1.9rem makes also all input field fully rounded  */
  /* we override this behaviour */
  .input,
  .textarea {
    @apply rounded-lg border border-gray-200 bg-white;
  }
}


================================================
FILE: app/assets/stylesheets/components/hotwire-combobox.css
================================================
@layer components {
  .hw-combobox__main__wrapper {
    @apply min-h-12;
  }

  .hw-combobox__main__wrapper:has(input:focus) {
    box-shadow: none;
    border-color: var(--fallback-bc, oklch(var(--bc)/0.2));
    outline-style: solid;
    outline-width: 2px;
    outline-offset: 2px;
    outline-color: var(--fallback-bc, oklch(var(--bc)/0.2));
  }

  .hw-combobox__main__wrapper input:focus {
    box-shadow: none;
    border-color: none;
    outline-style: none;
    outline-color: none;
  }

  :root {
    --hw-focus-color: rgb(var(--fallback-bc));
    --hw-combobox-width: 100%;
    --hw-combobox-width--multiple: 100%;
  }
}


================================================
FILE: app/assets/stylesheets/components/iframe.css
================================================
@layer components {
  .responsive-iframe-container iframe {
    width: 100%;
  }
}


================================================
FILE: app/assets/stylesheets/components/markdown.css
================================================
@layer components {
  .markdown {
    p {
      @apply mb-2;
    }

    h1,
    h2,
    h3,
    h4,
    h5,
    h6 {
      @apply mb-4 mt-8;
    }

    h1,
    h2,
    h3 {
      @apply text-primary;
    }

    ul {
      @apply mb-4;
      li {
        @apply ml-6 list-disc;
      }
    }

    ol {
      @apply mb-4;
      li {
        @apply ml-6 list-decimal;
      }
    }

    a {
      @apply text-primary;
    }

    /* Tables */
    table {
      @apply w-full border-collapse mb-4;
    }

    th,
    td {
      @apply border border-base-300 px-4 py-2 text-left;
    }

    th {
      @apply bg-base-200 font-semibold;
    }

    tr:nth-child(even) {
      @apply bg-base-200/50;
    }

    /* Code blocks - override prose styles */
    pre {
      @apply rounded-sm p-4 mb-4 overflow-x-auto text-base bg-base-200;
      color: #24292e !important;
    }

    pre.highlight {
      @apply bg-base-200;
    }

    pre code {
      @apply text-sm;
      color: inherit !important;
      background: transparent !important;
    }

    /* Inline code */
    :not(pre) > code {
      @apply bg-base-200 px-1.5 py-0.5 rounded text-sm;
      color: #24292e !important;
    }

    /* Rouge syntax highlighting - GitHub-like theme */
    .highlight {
      .c,
      .c1,
      .cm {
        color: #6a737d;
        font-style: italic;
      } /* Comments */
      .k,
      .kd,
      .kn,
      .kp,
      .kr,
      .kt {
        color: #d73a49;
      } /* Keywords */
      .s,
      .s1,
      .s2,
      .sb,
      .sc,
      .sd,
      .se,
      .sh,
      .si,
      .sx {
        color: #032f62;
      } /* Strings */
      .n,
      .na,
      .nb,
      .nc,
      .nd,
      .ne,
      .nf,
      .ni,
      .nl,
      .nn,
      .no,
      .nt,
      .nv {
        color: #6f42c1;
      } /* Names */
      .mi,
      .mf,
      .mh,
      .mo,
      .il {
        color: #005cc5;
      } /* Numbers */
      .o,
      .ow {
        color: #d73a49;
      } /* Operators */
      .p {
        color: #24292e;
      } /* Punctuation */
      .cp {
        color: #d73a49;
      } /* Preprocessor */
      .err {
        color: #b31d28;
        background-color: #ffeef0;
      } /* Errors */
    }
  }
}


================================================
FILE: app/assets/stylesheets/components/modal.css
================================================
@layer components {
  .modal-box {
    @apply bg-white;
  }

  .modal-top.spotlight {
    .modal-box {
      @apply absolute left-0 right-0 top-4 mx-4 w-auto rounded-lg lg:top-8 lg:mx-8;
    }
  }
}


================================================
FILE: app/assets/stylesheets/components/nav.css
================================================
@layer components {
  .desktop-menu {
    @apply hidden gap-6 md:flex;

    li,
    title {
      @apply m-0 inline-block;
      div {
        @apply invisible h-0.5 bg-primary;
      }
      &.active {
        @apply relative;
        & > div {
          view-transition-name: navbar-active;
          @apply visible absolute bottom-0 w-full font-bold;
        }
      }
    }
  }

  .mobile-menu {
    @apply flex md:hidden;
  }
}


================================================
FILE: app/assets/stylesheets/components/pagination.css
================================================
@layer components {
  nav.pagy.nav {
    @apply mx-auto flex justify-normal gap-4 bg-transparent text-base-content sm:gap-8;

    .current {
      @apply font-semibold text-primary;
    }

    .page.disabled {
      @apply text-base-300;
    }
  }
}


================================================
FILE: app/assets/stylesheets/components/skeleton.css
================================================
@layer components {
  .skeleton {
    border-radius: inherit;
  }
}


================================================
FILE: app/assets/stylesheets/components/spotlight.css
================================================
@layer components {
  .modal-box.spotlight {
    @apply max-w-full;
  }

  [role="option"][aria-selected="true"] {
    @apply font-bold;
  }
}


================================================
FILE: app/assets/stylesheets/components/tabs.css
================================================
@layer components {
  /* https://github.com/saadeghi/daisyui/issues/2988 */
  .tabs {
    display: flex;
    flex-wrap: wrap;
  }
  .tab {
    order: 0;
  }
  .tab-content {
    order: 1;
    width: 100%;
  }
}


================================================
FILE: app/assets/stylesheets/components/transition.css
================================================
@layer components {
  ::view-transition-group(root) {
    animation: none;
    mix-blend-mode: normal;
  }

  .navbar {
    view-transition-name: navbar;
    contain: layout;
  }

  .banner-img .v-vlite {
    contain: layout;
  }

  .card-horizontal-img img {
    contain: layout;
  }

  .gallery img {
    contain: layout;
  }

  @keyframes fade-in {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }

  @keyframes fade-out {
    from {
      opacity: 1;
    }
    to {
      opacity: 0;
    }
  }

  ::view-transition-old(card-horizontal-img),
  ::view-transition-new(card-horizontal-img) {
    animation: none;
    mix-blend-mode: normal;
  }

  ::view-transition-image-pair(card-horizontal-img) {
    isolation: none;
  }

  ::view-transition-old(banner-img),
  ::view-transition-new(banner-img) {
    animation: none;
    mix-blend-mode: normal;
  }

  ::view-transition-image-pair(banner-img) {
    isolation: none;
  }
}


================================================
FILE: app/assets/stylesheets/components/typography.css
================================================
@import url("https://fonts.googleapis.com/css2?family=Nunito:wght@200..1000&display=swap");

:root {
  font-family: Inter, sans-serif;
  font-feature-settings: "liga" 1, "calt" 1; /* fix for Chrome */
}
@supports (font-variation-settings: normal) {
  :root {
    font-family: InterVariable, sans-serif;
  }
}

@layer components {
  body {
    @apply bg-base-100 leading-relaxed text-base-content;
  }

  h1,
  .h1 {
    @apply font-serif text-3xl font-bold text-primary;
  }

  h2,
  .h2 {
    @apply font-serif text-xl  font-bold;
  }

  p.secondary {
    @apply text-neutral-content;
  }

  a.link-ghost {
    @apply hover:underline;
    text-decoration: none;
  }

  mark {
    /* search results highlight */
    background-color: rgb(242, 255, 140);
  }
}


================================================
FILE: app/assets/stylesheets/components/video.css
================================================
@layer components {
  .banner-img .v-vlite {
    --vlite-controlsColor: #ffffff;
    --vlite-controlsOpacity: 1;
    --vlite-controlBarBackground: linear-gradient(0deg, #000 -50%, #fff);
  }

  .v-playbackRateSelect.v-controlButton {
    color: var(--vlite-controlsColor);
    text-align: center;
  }

  .v-loader {
    display: none !important;
  }

  .v-bigPlay,
  .v-overlay,
  .v-poster {
    display: none !important;
  }

  .v-openInYouTube.v-controlButton svg {
    width: 65%;
    fill: var(--vlite-controlsColor);
  }

  /* Picture in picture styling */
  .picture-in-picture .picture-in-picture-container {
    @apply sm:fixed sm:bottom-4 sm:right-4 sm:z-10 sm:h-auto sm:w-full sm:max-w-sm sm:rounded-xl xl:max-w-lg;
    .v-video {
      @apply rounded-xl;
    }
  }
}


================================================
FILE: app/avo/actions/approve_topic.rb
================================================
class Avo::Actions::ApproveTopic < Avo::BaseAction
  self.name = "Publish Topic"

  def handle(query:, fields:, current_user:, resource:, **args)
    query.each do |record|
      record.approved!
    end
  end
end


================================================
FILE: app/avo/actions/assign_canonical_event.rb
================================================
class Avo::Actions::AssignCanonicalEvent < Avo::BaseAction
  self.name = "Assign Canonical Event"
  # self.visible = -> do
  #   true
  # end

  def fields
    field :event_id, as: :select, name: "Canonical event",
      help: "The name of the event to be set as canonical",
      options: -> { Event.order(:name).pluck(:name, :id) }
  end

  def handle(query:, fields:, current_user:, resource:, **args)
    canonical_event = Event.find(fields[:event_id])

    query.each do |record|
      record.assign_canonical_event!(canonical_event: canonical_event)
    end

    succeed "Assigning canonical event #{canonical_event.name} to #{query.count} events"
    redirect_to avo.resources_event_path(canonical_event)
  end
end


================================================
FILE: app/avo/actions/assign_canonical_speaker.rb
================================================
class Avo::Actions::AssignCanonicalSpeaker < Avo::BaseAction
  self.name = "Assign Canonical Speaker"
  # self.visible = -> do
  #   true
  # end

  def fields
    field :speaker_id, as: :select, name: "Canonical speaker",
      help: "The name of the speaker to be set as canonical",
      options: -> { User.speakers.order(:name).pluck(:name, :id) }
  end

  def handle(query:, fields:, current_user:, resource:, **args)
    canonical_speaker = User.find(fields[:speaker_id])

    query.each do |record|
      record.assign_canonical_speaker!(canonical_speaker: canonical_speaker)
    end

    succeed "Assigning canonical speaker #{canonical_speaker.name} to #{query.count} speakers"
    redirect_to avo.resources_user_path(canonical_speaker), status: :permanent_redirect
  end
end


================================================
FILE: app/avo/actions/assign_canonical_topic.rb
================================================
class Avo::Actions::AssignCanonicalTopic < Avo::BaseAction
  self.name = "Assign Canonical Topic"
  # self.visible = -> do
  #   true
  # end

  def fields
    field :topic_id, as: :select, name: "Canonical topic",
      help: "The name of the topic to be set as canonical",
      options: -> { Topic.approved.order(:name).pluck(:name, :id) }
  end

  def handle(query:, fields:, current_user:, resource:, **args)
    canonical_topic = Topic.find(fields[:topic_id])

    query.each do |record|
      record.assign_canonical_topic!(canonical_topic: canonical_topic)
    end

    succeed "Assigning canonical topic #{canonical_topic.name} to #{query.count} topics"
    redirect_to avo.resources_topic_path(canonical_topic)
  end
end


================================================
FILE: app/avo/actions/assign_canonical_user.rb
================================================
class Avo::Actions::AssignCanonicalUser < Avo::BaseAction
  self.name = "Assign Canonical User"

  def fields
    field :user_id, as: :select, name: "Canonical user",
      help: "The name of the speaker to be set as canonical",
      options: -> { User.order(:name).pluck(:name, :id) }
  end

  def handle(query:, fields:, current_user:, resource:, **args)
    canonical_user = User.find(fields[:user_id])

    query.each do |record|
      record.assign_canonical_user!(canonical_user: canonical_user)
    end

    succeed "Assigning canonical user #{canonical_user.name} to #{query.count} users"
    redirect_to avo.resources_user_path(canonical_user), status: :permanent_redirect
  end
end


================================================
FILE: app/avo/actions/clear_user.rb
================================================
class Avo::Actions::ClearUser < Avo::BaseAction
  self.name = "Clear Suspicion"
  self.message = "Mark this user as manually reviewed and not suspicious."

  def handle(query:, fields:, current_user:, resource:, **args)
    query.each do |user|
      user.clear_suspicion!
    end

    succeed "Cleared suspicion for #{query.count} user(s)."
  end
end


================================================
FILE: app/avo/actions/enhance_transcript.rb
================================================
class Avo::Actions::EnhanceTranscript < Avo::BaseAction
  self.name = "Enhance Transcript"
  def handle(query:, fields:, current_user:, resource:, **args)
    query.each do |item|
      talk = item.is_a?(Talk::Transcript) ? item.talk : item
      talk.agents.improve_transcript_later
    end
  end
end


================================================
FILE: app/avo/actions/extract_topics.rb
================================================
class Avo::Actions::ExtractTopics < Avo::BaseAction
  self.name = "Extract Topics"

  def handle(query:, fields:, current_user:, resource:, **args)
    query.each do |talk|
      talk.agents.analyze_topics_later
    end
  end
end


================================================
FILE: app/avo/actions/fetch_duration.rb
================================================
class Avo::Actions::FetchDuration < Avo::BaseAction
  self.name = "Fetch duration"

  def handle(query:, fields:, current_user:, resource:, **args)
    query.each do |record|
      record.fetch_duration_from_youtube_later!
    end

    succeed "Fetching the duration in the background"
  end
end


================================================
FILE: app/avo/actions/find_topic_talks.rb
================================================
class Avo::Actions::FindTopicTalks < Avo::BaseAction
  self.name = "Find Talks"

  def handle(query:, fields:, current_user:, resource:, **args)
    query.each do |topic|
      topic.agents.find_talks_later
    end

    succeed "Enqueued job to find talks for #{query.count} topic(s)"
  end
end


================================================
FILE: app/avo/actions/geocode_record.rb
================================================
class Avo::Actions::GeocodeRecord < Avo::BaseAction
  self.name = "Geocode location"

  def handle(query:, fields:, current_user:, resource:, records:, **args)
    items = records.presence || query.to_a
    perform_in_background = items.size >= 10
    processed = 0
    skipped = 0

    model_name = items.first&.model_name&.human&.downcase || "record"

    items.each do |record|
      unless record.geocodeable?
        skipped += 1
        next
      end

      if perform_in_background
        GeocodeRecordJob.perform_later(record)
      else
        GeocodeRecordJob.perform_now(record)
      end

      processed += 1
    end

    message = "Geocoding #{perform_in_background ? "enqueued" : "completed"} for #{processed} #{model_name.pluralize(processed)}"
    message += " (#{skipped} skipped without location)" if skipped > 0
    succeed message
  end
end


================================================
FILE: app/avo/actions/reject_topic.rb
================================================
class Avo::Actions::RejectTopic < Avo::BaseAction
  self.name = "Reject Topic"
  # self.visible = -> do
  #   true
  # end

  # def fields
  #   # Add Action fields here
  # end

  def handle(query:, fields:, current_user:, resource:, **args)
    query.each do |record|
      record.rejected!
    end
  end
end


================================================
FILE: app/avo/actions/summarize.rb
================================================
class Avo::Actions::Summarize < Avo::BaseAction
  self.name = "Summarize"

  def handle(query:, fields:, current_user:, resource:, **args)
    query.each do |talk|
      talk.agents.summarize_later
    end
  end
end


================================================
FILE: app/avo/actions/talk_index.rb
================================================
class Avo::Actions::TalkIndex < Avo::BaseAction
  self.name = "Talk Reindex"
  self.standalone = true

  def handle(query:, fields:, current_user:, resource:, **args)
    if query.empty?
      Talk.all.in_batches.each(&:update_fts_record_later_bulk)

      succeed "All Talks reindexed"
    else
      query.in_batches.each(&:update_fts_record_later_bulk)

      succeed "Selected talks are added to the index"
    end
  end
end


================================================
FILE: app/avo/actions/talk_ingest.rb
================================================
class Avo::Actions::TalkIngest < Avo::BaseAction
  self.name = "Ingest talk (fetch transcript, enhance transcript, summarize, extract topics)"

  def handle(query:, fields:, current_user:, resource:, **args)
    query.each do |record|
      record.agents.ingest_later
    end

    succeed "Ingesting the talks in the background"
  end
end


================================================
FILE: app/avo/actions/transcript.rb
================================================
class Avo::Actions::Transcript < Avo::BaseAction
  self.name = "Fetch raw transcript"

  def handle(query:, fields:, current_user:, resource:, **args)
    query.each do |record|
      record.fetch_and_update_raw_transcript_later!
    end

    succeed "Fetching the transcript in the background"
  end
end


================================================
FILE: app/avo/actions/update_from_yml.rb
================================================
class Avo::Actions::UpdateFromYml < Avo::BaseAction
  self.name = "Update talk from yml metadata"

  def handle(query:, fields:, current_user:, resource:, **args)
    query.each do |record|
      record.update_from_yml_metadata_later!
    end

    succeed "Updating talk from yml metadata"
  end
end


================================================
FILE: app/avo/actions/user_fetch_github.rb
================================================
class Avo::Actions::UserFetchGitHub < Avo::BaseAction
  self.name = "Fetch GitHub profile"

  def handle(query:, fields:, current_user:, resource:, **args)
    perform_in_background = !(query.count < 10)
    query.each do |user|
      perform_in_background ? user.profiles.enhance_with_github_later : user.profiles.enhance_with_github
    end
  end
end


================================================
FILE: app/avo/cards/duplicates_summary.rb
================================================
class Avo::Cards::DuplicatesSummary < Avo::Cards::PartialCard
  self.id = "duplicates_summary"
  self.label = "Duplicate Users"
  self.description = "Users with potential reversed name duplicates"
  self.cols = 1
  self.rows = 1
  self.partial = "avo/cards/duplicates_summary"
end


================================================
FILE: app/avo/cards/reversed_name_duplicates_list.rb
================================================
class Avo::Cards::ReversedNameDuplicatesList < Avo::Cards::PartialCard
  self.id = "reversed_name_duplicates_list"
  self.label = "Duplicate Pairs"
  self.description = "Users with reversed name matches"
  self.cols = 3
  self.rows = 4
  self.partial = "avo/cards/reversed_name_duplicates_list"
end


================================================
FILE: app/avo/cards/reversed_name_duplicates_metric.rb
================================================
class Avo::Cards::ReversedNameDuplicatesMetric < Avo::Cards::MetricCard
  self.id = "reversed_name_duplicates_metric"
  self.label = "Reversed Name Duplicates"
  self.description = "Number of users with potential duplicate profiles (name parts reversed)"
  self.cols = 1

  def query
    result User.with_reversed_name_duplicate.count
  end
end


================================================
FILE: app/avo/cards/same_name_duplicates_list.rb
================================================
class Avo::Cards::SameNameDuplicatesList < Avo::Cards::PartialCard
  self.id = "same_name_duplicates_list"
  self.label = "Same Name Duplicates"
  self.description = "Users with identical names (case-insensitive)"
  self.cols = 3
  self.rows = 2
  self.partial = "avo/cards/same_name_duplicates_list"
end


================================================
FILE: app/avo/cards/same_name_duplicates_metric.rb
================================================
class Avo::Cards::SameNameDuplicatesMetric < Avo::Cards::MetricCard
  self.id = "same_name_duplicates_metric"
  self.label = "Same Name Duplicates"
  self.description = "Users with identical names"
  self.cols = 1

  def query
    result User::DuplicateDetector.same_name_duplicate_ids.count
  end
end


================================================
FILE: app/avo/cards/suspicious_signals_breakdown.rb
================================================
class Avo::Cards::SuspiciousSignalsBreakdown < Avo::Cards::PartialCard
  self.id = "suspicious_signals_breakdown"
  self.label = "Signal Breakdown"
  self.description = "Breakdown of suspicious signals across flagged users"
  self.cols = 2
  self.rows = 2
  self.partial = "avo/cards/suspicious_signals_breakdown"
end


================================================
FILE: app/avo/cards/suspicious_summary.rb
================================================
class Avo::Cards::SuspiciousSummary < Avo::Cards::PartialCard
  self.id = "suspicious_summary"
  self.label = "Suspicious Users"
  self.description = "Users flagged with suspicious signals"
  self.cols = 1
  self.rows = 1
  self.partial = "avo/cards/suspicious_summary"
end


================================================
FILE: app/avo/cards/suspicious_users_list.rb
================================================
class Avo::Cards::SuspiciousUsersList < Avo::Cards::PartialCard
  self.id = "suspicious_users_list"
  self.label = "Suspicious Users"
  self.description = "Users flagged as suspicious based on signal detection"
  self.cols = 3
  self.rows = 4
  self.partial = "avo/cards/suspicious_users_list"
end


================================================
FILE: app/avo/cards/suspicious_users_metric.rb
================================================
class Avo::Cards::SuspiciousUsersMetric < Avo::Cards::MetricCard
  self.id = "suspicious_users_metric"
  self.label = "Suspicious Users"
  self.description = "Number of users flagged as suspicious"
  self.cols = 1

  def query
    result User.suspicious.count
  end
end


================================================
FILE: app/avo/cards/unavailable_videos_by_event.rb
================================================
class Avo::Cards::UnavailableVideosByEvent < Avo::Cards::PartialCard
  self.id = "unavailable_videos_by_event"
  self.label = "By Event"
  self.description = "Unavailable videos grouped by event"
  self.cols = 2
  self.rows = 2
  self.partial = "avo/cards/unavailable_videos_by_event"
end


================================================
FILE: app/avo/cards/unavailable_videos_list.rb
================================================
class Avo::Cards::UnavailableVideosList < Avo::Cards::PartialCard
  self.id = "unavailable_videos_list"
  self.label = "Unavailable Videos"
  self.description = "Talks with videos that are no longer available"
  self.cols = 3
  self.rows = 4
  self.partial = "avo/cards/unavailable_videos_list"
end


================================================
FILE: app/avo/cards/unavailable_videos_metric.rb
================================================
class Avo::Cards::UnavailableVideosMetric < Avo::Cards::MetricCard
  self.id = "unavailable_videos_metric"
  self.label = "Unavailable Videos"
  self.description = "Number of talks with unavailable videos"
  self.cols = 1

  def query
    result Talk.video_unavailable.count
  end
end


================================================
FILE: app/avo/cards/unavailable_videos_summary.rb
================================================
class Avo::Cards::UnavailableVideosSummary < Avo::Cards::PartialCard
  self.id = "unavailable_videos_summary"
  self.label = "Unavailable Videos"
  self.description = "Talks with videos no longer available"
  self.cols = 1
  self.rows = 1
  self.partial = "avo/cards/unavailable_videos_summary"
end


================================================
FILE: app/avo/dashboards/default.rb
================================================
class Avo::Dashboards::Default < Avo::Dashboards::BaseDashboard
  self.id = "default"
  self.name = "Dashboard"
  self.description = "Overview of key metrics and alerts"
  self.grid_cols = 3

  def cards
    card Avo::Cards::DuplicatesSummary
    card Avo::Cards::SuspiciousSummary
    card Avo::Cards::UnavailableVideosSummary
  end
end


================================================
FILE: app/avo/dashboards/duplicates.rb
================================================
class Avo::Dashboards::Duplicates < Avo::Dashboards::BaseDashboard
  self.id = "duplicates"
  self.name = "Duplicate Detection"
  self.description = "Find potential duplicate user profiles"
  self.grid_cols = 3

  def cards
    card Avo::Cards::SameNameDuplicatesMetric
    card Avo::Cards::ReversedNameDuplicatesMetric
    card Avo::Cards::SameNameDuplicatesList
    card Avo::Cards::ReversedNameDuplicatesList
  end
end


================================================
FILE: app/avo/dashboards/suspicious.rb
================================================
class Avo::Dashboards::Suspicious < Avo::Dashboards::BaseDashboard
  self.id = "suspicious"
  self.name = "Suspicious Users"
  self.description = "Monitor and manage suspicious user accounts"
  self.grid_cols = 3

  def cards
    card Avo::Cards::SuspiciousUsersMetric
    card Avo::Cards::SuspiciousSignalsBreakdown
    card Avo::Cards::SuspiciousUsersList
  end
end


================================================
FILE: app/avo/dashboards/unavailable_videos.rb
================================================
class Avo::Dashboards::UnavailableVideos < Avo::Dashboards::BaseDashboard
  self.id = "unavailable_videos"
  self.name = "Unavailable Videos"
  self.description = "Monitor talks with videos that are no longer available"
  self.grid_cols = 3

  def cards
    card Avo::Cards::UnavailableVideosMetric
    card Avo::Cards::UnavailableVideosByEvent
    card Avo::Cards::UnavailableVideosList
  end
end


================================================
FILE: app/avo/filters/aliasable_type.rb
================================================
class Avo::Filters::AliasableType < Avo::Filters::SelectFilter
  self.name = "Aliasable Type"

  def apply(request, query, type)
    if type
      query.where(aliasable_type: type)
    else
      query
    end
  end

  def options
    {
      "User" => "User",
      "EventSeries" => "EventSeries",
      "Organization" => "Organization",
      "Talk" => "Talk"
    }
  end
end


================================================
FILE: app/avo/filters/attended_as.rb
================================================
class Avo::Filters::AttendedAs < Avo::Filters::SelectFilter
  self.name = "Attended as"

  def apply(request, query, attended_as)
    if attended_as
      query.where("attended_as is ?", attended_as)
    else
      query
    end
  end

  def options
    EventParticipation.attended_as
  end
end


================================================
FILE: app/avo/filters/bio.rb
================================================
class Avo::Filters::Bio < Avo::Filters::TextFilter
  self.name = "Bio"
  self.button_label = "Filter by bio (contains)"

  def apply(request, query, value)
    query.where("bio LIKE ?", "%#{value}%")
  end
end


================================================
FILE: app/avo/filters/bio_presence.rb
================================================
class Avo::Filters::BioPresence < Avo::Filters::BooleanFilter
  self.name = "Bio presence"
  # self.visible = -> do
  #   true
  # end

  def apply(request, query, values)
    return query unless values["no_bio"]

    query.where(bio: [nil, ""])
  end

  def options
    {
      no_bio: "Without bio"
    }
  end
end


================================================
FILE: app/avo/filters/canonical.rb
================================================
class Avo::Filters::Canonical < Avo::Filters::BooleanFilter
  self.name = "Canonical"
  # self.visible = -> do
  #   true
  # end

  def apply(request, query, values)
    return query if values["canonical"] && values["not_canonical"]
    if values["canonical"]
      query = query.canonical
    elsif values["not_canonical"]
      query = query.not_canonical
    end
    query
  end

  def options
    {
      canonical: "Has canonical",
      not_canonical: "Without canonical"
    }
  end
end


================================================
FILE: app/avo/filters/enhanced_transcript.rb
================================================
class Avo::Filters::EnhancedTranscript < Avo::Filters::BooleanFilter
  self.name = "Enhanced transcript"
  # self.visible = -> do
  #   true
  # end

  def apply(request, query, values)
    return query if values["has_enhanced_transcript"] && values["no_enhanced_transcript"]

    if values["has_enhanced_transcript"]
      query = query.with_enhanced_transcript
    elsif values["no_enhanced_transcript"]
      query = query.without_enhanced_transcript
    end

    query
  end

  def options
    {
      has_enhanced_transcript: "With enhanced transcript",
      no_enhanced_transcript: "Without enhanced transcript"
    }
  end
end


================================================
FILE: app/avo/filters/geocoded_presence.rb
================================================
class Avo::Filters::GeocodedPresence < Avo::Filters::BooleanFilter
  self.name = "Geocoded"

  def apply(request, query, values)
    return query if values["geocoded"] && values["not_geocoded"]

    if values["geocoded"]
      query.geocoded
    elsif values["not_geocoded"]
      query.not_geocoded
    else
      query
    end
  end

  def options
    {
      geocoded: "Geocoded",
      not_geocoded: "Not geocoded"
    }
  end
end


================================================
FILE: app/avo/filters/github.rb
================================================
class Avo::Filters::GitHub < Avo::Filters::BooleanFilter
  self.name = "GitHub handle"

  def apply(request, query, values)
    return query if values["has_github"] && values["no_github"]
    if values["has_github"]
      query = query.where.not(github: ["", nil])
    elsif values["no_github"]
      query = query.where(github: ["", nil])
    end

    query
  end

  def options
    {
      has_github: "With GitHub handle",
      no_github: "Without GitHub handle"
    }
  end
end


================================================
FILE: app/avo/filters/github_handle.rb
================================================
class Avo::Filters::GitHubHandle < Avo::Filters::TextFilter
  self.name = "GitHub handle (contains)"

  def apply(request, query, value)
    query.where("lower(github_handle) LIKE ?", "%#{value.downcase}%")
  end
end


================================================
FILE: app/avo/filters/github_handle_presence.rb
================================================
class Avo::Filters::GitHubHandlePresence < Avo::Filters::BooleanFilter
  self.name = "GitHub handle presence"

  def apply(request, query, values)
    return query if values["has_github"] && values["no_github"]
    if values["has_github"]
      query = query.where.not(github_handle: ["", nil])
    elsif values["no_github"]
      query = query.where(github_handle: ["", nil])
    end

    query
  end

  def options
    {
      has_github: "With GitHub handle",
      no_github: "Without GitHub handle"
    }
  end
end


================================================
FILE: app/avo/filters/has_duplicate.rb
================================================
class Avo::Filters::HasDuplicate < Avo::Filters::BooleanFilter
  self.name = "Has duplicate"

  def apply(request, query, values)
    if values["has_any_duplicate"]
      query.with_any_duplicate
    elsif values["has_reversed_name_duplicate"]
      query.with_reversed_name_duplicate
    elsif values["has_same_name_duplicate"]
      query.with_same_name_duplicate
    else
      query
    end
  end

  def options
    {
      has_any_duplicate: "Has any duplicate",
      has_reversed_name_duplicate: "Has reversed name duplicate",
      has_same_name_duplicate: "Has same name duplicate"
    }
  end
end


================================================
FILE: app/avo/filters/involvement_role.rb
================================================
class Avo::Filters::InvolvementRole < Avo::Filters::SelectFilter
  self.name = "Role"

  def apply(request, query, role)
    if role
      query.where(role: role)
    else
      query
    end
  end

  def options
    EventInvolvement.distinct.pluck(:role).compact.sort.index_by(&:itself)
  end
end


================================================
FILE: app/avo/filters/language.rb
================================================
class Avo::Filters::Language < Avo::Filters::SelectFilter
  self.name = "Language"

  # self.visible = -> do
  #   true
  # end

  def apply(request, query, language)
    if language
      query.where("language is ?", language)
    else
      query
    end
  end

  def options
    Language.used
  end
end


================================================
FILE: app/avo/filters/location_presence.rb
================================================
class Avo::Filters::LocationPresence < Avo::Filters::BooleanFilter
  self.name = "Location presence"

  def apply(request, query, values)
    return query if values["has_location"] && values["no_location"]

    if values["has_location"]
      query = query.where.not(location: ["", nil])
    elsif values["no_location"]
      query = query.where(location: ["", nil])
    end

    query
  end

  def options
    {
      has_location: "With location",
      no_location: "Without location"
    }
  end
end


================================================
FILE: app/avo/filters/name.rb
================================================
class Avo::Filters::Name < Avo::Filters::TextFilter
  self.name = "Name"
  self.button_label = "Filter by name (contains)"

  def apply(request, query, value)
    query.where("name LIKE ?", "%#{value}%")
  end
end


================================================
FILE: app/avo/filters/provider.rb
================================================
class Avo::Filters::Provider < Avo::Filters::SelectFilter
  self.name = "Provider"

  def apply(request, query, provider)
    if provider
      query.where("provider is ?", provider)
    else
      query
    end
  end

  def options
    ConnectedAccount.providers
  end
end


================================================
FILE: app/avo/filters/published.rb
================================================
class Avo::Filters::Published < Avo::Filters::BooleanFilter
  self.name = "Approved Status"

  def apply(request, query, values)
    selected_statuses = values.select { |k, v| v }.keys

    if selected_statuses.any?
      query = query.where(status: selected_statuses)
    end

    query
  end

  def options
    {
      pending: "Pending",
      approved: "Approved",
      rejected: "Rejected",
      duplicate: "Duplicate"
    }
  end
end


================================================
FILE: app/avo/filters/raw_transcript.rb
================================================
class Avo::Filters::RawTranscript < Avo::Filters::BooleanFilter
  self.name = "Raw transcript"
  # self.visible = -> do
  #   true
  # end

  def apply(request, query, values)
    return query if values["has_transcript"] && values["no_transcript"]

    if values["has_transcript"]
      query = query.with_raw_transcript
    elsif values["no_transcript"]
      query = query.without_raw_transcript
    end

    query
  end

  def options
    {
      has_transcript: "With raw transcript",
      no_transcript: "Without raw transcript"
    }
  end
end


================================================
FILE: app/avo/filters/slug.rb
================================================
class Avo::Filters::Slug < Avo::Filters::TextFilter
  self.name = "Slug"
  self.button_label = "Filter by slug (contains)"

  def apply(request, query, value)
    query.where("slug LIKE ?", "%#{value}%")
  end
end


================================================
FILE: app/avo/filters/summary.rb
================================================
class Avo::Filters::Summary < Avo::Filters::BooleanFilter
  self.name = "Summary"

  def apply(request, query, values)
    return query if values["has_summary"] && values["no_summary"]

    if values["has_summary"]
      query = query.with_summary
    elsif values["no_summary"]
      query = query.without_summary
    end

    query
  end

  def options
    {
      has_summary: "With summary",
      no_summary: "Without summary"
    }
  end
end


================================================
FILE: app/avo/filters/suspicious.rb
================================================
class Avo::Filters::Suspicious < Avo::Filters::BooleanFilter
  self.name = "Suspicious"

  def apply(request, query, values)
    return query unless values["suspicious"]

    query.suspicious
  end

  def options
    {
      suspicious: "Suspicious users"
    }
  end
end


================================================
FILE: app/avo/filters/talk_event.rb
================================================
class Avo::Filters::TalkEvent < Avo::Filters::SelectFilter
  self.name = "Talk event"

  def apply(request, query, values)
    query.where(event_id: values) if values
  end

  def options
    Event.all.map { |event| [event.id, event.name] }.sort_by { |_, name| name }.to_h
  end
end


================================================
FILE: app/avo/filters/title.rb
================================================
class Avo::Filters::Title < Avo::Filters::TextFilter
  self.name = "Title"
  self.button_label = "Filter by title (contains)"

  def apply(request, query, value)
    query.where("title LIKE ?", "%#{value}%")
  end
end


================================================
FILE: app/avo/filters/topic_talks.rb
================================================
class Avo::Filters::TopicTalks < Avo::Filters::BooleanFilter
  self.name = "Topic talks"
  # self.visible = -> do
  #   true
  # end

  def apply(request, query, values)
    return query if values["has_talks"] && values["no_talks"] && values["one_talk"] && values["two_talks"]

    if values["has_talks"]
      query = query.with_talks
    elsif values["no_talks"]
      query = query.without_talks
    elsif values["one_talk"]
      query = query.with_n_talk(1)
    elsif values["two_talks"]
      query = query.with_n_talk(2)
    end

    query
  end

  def options
    {
      has_talks: "With talk topics",
      no_talks: "Without talk topics",
      one_talk: "One talk",
      two_talks: "Two talks"
    }
  end
end


================================================
FILE: app/avo/filters/topics.rb
================================================
class Avo::Filters::Topics < Avo::Filters::BooleanFilter
  self.name = "Topics"
  # self.visible = -> do
  #   true
  # end

  def apply(request, query, values)
    return query if values["has_topics"] && values["no_topics"]

    if values["has_topics"]
      query = query.with_topics
    elsif values["no_topics"]
      query = query.without_topics
    end

    query
  end

  def options
    {
      has_topics: "With topics",
      no_topics: "Without topics"
    }
  end
end


================================================
FILE: app/avo/filters/video_availability.rb
================================================
class Avo::Filters::VideoAvailability < Avo::Filters::BooleanFilter
  self.name = "Video Availability"

  def apply(request, query, values)
    if values["available"]
      query = query.video_available
    end

    if values["unavailable"]
      query = query.video_unavailable
    end

    if values["watchable"]
      query = query.watchable
    end

    if values["marked_unavailable"]
      query = query.where.not(video_unavailable_at: nil)
    end

    query
  end

  def options
    {
      available: "Watchable & Available",
      unavailable: "Watchable & Unavailable",
      watchable: "Watchable",
      marked_unavailable: "Marked Unavailable"
    }
  end
end


================================================
FILE: app/avo/filters/video_provider.rb
================================================
class Avo::Filters::VideoProvider < Avo::Filters::SelectFilter
  self.name = "Video Provider"

  # self.visible = -> do
  #   true
  # end

  def apply(request, query, provider)
    if provider
      query.where(video_provider: provider)
    else
      query
    end
  end

  def options
    Talk.video_providers
  end
end


================================================
FILE: app/avo/filters/without_talks.rb
================================================
class Avo::Filters::WithoutTalks < Avo::Filters::BooleanFilter
  self.name = "Without talks"
  # self.visible = -> do
  #   true
  # end

  def apply(request, query, values)
    if values["no_talks"]
      query = query.without_talks
    end

    query
  end

  def options
    {
      no_talks: "Without talks"
    }
  end
end


================================================
FILE: app/avo/resources/alias.rb
================================================
class Avo::Resources::Alias < Avo::BaseResource
  self.includes = [:aliasable]
  self.search = {
    query: -> { query.where("name LIKE ? OR slug LIKE ?", "%#{params[:q]}%", "%#{params[:q]}%") }
  }
  self.external_link = -> {
    Avo::Resources::Alias.aliasable_link(main_app, record)
  }

  def filters
    filter Avo::Filters::AliasableType
  end

  def fields
    field :id, as: :id
    field :aliasable, as: :belongs_to, polymorphic_as: :aliasable, types: [::User, ::Event, ::EventSeries, ::Organization, ::City]
    field :aliasable_type, as: :text, readonly: true, only_on: :show
    field :aliasable_id, as: :id, readonly: true, only_on: :show
    field :name, as: :text, required: true
    field :slug, as: :text, required: true
    field :external_url,
      as: :text,
      hide_on: [:edit, :new],
      format_using: -> { view_context.link_to(value, value, target: "_blank") if value.present? } do
      Avo::Resources::Alias.aliasable_link(main_app, record)
    end
    field :created_at, as: :date_time, readonly: true
    field :updated_at, as: :date_time, readonly: true
  end

  def self.aliasable_link(app, record)
    case record.aliasable_type
    when "User"
      app.profile_path(record.aliasable.slug)
    when "Event"
      app.event_path(record.aliasable.slug)
    when "EventSeries"
      app.series_path(record.aliasable.slug)
    when "Talk"
      app.talk_path(record.aliasable.slug)
    when "Organization"
      app.organization_path(record.aliasable.slug)
    when "City"
      app.city_path(record.aliasable.slug)
    else
      raise "Unknown aliasable type: #{record.aliasable_type}"
    end
  end
end


================================================
FILE: app/avo/resources/city.rb
================================================
class Avo::Resources::City < Avo::BaseResource
  self.model_class = ::City
  self.title = :name
  self.includes = []
  self.find_record_method = -> {
    if id.is_a?(Array)
      query.where(slug: id)
    else
      query.find_by(slug: id)
    end
  }
  self.search = {
    query: -> { query.where("name LIKE ?", "%#{params[:q]}%") }
  }
  self.external_link = -> {
    main_app.city_path(record)
  }
  self.map_view = {
    mapkick_options: {
      controls: true
    },
    record_marker: -> {
      {
        latitude: record.latitude,
        longitude: record.longitude,
        tooltip: record.name
      }
    },
    table: {
      visible: true
    }
  }

  def fields
    field :id, as: :id
    field :name, as: :text, link_to_record: true, sortable: true
    field :slug, as: :text, sortable: true
    field :state_code, as: :text
    field :country_code, as: :select, options: country_options, include_blank: true
    field :featured, as: :boolean, sortable: true
    field :latitude, as: :number, hide_on: :index
    field :longitude, as: :number, hide_on: :index
    field :geocode_metadata, as: :code, language: :json, hide_on: :index
    field :created_at, as: :date_time, hide_on: :forms, sortable: true
    field :updated_at, as: :date_time, hide_on: :forms, sortable: true
  end

  def filters
    filter Avo::Filters::Name
  end

  def country_options
    Country.select_options
  end
end


================================================
FILE: app/avo/resources/connected_account.rb
================================================
# id           :integer
# uid          :string
# provider     :string
# username     :string
# user_id      :integer
# access_token :string
# expires_at   :datetime
# created_at   :datetime
# updated_at   :datetime

class Avo::Resources::ConnectedAccount < Avo::BaseResource
  # self.includes = []
  # self.attachments = []
  self.search = {
    query: -> { query.ransack(id_eq: params[:q], uid_cont: params[:q], m: "or").result(distinct: false) }
  }

  def fields
    field :id, as: :id
    field :uid, as: :text
    field :provider, as: :text, sortable: true
    field :username, as: :text, sortable: true
    field :user, as: :belongs_to, sortable: true
    field :user_id, as: :text, sortable: true, hide_on: [:index]
    field :access_token, as: :text, hide_on: [:index]
    field :expires_at, as: :date_time, hide_on: [:index]
    field :created_at, as: :date_time, hide_on: [:index]
    field :updated_at, as: :date_time, hide_on: [:index]
  end

  def filters
    filter Avo::Filters::Provider
  end
end


================================================
FILE: app/avo/resources/contributor.rb
================================================
class Avo::Resources::Contributor < Avo::BaseResource
  # self.includes = []
  # self.attachments = []
  # self.search = {
  #   query: -> { query.ransack(id_eq: q, m: "or").result(distinct: false) }
  # }

  def fields
    field :id, as: :id
    field :login, as: :text
    field :name, as: :text
    field :avatar_url, as: :text
    field :html_url, as: :text
  end
end


================================================
FILE: app/avo/resources/event.rb
================================================
class Avo::Resources::Event < Avo::BaseResource
  self.includes = []
  # self.search = {
  #   query: -> { query.ransack(id_eq: params[:q], m: "or").result(distinct: false) }
  # }
  self.find_record_method = -> {
    if id.is_a?(Array)
      query.where(slug: id)
    else
      query.find_by(slug: id)
    end
  }
  self.external_link = -> {
    main_app.event_path(record)
  }

  def fields
    field :id, as: :id
    field :name, as: :text, link_to_record: true, sortable: true
    field :date, as: :date, hide_on: :index
    field :date_precision, as: :select, options: ::Event.date_precisions, hide_on: :index
    field :start_date, as: :date, hide_on: :index
    field :end_date, as: :date, hide_on: :index
    field :location, as: :text, hide_on: :index
    field :city, as: :text, hide_on: :index
    field :state_code, as: :text, hide_on: :index
    field :country_code, as: :select, options: country_options, include_blank: true
    field :latitude, as: :number, hide_on: :index
    field :longitude, as: :number, hide_on: :index
    field :geocode_metadata, as: :code, hide_on: :index
    field :kind, hide_on: :index
    field :slug, as: :text
    field :updated_at, as: :date, sortable: true
    # field :suggestions, as: :has_many
    field :series, as: :belongs_to
    field :talks, as: :has_many
    field :speakers, as: :has_many, through: :talks, class_name: "User"
    field :participants, as: :has_many, through: :event_participations, class_name: "User"
    field :event_involvements, as: :has_many
    field :topics, as: :has_many
    field :sponsors, as: :has_many
  end

  def actions
    action Avo::Actions::AssignCanonicalEvent
    action Avo::Actions::GeocodeRecord
  end

  def filters
    filter Avo::Filters::Name
    filter Avo::Filters::WithoutTalks
    filter Avo::Filters::Canonical
    filter Avo::Filters::LocationPresence
    filter Avo::Filters::GeocodedPresence
  end

  def country_options
    Country.select_options
  end
end


================================================
FILE: app/avo/resources/event_involvement.rb
================================================
class Avo::Resources::EventInvolvement < Avo::BaseResource
  self.includes = [:involvementable, :event]

  self.search = {
    query: -> {
      query
        .left_joins("LEFT JOIN users ON users.id = event_involvements.involvementable_id AND event_involvements.involvementable_type = 'User'")
        .left_joins("LEFT JOIN event_series ON event_series.id = event_involvements.involvementable_id AND event_involvements.involvementable_type = 'EventSeries'")
        .where("users.name LIKE ? OR event_series.name LIKE ? OR event_involvements.role LIKE ?", "%#{params[:q]}%", "%#{params[:q]}%", "%#{params[:q]}%")
    }
  }

  def fields
    field :id, as: :id
    field :involvementable, as: :belongs_to, polymorphic_as: :involvementable, types: [::User, ::EventSeries], searchable: true
    field :event, as: :belongs_to, searchable: true, attach_scope: -> { query.order(name: :asc) }
    field :role, as: :text
    field :created_at, as: :date_time
    field :updated_at, as: :date_time
  end

  def filters
    filter Avo::Filters::InvolvementRole
  end
end


================================================
FILE: app/avo/resources/event_participation.rb
================================================
class Avo::Resources::EventParticipation < Avo::BaseResource
  self.includes = [:user, :event]
  # self.attachments = []
  # self.search = {
  #   query: -> { query.ransack(id_eq: q, m: "or").result(distinct: false) }
  # }
  self.search = {
    query: -> { query.joins(:user).where("users.name LIKE ?", "%#{params[:q]}%") }
  }

  def fields
    field :id, as: :id
    field :attended_as, as: :select, enum: ::EventParticipation.attended_as
    field :user, as: :belongs_to, searchable: true
    field :event, as: :belongs_to, searchable: true, attach_scope: -> { query.order(name: :asc) }
  end

  def filters
    filter Avo::Filters::AttendedAs
  end
end


================================================
FILE: app/avo/resources/event_series.rb
================================================
class Avo::Resources::EventSeries < Avo::BaseResource
  self.single_includes = [:events]
  # self.search = {
  #   query: -> { query.ransack(id_eq: params[:q], m: "or").result(distinct: false) }
  # }
  self.find_record_method = -> {
    if id.is_a?(Array)
      query.where(slug: id)
    else
      query.find_by(slug: id)
    end
  }
  self.external_link = -> {
    main_app.series_path(record)
  }

  def fields
    field :id, as: :id
    field :name, as: :text, link_to_record: true
    field :description, as: :text, hide_on: [:index, :forms]
    field :website, as: :text
    field :language, as: :text
    field :kind, as: :select, enum: ::EventSeries.kinds
    field :frequency, as: :select, enum: ::EventSeries.frequencies, hide_on: :index
    field :youtube_channel_id, as: :text, hide_on: :index
    field :youtube_channel_name, as: :text, hide_on: :index
    field :slug, as: :text, hide_on: :index
    field :twitter, as: :text, hide_on: :index
    # field :suggestions, as: :has_many
    field :events, as: :has_many
    field :talks, as: :has_many, through: :events
  end

  def filters
    filter Avo::Filters::Name
    filter Avo::Filters::Slug
  end
end


================================================
FILE: app/avo/resources/favorite_user.rb
================================================
class Avo::Resources::FavoriteUser < Avo::BaseResource
  # self.includes = []
  # self.attachments = []
  # self.search = {
  #   query: -> { query.ransack(id_eq: q, m: "or").result(distinct: false) }
  # }

  def fields
    field :id, as: :id
    field :user, as: :belongs_to
    field :favorite_user, as: :belongs_to
  end
end


================================================
FILE: app/avo/resources/geocode_result.rb
================================================
class Avo::Resources::GeocodeResult < Avo::BaseResource
  self.model_class = ::GeocodeResult
  self.title = :query
  self.includes = []
  self.search = {
    query: -> { query.where("query LIKE ?", "%#{params[:q]}%") }
  }

  def fields
    field :id, as: :id
    field :query, as: :text, link_to_record: true, sortable: true
    field :response_body, as: :code, language: "json", hide_on: :index
    field :created_at, as: :date_time, hide_on: :forms, sortable: true
    field :updated_at, as: :date_time, hide_on: :forms, sortable: true
  end
end


================================================
FILE: app/avo/resources/organization.rb
================================================
class Avo::Resources::Organization < Avo::BaseResource
  # self.includes = []
  # self.attachments = []
  # self.search = {
  #   query: -> { query.ransack(id_eq: params[:q], m: "or").result(distinct: false) }
  # }
  self.find_record_method = -> {
    if id.is_a?(Array)
      query.where(slug: id)
    else
      query.find_by(slug: id)
    end
  }

  self.search = {
    query: -> { query.where("lower(name) LIKE ?", "%#{params[:q]&.downcase}%") }
  }

  def fields
    field :id, as: :id
    field :name, as: :text
    field :kind, as: :select, enum: ::Organization.kinds
    field :website, as: :text
    field :slug, as: :text
    field :description, as: :textarea
    field :main_location, as: :text
    field :sponsors, as: :has_many
    field :event_involvements, as: :has_many
  end
end


================================================
FILE: app/avo/resources/session.rb
================================================
class Avo::Resources::Session < Avo::BaseResource
  self.includes = []
  # self.search = {
  #   query: -> { query.ransack(id_eq: params[:q], m: "or").result(distinct: false) }
  # }

  def fields
    field :id, as: :id, link_to_record: true
    field :user_agent, as: :text, format_using: -> { value.truncate(50) }, only_on: :index
    field :user_agent, as: :text, hide_on: :index
    field :ip_address, as: :text
    field :user, as: :belongs_to, use_resource: Avo::Resources::User, link_to_record: true, hide_on: :index
  end
end


================================================
FILE: app/avo/resources/sponsor.rb
================================================
class Avo::Resources::Sponsor < Avo::BaseResource
  # self.includes = []
  # self.attachments = []
  # self.search = {
  #   query: -> { query.ransack(id_eq: params[:q], m: "or").result(distinct: false) }
  # }

  def fields
    field :id, as: :id
    field :event, as: :belongs_to
    field :organization, as: :belongs_to
    field :tier, as: :text
    field :badge, as: :text
  end
end


================================================
FILE: app/avo/resources/suggestion.rb
================================================
class Avo::Resources::Suggestion < Avo::BaseResource
  # self.includes = []
  # self.attachments = []
  # self.search = {
  #   query: -> { query.ransack(id_eq: params[:q], m: "or").result(distinct: false) }
  # }

  def fields
    field :id, as: :idlo
    field :content, as: :text, only_on: :index do
      record.content.map { |key, value| "#{key}: #{value}" }.to_sentence.truncate(50)
    end
    field :content, as: :key_value, hide_on: :index
    field :status, as: :status, loading_when: [:pending], success_when: [:approved], link_to_record: true, hide_on: [:forms]
    field :suggestable, as: :belongs_to, polymorphic_as: :suggestable
    field :approved_by, as: :belongs_to
    field :suggested_by, as: :belongs_to
  end
end


================================================
FILE: app/avo/resources/talk.rb
================================================
class Avo::Resources::Talk < Avo::BaseResource
  self.includes = [:event, :speakers, :topics]
  self.find_record_method = -> {
    if id.is_a?(Array)
      query.where(slug: id)
    else
      query.find_by(slug: id)
    end
  }
  self.keep_filters_panel_open = true

  self.search = {
    query: -> { query.where(id: Talk.search(params[:q]).map(&:id)) }
  }
  self.external_link = -> {
    main_app.talk_path(record)
  }

  def fields
    field :id, as: :id
    field :title, as: :text, link_to_record: true, sortable: true
    field :event, as: :belongs_to

    field :speaker_tags, for_attribute: :speakers, name: "Speakers", through: :speaker_talks, as: :tags, hide_on: [:show, :forms] do
      record.speakers.map(&:name)
    end

    field :topics, as: :tags, hide_on: [:index, :forms] do
      record.topics.map(&:name)
    end
    field :updated_at, as: :date, sortable: true
    field :slides_url, as: :text, hide_on: :index
    field :summary, as: :easy_mde, hide_on: :index
    field :has_raw_transcript, name: "Raw Transcript", as: :boolean do
      record.raw_transcript.present?
    end
    field :has_enhanced_transcript, hide_on: :index, name: "Enhanced Transcript", as: :boolean do
      record.enhanced_transcript.present?
    end
    field :raw_transcript_length, name: "Raw Transcript length", as: :number do
      record.raw_transcript&.to_text&.length
    end
    field :enhanced_transcript_length, name: "Enhanced Transcript length", as: :number do
      record.enhanced_transcript&.to_text&.length
    end
    field :has_duration, name: "Duration", as: :boolean do
      record.duration_in_seconds.present?
    end
    field :has_summary, name: "Summary", as: :boolean do
      record.summary.present?
    end
    field :has_topics, name: "Topics", as: :boolean do
      record.topics.any?
    end
    field :language, hide_on: :index
    field :slug, as: :text, hide_on: :index
    field :year, as: :number, hide_on: :index
    field :video_id, as: :text, hide_on: :index
    field :video_provider, as: :text, hide_on: :index
    field :video_available, name: "Video Available", as: :boolean do
      record.video_available?
    end
    field :video_unavailable_at, as: :date_time, hide_on: :index
    field :external_player, as: :boolean, hide_on: :index
    field :date, as: :date, hide_on: :index
    field :like_count, as: :number, hide_on: :index
    field :view_count, as: :number, hide_on: :index
    field :duration_in_seconds, as: :number, hide_on: [:index, :edit], format_using: -> { Duration.seconds_to_formatted_duration(value, raise: false) }, name: "Duration", readonly: true
    field :duration_in_seconds, as: :number, hide_on: :index, show_on: [:edit], name: "Duration in seconds"
    field :created_at, as: :date, hide_on: :index
    field :updated_at, as: :date, sortable: true, filterable: true
    field :description, as: :textarea, hide_on: :index

    field :thumbnail_xs, as: :external_image, hide_on: :index
    field :thumbnail_sm, as: :external_image, hide_on: :index
    field :thumbnail_md, as: :external_image, hide_on: :index
    field :thumbnail_lg, as: :external_image, hide_on: :index
    field :thumbnail_xl, as: :external_image, hide_on: :index
    # field :speaker_talks, as: :has_many, attach_scope: -> { query.order(name: :asc) }
    field :speakers, as: :has_many
    field :raw_transcript, as: :textarea, hide_on: :index, format_using: -> { value&.to_text }, readonly: true
    field :enhanced_transcript, as: :textarea, hide_on: :index, format_using: -> { value&.to_text }, readonly: true
    # field :suggestions, as: :has_many
  end

  def actions
    action Avo::Actions::TalkIngest
    action Avo::Actions::UpdateFromYml
    action Avo::Actions::TalkIndex
    action Avo::Actions::FetchDuration
  end

  def filters
    filter Avo::Filters::TalkEvent
    filter Avo::Filters::RawTranscript
    filter Avo::Filters::EnhancedTranscript
    filter Avo::Filters::Summary
    filter Avo::Filters::Topics
    filter Avo::Filters::Title
    filter Avo::Filters::Slug
    filter Avo::Filters::Language
    filter Avo::Filters::VideoProvider
    filter Avo::Filters::VideoAvailability
  end
end


================================================
FILE: app/avo/resources/talk_topic.rb
================================================
class Avo::Resources::TalkTopic < Avo::BaseResource
  self.includes = [:talk, :topic]
  # self.attachments = []
  # self.search = {
  #   query: -> { query.ransack(id_eq: params[:q], m: "or").result(distinct: false) }
  # }

  def fields
    field :id, as: :id
    field :talk_title, as: :text do
      record.talk.title
    end
    field :topic_name, as: :text do
      record.topic.name
    end
  end
end


================================================
FILE: app/avo/resources/talk_transcript.rb
================================================
class Avo::Resources::TalkTranscript < Avo::BaseResource
  # self.includes = []
  # self.attachments = []
  self.model_class = ::Talk::Transcript
  # self.search = {
  #   query: -> { query.ransack(id_eq: params[:q], m: "or").result(distinct: false) }
  # }

  def fields
    field :id, as: :id
    field :talk, as: :belongs_to
    field :raw_transcript, as: :textarea, hide_on: [:index], format_using: -> { value&.to_text }
    field :enhanced_transcript, as: :textarea, hide_on: [:index], format_using: -> { value&.to_text }
    field :created_at, as: :date_time, sortable: true, hide_on: [:index]
    field :updated_at, as: :date_time, sortable: true
  end

  def actions
    action Avo::Actions::EnhanceTranscript
  end
end


================================================
FILE: app/avo/resources/topic.rb
================================================
class Avo::Resources::Topic < Avo::BaseResource
  # self.includes = []
  # self.attachments = []
  self.search = {
    query: -> { query.where("name LIKE ?", "%#{params[:q]}%") }
  }
  self.find_record_method = -> {
    if id.is_a?(Array)
      query.where(slug: id)
    else
      query.find_by(slug: id)
    end
  }
  self.keep_filters_panel_open = true
  self.external_link = -> {
    main_app.topic_path(record)
  }

  def fields
    field :id, as: :id
    field :name, as: :text, link_to_record: true
    field :talks_count, as: :number, hide_on: :forms, sortable: true
    field :canonical, as: :belongs_to, use_resource: "Topic", hide_on: :index
    field :description, as: :markdown, hide_on: :index
    field :status, as: :status, loading_when: "pending", success_when: "approved", failed_when: "rejected", hide_on: :forms
    field :status, as: :select, enum: ::Topic.statuses, only_on: :forms
    field :gem_names, as: :text, hide_on: :forms do
      record.topic_gems.pluck(:gem_name).join(", ")
    end
    field :talks, as: :has_many
    field :topic_gems, as: :has_many
  end

  def actions
    action Avo::Actions::ApproveTopic
    action Avo::Actions::RejectTopic
    action Avo::Actions::AssignCanonicalTopic
    action Avo::Actions::FindTopicTalks
  end

  def filters
    filter Avo::Filters::Name
    filter Avo::Filters::Published
    filter Avo::Filters::TopicTalks
  end
end


================================================
FILE: app/avo/resources/topic_gem.rb
================================================
class Avo::Resources::TopicGem < Avo::BaseResource
  self.title = :gem_name
  self.search = {
    query: -> { query.where("gem_name LIKE ?", "%#{params[:q]}%") }
  }
  self.external_link = -> {
    record.rubygems_url
  }

  def self.name
    "Gem"
  end

  def fields
    field :id, as: :id
    field :gem_name, as: :text, link_to_record: true, help: "Exact gem name from RubyGems.org (e.g., 'sidekiq', 'activerecord')"
    field :topic, as: :belongs_to, link_to_record: true
  end
end


================================================
FILE: app/avo/resources/user.rb
================================================
class Avo::Resources::User < Avo::BaseResource
  self.title = :name
  self.includes = []
  self.find_record_method = -> {
    if id.is_a?(Array)
      if id.first.to_i == 0
        query.where(slug: id).or(query.where(github_handle: id))
      else
        query.where(id: id)
      end
    else
      (id.to_i == 0) ? (query.find_by_slug_or_alias(id) || query.find_by_github_handle(id)) : query.find(id)
    end
  }
  self.search = {
    query: -> { query.where("lower(name) LIKE ? OR email LIKE ?", "%#{params[:q]&.downcase}%", "%#{params[:q]}%") }
  }
  self.external_link = -> {
    main_app.profile_path(record)
  }

  def fields
    field :id, as: :id, link_to_record: true
    field :name, as: :text, link_to_record: true
    field :email, as: :text, link_to_record: true, format_using: -> { value&.truncate(30) }, only_on: :index
    field :email, as: :text, link_to_record: true, hide_on: :index
    field :github_handle, as: :text, link_to_record: true
    field :admin, as: :boolean
    field :marked_for_deletion, as: :boolean, hide_on: :index
    field :suspicion_marked_at, as: :date_time, hide_on: :index
    field :suspicion_cleared_at, as: :date_time, hide_on: :index

    field :slug, as: :text, hide_on: :index
    field :bio, as: :textarea, hide_on: :index
    field :website, as: :text, hide_on: :index
    field :twitter, as: :text, hide_on: :index
    field :bsky, as: :text, hide_on: :index
    field :linkedin, as: :text, hide_on: :index
    field :mastodon, as: :text, hide_on: :index
    field :speakerdeck, as: :text, hide_on: :index
    field :pronouns, as: :text, hide_on: :index
    field :pronouns_type, as: :text, hide_on: :index
    field :location, as: :text, hide_on: :index
    field :city, as: :text, hide_on: :index, readonly: true
    field :state_code, as: :text, hide_on: :index, readonly: true
    field :country_code, as: :text, hide_on: :index, readonly: true
    field :latitude, as: :number, hide_on: :index, readonly: true
    field :longitude, as: :number, hide_on: :index, readonly: true
    field :geocode_metadata, as: :code, hide_on: :index, readonly: true
    field :talks_count, as: :number, sortable: true

    field :aliases, as: :has_many, hide_on: :index
    field :talks, as: :has_many, hide_on: :index
    field :user_talks, as: :has_many, hide_on: :index
    field :connected_accounts, as: :has_many
    field :sessions, as: :has_many
    field :event_participations, as: :has_many, hide_on: :index, use_resource: Avo::Resources::EventParticipation
    field :participated_events, as: :has_many, hide_on: :index, use_resource: Avo::Resources::Event
    field :event_involvements, as: :has_many, hide_on: :index
  end

  def filters
    filter Avo::Filters::Name
    filter Avo::Filters::Slug
    filter Avo::Filters::GitHubHandle
    filter Avo::Filters::GitHubHandlePresence
    filter Avo::Filters::BioPresence
    filter Avo::Filters::LocationPresence
    filter Avo::Filters::GeocodedPresence
    filter Avo::Filters::Suspicious
    filter Avo::Filters::HasDuplicate
  end

  def actions
    action Avo::Actions::UserFetchGitHub
    action Avo::Actions::GeocodeRecord
    action Avo::Actions::ClearUser
  end
end


================================================
FILE: app/avo/resources/user_talk.rb
================================================
class Avo::Resources::UserTalk < Avo::BaseResource
  # self.includes = []
  # self.attachments = []
  # self.search = {
  #   query: -> { query.ransack(id_eq: q, m: "or").result(distinct: false) }
  # }

  def fields
    field :id, as: :id
    field :user, as: :belongs_to
    field :talk, as: :belongs_to
  end
end


================================================
FILE: app/avo/resources/watch_list.rb
================================================
class Avo::Resources::WatchList < Avo::BaseResource
  self.title = :name
  self.includes = []

  def fields
    field :id, as: :id
    field :name, as: :text
    field :description, as: :textarea
    field :user, as: :belongs_to
    field :talks, as: :has_many, through: :watch_list_talks
  end
end


================================================
FILE: app/avo/resources/watch_list_talk.rb
================================================
class Avo::Resources::WatchListTalk < Avo::BaseResource
  self.includes = [:talk, :watch_list]

  def fields
    field :id, as: :id
    field :talk, as: :belongs_to
    field :watch_list, as: :belongs_to
    field :created_at, as: :date_time
  end
end


================================================
FILE: app/channels/application_cable/channel.rb
================================================
module ApplicationCable
  class Channel < ActionCable::Channel::Base
  end
end


================================================
FILE: app/channels/application_cable/connection.rb
================================================
module ApplicationCable
  class Connection < ActionCable::Connection::Base
  end
end


================================================
FILE: app/clients/application_client.rb
================================================
class ApplicationClient
  class Error < StandardError; end

  class Forbidden < Error; end

  class Unauthorized < Error; end

  class RateLimit < Error; end

  class NotFound < Error; end

  class InternalError < Error; end

  BASE_URI = "https://example.org"
  NET_HTTP_ERRORS = [Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError]

  def initialize(token: nil)
    @token = token
  end

  def default_headers
    {
      "Accept" => content_type,
      "Content-Type" => content_type
    }.merge(authorization_header)
  end

  def content_type
    "application/json"
  end

  def authorization_header
    token ? {"Authorization" => "Bearer #{token}"} : {}
  end

  def default_query_params
    {}
  end

  def get(path, headers: {}, query: nil)
    make_request(klass: Net::HTTP::Get, path: path, headers: headers, query: query)
  end

  def post(path, headers: {}, query: nil, body: nil, form_data: nil)
    make_request(
      klass: Net::HTTP::Post,
      path: path,
      headers: headers,
      query: query,
      body: body,
      form_data: form_data
    )
  end

  def patch(path, headers: {}, query: nil, body: nil, form_data: nil)
    make_request(
      klass: Net::HTTP::Patch,
      path: path,
      headers: headers,
      query: query,
      body: body,
      form_data: form_data
    )
  end

  def put(path, headers: {}, query: nil, body: nil, form_data: nil)
    make_request(
      klass: Net::HTTP::Put,
      path: path,
      headers: headers,
      query: query,
      body: body,
      form_data: form_data
    )
  end

  def delete(path, headers: {}, query: nil, body: nil)
    make_request(klass: Net::HTTP::Delete, path: path, headers: headers, query: query, body: body)
  end

  def base_uri
    self.class::BASE_URI
  end

  attr_reader :token

  def make_request(klass:, path:, headers: {}, body: nil, query: nil, form_data: nil)
    raise ArgumentError, "Cannot pass both body and form_data" if body.present? && form_data.present?

    uri = URI("#{base_uri}#{path}")
    existing_params = Rack::Utils.parse_query(uri.query).with_defaults(default_query_params)
    query_params = existing_params.merge(query || {})
    uri.query = Rack::Utils.build_query(query_params) if query_params.present?

    Rails.logger.debug("#{klass.name.split("::").last.upcase}: #{uri}")

    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = true if uri.instance_of? URI::HTTPS

    all_headers = default_headers.merge(headers)
    all_headers.delete("Content-Type") if klass == Net::HTTP::Get

    request = klass.new(uri.request_uri, all_headers)

    if body.present?
      request.body = build_body(body)
    elsif form_data.present?
      request.set_form(form_data, "multipart/form-data")
    end

    handle_response Response.new(http.request(request))
  end

  def handle_response(response)
    case response.code
    when "200", "201", "202", "203", "204"
      response
    when "401"
      raise Unauthorized, response.body
    when "403"
      raise Forbidden, response.body
    when "404"
      raise NotFound, response.body
    when "429"
      raise RateLimit, response.body
    when "500"
      raise InternalError, response.body
    else
      raise Error, "#{response.code} - #{response.body}"
    end
  end

  def build_body(body)
    case body
    when String
      body
    else
      body.to_json
    end
  end

  class Response
    JSON_OBJECT_CLASS = OpenStruct
    PARSER = {
      "application/json" => ->(response) { JSON.parse(response.body, object_class: JSON_OBJECT_CLASS) },
      "application/xml" => ->(response) { Nokogiri::XML(response.body) }
    }
    FALLBACK_PARSER = ->(response) { response.body }

    attr_reader :original_response

    delegate :code, :body, to: :original_response
    delegate_missing_to :parsed_body

    def initialize(original_response)
      @original_response = original_response
    end

    def headers
      @headers ||= original_response.each_header.to_h.transform_keys { |k| k.underscore.to_sym }
    end

    def content_type
      headers[:content_type].split(";").first
    end

    def parsed_body
      @parsed_body ||= PARSER.fetch(content_type, FALLBACK_PARSER).call(self)
    end
  end
end


================================================
FILE: app/clients/blue_sky.rb
================================================
# frozen_string_literal: true

BlueSky = DelegateClass(Minisky) do
  alias_method :client, :__getobj__

  singleton_class.attr_reader :host
  @host = "api.bsky.app"

  def self.build(host = self.host, **options)
    new Minisky.new(host, nil, options)
  end

  # client = BlueSky.build("other.pds.host", id:, pass:) # Allow creating ad-hoc authenticated clients.
  # client = BlueSky.new FakeMinisky.new("example.com")  # Allow injecting a stubbed Minisky for testing.
  delegate :new, :build, to: :class

  def profile_metadata(handle)
    get_request("app.bsky.actor.getProfile", {actor: handle})
  end
end.build


================================================
FILE: app/clients/github/client.rb
================================================
module GitHub
  class Client < ApplicationClient
    BASE_URI = "https://api.github.com"

    def initialize
      super
    end

    private

    def authorization_header
      token ? {"Authorization" => "Bearer #{token}"} : {}
    end

    def content_type
      "application/vnd.github+json"
    end

    def token
      Rails.application.credentials.github&.dig(:token) || ENV["RUBYVIDEO_GITHUB_TOKEN"]
    end
  end
end


================================================
FILE: app/clients/github/contributors_client.rb
================================================
module GitHub
  class ContributorsClient < Client
    OWNER = "rubyevents"
    REPO = "rubyevents"

    def fetch_all
      contributors = fetch_contributors
      enrich_with_user_data(contributors)
    end

    private

    def fetch_contributors
      contributors = []
      page = 1
      per_page = 100

      loop do
        response = get("/repos/#{OWNER}/#{REPO}/contributors", query: {page: page, per_page: per_page})
        batch = response.parsed_body

        break if batch.empty?

        contributors.concat(batch.reject { |c| c.login.include?("[bot]") })
        page += 1
      end

      contributors
    end

    def enrich_with_user_data(contributors)
      query_fields = contributors.map.with_index do |contributor, index|
        %{user#{index}: user(login: "#{contributor.login}") { login name avatarUrl url }}
      end.join("\n")

      graphql_query = "{ #{query_fields} }"

      response = post("/graphql", body: {query: graphql_query})
      users = response.parsed_body.data.to_h.values.compact

      users_by_login = users.index_by { |u| u.login }

      contributors.map do |contributor|
        user = users_by_login[contributor.login]
        {
          login: contributor.login,
          name: user&.name,
          avatar_url: user&.avatarUrl || contributor.avatar_url,
          html_url: user&.url || contributor.html_url
        }
      end
    end
  end
end


================================================
FILE: app/clients/github/user_client.rb
================================================
module GitHub
  class UserClient < GitHub::Client
    def profile(username)
      get("/users/#{username}")
    end

    def social_accounts(username)
      get("/users/#{username}/social_accounts")
    end

    def search(q, per_page: 10, page: 1)
      get("/search/users", query: {q: q, per_page: per_page, page: page})
    end

    def emails
      get("/user/emails")
    end
  end
end


================================================
FILE: app/clients/ruby_conferences/client.rb
================================================
module RubyConferences
  class Client < ApplicationClient
    BASE_URI = "https://raw.githubusercontent.com/ruby-conferences/ruby-conferences.github.io/refs/heads/main"

    def conferences
      YAML.load(get("/_data/conferences.yml").body, permitted_classes: [Date])
    end

    def conferences_cached
      Rails.cache.fetch("ruby-conferences/_data/conferences.yml", expires_in: 1.day) do
        conferences
      end
    end

    private

    def content_type
      "text/yaml"
    end
  end
end


================================================
FILE: app/clients/speakerdeck/client.rb
================================================
# frozen_string_literal: true

module Speakerdeck
  class Client < ApplicationClient
    BASE_URI = "https://speakerdeck.com"

    def oembed(url)
      deck_url = normalize_url(url)
      get("/oembed.json", query: {url: deck_url})
    end

    private

    def normalize_url(url)
      if url.start_with?("http://", "https://")
        url
      else
        "#{BASE_URI}/#{url}"
      end
    end

    def authorization_header
      {}
    end
  end
end


================================================
FILE: app/clients/youtube/channels.rb
================================================
require "open-uri"

module YouTube
  class Channels < YouTube::Client
    def id_by_name(channel_name:)
      response = get("/channels", query: {forUsername: "\"#{channel_name}\"", key: token, part: "snippet,contentDetails,statistics"})
      response.try(:items)&.first&.id || fallback_using_scrapping(channel_name: channel_name)
    end

    private

    def default_headers
      {
        "Content-Type" => "application/json"
      }
    end

    def fallback_using_scrapping(channel_name:)
      # for some reason I was unable to get the channel id for paris-rb
      # this is a fallback solution using a scrapping approach
      html = URI.open("https://www.youtube.com/@#{channel_name}")
      doc = Nokogiri::HTML(html)

      meta_tag = doc.at_css('meta[itemprop="identifier"]')
      meta_tag["content"]
    end
  end
end


================================================
FILE: app/clients/youtube/client.rb
================================================
module YouTube
  class Client < ApplicationClient
    BASE_URI = "https://youtube.googleapis.com/youtube/v3"

    private

    def all_items(path, query: {})
      response = get(path, query: query.merge({key: token, maxResults: 50}))
      all_items = response.items

      loop do
        next_page_token = response.try(:nextPageToken)
        break if next_page_token.nil?
        response = get(path, query: query.merge({key: token, maxResults: 50, pageToken: next_page_token}))
        all_items += response.items
      end
      all_items
    end

    def default_headers
      {
        "Content-Type" => "application/json"
      }
    end

    def token
      Rails.application.credentials.youtube&.dig(:api_key) || ENV["YOUTUBE_API_KEY"]
    end
  end
end


================================================
FILE: app/clients/youtube/playlist_items.rb
================================================
module YouTube
  class PlaylistItems < YouTube::Client
    def all(playlist_id:)
      all_items("/playlistItems", query: {playlistId: playlist_id, part: "snippet,contentDetails"}).map do |metadata|
        OpenStruct.new({
          id: metadata.id,
          title: metadata.snippet.title,
          description: metadata.snippet.description,
          published_at: DateTime.parse(metadata.snippet.publishedAt).to_date.to_s,
          channel_id: metadata.snippet.channelId,
          year: metadata.snippet.title.match(/\d{4}/).to_s.presence || DateTime.parse(metadata.snippet.publishedAt).year,
          slug: metadata.snippet.title.parameterize,
          thumbnail_xs: metadata.snippet.thumbnails.default&.url,
          thumbnail_sm: metadata.snippet.thumbnails.medium&.url,
          thumbnail_md: metadata.snippet.thumbnails.high&.url,
          thumbnail_lg: metadata.snippet.thumbnails.standard&.url,
          thumbnail_xl: metadata.snippet.thumbnails.maxres&.url,
          video_provider: "youtube",
          video_id: metadata.contentDetails.videoId
        })
      end
    end
  end
end


================================================
FILE: app/clients/youtube/playlists.rb
================================================
module YouTube
  class Playlists < YouTube::Client
    DEFAULT_METADATA_PARSER = "YouTube::VideoMetadata"

    def all(channel_id:, title_matcher: nil)
      items = all_items("/playlists", query: {channelId: channel_id, part: "snippet,contentDetails"}).map do |metadata|
        year = metadata.snippet.title.match(/\d{4}/).to_s.presence || DateTime.parse(metadata.snippet.publishedAt).year

        OpenStruct.new({
          id: metadata.id,
          title: metadata.snippet.title,
          kind: "conference",
          location: "Earth",
          description: metadata.snippet.description,
          published_at: DateTime.parse(metadata.snippet.publishedAt).to_date.to_s,
          start_date: "#{year}-xx-xx",
          end_date: "#{year}-xx-xx",
          channel_id: metadata.snippet.channelId,
          year: year.to_i,
          videos_count: metadata.contentDetails.itemCount,
          metadata_parser: DEFAULT_METADATA_PARSER,
          slug: metadata.snippet.title.parameterize,
          banner_background: "#081625",
          featured_background: "#000000",
          featured_color: "#FFFFFF"
        })
      end
      items = items.select { |item| item.title.match?(string_to_regex(title_matcher)) } if title_matcher
      items
    end

    private

    def string_to_regex(str)
      Regexp.new(str, "i")
    end
  end
end


================================================
FILE: app/clients/youtube/thumbnail.rb
================================================
# frozen_string_literal: true

module YouTube
  class Thumbnail
    SIZES = %w[maxresdefault sddefault hqdefault mqdefault default].freeze
    DEFAULT_MAX_SIZE = 5000
    EXPECTED_ASPECT_RATIO = 16.0 / 9.0
    ASPECT_RATIO_TOLERANCE = 0.1

    SIZE_MAPPING = {
      thumbnail_xl: "maxresdefault",
      thumbnail_lg: "sddefault",
      thumbnail_md: "hqdefault",
      thumbnail_sm: "mqdefault",
      thumbnail_xs: "default"
    }.freeze

    def initialize(video_id)
      @video_id = video_id
    end

    def best_url
      best_url_from("maxresdefault")
    end

    def best_url_for(talk_size)
      starting_size = SIZE_MAPPING[talk_size.to_sym]
      return nil unless starting_size

      best_url_from(starting_size)
    end

    def best_url_from(starting_size)
      start_index = SIZES.index(starting_size) || 0
      candidate_sizes = SIZES[start_index..]

      candidate_sizes.each do |size|
        url = url_for(size)

        next if default?(url)
        next unless valid_aspect_ratio?(url)

        return url
      end

      candidate_sizes.each do |size|
        url = url_for(size)

        return url unless default?(url)
      end

      nil
    end

    def url_for(size)
      "https://i.ytimg.com/vi/#{@video_id}/#{size}.jpg"
    end

    def default?(url)
      content_length(url) < DEFAULT_MAX_SIZE
    rescue => e
      Rails.logger.error("Error checking YouTube thumbnail #{url}: #{e.message}")
      false
    end

    def valid_aspect_ratio?(url)
      uri = URI.parse(url)

      response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
        http.open_timeout = 5
        http.read_timeout = 5
        http.request_get(uri.path)
      end

      image = MiniMagick::Image.read(response.body)
      aspect_ratio = image.width.to_f / image.height

      (aspect_ratio - EXPECTED_ASPECT_RATIO).abs < ASPECT_RATIO_TOLERANCE
    rescue => e
      Rails.logger.error("Error checking aspect ratio for #{url}: #{e.message}")
      false
    end

    private

    def content_length(url)
      uri = URI.parse(url)

      response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
        http.open_timeout = 5
        http.read_timeout = 5
        http.request_head(uri.path)
      end

      response["Content-Length"].to_i
    end
  end
end


================================================
FILE: app/clients/youtube/transcript.rb
================================================
require "protobuf/message_type"

module YouTube
  class Transcript
    attr_reader :response

    def get(video_id)
      message = {one: "asr", two: "en"}
      typedef = MessageType
      two = get_base64_protobuf(message, typedef)

      message = {one: video_id, two: two}
      params = get_base64_protobuf(message, typedef)

      url = "https://www.youtube.com/youtubei/v1/get_transcript"
      headers = {"Content-Type" => "application/json"}
      body = {
        context: {
          client: {
            clientName: "WEB",
            clientVersion: "2.20240313"
          }
        },
        params: params
      }

      @response = HTTParty.post(url, headers: headers, body: body.to_json)
      JSON.parse(@response.body)
    end

    def self.get(video_id)
      new.get(video_id)
    end

    private

    def encode_message(message, typedef)
      encoded_message = typedef.new(message)
      encoded_message.to_proto
    end

    def get_base64_protobuf(message, typedef)
      encoded_data = encode_message(message, typedef)
      Base64.encode64(encoded_data).delete("\n")
    end
  end
end


================================================
FILE: app/clients/youtube/video.rb
================================================
module YouTube
  class Video < Client
    def available?(video_id)
      path = "/videos"
      query = {
        part: "status",
        id: video_id
      }

      response = all_items(path, query: query)
      response.present?
    end

    def get_statistics(video_id)
      path = "/videos"
      query = {
        part: "statistics",
        id: video_id
      }

      response = all_items(path, query: query)

      return unless response.present?

      response.each_with_object({}) do |item, hash|
        hash[item["id"]] = {
          view_count: item["statistics"]["viewCount"],
          like_count: item["statistics"]["likeCount"]
        }
      end
    end

    def duration(video_id)
      path = "/videos"
      query = {
        part: "contentDetails",
        id: video_id
      }

      response = all_items(path, query: query)

      duration_str = response&.first&.dig("contentDetails", "duration")

      return nil unless duration_str

      # Convert ISO 8601 duration (PT1H1M17S) to seconds
      ActiveSupport::Duration.parse(duration_str).to_i
    end
  end
end


================================================
FILE: app/components/application_component.rb
================================================
# frozen_string_literal: true

class ApplicationComponent < ViewComponent::Base
  extend Dry::Initializer

  attr_accessor :attributes
  option :display, default: proc { true }

  def initialize(*, **options)
    super
    defined_option_keys = self.class.dry_initializer.options.map(&:source)
    self.attributes = options.except(*defined_option_keys)
  end

  def render?
    display
  end
end


================================================
FILE: app/components/events/upcoming_event_banner_component.html.erb
================================================
<a href="<%= helpers.event_tickets_path(upcoming_event) %>" data-turbo-frame="_top" class="rounded-xl group border hover:opacity-95 transition-opacity duration-300 ease-in-out w-full flex flex-row px-6 py-6 gap-8 mt-4 overflow-hidden" style="background: <%= background_style %>; color: <%= text_color %>;">
  <div class="aspect-video hidden md:block">
    <%= image_tag helpers.image_path(upcoming_event.featured_image_path), alt: upcoming_event.name, class: "h-24 aspect-video rounded-xl group-hover:scale-105 transition ease-in-out duration-300" %>
  </div>

  <div class="flex flex-col w-full flex-1 self-center">
    <span class="text-lg font-semibold sm:text-md">
      <%= upcoming_event.name %> is coming up!
    </span>

    <span class="opacity-80 text-sm mt-1">
      <%= upcoming_event.location %> &bull; <%= upcoming_event.formatted_dates %>
    </span>

    <div class="mt-3">
      <span class="btn btn-sm border-0" style="background: <%= text_color %>; color: <%= background_color %>;">
        Get Tickets
      </span>
    </div>
  </div>
</a>


================================================
FILE: app/components/events/upcoming_event_banner_component.rb
================================================
# frozen_string_literal: true

class Events::UpcomingEventBannerComponent < ApplicationComponent
  option :event, optional: true
  option :event_series, optional: true

  def render?
    upcoming_event.present? && should_show_banner?
  end

  def upcoming_event
    @upcoming_event ||= if event.present?
      event.next_upcoming_event_with_tickets
    elsif event_series.present?
      event_series.next_upcoming_event_with_tickets
    end
  end

  def background_style
    bg = upcoming_event.static_metadata.featured_background
    return bg unless bg.start_with?("data:")

    "url('#{bg}'); background-repeat: no-repeat; background-size: cover"
  end

  def background_color
    bg = upcoming_event.static_metadata.featured_background
    bg.start_with?("data:") ? "#000000" : bg
  end

  def text_color
    upcoming_event.static_metadata.featured_color
  end

  private

  def should_show_banner?
    if event.present?
      event.past?
    else
      true
    end
  end
end


================================================
FILE: app/components/hover_card/base_component.html.erb
================================================
<div class="absolute left-1/2 -translate-x-1/2 bottom-full mb-2 w-80 opacity-0 invisible group-hover/card:opacity-100 group-hover/card:visible transition-opacity duration-150 z-50" data-hover-card-target="card" hidden>
  <%= turbo_frame_tag frame_id, src: hover_card_url, loading: "lazy", target: "_top" %>
</div>


================================================
FILE: app/components/hover_card/base_component.rb
================================================
# frozen_string_literal: true

class HoverCard::BaseComponent < ViewComponent::Base
  include Turbo::FramesHelper

  attr_reader :record, :avatar_size

  def initialize(record:, avatar_size: :sm)
    @record = record
    @avatar_size = avatar_size
  end

  def frame_id
    dom_id(record, :hover_card)
  end

  def hover_card_url
    raise NotImplementedError, "Subclasses must implement #hover_card_url"
  end

  def render?
    record.present?
  end
end


================================================
FILE: app/components/hover_card/event_component.rb
================================================
# frozen_string_literal: true

class HoverCard::EventComponent < HoverCard::BaseComponent
  def hover_card_url
    Router.hover_cards_event_path(slug: record.slug)
  end
end


================================================
FILE: app/components/hover_card/user_component.rb
================================================
# frozen_string_literal: true

class HoverCard::UserComponent < HoverCard::BaseComponent
  def hover_card_url
    Router.hover_cards_user_path(slug: record.slug, avatar_size: avatar_size)
  end

  def render?
    super && !record.suspicious?
  end
end


================================================
FILE: app/components/tito/button_component.html.erb
================================================
<%= link_to label, helpers.event_tickets_path(event), class: classes %>


================================================
FILE: app/components/tito/button_component.rb
================================================
# frozen_string_literal: true

class Tito::ButtonComponent < ApplicationComponent
  option :event
  option :label, default: -> { "Tickets" }

  def render?
    display && event.tickets.available?
  end

  def classes
    "btn btn-primary btn-sm w-full no-animation"
  end
end


================================================
FILE: app/components/tito/widget_component.html.erb
================================================
<% content_for :head do %>
  <script src="https://js.tito.io/v2" async></script>
<% end %>

<% if wrapper %>
  <div class="mt-6 p-4 bg-gray-100 rounded-lg max-w-[700px]">
    <h3 class="font-bold text-lg mb-2">Register</h3>
    <tito-widget event="<%= event_slug %>"></tito-widget>
  </div>
<% else %>
  <tito-widget event="<%= event_slug %>"></tito-widget>
<% end %>


================================================
FILE: app/components/tito/widget_component.rb
================================================
# frozen_string_literal: true

class Tito::WidgetComponent < ApplicationComponent
  option :event
  option :wrapper, default: -> { true }

  def render?
    display && event.tickets.tito? && event.upcoming?
  end

  def event_slug
    event.tickets.tito_event_slug
  end
end


================================================
FILE: app/components/ui/avatar_component.html.erb
================================================
<% avatar_markup = capture do %>
  <div class="avatar placeholder">
    <div class="<%= avatar_classes %>">
      <% if content %>
        <%= content %>
      <% else %>
        <span class="<%= text_size %> <%= "hidden" if show_custom_avatar? %>"><%= initials %></span>
        <% if show_custom_avatar? %>
          <%= image_tag avatar_url_for_size, loading: "lazy", onerror: "this.previousElementSibling.classList.remove('hidden'); this.remove()" %>
        <% end %>
      <% end %>
    </div>
  </div>
<% end %>

<% if show_hover_card? %>
  <div class="relative group/card" data-controller="hover-card" data-action="mouseenter->hover-card#reveal">
    <% if show_link? %>
      <%= link_to link_path do %><%= avatar_markup %><% end %>
    <% else %>
      <%= avatar_markup %>
    <% end %>
    <%= render HoverCard::UserComponent.new(record: avatarable, avatar_size: size) %>
  </div>
<% elsif show_link? %>
  <%= link_to link_path do %><%= avatar_markup %><% end %>
<% else %>
  <%= avatar_markup %>
<% end %>


================================================
FILE: app/components/ui/avatar_component.rb
================================================
# frozen_string_literal: true

class Ui::AvatarComponent < ApplicationComponent
  SIZE_MAPPING = {
    xs: {
      size_class: "w-6",
      image_size: 32,
      text_size: "text-xs"
    },
    sm: {
      size_class: "w-8",
      image_size: 48,
      text_size: "text-xs"
    },
    md: {
      size_class: "w-12",
      image_size: 96,
      text_size: "text-lg"
    },
    lg: {
      size_class: "w-40",
      image_size: 200,
      text_size: "text-6xl"
    }
  }.freeze

  KIND_MAPPING = {
    primary: "bg-primary",
    neutral: "bg-neutral"
  }.freeze

  param :avatarable
  option :size, Dry::Types["coercible.symbol"].enum(*SIZE_MAPPING.keys), default: proc { :md }
  option :size_class, Dry::Types["coercible.string"], default: proc { SIZE_MAPPING[size][:size_class] }
  option :outline, type: Dry::Types["strict.bool"], default: proc { false }
  option :kind, Dry::Types["coercible.symbol"].enum(*KIND_MAPPING.keys), default: proc { :primary }
  option :hover_card, type: Dry::Types["strict.bool"], default: proc { false }
  option :linked, type: Dry::Types["strict.bool"], default: proc { false }

  def show_hover_card?
    hover_card && avatarable.is_a?(User)
  end

  def show_link?
    linked && avatarable.present?
  end

  def link_path
    return nil unless avatarable.present?

    if avatarable.is_a?(User)
      helpers.profile_path(avatarable)
    elsif avatarable.respond_to?(:slug)
      helpers.speaker_path(avatarable)
    end
  end

  def avatar_classes
    [
      size_class,
      "rounded-full",
      kind_class,
      "text-neutral-content",
      (outline ? "outline outline-2" : nil)
    ].compact.join(" ")
  end

  def initials
    return "" unless avatarable&.name.present?
    avatarable.name.split(" ").map(&:first).join
  end

  def has_custom_avatar?
    avatarable&.respond_to?(:custom_avatar?) && avatarable.custom_avatar?
  end

  def avatar_url_for_size
    avatarable.avatar_url(size: image_size)
  end

  private

  def image_size
    SIZE_MAPPING[size][:image_size]
  end

  def text_size
    SIZE_MAPPING[size][:text_size]
  end

  def kind_class
    KIND_MAPPING[kind]
  end

  def suspicious?
    avatarable&.respond_to?(:suspicious?) && avatarable.suspicious?
  end

  def show_custom_avatar?
    avatarable&.custom_avatar? && !suspicious?
  end
end


================================================
FILE: app/components/ui/avatar_group_component.html.erb
================================================
<div class="avatar-group <%= overlap %> rtl:space-x-reverse">
  <% visible_avatarables.each do |avatarable| %>
    <%= render Ui::AvatarComponent.new(avatarable, size: size, hover_card: hover_card, linked: linked) %>
  <% end %>

  <% if remaining_count > 0 %>
    <%= render Ui::AvatarComponent.new(nil, size: size) do %>
      <span>+<%= remaining_count %></span>
    <% end %>
  <% end %>
</div>


================================================
FILE: app/components/ui/avatar_group_component.rb
================================================
# frozen_string_literal: true

class Ui::AvatarGroupComponent < ApplicationComponent
  SIZE_MAPPING = {
    sm: "w-8",
    md: "w-12",
    lg: "w-16"
  }.freeze

  param :avatarables, Dry::Types["strict.array"]
  option :size, Dry::Types["coercible.symbol"].enum(*SIZE_MAPPING.keys), default: proc { :md }
  option :max, Dry::Types["coercible.integer"], default: proc { 8 }
  option :overlap, Dry::Types["coercible.string"], default: proc { "-space-x-3" }
  option :hover_card, type: Dry::Types["strict.bool"], default: proc { false }
  option :linked, type: Dry::Types["strict.bool"], default: proc { false }

  private

  def visible_avatarables
    avatarables.first(max)
  end

  def remaining_count
    [avatarables.size - max, 0].max
  end

  def size_class
    SIZE_MAPPING[size]
  end
end


================================================
FILE: app/components/ui/badge_component.rb
================================================
# frozen_string_literal: true

class Ui::BadgeComponent < ApplicationComponent
  KIND_MAPPING = {
    neutral: "badge-neutral",
    primary: "badge-primary",
    secondary: "badge-secondary",
    accent: "badge-accent",
    info: "badge-info",
    success: "badge-success",
    warning: "badge-warning",
    error: "badge-error",
    ghost: "badge-ghost"
  }

  SIZE_MAPPING = {
    xs: "badge-xs",
    sm: "badge-sm",
    md: "badge-md",
    lg: "badge-lg"
  }

  param :text, optional: true
  option :kind, type: Dry::Types["coercible.symbol"].enum(*KIND_MAPPING.keys), default: proc { :primary }
  option :size, type: Dry::Types["coercible.symbol"].enum(*SIZE_MAPPING.keys), default: proc { :md }
  option :outline, type: Dry::Types["strict.bool"], default: proc { false }

  def call
    content_tag(:span, class: classes, **attributes.except(:class)) do
      concat content
    end
  end

  private

  def classes
    [component_classes, attributes[:class]].join(" ")
  end

  def component_classes
    class_names(
      "badge",
      KIND_MAPPING[kind],
      SIZE_MAPPING[size],
      "badge-outline": outline
    )
  end

  def content
    text.presence || super
  end
end


================================================
FILE: app/components/ui/button_component.rb
================================================
# frozen_string_literal: true

class Ui::ButtonComponent < ApplicationComponent
  KIND_MAPPING = {
    primary: "btn-primary",
    secondary: "btn-secondary",
    neutral: "btn-neutral btn-outline",
    rounded: "btn btn-rounded",
    pill: "btn btn-pill btn-sm",
    circle: "btn btn-circle",
    ghost: "btn-ghost",
    link: "btn-link",
    none: ""
  }

  SIZE_MAPPING = {
    sm: "btn-sm",
    md: "",
    lg: "btn-lg"
  }

  param :text, default: proc {}
  option :url, Dry::Types["coercible.string"], optional: true
  option :method, Dry::Types["coercible.symbol"].enum(:get, :post, :patch, :put, :delete), optional: true
  option :kind, type: Dry::Types["coercible.symbol"].enum(*KIND_MAPPING.keys), default: proc { :primary }
  option :size, type: Dry::Types["coercible.symbol"].enum(*SIZE_MAPPING.keys), default: proc { :md }
  option :type, type: Dry::Types["coercible.symbol"].enum(:button, :submit, :input), default: proc { :button }
  option :disabled, type: Dry::Types["strict.bool"], default: proc { false }
  option :outline, type: Dry::Types["strict.bool"], default: proc { false }
  option :animation, type: Dry::Types["strict.bool"], default: proc { false }

  def call
    case button_kind
    when :link
      link_to(url, disabled: disabled, class: classes, **attributes.except(:class, :type)) { content }
    when :button_to
      button_to(url, disabled: disabled, method: method, class: classes, **attributes.except(:class, :type)) { content }
    when :button
      tag.button(type: type, disabled: disabled, class: classes, **attributes.except(:class, :type)) { content }
    end
  end

  private

  def classes
    [component_classes, attributes[:class]].join(" ")
  end

  def component_classes
    class_names(
      "btn",
      KIND_MAPPING[kind],
      SIZE_MAPPING[size],
      "btn-outline": outline,
      "btn-disabled": disabled,
      "no-animation": !animation # animation is disabled by default, I don't really like the effect when you enter the page
    )
  end

  def content
    text.presence || super
  end

  def button_kind
    return :link if url.present? && default_method?
    return :button_to if url.present? && !default_method?

    :button
  end

  def default_method?
    method.blank? || method == :get
  end
end


================================================
FILE: app/components/ui/divider_component.rb
================================================
# frozen_string_literal: true

class Ui::DividerComponent < ApplicationComponent
  KIND_MAPPING = {
    horizontal: "divider-horizontal",
    vertical: "divider-vertical"
  }

  param :text, optional: true
  option :kind, type: Dry::Types["coercible.symbol"].enum(*KIND_MAPPING.keys), optional: true

  def call
    content_tag(:div, class: classes, **attributes.except(:class)) do
      concat content
    end
  end

  private

  def classes
    [component_classes, attributes[:class]].join(" ")
  end

  def component_classes
    class_names(
      "divider",
      KIND_MAPPING[kind]
    )
  end

  def content
    text.presence || super
  end
end


================================================
FILE: app/components/ui/dropdown_component.html.erb
================================================
<%= content_tag :details, class: classes, **attributes do %>
  <summary class="flex after:hidden">
    <% if toggle_open? && toggle_close? %>
      <div class="swap" data-dropdown-target="swap">
        <div class="swap-on"><%= toggle_open %></div>
        <div class="swap-off"><%= toggle_close %></div>
      </div>
    <% else %>
      <%= content %>
    <% end %>
  </summary>
  <%= content_tag :ul, class: content_classes do %>
    <% menu_items.each do |menu_item| %>
      <%= menu_item %>
    <% end %>
  <% end %>
<% end %>


================================================
FILE: app/components/ui/dropdown_component.rb
================================================
# frozen_string_literal: true

class Ui::DropdownComponent < ApplicationComponent
  renders_many :menu_items, types: {
    divider: lambda { render Ui::DividerComponent.new(class: "my-2") },
    link_to: lambda { |*args, **attributes, &block|
      content_tag :li do
        attributes[:class] = class_names("!whitespace-nowrap", attributes[:class])
        concat link_to(*args, **attributes, &block)
      end
    },
    button_to: lambda { |*args, **attributes|
      content_tag :li do
        attributes[:class] = class_names("!whitespace-nowrap", attributes[:class])
        concat button_to(*args, **attributes)
      end
    }
  }

  renders_one :toggle_open
  renders_one :toggle_close

  OPEN_FROM_MAPPING = {
    left: "dropdown-left",
    right: "dropdown-right",
    top: "dropdown-top",
    bottom: "dropdown-bottom"
  }

  ALIGN_MAPPING = {
    end: "dropdown-end"
  }

  option :open, type: Dry::Types["strict.bool"], default: proc { false }
  option :hover, type: Dry::Types["strict.bool"], default: proc { false }
  option :align, type: Dry::Types["coercible.symbol"].enum(*ALIGN_MAPPING.keys), optional: true
  option :open_from, type: Dry::Types["coercible.symbol"].enum(*OPEN_FROM_MAPPING.keys), optional: true

  private

  def before_render
    attributes[:data] = {controller: "dropdown"}
  end

  def classes
    [component_classes, attributes.delete(:class)].compact_blank.join(" ")
  end

  def component_classes
    class_names(
      "dropdown",
      OPEN_FROM_MAPPING[open_from],
      ALIGN_MAPPING[align],
      "dropdown-hover": hover,
      "dropdown-open": open
    )
  end

  def content_classes
    class_names("dropdown-content menu menu-smp-2 mt-4 w-max z-30 rounded-lg shadow-2xl bg-white text-neutral", attributes.delete(:content_classes))
  end
end


================================================
FILE: app/components/ui/modal_component.html.erb
================================================
<%= content_tag :dialog, role: :dialog, aria: {modal: true}, class: classes, **attributes do %>
  <div class="modal-box <%= size_class %>" data-modal-target="modalBox">
    <% if close_button %>
      <button
        class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
        data-action="click->modal#close">
        <%= helpers.fa :xmark %>
      </button>
    <% end %>
    <%= content %>
  </div>
<% end %>


================================================
FILE: app/components/ui/modal_component.rb
================================================
# frozen_string_literal: true

class Ui::ModalComponent < ApplicationComponent
  POSITION_MAPPING = {
    top: "modal-top",
    bottom: "modal-bottom",
    middle: "modal-middle",
    responsive: "modal-bottom sm:modal-middle"
  }

  SIZE_MAPPING = {
    md: "",
    lg: "!max-w-[800px]",
    xl: "!max-w-[1200px]",
    full: "!max-w-[95vw] !w-[95vw] !max-h-[90vh]"
  }

  option :open, type: Dry::Types["strict.bool"], default: proc { false }
  option :
Download .txt
Showing preview only (205K chars total). Download the full file or copy to clipboard to get everything.
gitextract_xohe3ehl/

├── .annotaterb.yml
├── .cursor/
│   ├── commands/
│   │   └── plan_commands.md
│   └── rules/
│       ├── cursorrules.mdc
│       └── viewcomponents.mdc
├── .devcontainer/
│   ├── Dockerfile
│   ├── devcontainer.json
│   └── docker-compose.yml
├── .dockerignore
├── .erb_lint.yml
├── .eslintignore
├── .eslintrc
├── .gitattributes
├── .github/
│   ├── pull_request_template.md
│   ├── skills/
│   │   └── event-data/
│   │       └── SKILL.md
│   └── workflows/
│       ├── ci.yml
│       ├── copilot-setup-steps.yml
│       ├── deploy-staging.yml
│       ├── migrate-production.yml
│       ├── migrate-staging.yml
│       ├── release-lock-production.yml
│       ├── release-lock-staging.yml
│       ├── seed-production.yml
│       └── seed-staging.yml
├── .gitignore
├── .herb.yml
├── .kamal/
│   ├── hooks/
│   │   ├── docker-setup.sample
│   │   ├── post-deploy.sample
│   │   ├── post-proxy-reboot.sample
│   │   ├── pre-build.sample
│   │   ├── pre-connect.sample
│   │   ├── pre-deploy.sample
│   │   └── pre-proxy-reboot.sample
│   ├── secrets
│   └── secrets.staging
├── .mcp.json
├── .node-version
├── .prettierignore
├── .ruby-version
├── .standard.yml
├── .vscode/
│   ├── extensions.json
│   └── settings.json
├── CLAUDE.md
├── CONTRIBUTING.md
├── Dockerfile
├── Gemfile
├── Guardfile
├── Procfile.dev
├── README.md
├── Rakefile
├── app/
│   ├── assets/
│   │   ├── builds/
│   │   │   └── .keep
│   │   └── stylesheets/
│   │       ├── application.css
│   │       ├── bridge/
│   │       │   └── components.css
│   │       └── components/
│   │           ├── button.css
│   │           ├── diff.css
│   │           ├── dropdown.css
│   │           ├── event.css
│   │           ├── form.css
│   │           ├── hotwire-combobox.css
│   │           ├── iframe.css
│   │           ├── markdown.css
│   │           ├── modal.css
│   │           ├── nav.css
│   │           ├── pagination.css
│   │           ├── skeleton.css
│   │           ├── spotlight.css
│   │           ├── tabs.css
│   │           ├── transition.css
│   │           ├── typography.css
│   │           └── video.css
│   ├── avo/
│   │   ├── actions/
│   │   │   ├── approve_topic.rb
│   │   │   ├── assign_canonical_event.rb
│   │   │   ├── assign_canonical_speaker.rb
│   │   │   ├── assign_canonical_topic.rb
│   │   │   ├── assign_canonical_user.rb
│   │   │   ├── clear_user.rb
│   │   │   ├── enhance_transcript.rb
│   │   │   ├── extract_topics.rb
│   │   │   ├── fetch_duration.rb
│   │   │   ├── find_topic_talks.rb
│   │   │   ├── geocode_record.rb
│   │   │   ├── reject_topic.rb
│   │   │   ├── summarize.rb
│   │   │   ├── talk_index.rb
│   │   │   ├── talk_ingest.rb
│   │   │   ├── transcript.rb
│   │   │   ├── update_from_yml.rb
│   │   │   └── user_fetch_github.rb
│   │   ├── cards/
│   │   │   ├── duplicates_summary.rb
│   │   │   ├── reversed_name_duplicates_list.rb
│   │   │   ├── reversed_name_duplicates_metric.rb
│   │   │   ├── same_name_duplicates_list.rb
│   │   │   ├── same_name_duplicates_metric.rb
│   │   │   ├── suspicious_signals_breakdown.rb
│   │   │   ├── suspicious_summary.rb
│   │   │   ├── suspicious_users_list.rb
│   │   │   ├── suspicious_users_metric.rb
│   │   │   ├── unavailable_videos_by_event.rb
│   │   │   ├── unavailable_videos_list.rb
│   │   │   ├── unavailable_videos_metric.rb
│   │   │   └── unavailable_videos_summary.rb
│   │   ├── dashboards/
│   │   │   ├── default.rb
│   │   │   ├── duplicates.rb
│   │   │   ├── suspicious.rb
│   │   │   └── unavailable_videos.rb
│   │   ├── filters/
│   │   │   ├── aliasable_type.rb
│   │   │   ├── attended_as.rb
│   │   │   ├── bio.rb
│   │   │   ├── bio_presence.rb
│   │   │   ├── canonical.rb
│   │   │   ├── enhanced_transcript.rb
│   │   │   ├── geocoded_presence.rb
│   │   │   ├── github.rb
│   │   │   ├── github_handle.rb
│   │   │   ├── github_handle_presence.rb
│   │   │   ├── has_duplicate.rb
│   │   │   ├── involvement_role.rb
│   │   │   ├── language.rb
│   │   │   ├── location_presence.rb
│   │   │   ├── name.rb
│   │   │   ├── provider.rb
│   │   │   ├── published.rb
│   │   │   ├── raw_transcript.rb
│   │   │   ├── slug.rb
│   │   │   ├── summary.rb
│   │   │   ├── suspicious.rb
│   │   │   ├── talk_event.rb
│   │   │   ├── title.rb
│   │   │   ├── topic_talks.rb
│   │   │   ├── topics.rb
│   │   │   ├── video_availability.rb
│   │   │   ├── video_provider.rb
│   │   │   └── without_talks.rb
│   │   └── resources/
│   │       ├── alias.rb
│   │       ├── city.rb
│   │       ├── connected_account.rb
│   │       ├── contributor.rb
│   │       ├── event.rb
│   │       ├── event_involvement.rb
│   │       ├── event_participation.rb
│   │       ├── event_series.rb
│   │       ├── favorite_user.rb
│   │       ├── geocode_result.rb
│   │       ├── organization.rb
│   │       ├── session.rb
│   │       ├── sponsor.rb
│   │       ├── suggestion.rb
│   │       ├── talk.rb
│   │       ├── talk_topic.rb
│   │       ├── talk_transcript.rb
│   │       ├── topic.rb
│   │       ├── topic_gem.rb
│   │       ├── user.rb
│   │       ├── user_talk.rb
│   │       ├── watch_list.rb
│   │       └── watch_list_talk.rb
│   ├── channels/
│   │   └── application_cable/
│   │       ├── channel.rb
│   │       └── connection.rb
│   ├── clients/
│   │   ├── application_client.rb
│   │   ├── blue_sky.rb
│   │   ├── github/
│   │   │   ├── client.rb
│   │   │   ├── contributors_client.rb
│   │   │   └── user_client.rb
│   │   ├── ruby_conferences/
│   │   │   └── client.rb
│   │   ├── speakerdeck/
│   │   │   └── client.rb
│   │   └── youtube/
│   │       ├── channels.rb
│   │       ├── client.rb
│   │       ├── playlist_items.rb
│   │       ├── playlists.rb
│   │       ├── thumbnail.rb
│   │       ├── transcript.rb
│   │       └── video.rb
│   ├── components/
│   │   ├── application_component.rb
│   │   ├── events/
│   │   │   ├── upcoming_event_banner_component.html.erb
│   │   │   └── upcoming_event_banner_component.rb
│   │   ├── hover_card/
│   │   │   ├── base_component.html.erb
│   │   │   ├── base_component.rb
│   │   │   ├── event_component.rb
│   │   │   └── user_component.rb
│   │   ├── tito/
│   │   │   ├── button_component.html.erb
│   │   │   ├── button_component.rb
│   │   │   ├── widget_component.html.erb
│   │   │   └── widget_component.rb
│   │   └── ui/
│   │       ├── avatar_component.html.erb
│   │       ├── avatar_component.rb
│   │       ├── avatar_group_component.html.erb
│   │       ├── avatar_group_component.rb
│   │       ├── badge_component.rb
│   │       ├── button_component.rb
│   │       ├── divider_component.rb
│   │       ├── dropdown_component.html.erb
│   │       ├── dropdown_component.rb
│   │       ├── modal_component.html.erb
│   │       ├── modal_component.rb
│   │       ├── stamp_component.html.erb
│   │       └── stamp_component.rb
│   ├── controllers/
│   │   ├── admin/
│   │   │   └── suggestions_controller.rb
│   │   ├── analytics/
│   │   │   └── dashboards_controller.rb
│   │   ├── announcements_controller.rb
│   │   ├── api/
│   │   │   └── v1/
│   │   │       └── embed/
│   │   │           ├── base_controller.rb
│   │   │           ├── events_controller.rb
│   │   │           ├── profiles_controller.rb
│   │   │           ├── speakers_controller.rb
│   │   │           ├── stamps_controller.rb
│   │   │           ├── stickers_controller.rb
│   │   │           ├── talks_controller.rb
│   │   │           └── topics_controller.rb
│   │   ├── application_controller.rb
│   │   ├── avo/
│   │   │   ├── aliases_controller.rb
│   │   │   ├── cities_controller.rb
│   │   │   ├── connected_accounts_controller.rb
│   │   │   ├── contributors_controller.rb
│   │   │   ├── event_involvements_controller.rb
│   │   │   ├── event_participations_controller.rb
│   │   │   ├── event_series_controller.rb
│   │   │   ├── events_controller.rb
│   │   │   ├── favorite_users_controller.rb
│   │   │   ├── geocode_results_controller.rb
│   │   │   ├── organizations_controller.rb
│   │   │   ├── sessions_controller.rb
│   │   │   ├── speaker_talks_controller.rb
│   │   │   ├── speakers_controller.rb
│   │   │   ├── sponsors_controller.rb
│   │   │   ├── suggestions_controller.rb
│   │   │   ├── talk_topics_controller.rb
│   │   │   ├── talk_transcripts_controller.rb
│   │   │   ├── talks_controller.rb
│   │   │   ├── topic_gems_controller.rb
│   │   │   ├── topics_controller.rb
│   │   │   ├── user_talks_controller.rb
│   │   │   ├── users_controller.rb
│   │   │   ├── watch_list_talks_controller.rb
│   │   │   └── watch_lists_controller.rb
│   │   ├── browse_controller.rb
│   │   ├── cfp_controller.rb
│   │   ├── cities_controller.rb
│   │   ├── concerns/
│   │   │   ├── analytics.rb
│   │   │   ├── authenticable.rb
│   │   │   ├── event_data.rb
│   │   │   ├── event_map_markers.rb
│   │   │   ├── favorite_users.rb
│   │   │   ├── geo_map_layers.rb
│   │   │   ├── location_events.rb
│   │   │   ├── metadata.rb
│   │   │   ├── profile_data.rb
│   │   │   ├── remote_modal.rb
│   │   │   ├── spotlight_search.rb
│   │   │   ├── turbo/
│   │   │   │   └── force_response.rb
│   │   │   └── watched_talks.rb
│   │   ├── continents/
│   │   │   ├── base_controller.rb
│   │   │   └── countries_controller.rb
│   │   ├── continents_controller.rb
│   │   ├── contributions_controller.rb
│   │   ├── coordinates_controller.rb
│   │   ├── countries/
│   │   │   ├── base_controller.rb
│   │   │   └── cities_controller.rb
│   │   ├── countries_controller.rb
│   │   ├── event_participations_controller.rb
│   │   ├── events/
│   │   │   ├── archive_controller.rb
│   │   │   ├── attendances_controller.rb
│   │   │   ├── cfp_controller.rb
│   │   │   ├── collectibles_controller.rb
│   │   │   ├── events_controller.rb
│   │   │   ├── involvements_controller.rb
│   │   │   ├── meetups_controller.rb
│   │   │   ├── participants_controller.rb
│   │   │   ├── past_controller.rb
│   │   │   ├── related_talks_controller.rb
│   │   │   ├── schedules_controller.rb
│   │   │   ├── series_controller.rb
│   │   │   ├── speakers_controller.rb
│   │   │   ├── sponsors_controller.rb
│   │   │   ├── talks_controller.rb
│   │   │   ├── tickets_controller.rb
│   │   │   ├── todos_controller.rb
│   │   │   ├── upcoming_controller.rb
│   │   │   ├── venues_controller.rb
│   │   │   ├── videos_controller.rb
│   │   │   └── years_controller.rb
│   │   ├── events_controller.rb
│   │   ├── favorite_users_controller.rb
│   │   ├── gems_controller.rb
│   │   ├── hotwire/
│   │   │   └── native/
│   │   │       └── v1/
│   │   │           ├── android/
│   │   │           │   └── path_configurations_controller.rb
│   │   │           └── ios/
│   │   │               └── path_configurations_controller.rb
│   │   ├── hover_cards/
│   │   │   ├── events_controller.rb
│   │   │   └── users_controller.rb
│   │   ├── leaderboard_controller.rb
│   │   ├── locations/
│   │   │   ├── base_controller.rb
│   │   │   ├── map_controller.rb
│   │   │   ├── meetups_controller.rb
│   │   │   ├── past_controller.rb
│   │   │   ├── stamps_controller.rb
│   │   │   └── users_controller.rb
│   │   ├── online_controller.rb
│   │   ├── organizations/
│   │   │   ├── logos_controller.rb
│   │   │   └── wrapped_controller.rb
│   │   ├── organizations_controller.rb
│   │   ├── page_controller.rb
│   │   ├── profiles/
│   │   │   ├── aliases_controller.rb
│   │   │   ├── claims_controller.rb
│   │   │   ├── connect_controller.rb
│   │   │   ├── enhance_controller.rb
│   │   │   ├── events_controller.rb
│   │   │   ├── involvements_controller.rb
│   │   │   ├── map_controller.rb
│   │   │   ├── mutual_events_controller.rb
│   │   │   ├── notes_controller.rb
│   │   │   ├── stamps_controller.rb
│   │   │   ├── stickers_controller.rb
│   │   │   ├── talks_controller.rb
│   │   │   └── wrapped_controller.rb
│   │   ├── profiles_controller.rb
│   │   ├── recommendations_controller.rb
│   │   ├── sessions/
│   │   │   └── omniauth_controller.rb
│   │   ├── sessions_controller.rb
│   │   ├── settings_controller.rb
│   │   ├── sitemaps_controller.rb
│   │   ├── speakers_controller.rb
│   │   ├── sponsors/
│   │   │   └── missing_controller.rb
│   │   ├── spotlight/
│   │   │   ├── events_controller.rb
│   │   │   ├── kinds_controller.rb
│   │   │   ├── languages_controller.rb
│   │   │   ├── locations_controller.rb
│   │   │   ├── organizations_controller.rb
│   │   │   ├── series_controller.rb
│   │   │   ├── speakers_controller.rb
│   │   │   ├── talks_controller.rb
│   │   │   └── topics_controller.rb
│   │   ├── stamps_controller.rb
│   │   ├── states/
│   │   │   ├── base_controller.rb
│   │   │   └── cities_controller.rb
│   │   ├── states_controller.rb
│   │   ├── talks/
│   │   │   ├── recommendations_controller.rb
│   │   │   ├── slides_controller.rb
│   │   │   └── watched_talks_controller.rb
│   │   ├── talks_controller.rb
│   │   ├── templates_controller.rb
│   │   ├── todos_controller.rb
│   │   ├── topics_controller.rb
│   │   ├── watch_list_talks_controller.rb
│   │   ├── watch_lists_controller.rb
│   │   ├── watched_talks_controller.rb
│   │   └── wrapped_controller.rb
│   ├── helpers/
│   │   ├── application_helper.rb
│   │   ├── events/
│   │   │   └── talks_helper.rb
│   │   ├── events_helper.rb
│   │   ├── icon_helper.rb
│   │   ├── language_helper.rb
│   │   ├── location_helper.rb
│   │   ├── markdown_helper.rb
│   │   ├── page_helper.rb
│   │   ├── speakers/
│   │   │   └── enhance_helper.rb
│   │   ├── speakers_helper.rb
│   │   ├── spotlight_helper.rb
│   │   ├── suggestions_helper.rb
│   │   ├── talks_helper.rb
│   │   └── view_component_helper.rb
│   ├── javascript/
│   │   ├── controllers/
│   │   │   ├── application.js
│   │   │   ├── auto-click_controller.js
│   │   │   ├── auto_submit_controller.js
│   │   │   ├── bridge/
│   │   │   │   └── button_controller.js
│   │   │   ├── collapsible_controller.js
│   │   │   ├── content_row_controller.js
│   │   │   ├── copy_to_clipboard_controller.js
│   │   │   ├── dropdown_controller.js
│   │   │   ├── event_controller.js
│   │   │   ├── event_list_controller.js
│   │   │   ├── events_filter_controller.js
│   │   │   ├── events_view_switcher_controller.js
│   │   │   ├── geolocation_controller.js
│   │   │   ├── hover_card_controller.js
│   │   │   ├── index.js
│   │   │   ├── lazy_loading_controller.js
│   │   │   ├── map_controller.js
│   │   │   ├── modal_controller.js
│   │   │   ├── preserve_scroll_controller.js
│   │   │   ├── pronouns_select_controller.js
│   │   │   ├── scroll_controller.js
│   │   │   ├── scroll_into_view_controller.js
│   │   │   ├── splide_controller.js
│   │   │   ├── spotlight_search_controller.js
│   │   │   ├── tabs_controller.js
│   │   │   ├── talks_filter_controller.js
│   │   │   ├── talks_filter_pill_controller.js
│   │   │   ├── talks_navigation_controller.js
│   │   │   ├── toggable_controller.js
│   │   │   ├── tooltip_controller.js
│   │   │   ├── top_banner_controller.js
│   │   │   ├── transition_controller.js
│   │   │   ├── video_player_controller.js
│   │   │   ├── watched_talk_form_controller.js
│   │   │   └── wrapped_stories_controller.js
│   │   ├── entrypoints/
│   │   │   ├── application.css
│   │   │   ├── application.js
│   │   │   └── chartkick.js
│   │   ├── helpers/
│   │   │   └── timing_helpers.js
│   │   └── support/
│   │       └── appsignal.js
│   ├── jobs/
│   │   ├── application_job.rb
│   │   ├── generate_wrapped_screenshot_job.rb
│   │   ├── geocode_record_job.rb
│   │   ├── recurring/
│   │   │   ├── fetch_contributors_job.rb
│   │   │   ├── mark_suspicious_users_job.rb
│   │   │   ├── rollup_job.rb
│   │   │   ├── youtube_thumbnail_validation_job.rb
│   │   │   ├── youtube_video_availability_job.rb
│   │   │   ├── youtube_video_duration_job.rb
│   │   │   └── youtube_video_statistics_job.rb
│   │   └── typesense_index_job.rb
│   ├── lib/
│   │   ├── command.rb
│   │   ├── download_sponsors.rb
│   │   ├── duration.rb
│   │   └── router.rb
│   ├── mailers/
│   │   └── application_mailer.rb
│   ├── models/
│   │   ├── active_record/
│   │   │   └── sqlite/
│   │   │       └── index.rb
│   │   ├── ahoy/
│   │   │   ├── event.rb
│   │   │   └── visit.rb
│   │   ├── alias.rb
│   │   ├── announcement.rb
│   │   ├── application_record.rb
│   │   ├── cfp.rb
│   │   ├── city.rb
│   │   ├── concerns/
│   │   │   ├── appsignal/
│   │   │   │   └── admin_namespace.rb
│   │   │   ├── geocodeable.rb
│   │   │   ├── locatable.rb
│   │   │   ├── rollupable.rb
│   │   │   ├── sluggable.rb
│   │   │   ├── suggestable.rb
│   │   │   ├── todoable.rb
│   │   │   ├── url_normalizable.rb
│   │   │   ├── watchable.rb
│   │   │   └── yaml_file.rb
│   │   ├── connected_account.rb
│   │   ├── continent.rb
│   │   ├── contributor.rb
│   │   ├── coordinate_location.rb
│   │   ├── country.rb
│   │   ├── cue.rb
│   │   ├── current.rb
│   │   ├── email_verification_token.rb
│   │   ├── event/
│   │   │   ├── assets.rb
│   │   │   ├── cfp_file.rb
│   │   │   ├── involvements_file.rb
│   │   │   ├── schedule.rb
│   │   │   ├── sponsors_file.rb
│   │   │   ├── static_metadata.rb
│   │   │   ├── tickets.rb
│   │   │   ├── transcripts_file.rb
│   │   │   ├── typesense_searchable.rb
│   │   │   ├── venue.rb
│   │   │   └── videos_file.rb
│   │   ├── event.rb
│   │   ├── event_involvement.rb
│   │   ├── event_participation.rb
│   │   ├── event_series/
│   │   │   ├── static_metadata.rb
│   │   │   └── typesense_searchable.rb
│   │   ├── event_series.rb
│   │   ├── favorite_user.rb
│   │   ├── geocode_result.rb
│   │   ├── language.rb
│   │   ├── llm/
│   │   │   ├── client.rb
│   │   │   └── request.rb
│   │   ├── location.rb
│   │   ├── online_location.rb
│   │   ├── organization/
│   │   │   ├── typesense_searchable.rb
│   │   │   └── wrapped_screenshot_generator.rb
│   │   ├── organization.rb
│   │   ├── password_reset_token.rb
│   │   ├── prompts/
│   │   │   ├── base.rb
│   │   │   ├── talk/
│   │   │   │   ├── enhance_transcript.rb
│   │   │   │   ├── summary.rb
│   │   │   │   └── topics.rb
│   │   │   └── topic/
│   │   │       ├── match_talks.rb
│   │   │       └── suggest_gems.rb
│   │   ├── rollup.rb
│   │   ├── search/
│   │   │   ├── backend/
│   │   │   │   ├── sqlite_fts/
│   │   │   │   │   └── indexer.rb
│   │   │   │   ├── sqlite_fts.rb
│   │   │   │   ├── typesense/
│   │   │   │   │   ├── circuit_breaker.rb
│   │   │   │   │   ├── indexer.rb
│   │   │   │   │   ├── kind_indexer.rb
│   │   │   │   │   ├── language_indexer.rb
│   │   │   │   │   └── location_indexer.rb
│   │   │   │   └── typesense.rb
│   │   │   └── backend.rb
│   │   ├── session.rb
│   │   ├── speaker.rb
│   │   ├── sponsor.rb
│   │   ├── stamp.rb
│   │   ├── state.rb
│   │   ├── static/
│   │   │   ├── backends/
│   │   │   │   ├── array_backend.rb
│   │   │   │   ├── file_backend.rb
│   │   │   │   └── multi_file_backend.rb
│   │   │   ├── city.rb
│   │   │   ├── event.rb
│   │   │   ├── event_series.rb
│   │   │   ├── speaker.rb
│   │   │   ├── sponsor.rb
│   │   │   ├── topic.rb
│   │   │   ├── transcript.rb
│   │   │   └── video.rb
│   │   ├── sticker.rb
│   │   ├── suggestion.rb
│   │   ├── talk/
│   │   │   ├── agents.rb
│   │   │   ├── downloader.rb
│   │   │   ├── index.rb
│   │   │   ├── similar_recommender.rb
│   │   │   ├── sqlite_fts_searchable.rb
│   │   │   ├── thumbnails.rb
│   │   │   ├── transcript.rb
│   │   │   └── typesense_searchable.rb
│   │   ├── talk.rb
│   │   ├── talk_topic.rb
│   │   ├── template.rb
│   │   ├── todo.rb
│   │   ├── topic/
│   │   │   ├── agents.rb
│   │   │   ├── gem_info.rb
│   │   │   └── typesense_searchable.rb
│   │   ├── topic.rb
│   │   ├── topic_gem.rb
│   │   ├── transcript.rb
│   │   ├── uk_nation.rb
│   │   ├── user/
│   │   │   ├── duplicate_detector.rb
│   │   │   ├── index.rb
│   │   │   ├── profiles.rb
│   │   │   ├── speakerdeck_feed.rb
│   │   │   ├── sqlite_fts_searchable.rb
│   │   │   ├── suspicion_detector.rb
│   │   │   ├── talk_recommender.rb
│   │   │   ├── typesense_searchable.rb
│   │   │   ├── watched_talk_seeder.rb
│   │   │   ├── wrapped_image_generator.rb
│   │   │   └── wrapped_screenshot_generator.rb
│   │   ├── user.rb
│   │   ├── user_talk.rb
│   │   ├── watch_list.rb
│   │   ├── watch_list_talk.rb
│   │   ├── watched_talk.rb
│   │   └── youtube/
│   │       ├── null_parser.rb
│   │       ├── video_metadata.rb
│   │       ├── video_metadata_baltic_ruby_2024.rb
│   │       ├── video_metadata_kaigi_on_rails.rb
│   │       └── video_metadata_rails_world.rb
│   ├── schemas/
│   │   ├── address_schema.rb
│   │   ├── cfp_schema.rb
│   │   ├── coordinates_schema.rb
│   │   ├── event_schema.rb
│   │   ├── featured_city_schema.rb
│   │   ├── hotel_schema.rb
│   │   ├── involvement_schema.rb
│   │   ├── location_schema.rb
│   │   ├── maps_schema.rb
│   │   ├── schedule_schema.rb
│   │   ├── series_schema.rb
│   │   ├── speaker_schema.rb
│   │   ├── sponsors_schema.rb
│   │   ├── transcript_schema.rb
│   │   ├── venue_schema.rb
│   │   └── video_schema.rb
│   ├── serializers/
│   │   └── transcript_serializer.rb
│   ├── tools/
│   │   ├── cfp_create_tool.rb
│   │   ├── cfp_info_tool.rb
│   │   ├── cfp_update_tool.rb
│   │   ├── event_create_tool.rb
│   │   ├── event_lookup_tool.rb
│   │   ├── event_series_create_tool.rb
│   │   ├── event_series_events_tool.rb
│   │   ├── event_series_lookup_tool.rb
│   │   ├── event_talks_tool.rb
│   │   ├── geocode_tool.rb
│   │   ├── github_profile_tool.rb
│   │   ├── speaker_lookup_tool.rb
│   │   ├── speaker_talks_tool.rb
│   │   ├── speakerdeck_deck_tool.rb
│   │   ├── speakerdeck_user_decks_tool.rb
│   │   ├── venue_create_tool.rb
│   │   ├── vimeo_video_tool.rb
│   │   ├── youtube_channel_videos_tool.rb
│   │   ├── youtube_playlist_items_tool.rb
│   │   ├── youtube_playlist_tool.rb
│   │   ├── youtube_video_tool.rb
│   │   └── youtube_videos_tool.rb
│   └── views/
│       ├── admin/
│       │   └── suggestions/
│       │       ├── _suggestion.html.erb
│       │       └── index.html.erb
│       ├── analytics/
│       │   └── dashboards/
│       │       ├── daily_page_views.html.erb
│       │       ├── daily_visits.html.erb
│       │       ├── monthly_page_views.html.erb
│       │       ├── monthly_visits.html.erb
│       │       ├── show.html.erb
│       │       ├── top_landing_pages.html.erb
│       │       ├── top_referrers.html.erb
│       │       ├── top_searches.html.erb
│       │       ├── yearly_conferences.html.erb
│       │       └── yearly_talks.html.erb
│       ├── announcements/
│       │   ├── feed.rss.builder
│       │   ├── index.html.erb
│       │   └── show.html.erb
│       ├── avo/
│       │   └── cards/
│       │       ├── _duplicates_summary.html.erb
│       │       ├── _reversed_name_duplicates_list.html.erb
│       │       ├── _same_name_duplicates_list.html.erb
│       │       ├── _suspicious_signals_breakdown.html.erb
│       │       ├── _suspicious_summary.html.erb
│       │       ├── _suspicious_users_list.html.erb
│       │       ├── _unavailable_videos_by_event.html.erb
│       │       ├── _unavailable_videos_list.html.erb
│       │       └── _unavailable_videos_summary.html.erb
│       ├── browse/
│       │   ├── _content_row.html.erb
│       │   ├── _content_row_skeleton.html.erb
│       │   ├── _featured_events.html.erb
│       │   ├── _kind_row.html.erb
│       │   ├── _topic_row.html.erb
│       │   ├── index.html.erb
│       │   └── sections/
│       │       ├── _beginner_friendly.html.erb
│       │       ├── _continue_watching.html.erb
│       │       ├── _deep_dives.html.erb
│       │       ├── _event_rows.html.erb
│       │       ├── _events_attended.html.erb
│       │       ├── _evergreen.html.erb
│       │       ├── _favorite_rubyists.html.erb
│       │       ├── _favorite_speakers.html.erb
│       │       ├── _featured_events.html.erb
│       │       ├── _for_you.html.erb
│       │       ├── _from_bookmarks.html.erb
│       │       ├── _hidden_gems.html.erb
│       │       ├── _inspiring.html.erb
│       │       ├── _language_rows.html.erb
│       │       ├── _mind_blowing.html.erb
│       │       ├── _most_bookmarked.html.erb
│       │       ├── _most_liked.html.erb
│       │       ├── _newest_talks.html.erb
│       │       ├── _popular.html.erb
│       │       ├── _popular_topics.html.erb
│       │       ├── _popular_youtube.html.erb
│       │       ├── _quick_watches.html.erb
│       │       ├── _recently_published.html.erb
│       │       ├── _recommended_community.html.erb
│       │       ├── _talk_kinds.html.erb
│       │       ├── _topic_rows.html.erb
│       │       ├── _trending.html.erb
│       │       └── _unwatched_attended.html.erb
│       ├── cfp/
│       │   ├── _event_list.html.erb
│       │   └── index.html.erb
│       ├── cities/
│       │   ├── index.html.erb
│       │   ├── map/
│       │   │   └── index.html.erb
│       │   ├── meetups/
│       │   │   └── index.html.erb
│       │   ├── past/
│       │   │   └── index.html.erb
│       │   ├── show.html.erb
│       │   ├── stamps/
│       │   │   └── index.html.erb
│       │   └── users/
│       │       └── index.html.erb
│       ├── continents/
│       │   ├── countries/
│       │   │   └── index.html.erb
│       │   ├── index.html.erb
│       │   ├── map/
│       │   │   └── index.html.erb
│       │   ├── past/
│       │   │   └── index.html.erb
│       │   ├── show.html.erb
│       │   ├── stamps/
│       │   │   └── index.html.erb
│       │   └── users/
│       │       └── index.html.erb
│       ├── contributions/
│       │   ├── _events_without_dates.html.erb
│       │   ├── _events_without_location.html.erb
│       │   ├── _events_without_videos.html.erb
│       │   ├── _introduction.html.erb
│       │   ├── _missing_videos_cue.html.erb
│       │   ├── _speakers_without_github.html.erb
│       │   ├── _talks_dates_out_of_bounds.html.erb
│       │   ├── _talks_without_slides.html.erb
│       │   ├── index.html.erb
│       │   └── show.html.erb
│       ├── coordinates/
│       │   ├── index.html.erb
│       │   ├── map/
│       │   │   └── index.html.erb
│       │   ├── past/
│       │   │   └── index.html.erb
│       │   ├── show.html.erb
│       │   └── users/
│       │       └── index.html.erb
│       ├── countries/
│       │   ├── cities/
│       │   │   └── index.html.erb
│       │   ├── index.html.erb
│       │   ├── map/
│       │   │   └── index.html.erb
│       │   ├── meetups/
│       │   │   └── index.html.erb
│       │   ├── past/
│       │   │   └── index.html.erb
│       │   ├── show.html.erb
│       │   ├── stamps/
│       │   │   └── index.html.erb
│       │   ├── state.html.erb
│       │   └── users/
│       │       └── index.html.erb
│       ├── event_participations/
│       │   ├── create.turbo_stream.erb
│       │   └── destroy.turbo_stream.erb
│       ├── events/
│       │   ├── _card.html.erb
│       │   ├── _event.html.erb
│       │   ├── _event_list.html.erb
│       │   ├── _featured.html.erb
│       │   ├── _featured_card.html.erb
│       │   ├── _featured_card_list.html.erb
│       │   ├── _featured_home.html.erb
│       │   ├── _form.html.erb
│       │   ├── _header.html.erb
│       │   ├── _my_attendance.html.erb
│       │   ├── _my_attendance_day.html.erb
│       │   ├── _my_attendance_talk.html.erb
│       │   ├── _navigation.html.erb
│       │   ├── _participation_button.html.erb
│       │   ├── _plain_list.html.erb
│       │   ├── archive/
│       │   │   └── index.html.erb
│       │   ├── attendances/
│       │   │   ├── index.html.erb
│       │   │   └── show.html.erb
│       │   ├── cfp/
│       │   │   └── index.html.erb
│       │   ├── collectibles/
│       │   │   └── index.html.erb
│       │   ├── edit.html.erb
│       │   ├── events/
│       │   │   ├── index.html.erb
│       │   │   └── show.html.erb
│       │   ├── index.html.erb
│       │   ├── involvements/
│       │   │   ├── _list.html.erb
│       │   │   └── index.html.erb
│       │   ├── meetups/
│       │   │   └── index.html.erb
│       │   ├── new.html.erb
│       │   ├── participants/
│       │   │   ├── _list.html.erb
│       │   │   └── index.html.erb
│       │   ├── past/
│       │   │   └── index.html.erb
│       │   ├── related_talks/
│       │   │   ├── _list.html.erb
│       │   │   └── index.html.erb
│       │   ├── schedules/
│       │   │   ├── _day.html.erb
│       │   │   ├── _schedule.html.erb
│       │   │   ├── index.html.erb
│       │   │   ├── missing_schedule.html.erb
│       │   │   └── show.html.erb
│       │   ├── series/
│       │   │   ├── _card.html.erb
│       │   │   ├── index.html.erb
│       │   │   └── show.html.erb
│       │   ├── show.html.erb
│       │   ├── speakers/
│       │   │   └── index.html.erb
│       │   ├── sponsors/
│       │   │   └── index.html.erb
│       │   ├── talks/
│       │   │   └── index.html.erb
│       │   ├── tickets/
│       │   │   └── show.html.erb
│       │   ├── todos/
│       │   │   └── index.html.erb
│       │   ├── venues/
│       │   │   ├── missing_venue.html.erb
│       │   │   └── show.html.erb
│       │   ├── videos/
│       │   │   └── index.html.erb
│       │   └── years/
│       │       ├── _desktop_calendar.html.erb
│       │       ├── _event_hover_card.html.erb
│       │       ├── _header.html.erb
│       │       ├── _mobile_calendar.html.erb
│       │       ├── _yearly_events.html.erb
│       │       └── index.html.erb
│       ├── favorite_users/
│       │   ├── _favorite_user.html.erb
│       │   ├── _form.html.erb
│       │   ├── _list.html.erb
│       │   ├── _no_favorites.html.erb
│       │   └── index.html.erb
│       ├── gems/
│       │   ├── _gem_card.html.erb
│       │   ├── index.html.erb
│       │   ├── index.turbo_stream.erb
│       │   ├── show.html.erb
│       │   ├── talks.html.erb
│       │   └── talks.turbo_stream.erb
│       ├── home/
│       │   └── index.html.erb
│       ├── hover_cards/
│       │   ├── events/
│       │   │   ├── _content.html.erb
│       │   │   └── show.html.erb
│       │   └── users/
│       │       ├── _content.html.erb
│       │       └── show.html.erb
│       ├── identity/
│       │   ├── emails/
│       │   │   └── edit.html.erb
│       │   └── password_resets/
│       │       ├── edit.html.erb
│       │       └── new.html.erb
│       ├── layouts/
│       │   ├── application.html.erb
│       │   ├── application.turbo_stream.erb
│       │   ├── mailer.html.erb
│       │   ├── mailer.text.erb
│       │   ├── modal.html.erb
│       │   ├── turbo_rails/
│       │   │   └── frame.turbo_stream.erb
│       │   └── wrapped.html.erb
│       ├── leaderboard/
│       │   ├── _speaker.html.erb
│       │   └── index.html.erb
│       ├── online/
│       │   ├── past/
│       │   │   └── index.html.erb
│       │   └── show.html.erb
│       ├── organizations/
│       │   ├── _card.html.erb
│       │   ├── _compact_card.html.erb
│       │   ├── _header.html.erb
│       │   ├── _navigation.html.erb
│       │   ├── _organization.html.erb
│       │   ├── index.html.erb
│       │   ├── logos/
│       │   │   └── show.html.erb
│       │   ├── show.html.erb
│       │   └── wrapped/
│       │       ├── index.html.erb
│       │       └── pages/
│       │           └── _summary_card_horizontal.html.erb
│       ├── page/
│       │   ├── about.md
│       │   ├── assets.html.erb
│       │   ├── components/
│       │   │   ├── _avatars.html.erb
│       │   │   ├── _buttons.html.erb
│       │   │   ├── _dropdowns.html.erb
│       │   │   ├── _links.html.erb
│       │   │   ├── _modals.html.erb
│       │   │   ├── _stamps.html.erb
│       │   │   ├── _tabs.html.erb
│       │   │   └── _tooltips.html.erb
│       │   ├── components.html.erb
│       │   ├── contributors.html.erb
│       │   ├── featured.html.erb
│       │   ├── home.html.erb
│       │   ├── privacy.md
│       │   ├── stickers.html.erb
│       │   └── uses.md
│       ├── profiles/
│       │   ├── _actions.html.erb
│       │   ├── _aliases.html.erb
│       │   ├── _events.html.erb
│       │   ├── _form.html.erb
│       │   ├── _header.html.erb
│       │   ├── _header_content.html.erb
│       │   ├── _involvements.html.erb
│       │   ├── _map.html.erb
│       │   ├── _mutual_events.html.erb
│       │   ├── _navigation.html.erb
│       │   ├── _notes.html.erb
│       │   ├── _socials.html.erb
│       │   ├── _stamps.html.erb
│       │   ├── _stickers.html.erb
│       │   ├── _tab_layout.html.erb
│       │   ├── _talks.html.erb
│       │   ├── _topics.html.erb
│       │   ├── actions/
│       │   │   ├── _admin.html.erb
│       │   │   ├── _anonymous.html.erb
│       │   │   ├── _owner.html.erb
│       │   │   └── _signed_in.html.erb
│       │   ├── aliases/
│       │   │   └── index.html.erb
│       │   ├── connect/
│       │   │   ├── _claim_profile.html.erb
│       │   │   ├── _friend_prompt.html.erb
│       │   │   ├── _no_profile_found.html.erb
│       │   │   └── show.html.erb
│       │   ├── edit.html.erb
│       │   ├── enhance/
│       │   │   └── update.turbo_stream.erb
│       │   ├── events/
│       │   │   └── index.html.erb
│       │   ├── involvements/
│       │   │   └── index.html.erb
│       │   ├── map/
│       │   │   └── index.html.erb
│       │   ├── mutual_events/
│       │   │   └── index.html.erb
│       │   ├── notes/
│       │   │   ├── edit.html.erb
│       │   │   └── show.html.erb
│       │   ├── show.html.erb
│       │   ├── stamps/
│       │   │   └── index.html.erb
│       │   ├── stickers/
│       │   │   └── index.html.erb
│       │   ├── talks/
│       │   │   └── index.html.erb
│       │   └── wrapped/
│       │       ├── _share.html.erb
│       │       ├── card.html.erb
│       │       ├── index.html.erb
│       │       ├── pages/
│       │       │   ├── _bookends.html.erb
│       │       │   ├── _closing.html.erb
│       │       │   ├── _conference_buddies.html.erb
│       │       │   ├── _content_mix.html.erb
│       │       │   ├── _contributor.html.erb
│       │       │   ├── _cover.html.erb
│       │       │   ├── _event_map.html.erb
│       │       │   ├── _events_attended.html.erb
│       │       │   ├── _fun_facts.html.erb
│       │       │   ├── _involvements.html.erb
│       │       │   ├── _languages.html.erb
│       │       │   ├── _og_image.html.erb
│       │       │   ├── _passport_holder.html.erb
│       │       │   ├── _speaker_journey.html.erb
│       │       │   ├── _speaking_calendar.html.erb
│       │       │   ├── _stamps.html.erb
│       │       │   ├── _stickers.html.erb
│       │       │   ├── _summary_card.html.erb
│       │       │   ├── _summary_card_horizontal.html.erb
│       │       │   ├── _top_events.html.erb
│       │       │   ├── _top_speakers.html.erb
│       │       │   ├── _top_topics.html.erb
│       │       │   ├── _watch_twin.html.erb
│       │       │   ├── _watching_calendar.html.erb
│       │       │   └── _watching_journey.html.erb
│       │       └── private.html.erb
│       ├── recommendations/
│       │   └── index.html.erb
│       ├── sessions/
│       │   └── new.html.erb
│       ├── settings/
│       │   └── show.html.erb
│       ├── shared/
│       │   ├── _breakpoints.html.erb
│       │   ├── _cfp_countdown_badge.html.erb
│       │   ├── _city_sidebar.html.erb
│       │   ├── _country_card.html.erb
│       │   ├── _date_grouped_events.html.erb
│       │   ├── _event_countdown_badge.html.erb
│       │   ├── _event_row.html.erb
│       │   ├── _events_section.html.erb
│       │   ├── _filter_buttons.html.erb
│       │   ├── _flashes.html.erb
│       │   ├── _footer.html.erb
│       │   ├── _location_header.html.erb
│       │   ├── _location_map.html.erb
│       │   ├── _location_meetups.html.erb
│       │   ├── _location_navigation.html.erb
│       │   ├── _location_past.html.erb
│       │   ├── _location_show.html.erb
│       │   ├── _location_sidebar.html.erb
│       │   ├── _location_stamps.html.erb
│       │   ├── _location_users.html.erb
│       │   ├── _map_layer_controls.html.erb
│       │   ├── _map_time_filter.html.erb
│       │   ├── _meta_talk_card.html.erb
│       │   ├── _month_grouped_events.html.erb
│       │   ├── _navbar.html.erb
│       │   ├── _nearby_events_section.html.erb
│       │   ├── _rubyists_preview.html.erb
│       │   ├── _spotlight_search.html.erb
│       │   ├── _stamps_grid.html.erb
│       │   ├── _stickers_display.html.erb
│       │   ├── _toast.html.erb
│       │   ├── _top_banner.html.erb
│       │   ├── _user_dropdown.html.erb
│       │   ├── _user_mobile_dropdown.html.erb
│       │   └── navbar/
│       │       ├── _link.html.erb
│       │       └── _search_bar.html.erb
│       ├── speakers/
│       │   ├── _card.html.erb
│       │   ├── _speaker.html.erb
│       │   ├── _speaker.json.jbuilder
│       │   ├── index.html.erb
│       │   ├── index.json.jbuilder
│       │   ├── index.turbo_stream.erb
│       │   └── show.html.erb
│       ├── sponsors/
│       │   └── missing/
│       │       └── index.html.erb
│       ├── spotlight/
│       │   ├── events/
│       │   │   ├── _event.html.erb
│       │   │   └── index.turbo_stream.erb
│       │   ├── kinds/
│       │   │   └── index.turbo_stream.erb
│       │   ├── languages/
│       │   │   └── index.turbo_stream.erb
│       │   ├── locations/
│       │   │   └── index.turbo_stream.erb
│       │   ├── organizations/
│       │   │   └── index.turbo_stream.erb
│       │   ├── series/
│       │   │   └── index.turbo_stream.erb
│       │   ├── speakers/
│       │   │   ├── _speaker.html.erb
│       │   │   └── index.turbo_stream.erb
│       │   ├── talks/
│       │   │   ├── _talk.html.erb
│       │   │   └── index.turbo_stream.erb
│       │   └── topics/
│       │       └── index.turbo_stream.erb
│       ├── stamps/
│       │   └── index.html.erb
│       ├── states/
│       │   ├── cities/
│       │   │   └── index.html.erb
│       │   ├── country_index.html.erb
│       │   ├── index.html.erb
│       │   ├── map/
│       │   │   └── index.html.erb
│       │   ├── meetups/
│       │   │   └── index.html.erb
│       │   ├── past/
│       │   │   └── index.html.erb
│       │   ├── show.html.erb
│       │   ├── stamps/
│       │   │   └── index.html.erb
│       │   └── users/
│       │       └── index.html.erb
│       ├── talks/
│       │   ├── _card.html.erb
│       │   ├── _card_horizontal.html.erb
│       │   ├── _card_thumbnail.html.erb
│       │   ├── _event.html.erb
│       │   ├── _event_tab.html.erb
│       │   ├── _explore_event.html.erb
│       │   ├── _form.html.erb
│       │   ├── _schedule_tab.html.erb
│       │   ├── _sections.html.erb
│       │   ├── _similar_talks_tab.html.erb
│       │   ├── _speaker_tab.html.erb
│       │   ├── _talk.html.erb
│       │   ├── _talk_filter.html.erb
│       │   ├── _transcript.html.erb
│       │   ├── _video_player.html.erb
│       │   ├── edit.html.erb
│       │   ├── index.html.erb
│       │   ├── index.json.jbuilder
│       │   ├── new.html.erb
│       │   ├── recommendations/
│       │   │   └── index.html.erb
│       │   ├── show.html.erb
│       │   ├── show.json.jbuilder
│       │   ├── slides/
│       │   │   └── show.html.erb
│       │   ├── video_providers/
│       │   │   ├── _children.html.erb
│       │   │   ├── _mp4.html.erb
│       │   │   ├── _not_published.html.erb
│       │   │   ├── _not_recorded.html.erb
│       │   │   ├── _scheduled.html.erb
│       │   │   ├── _video_unavailable.html.erb
│       │   │   ├── _vimeo.html.erb
│       │   │   └── _youtube.html.erb
│       │   └── watched_talks/
│       │       ├── _button.html.erb
│       │       ├── _feedback_banner.html.erb
│       │       ├── _feedback_questions.html.erb
│       │       ├── _form.html.erb
│       │       ├── _watched_overlay.html.erb
│       │       ├── _where_watched.html.erb
│       │       ├── create.turbo_stream.erb
│       │       ├── destroy.turbo_stream.erb
│       │       ├── new.html.erb
│       │       ├── toggle_attendance.turbo_stream.erb
│       │       └── update.turbo_stream.erb
│       ├── templates/
│       │   ├── _talk_fields.html.erb
│       │   ├── create.turbo_stream.erb
│       │   ├── delete_child.turbo_stream.erb
│       │   ├── new.html.erb
│       │   ├── new_child.turbo_stream.erb
│       │   └── speakers_search.turbo_stream.erb
│       ├── todos/
│       │   ├── _by_event.html.erb
│       │   ├── _by_type.html.erb
│       │   └── index.html.erb
│       ├── topics/
│       │   ├── _badge.html.erb
│       │   ├── _badge_list.html.erb
│       │   ├── _gem_info.html.erb
│       │   ├── _talks_cursor.html.erb
│       │   ├── _topic.html.erb
│       │   ├── index.html.erb
│       │   ├── index.turbo_stream.erb
│       │   ├── show.html.erb
│       │   └── show.turbo_stream.erb
│       ├── users/
│       │   └── _card.html.erb
│       ├── watch_lists/
│       │   ├── _watch_list.html.erb
│       │   ├── edit.html.erb
│       │   ├── index.html.erb
│       │   ├── new.html.erb
│       │   └── show.html.erb
│       ├── watched_talks/
│       │   └── index.html.erb
│       └── wrapped/
│           ├── _card.html.erb
│           ├── _featured.html.erb
│           └── index.html.erb
├── bin/
│   ├── brakeman
│   ├── bundle
│   ├── bundler-audit
│   ├── ci
│   ├── dev
│   ├── docker-entrypoint
│   ├── dump_prod.sh
│   ├── jobs
│   ├── lint
│   ├── mcp_server
│   ├── rails
│   ├── rake
│   ├── rubocop
│   ├── setup
│   ├── thrust
│   ├── update_lrug_meetups
│   └── vite
├── config/
│   ├── application.rb
│   ├── appsignal.yml
│   ├── boot.rb
│   ├── bundler-audit.yml
│   ├── cable.yml
│   ├── cache.yml
│   ├── ci.rb
│   ├── credentials/
│   │   ├── development.key
│   │   ├── development.yml.enc
│   │   ├── production.yml.enc
│   │   ├── staging.yml.enc
│   │   ├── test.key
│   │   └── test.yml.enc
│   ├── database.yml
│   ├── deploy.staging.yml
│   ├── deploy.yml
│   ├── environment.rb
│   ├── environments/
│   │   ├── development.rb
│   │   ├── production.rb
│   │   ├── staging.rb
│   │   └── test.rb
│   ├── initializers/
│   │   ├── active_genie.rb
│   │   ├── ahoy.rb
│   │   ├── assets.rb
│   │   ├── avo.rb
│   │   ├── content_security_policy.rb
│   │   ├── filter_parameter_logging.rb
│   │   ├── geocoder.rb
│   │   ├── groupe_date.rb
│   │   ├── inflections.rb
│   │   ├── locale.rb
│   │   ├── markdown.rb
│   │   ├── meta_tags.rb
│   │   ├── omniauth.rb
│   │   ├── openai.rb
│   │   ├── pagy.rb
│   │   ├── permissions_policy.rb
│   │   ├── reactionview.rb
│   │   ├── ruby_llm.rb
│   │   ├── typesense.rb
│   │   ├── yjit.rb
│   │   └── yt.rb
│   ├── litestream.staging.yml
│   ├── litestream.yml
│   ├── locales/
│   │   ├── en.yml
│   │   ├── models/
│   │   │   └── event_participation.en.yml
│   │   └── transliterate.en.yml
│   ├── puma.rb
│   ├── queue.yml
│   ├── recurring.yml
│   ├── routes.rb
│   ├── storage.yml
│   └── vite.json
├── config.ru
├── content/
│   └── announcements/
│       ├── 2026-01-01-happy-new-year-2026.md
│       ├── 2026-01-21-introducing-web-components.md
│       ├── 2026-01-22-announcements-and-news.md
│       ├── 2026-03-01-february-newsletter.md
│       └── 2026-04-01-march-newsletter.md
├── data/
│   ├── acts-as-conference/
│   │   ├── acts-as-conference-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── acts-as-conference-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── african-ruby-community/
│   │   ├── african-ruby-mini-conference-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── akashi-rb/
│   │   ├── akashi-rb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── aloha-on-rails/
│   │   ├── aloha-on-rails-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── aloha-rubyconf/
│   │   ├── aloha-rubyconf-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── amsterdam-rb/
│   │   ├── amsterdam-rb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ancient-city-ruby/
│   │   ├── ancient-city-ruby-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ancient-city-ruby-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ancient-city-ruby-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ancient-city-ruby-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ancient-city-ruby-2019/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── arrrrcamp/
│   │   ├── arrrrcamp-2009-may/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── arrrrcamp-2009-october/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── arrrrcamp-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── arrrrcamp-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── arrrrcamp-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── arrrrcamp-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── arrrrcamp-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── arrrrcamp-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── artificialruby/
│   │   ├── artificialruby/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── austinrb/
│   │   ├── austinrb/
│   │   │   ├── cfp.yml
│   │   │   └── event.yml
│   │   └── series.yml
│   ├── balkanruby/
│   │   ├── balkanruby-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── balkanruby-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── balkanruby-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── balkanruby-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── balkanruby-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── balkanruby-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── balticruby/
│   │   ├── balticruby-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── balticruby-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── balticruby-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── bangkok-rb/
│   │   ├── ruby-tuesday/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── barcelona-rb/
│   │   ├── barcelona-rb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── baruco/
│   │   ├── barcelona-ruby-conf-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── barcelona-ruby-conf-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── barcelona-ruby-conf-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── barcelona-ruby-conf-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── bathruby/
│   │   ├── bathruby-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── bathruby-2016/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── bathruby-2018/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── belfastruby/
│   │   ├── belfast-rubyfest-2026/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── belfastruby-meetup/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── big-ruby/
│   │   ├── big-ruby-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── big-ruby-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── birmingham-on-rails/
│   │   ├── birmingham-on-rails-2020/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── blastoffrails/
│   │   ├── blastoffrails-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── blue-ridge-ruby/
│   │   ├── blue-ridge-ruby-2023/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── blue-ridge-ruby-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── blue-ridge-ruby-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── bluegrass-ruby/
│   │   ├── bluegrass-ruby/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── bridgetownconf/
│   │   ├── bridgetownconf-2022/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── brightonruby/
│   │   ├── brightonruby-2014/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2015/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2016/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2017/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2018/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2019/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2020/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2022/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2023/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── brightonruby-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── burlington-ruby-conference/
│   │   ├── burlington-ruby-conference-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── burlington-ruby-conference-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── burlington-ruby-conference-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── burlington-ruby-conference-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── cascadia-ruby/
│   │   ├── cascadia-ruby-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── cascadia-ruby-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── cascadia-ruby-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ceru-camp/
│   │   ├── ceru-camp-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── chicagoruby/
│   │   ├── chicagoruby/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── conferencia-rails/
│   │   ├── conferencia-rails-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── conferencia-rails-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── conferencia-rails-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── deccan-queen-on-rails/
│   │   ├── deccan-queen-on-rails-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── deccanrubyconf/
│   │   ├── deccanrubyconf-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── deccanrubyconf-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── deccanrubyconf-2016/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   └── videos.yml
│   │   ├── deccanrubyconf-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── deccanrubyconf-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── deccanrubyconf-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── dotrb/
│   │   ├── dotrb-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── dresden-rb/
│   │   ├── dresden-rb-meetup/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── emea-on-rails/
│   │   ├── emea-on-rails-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── erubycon/
│   │   ├── erubycon-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── eurucamp/
│   │   ├── eurucamp-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── eurucamp-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── euruko/
│   │   ├── euruko-2003/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2004/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2005/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2006/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2007/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2019/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2022/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2023/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2024/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── euruko-2026/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── noruko-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── featured_cities.yml
│   ├── fosdem/
│   │   ├── ruby-devroom-at-fosdem-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-devroom-at-fosdem-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-devroom-at-fosdem-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-devroom-at-fosdem-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── friendly-rb/
│   │   ├── friendly-rb-2023/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── friendly-rb-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── friendly-rb-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── frozen-rails/
│   │   ├── frozen-rails-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── frozen-rails-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── frozen-rails-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── frozen-rails-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── fukuoka-rubyistkaigi/
│   │   ├── fukuoka-rubyistkaigi-03/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── fukuoka-rubyistkaigi-04/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── fukuoka-rubyistkaigi-05/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── fukuoka-rubykaigi-01/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── fukuoka-rubykaigi-02/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── garden-city-ruby/
│   │   ├── garden-city-ruby-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── garden-city-ruby-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── geneva-rb/
│   │   ├── geneva-rb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── gogaruco/
│   │   ├── gogaruco-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── gogaruco-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── gogaruco-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── gogaruco-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── gogaruco-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── gogaruco-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── goruco/
│   │   ├── goruco-2007/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2010/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2011/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── goruco-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── grill-rb/
│   │   ├── grill-rb-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── grill-rb-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── grill-rb-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── grill-rb-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── guru-pr/
│   │   ├── series.yml
│   │   └── tech-day-by-guru-pr-2016/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── haggis-ruby/
│   │   ├── haggis-ruby-2024/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── haggis-ruby-2026/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── helsinki-ruby/
│   │   ├── helsinki-ruby-brigade/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── helveticruby/
│   │   ├── helveticruby-2023/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── helveticruby-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── helveticruby-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── helveticruby-2026/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── hirakatarb/
│   │   ├── hirakatarb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── hokuriku-rubykaigi/
│   │   ├── hokuriku-rubykaigi-01/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── isle-of-ruby/
│   │   ├── isle-of-ruby-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── jrubyconf-eu/
│   │   ├── jrubyconf-eu-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── jrubyconf-eu-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── jrubyconf-eu-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── jrubyconf-eu-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── kaigi-on-rails/
│   │   ├── kaigi-on-rails-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── kaigi-on-rails-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── kaigi-on-rails-2022/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── kaigi-on-rails-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── kaigi-on-rails-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── kaigi-on-rails-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── kaigi-on-rails-2026/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── kansai-rubykaigi/
│   │   ├── kansai-rubykaigi-08/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── kansai-rubykaigi-09/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── kashiwarb/
│   │   ├── kashiwarb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── keeprubyweird/
│   │   ├── keep-ruby-weird-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── keep-ruby-weird-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── keep-ruby-weird-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── keep-ruby-weird-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── keep-ruby-weird-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── kiwi-ruby/
│   │   ├── kiwi-ruby-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── kiwi-ruby-2019/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── koberb/
│   │   ├── koberb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── krk-rb/
│   │   ├── krk-rb-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── kyobashirb/
│   │   ├── kyobashirb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── kyotorb/
│   │   ├── kyotorb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── la-conf/
│   │   └── series.yml
│   ├── la-rubyconf/
│   │   ├── la-rubyconf-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── la-rubyconf-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── la-rubyconf-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── la-rubyconf-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── la-rubyconf-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── la-rubyconf-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── la-rubyconf-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── latvian-ruby-community/
│   │   ├── latviarb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── london-ruby-unconference/
│   │   ├── london-ruby-unconference-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── london-ruby-unconference-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── london-ruby-unconference-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── lone-star-ruby-conf/
│   │   ├── lone-star-ruby-conf-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── lone-star-ruby-conf-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── lone-star-ruby-conf-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── lone-star-ruby-conf-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── lone-star-ruby-conf-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── lone-star-ruby-conf-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── lone-star-ruby-conf-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── lrug/
│   │   ├── lrug-meetup/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── lyon-rb/
│   │   ├── lyon-rb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── madison-ruby/
│   │   ├── madison-ruby-2011/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── madison-ruby-2012/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── madison-ruby-2013/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── madison-ruby-2014/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── madison-ruby-2015/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── madison-ruby-2016/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── madison-ruby-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── madison-ruby-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── madrid-rb/
│   │   ├── madrid-rb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── magic-ruby/
│   │   ├── magic-ruby-2011/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── magic-ruby-2012/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── matsue-rubykaigi/
│   │   ├── matsue-rubykaigi-01/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-02/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-03/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-04/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-05/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-06/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-07/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-08/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-09/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-10/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-11/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── matsue-rubykaigi-12/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── merseyrails/
│   │   ├── merseyrails/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── montreal-rb/
│   │   ├── montreal-rb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── mountainwest-rubyconf/
│   │   ├── mountainwest-rubyconf-2007/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── mountainwest-rubyconf-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── mountainwest-rubyconf-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── mountainwest-rubyconf-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── mountainwest-rubyconf-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── mountainwest-rubyconf-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── mountainwest-rubyconf-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── mountainwest-rubyconf-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── mountainwest-rubyconf-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── mountainwest-rubyconf-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── munich-rubyshift/
│   │   ├── munich-rubyshift/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── nairuby/
│   │   ├── rubyconf-kenya-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-kenya-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-kenya-2017/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-kenya-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-kenya-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── naniwarb/
│   │   ├── naniwarb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── picorubyoverflowkaigi-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── nantes-rb/
│   │   ├── nantes-rb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── nepal-ruby/
│   │   ├── nepal-ruby-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── nickel-city-ruby/
│   │   ├── nickel-city-ruby-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── nickel-city-ruby-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── nordicruby/
│   │   ├── nordicruby-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── nordicruby-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── nordicruby-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── nordicruby-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── nordicruby-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── oedo-rubykaigi/
│   │   ├── oedo-rubykaigi-01/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── oedo-rubykaigi-02/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── oedo-rubykaigi-03/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── oedo-rubykaigi-04/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── osaka-rubykaigi/
│   │   ├── osaka-rubykaigi-01/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── osaka-rubykaigi-02/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── osaka-rubykaigi-03/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── osaka-rubykaigi-04/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── oxente-rails/
│   │   ├── oxente-rails-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── paris-rb/
│   │   ├── paris-rb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── paris-rb-conf/
│   │   ├── paris-rb-conf-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── paris-rb-conf-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── philly-rb/
│   │   ├── philly-rb/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── pivorak/
│   │   ├── pivorak-conf-1/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── pivorak-conf-2/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── pivorak-conf-3/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── pivorak-conf-4/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── pivorak-conf-5/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── polishrubyusergroup/
│   │   ├── ruby-warsaw-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── poznanrubyusergroup/
│   │   ├── poznan-ruby-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-at-scale-summit/
│   │   ├── rails-at-scale-summit-2025/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rails-at-scale-summit-2026/
│   │   │   └── event.yml
│   │   └── series.yml
│   ├── rails-camp-south/
│   │   ├── rails-camp-south-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-camp-uk/
│   │   ├── rails-camp-uk-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-camp-us/
│   │   ├── rails-camp-us-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-camp-west/
│   │   ├── rails-camp-west-2022/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rails-camp-west-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rails-camp-west-2024/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rails-camp-west-2025/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rails-camp-west-2026/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── venue.yml
│   │   └── series.yml
│   ├── rails-girls-sao-paulo/
│   │   ├── rails-girls-sao-paulo-evolution-2026/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   └── venue.yml
│   │   └── series.yml
│   ├── rails-hackathon/
│   │   ├── rails-hackathon-community/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rails-hackathon-hotwire/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-israel/
│   │   ├── rails-israel-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rails-israel-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rails-israel-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rails-israel-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-konferenz/
│   │   ├── rails-konferenz-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-outreach-workshop/
│   │   ├── rails-outreach-workshop-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-pacific/
│   │   ├── rails-pacific-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rails-pacific-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-remote-conf/
│   │   ├── rails-remote-conf-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-saas-conference/
│   │   ├── rails-saas-conference-2022/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rails-saas-conference-2023/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-studio/
│   │   ├── rails-studio-2006-pasadena/
│   │   │   └── event.yml
│   │   ├── rails-studio-portland/
│   │   │   └── event.yml
│   │   └── series.yml
│   ├── rails-summit-latin-america/
│   │   ├── rails-summit-latin-america-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-to-italy/
│   │   └── series.yml
│   ├── rails-underground/
│   │   ├── rails-underground-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rails-world/
│   │   ├── rails-world-2023/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rails-world-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rails-world-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rails-world-2026/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── railsberry/
│   │   ├── railsberry-2012/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── railsclub/
│   │   ├── railsclub-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsclub-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsclub-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsclub-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── railsconf/
│   │   ├── railsconf-2006/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2007/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2022/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2023/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── railsconf-europe/
│   │   ├── railsconf-europe-2006/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-europe-2007/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railsconf-europe-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── railswaycon/
│   │   ├── railswaycon-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railswaycon-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railswaycon-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── railswaycon-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rbqconf/
│   │   ├── rbqconf-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── red-dirt-rubyconf/
│   │   ├── red-dirt-rubyconf-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── red-dirt-rubyconf-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── red-dot-ruby-conference/
│   │   ├── red-dot-ruby-conference-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── red-dot-ruby-conference-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── red-dot-ruby-conference-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── red-dot-ruby-conference-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── red-dot-ruby-conference-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── red-dot-ruby-conference-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── red-dot-ruby-conference-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── red-dot-ruby-conference-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── redfrogconf/
│   │   ├── redfrogconf-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rocky-mountain-ruby/
│   │   ├── rocky-mountain-ruby-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rocky-mountain-ruby-2026/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── venue.yml
│   │   └── series.yml
│   ├── rossconf/
│   │   ├── rossconf-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rossconf-2015-berlin/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rossconf-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rossconf-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rs-on-rails/
│   │   ├── rs-on-rails-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-argentina/
│   │   ├── rubysur-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-australia/
│   │   ├── ruby-australia-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-banitsa/
│   │   ├── ruby-banitsa-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-banitsa-conf/
│   │   ├── ruby-banitsa-conf-2024/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-community-conference/
│   │   ├── ruby-community-conference-summer-edition-2023/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── ruby-community-conference-summer-edition-2024/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── ruby-community-conference-winter-edition-2024/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── ruby-community-conference-winter-edition-2025/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── ruby-community-conference-winter-edition-2026/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-cwb/
│   │   ├── ruby-cwb-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-dcamp/
│   │   ├── ruby-dcamp-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-dev-summit/
│   │   ├── ruby-dev-summit-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-df/
│   │   ├── ruby-df-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-foo/
│   │   ├── ruby-foo-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-for-good/
│   │   ├── ruby-for-good-2016/
│   │   │   └── event.yml
│   │   ├── ruby-for-good-2020/
│   │   │   └── event.yml
│   │   ├── ruby-for-good-2023/
│   │   │   └── event.yml
│   │   ├── ruby-for-good-2024/
│   │   │   ├── event.yml
│   │   │   └── venue.yml
│   │   ├── ruby-for-good-2025/
│   │   │   └── event.yml
│   │   ├── ruby-for-good-belgium-2025/
│   │   │   └── event.yml
│   │   ├── ruby-for-good-belgium-2026/
│   │   │   ├── event.yml
│   │   │   └── venue.yml
│   │   └── series.yml
│   ├── ruby-frankfurt/
│   │   ├── ruby-frankfurt/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-fringe/
│   │   ├── futureruby-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyfringe-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-galaxy/
│   │   ├── ruby-galaxy-v01/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-galaxy-v02/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-galaxy-v03/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-galaxy-v04/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-galaxy-v05/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-galaxy-v06/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-hoedown/
│   │   ├── nuby-hoedown-2010/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── ruby-hoedown-2007/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── ruby-hoedown-2008/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── ruby-hoedown-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-hoedown-2010/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-in-common/
│   │   ├── ruby-in-common-2024/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-in-london/
│   │   ├── ruby-in-london-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-india/
│   │   ├── pune-ruby-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-maizuru/
│   │   ├── ruby-maizuru-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-manor/
│   │   ├── ruby-manor-1/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   ├── ruby-manor-2/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   ├── ruby-manor-3/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   ├── ruby-manor-4/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-midwest/
│   │   ├── ruby-midwest-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-midwest-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-montevideo/
│   │   ├── ruby-montevideo/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-on-ales/
│   │   ├── ruby-on-ales-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-on-ales-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-on-ales-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-on-ales-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-on-ales-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-on-ales-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-on-ice/
│   │   ├── ruby-on-ice-2018/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   └── videos.yml
│   │   ├── ruby-on-ice-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-on-rails-global-summit/
│   │   ├── ruby-on-rails-global-summit-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-on-rails-switzerland/
│   │   ├── railshock/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-on-waves/
│   │   ├── ruby-on-waves-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-phil/
│   │   ├── ruby-phil/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-retreat-au/
│   │   ├── rails-camp-au-1-2007/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-10-2012/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-11-2012/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-12-2012/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-13-2013/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-14-2013/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-15-2014/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-16-2014/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-17-2015/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-18-2015/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-19-2016/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-2-2007/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-20-2016/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-21-2017/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-22-2017/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-23-2018/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-24-2018/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-25-2019/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-26-2019/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-27-2022/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-3-2008/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-4-2008/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-5-2009/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-6-2009/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-7-2010/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-8-2010/
│   │   │   └── event.yml
│   │   ├── rails-camp-au-9-2011/
│   │   │   └── event.yml
│   │   ├── ruby-retreat-au-2024/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── ruby-retreat-au-2025/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-retreat-nz/
│   │   ├── ruby-retreat-nz-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-retreat-nz-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-retreat-nz-2025/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-romania/
│   │   ├── ruby-romania-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-summit-china/
│   │   ├── ruby-summit-china-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-tuesday/
│   │   ├── ruby-tuesday-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-turkiye/
│   │   ├── ruby-turkiye/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-web-conference/
│   │   ├── ruby-web-conference-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── ruby-wine/
│   │   ├── ruby-wine-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── ruby-wine-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubybelgium/
│   │   ├── rubybelgium-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyc/
│   │   ├── rubyc-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyc-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyc-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyc-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyc-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyc-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyc-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubycon/
│   │   ├── rubycon-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf/
│   │   ├── rubyconf-2001/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2002/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2003/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2004/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2005/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2006/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2007/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2016/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2022/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2022-mini/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2023/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-africa/
│   │   ├── rubyconf-africa-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-africa-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-africa-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-argentina/
│   │   ├── rubyconf-argentina-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-argentina-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-argentina-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-argentina-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-au/
│   │   ├── rubyconf-au-2013/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-au-2014/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-au-2015/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-au-2016/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-au-2017/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-au-2018/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-au-2019/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-au-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-au-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-au-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-austria/
│   │   ├── rubyconf-austria-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-brazil/
│   │   ├── rubyconf-brazil-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-brazil-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-brazil-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-brazil-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-brazil-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-brazil-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-by/
│   │   ├── rubyconfby-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconfby-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconfby-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconfby-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconfby-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-china/
│   │   ├── rubyconf-china-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-china-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-china-2024/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-colombia/
│   │   ├── rubyconf-colombia-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-colombia-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-colombia-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-colombia-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-india/
│   │   ├── rubyconf-india-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2019/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2022/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-india-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-indonesia/
│   │   ├── rubyconf-indonesia-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-jakarta/
│   │   ├── rubyconf-jakarta-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-lt/
│   │   ├── rubyconf-lt-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-lt-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-lt-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-my/
│   │   ├── rubyconf-kl-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-my-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-my-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-philippines/
│   │   ├── rubyconf-philippines-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-philippines-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-philippines-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-philippines-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-philippines-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-portugal/
│   │   ├── rubyconf-portugal-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-portugal-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-portugal-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-taiwan/
│   │   ├── rubyconf-taiwan-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-taiwan-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-taiwan-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-taiwan-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-taiwan-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-taiwan-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-taiwan-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-taiwan-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconf-uruguay/
│   │   ├── rubyconf-uruguay-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyconf-uruguay-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyconfth/
│   │   ├── rubyconf-th-2020/
│   │   │   └── event.yml
│   │   ├── rubyconfth-2019/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyconfth-2022/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyconfth-2023/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyconfth-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyday/
│   │   ├── rubyday-2011/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyday-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyday-2015/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyday-2016/
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   └── videos.yml
│   │   ├── rubyday-2019/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyday-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyday-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyday-2023/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyday-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyenrails/
│   │   ├── rubyandrails-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyenrails-2006/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyenrails-2007/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyenrails-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyenrails-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyeurope/
│   │   ├── rubyeurope-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyevents/
│   │   ├── rubyevents/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyfuza/
│   │   ├── rubyfuza-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyfuza-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyfuza-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyfuza-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyfuza-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyfuza-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyfuza-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyfuza-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyhack/
│   │   ├── rubyhack-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyhack-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyhack-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyhiroba/
│   │   ├── rubyhiroba-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyhiroba-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubykaigi/
│   │   ├── rubykaigi-2006/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2007/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2019/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2022/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2023/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubykaigi-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubykansai/
│   │   ├── rubykansai-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubymotion-inspect/
│   │   ├── rubymotion-inspect-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubymotion-inspect-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubymx/
│   │   ├── rubymx-meetup/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubynation/
│   │   ├── rubynation-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubynation-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubynation-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubynation-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubynation-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyness/
│   │   ├── rubyness-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyrussia/
│   │   ├── rubyrussia-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyrussia-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyrussia-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyrussia-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyrussia-2023/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyrussia-2024/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyrx/
│   │   ├── rubyrx-2009-philadelphia/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyrx-2009-washington-dc/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubysauna/
│   │   ├── rubysauna-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyunconf/
│   │   ├── rubyunconf-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyunconf-2019/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyunconf-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyunconf-2023/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyunconf-2024/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rubyworld/
│   │   ├── rubyworld-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2019/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2023/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2024/
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── rubyworld-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rulu/
│   │   ├── rulu-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rulu-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rulu-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── rulu-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── rupy/
│   │   ├── rupy-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── saint-p-rubyconf/
│   │   ├── saint-p-rubyconf-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── saint-p-rubyconf-2019/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── saint-p-rubyconf-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── saint-p-rubyconf-2021/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── scotlandonrails/
│   │   ├── scotlandonrails-2008/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── scotlandonrails-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── scottish-ruby-conf/
│   │   ├── scottish-ruby-conf-2010/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── scottish-ruby-conf-2011/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── scottish-ruby-conf-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── scottish-ruby-conf-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── scottish-ruby-conf-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── series.yml
│   ├── sekigahara-rubykaigi/
│   │   ├── sekigahara-rubykaigi-01/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   └── venue.yml
│   │   └── series.yml
│   ├── sf-bay-area-ruby/
│   │   ├── series.yml
│   │   └── sf-bay-area-ruby-meetup/
│   │       ├── cfp.yml
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── sfruby/
│   │   ├── series.yml
│   │   └── sfruby-2025/
│   │       ├── cfp.yml
│   │       ├── event.yml
│   │       ├── involvements.yml
│   │       ├── schedule.yml
│   │       ├── sponsors.yml
│   │       ├── venue.yml
│   │       └── videos.yml
│   ├── shinosakarb/
│   │   ├── series.yml
│   │   └── shinosakarb-meetup/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── shrug/
│   │   ├── series.yml
│   │   └── shrug-meetup/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── sin-city-ruby/
│   │   ├── series.yml
│   │   ├── sin-city-ruby-2022/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── sin-city-ruby-2024/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── sin-city-ruby-2025/
│   │       ├── event.yml
│   │       ├── schedule.yml
│   │       ├── sponsors.yml
│   │       ├── venue.yml
│   │       └── videos.yml
│   ├── solidusconf/
│   │   ├── series.yml
│   │   ├── solidusconf-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── solidusconf-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── solidusconf-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── solidusconf-2019/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── solidusconf-2020/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── solidusconf-2022/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── southeast-ruby/
│   │   ├── series.yml
│   │   ├── southeast-ruby-2017/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── southeast-ruby-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── southeast-ruby-2019/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── speakers.yml
│   ├── steelcityruby/
│   │   ├── series.yml
│   │   ├── steelcityruby-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── steelcityruby-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── steelcityruby-2014/
│   │       ├── event.yml
│   │       ├── sponsors.yml
│   │       └── videos.yml
│   ├── the-rails-edge/
│   │   ├── series.yml
│   │   └── the-rails-edge-2007/
│   │       ├── event.yml
│   │       ├── venue.yml
│   │       └── videos.yml
│   ├── thoughtbot-open-summit/
│   │   ├── series.yml
│   │   ├── thoughtbot-open-summit-2024/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── thoughtbot-open-summit-2025/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── tiny-ruby-conf/
│   │   ├── series.yml
│   │   ├── tiny-ruby-conf-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── tiny-ruby-conf-2026/
│   │       ├── cfp.yml
│   │       ├── event.yml
│   │       └── venue.yml
│   ├── tokyo-rubykaigi/
│   │   ├── series.yml
│   │   ├── tokyo-rubykaigi-10/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── tokyo-rubykaigi-11/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── tokyo-rubykaigi-12/
│   │       ├── event.yml
│   │       ├── schedule.yml
│   │       ├── sponsors.yml
│   │       └── videos.yml
│   ├── topics.yml
│   ├── toronto-ruby/
│   │   ├── series.yml
│   │   └── toronto-ruby-meetup/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── tropicalrb/
│   │   ├── abril-pro-ruby-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── abril-pro-ruby-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── abril-pro-ruby-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── series.yml
│   │   ├── tropical-on-rails-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── tropical-on-rails-2026/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── tropicalrb-2015/
│   │   │   ├── event.yml
│   │   │   ├── involvements.yml
│   │   │   ├── schedule.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── tropicalrb-2024/
│   │       ├── cfp.yml
│   │       ├── event.yml
│   │       ├── involvements.yml
│   │       ├── schedule.yml
│   │       ├── sponsors.yml
│   │       ├── venue.yml
│   │       └── videos.yml
│   ├── umedarb/
│   │   ├── series.yml
│   │   └── umedarb-meetup/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── valencia-rb/
│   │   ├── series.yml
│   │   └── valencia-rb-meetup/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── vienna-rb/
│   │   ├── series.yml
│   │   └── vienna-rb-meetup/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── wakayama-rb/
│   │   ├── series.yml
│   │   └── wakayama-rb-meetup/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── windycityrails/
│   │   ├── series.yml
│   │   ├── windycityrails-2009/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── windycityrails-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── windycityrails-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   └── windycityrails-2016/
│   │       ├── event.yml
│   │       └── videos.yml
│   ├── winnipeg-rb/
│   │   ├── series.yml
│   │   └── winnipeg-rb-meetup/
│   │       ├── event.yml
│   │       ├── involvements.yml
│   │       ├── sponsors.yml
│   │       ├── venue.yml
│   │       └── videos.yml
│   ├── wnb-rb/
│   │   ├── series.yml
│   │   └── wnb-rb-meetup/
│   │       ├── event.yml
│   │       ├── sponsors.yml
│   │       └── videos.yml
│   ├── wroclove-rb/
│   │   ├── series.yml
│   │   ├── wroclove-rb-2012/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2013/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2014/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2015/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2016/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2017/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2018/
│   │   │   ├── event.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2019/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2022/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2023/
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2024/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   ├── wroclove-rb-2025/
│   │   │   ├── cfp.yml
│   │   │   ├── event.yml
│   │   │   ├── sponsors.yml
│   │   │   ├── venue.yml
│   │   │   └── videos.yml
│   │   └── wroclove-rb-2026/
│   │       ├── cfp.yml
│   │       ├── event.yml
│   │       ├── schedule.yml
│   │       ├── sponsors.yml
│   │       ├── venue.yml
│   │       └── videos.yml
│   └── xoruby/
│       ├── series.yml
│       ├── xoruby-atlanta-2025/
│       │   ├── cfp.yml
│       │   ├── event.yml
│       │   ├── involvements.yml
│       │   ├── schedule.yml
│       │   ├── sponsors.yml
│       │   ├── venue.yml
│       │   └── videos.yml
│       ├── xoruby-austin-2025/
│       │   ├── event.yml
│       │   ├── involvements.yml
│       │   ├── sponsors.yml
│       │   ├── venue.yml
│       │   └── videos.yml
│       ├── xoruby-chicago-2025/
│       │   ├── cfp.yml
│       │   ├── event.yml
│       │   ├── involvements.yml
│       │   ├── schedule.yml
│       │   ├── sponsors.yml
│       │   ├── venue.yml
│       │   └── videos.yml
│       ├── xoruby-new-orleans-2025/
│       │   ├── cfp.yml
│       │   ├── event.yml
│       │   ├── involvements.yml
│       │   ├── schedule.yml
│       │   ├── sponsors.yml
│       │   ├── venue.yml
│       │   └── videos.yml
│       ├── xoruby-portland-2025/
│       │   ├── event.yml
│       │   ├── involvements.yml
│       │   ├── schedule.yml
│       │   ├── sponsors.yml
│       │   ├── venue.yml
│       │   └── videos.yml
│       └── xoruby-san-diego-2025/
│           ├── event.yml
│           ├── involvements.yml
│           ├── schedule.yml
│           ├── sponsors.yml
│           ├── venue.yml
│           └── videos.yml
├── db/
│   ├── cache_migrate/
│   │   ├── 20240516085648_create_solid_cache_entries.solid_cache.rb
│   │   ├── 20240516085649_add_key_hash_and_byte_size_to_solid_cache_entries.solid_cache.rb
│   │   ├── 20240516085650_add_key_hash_and_byte_size_indexes_and_null_constraints_to_solid_cache_entries.solid_cache.rb
│   │   └── 20240516085651_remove_key_index_from_solid_cache_entries.solid_cache.rb
│   ├── cache_schema.rb
│   ├── migrate/
│   │   ├── 20230512050041_create_speakers.rb
│   │   ├── 20230512051225_create_talks.rb
│   │   ├── 20230521202931_create_join_table_speakers_talks.rb
│   │   ├── 20230521211825_add_talks_count_to_speaker.rb
│   │   ├── 20230522051939_create_suggestions.rb
│   │   ├── 20230522133312_create_users.rb
│   │   ├── 20230522133313_create_sessions.rb
│   │   ├── 20230522133314_create_password_reset_tokens.rb
│   │   ├── 20230522133315_create_email_verification_tokens.rb
│   │   ├── 20230522212710_create_events.rb
│   │   ├── 20230522213244_add_event_references_to_talk.rb
│   │   ├── 20230525132507_add_index_slug_to_speaker.rb
│   │   ├── 20230604215247_create_ahoy_visits_and_events.rb
│   │   ├── 20230614230539_rename_event_table_to_organisation.rb
│   │   ├── 20230614231651_create_new_events.rb
│   │   ├── 20230614232412_add_youtube_channel_id_to_organisation.rb
│   │   ├── 20230614233712_add_slug_to_organisation.rb
│   │   ├── 20230614234246_add_name_to_event.rb
│   │   ├── 20230615053959_add_slug_to_event.rb
│   │   ├── 20230615055319_add_thumbnails_to_talk.rb
│   │   ├── 20230615055800_fix_foreign_constrain.rb
│   │   ├── 20230615105716_add_date_to_talk.rb
│   │   ├── 20230622202051_add_upvotes_and_views_to_talks.rb
│   │   ├── 20230625215935_add_twitter_to_organisation.rb
│   │   ├── 20230720104208_add_uniq_index_speaker_talk.rb
│   │   ├── 20230720151537_add_primary_key_to_speaker_talks.rb
│   │   ├── 20240611113918_add_transcript_to_talk.rb
│   │   ├── 20240614060121_add_service_name_to_active_storage_blobs.active_storage.rb
│   │   ├── 20240614060122_create_active_storage_variant_records.active_storage.rb
│   │   ├── 20240614060123_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb
│   │   ├── 20240709194147_add_enhanced_transcript_to_talk.rb
│   │   ├── 20240709200506_rename_transcript_in_talk.rb
│   │   ├── 20240718202658_add_summary_to_talk.rb
│   │   ├── 20240811121204_create_topics.rb
│   │   ├── 20240811122145_create_talk_topics.rb
│   │   ├── 20240815155647_add_uniq_index_on_talk_topic.rb
│   │   ├── 20240816074626_add_status_to_topic.rb
│   │   ├── 20240817083428_add_canonical_reference_to_topic.rb
│   │   ├── 20240818212042_add_language_to_talk.rb
│   │   ├── 20240819134138_drop_year_from_talk.rb
│   │   ├── 20240821191208_add_talks_count_to_event.rb
│   │   ├── 20240823221832_add_slides_url_to_talks.rb
│   │   ├── 20240901163900_add_canonical_reference_to_speaker.rb
│   │   ├── 20240902204752_add_canonical_reference_to_event.rb
│   │   ├── 20240908072757_create_watch_list_talks.rb
│   │   ├── 20240908072819_create_watch_lists.rb
│   │   ├── 20240909194059_create_connected_accounts.rb
│   │   ├── 20240912163015_add_name_to_user.rb
│   │   ├── 20240912163159_encrypt_user_fields.rb
│   │   ├── 20240912164120_encrypt_connected_account_field.rb
│   │   ├── 20240914162252_add_github_handle_to_user.rb
│   │   ├── 20240918050951_add_approved_by_to_suggestion.rb
│   │   ├── 20240918215740_add_suggestor_to_suggestions.rb
│   │   ├── 20240919193323_add_index_on_updated_at_for_talks.rb
│   │   ├── 20240920054416_add_talks_count_to_topic.rb
│   │   ├── 20240920154237_add_talks_count_to_watch_list.rb
│   │   ├── 20241019135118_create_talk_fts.rb
│   │   ├── 20241020174649_add_speakerdeck_to_speaker.rb
│   │   ├── 20241022012631_add_summarized_using_ai_to_talk.rb
│   │   ├── 20241023093844_add_pronouns_to_speaker.rb
│   │   ├── 20241023150341_remove_index_talk_topics_on_talk_id.rb
│   │   ├── 20241023154126_recreate_talk_topic_indexes.rb
│   │   ├── 20241029112719_add_mastodown_bluesky_linkedin_to_speaker.rb
│   │   ├── 20241031112333_add_kind_to_talk.rb
│   │   ├── 20241101185604_add_external_player_to_talk.rb
│   │   ├── 20241105143943_add_website_to_events.rb
│   │   ├── 20241105151601_create_watched_talks.rb
│   │   ├── 20241108215612_add_indexes_speaker_talks.rb
│   │   ├── 20241122155013_add_index_on_slug_for_topics.rb
│   │   ├── 20241122163052_add_index_on_kind_for_talks.rb
│   │   ├── 20241128073415_add_bsky_metadata_to_speaker.rb
│   │   ├── 20241130095835_add_parent_talk_to_talk.rb
│   │   ├── 20241203001515_add_github_metadata_to_speaker.rb
│   │   ├── 20241227192232_add_duration_to_talk.rb
│   │   ├── 20250102175230_create_speaker_full_text_search.rb
│   │   ├── 20250104095544_create_talk_transcript.rb
│   │   ├── 20250104230927_create_rollups.rb
│   │   ├── 20250108221813_set_view_count_default_on_talk.rb
│   │   ├── 20250115215944_add_index_video_provider_to_talk.rb
│   │   ├── 20250124210823_add_discarded_at_speaker_talk.rb
│   │   ├── 20250127012711_add_published_at_and_announced_at_to_talk.rb
│   │   ├── 20250128070756_add_unique_index_on_github_in_speaker.rb
│   │   ├── 20250128085252_remove_github_of_speaker_with_canonical.rb
│   │   ├── 20250218073648_normalize_github_handle.rb
│   │   ├── 20250426063312_add_llm_requests.rb
│   │   ├── 20250427062021_add_success_to_llm_requests.rb
│   │   ├── 20250521011731_add_original_title_to_talks.rb
│   │   ├── 20250524174213_normalize_speaker_website.rb
│   │   ├── 20250605203429_add_start_and_end_date_to_event.rb
│   │   ├── 20250609072113_remove_talk_parent_id_self.rb
│   │   ├── 20250614131810_add_kind_to_event.rb
│   │   ├── 20250617115359_add_date_precision_to_events.rb
│   │   ├── 20250618000304_add_call_for_papers_to_events.rb
│   │   ├── 20250719180249_create_sponsors.rb
│   │   ├── 20250719190411_add_slug_to_sponsors.rb
│   │   ├── 20250719200918_create_event_sponsors.rb
│   │   ├── 20250719204509_add_banner_url_to_sponsors.rb
│   │   ├── 20250719205313_add_main_location_to_sponsors.rb
│   │   ├── 20250719205756_remove_url_fields_from_sponsors.rb
│   │   ├── 20250719225634_add_tier_to_event_sponsors.rb
│   │   ├── 20250719231642_add_logo_url_to_sponsors.rb
│   │   ├── 20250808095915_add_logo_urls_to_sponsors.rb
│   │   ├── 20250808192916_clean_sponsor_website_urls.rb
│   │   ├── 20250809194302_add_badge_to_event_sponsors.rb
│   │   ├── 20250813211012_decrypt_user_name.rb
│   │   ├── 20250814214127_add_speaker_attributes_to_users.rb
│   │   ├── 20250814214146_create_user_talks.rb
│   │   ├── 20250814214412_create_users_search_index.rb
│   │   ├── 20250817060410_set_users_email_null_true.rb
│   │   ├── 20250817223427_update_user_indexes.rb
│   │   ├── 20250819022348_create_cfps.rb
│   │   ├── 20250820183955_add_progress_seconds_to_watched_talks.rb
│   │   ├── 20250820225005_add_watched_talks_count_to_users.rb
│   │   ├── 20250822175423_add_unique_index_to_event_sponsors.rb
│   │   ├── 20250823020826_remove_cfp_fields_from_events.rb
│   │   ├── 20250901185702_update_suggestions_suggestable.rb
│   │   ├── 20250903125458_create_event_participations.rb
│   │   ├── 20250920194438_add_country_code_to_event.rb
│   │   ├── 20250930165602_add_location_to_user.rb
│   │   ├── 20251010092526_create_event_involvements.rb
│   │   ├── 20251012114916_create_contributors.rb
│   │   ├── 20251019071129_add_case_insensitive_github_handle_index_to_users.rb
│   │   ├── 20251019212653_remove_badge_awards_table.rb
│   │   ├── 20251028143012_create_aliases.rb
│   │   ├── 20251028143916_add_marked_for_deletion_to_users.rb
│   │   ├── 20251028143917_migrate_canonical_users_to_aliases.rb
│   │   ├── 20251029032709_rename_organisation_to_event_series.rb
│   │   ├── 20251126171800_rename_sponsor_to_organization.rb
│   │   ├── 20251126171948_rename_event_sponsor_to_sponsor.rb
│   │   ├── 20251126203734_add_coordinates_to_events.rb
│   │   ├── 20251201143109_add_event_names_to_talks_search_index.rb
│   │   ├── 20251201144052_change_slug_to_optional_in_aliases.rb
│   │   ├── 20251203110611_change_youtube_channel_id_nullable_on_event_series.rb
│   │   ├── 20251203110659_change_youtube_channel_name_nullable_on_event_series.rb
│   │   ├── 20251204145850_add_static_id_to_talks.rb
│   │   ├── 20251204195048_change_static_id_null_constraint_on_talks.rb
│   │   ├── 20251206194409_add_additional_resources_to_talks.rb
│   │   ├── 20260101090225_add_wrapped_public_to_users.rb
│   │   ├── 20260101125732_create_active_storage_tables.active_storage.rb
│   │   ├── 20260103114901_add_feedback_to_watched_talks.rb
│   │   ├── 20260103122047_add_feedback_shared_at_to_watched_talks.rb
│   │   ├── 20260103125129_backfill_watched_at_on_watched_talks.rb
│   │   ├── 20260103130348_add_watched_to_watched_talks.rb
│   │   ├── 20260103134407_add_feedback_enabled_to_users.rb
│   │   ├── 20260103210603_add_settings_to_users.rb
│   │   ├── 20260103232220_create_topic_gems.rb
│   │   ├── 20260104181518_create_favorite_users.rb
│   │   ├── 20260105100000_add_indexes_to_ahoy_visits_for_cleanup.rb
│   │   ├── 20260105120000_add_video_provider_to_talks_search_index.rb
│   │   ├── 20260106092124_add_geocoding_to_users.rb
│   │   ├── 20260106121436_add_state_to_events.rb
│   │   ├── 20260106121459_create_featured_cities.rb
│   │   ├── 20260106135053_create_geocode_results.rb
│   │   ├── 20260106141308_add_location_to_events.rb
│   │   ├── 20260106232656_add_marked_suspicious_at_to_users.rb
│   │   ├── 20260109095858_add_geocode_metadata_to_events.rb
│   │   ├── 20260109152525_change_aliases_slug_index.rb
│   │   ├── 20260110193214_rename_featured_cities_to_cities.rb
│   │   ├── 20260110194925_rename_state_to_state_code_on_events_and_users.rb
│   │   ├── 20260110201634_remove_city_column_from_cities.rb
│   │   ├── 20260112065507_add_youtube_thumbnail_checked_at_to_talks.rb
│   │   ├── 20260112071922_add_video_availability_fields_to_talks.rb
│   │   ├── 20260301182003_add_notes_to_favorite_user.rb
│   │   └── 20260306110802_add_level_to_sponsors.rb
│   ├── queue_migrate/
│   │   ├── 20240516090838_create_solid_queue_tables.solid_queue.rb
│   │   ├── 20240516090839_add_missing_index_to_blocked_executions.solid_queue.rb
│   │   ├── 20240516090840_create_recurring_executions.solid_queue.rb
│   │   ├── 20240814230055_create_recurring_tasks.solid_queue.rb
│   │   ├── 20240908182634_add_name_to_processes.solid_queue.rb
│   │   ├── 20240908191029_make_name_not_null.solid_queue.rb
│   │   └── 20240908191030_change_solid_queue_recurring_tasks_static_to_not_null.solid_queue.rb
│   ├── queue_schema.rb
│   ├── schema.rb
│   └── seeds.rb
├── docker-compose.typesense.yml
├── docs/
│   ├── ADDING_CFPS.md
│   ├── ADDING_EVENTS.md
│   ├── ADDING_INVOLVEMENTS.md
│   ├── ADDING_MEETUPS.md
│   ├── ADDING_SCHEDULES.md
│   ├── ADDING_SPONSORS.md
│   ├── ADDING_UNPUBLISHED_TALKS.md
│   ├── ADDING_VENUES.md
│   ├── ADDING_VIDEOS.md
│   ├── ADDING_VISUAL_ASSETS.md
│   └── FIXING_PROFILE_NAMES.md
├── lib/
│   ├── assets/
│   │   └── .keep
│   ├── authenticator.rb
│   ├── generators/
│   │   ├── cfp/
│   │   │   ├── USAGE
│   │   │   ├── cfp_generator.rb
│   │   │   └── templates/
│   │   │       ├── cfp.yml.tt
│   │   │       └── header.yml.tt
│   │   ├── event/
│   │   │   ├── USAGE
│   │   │   ├── event_generator.rb
│   │   │   └── templates/
│   │   │       └── event.yml.tt
│   │   ├── event_base.rb
│   │   ├── schedule/
│   │   │   ├── USAGE
│   │   │   ├── schedule_generator.rb
│   │   │   └── templates/
│   │   │       └── schedule.yml.tt
│   │   ├── sponsors/
│   │   │   ├── USAGE
│   │   │   ├── sponsors_generator.rb
│   │   │   └── templates/
│   │   │       └── sponsors.yml.tt
│   │   ├── talk/
│   │   │   ├── USAGE
│   │   │   ├── talk_generator.rb
│   │   │   └── templates/
│   │   │       ├── lightning_talks.yml.tt
│   │   │       ├── talk.yml.tt
│   │   │       └── videos.yml.tt
│   │   └── venue/
│   │       ├── USAGE
│   │       ├── templates/
│   │       │   ├── location.yml.tt
│   │       │   └── venue.yml.tt
│   │       └── venue_generator.rb
│   ├── guard/
│   │   └── data_import.rb
│   ├── protobuf/
│   │   └── message_type.rb
│   ├── schemas/
│   │   ├── address_schema.json
│   │   ├── cfp_schema.json
│   │   ├── cfps_schema.json
│   │   ├── coordinates_schema.json
│   │   ├── event_schema.json
│   │   ├── featured_city_schema.json
│   │   ├── hotel_schema.json
│   │   ├── involvement_schema.json
│   │   ├── location_schema.json
│   │   ├── maps_schema.json
│   │   ├── schedule_schema.json
│   │   ├── series_schema.json
│   │   ├── speaker_schema.json
│   │   ├── sponsors_schema.json
│   │   ├── tiers_sponsors_schema.json
│   │   ├── transcript_schema.json
│   │   ├── venue_schema.json
│   │   ├── video_schema.json
│   │   └── videos_schema.json
│   ├── tasks/
│   │   ├── annotate_rb.rake
│   │   ├── assets.rake
│   │   ├── backfill_event_involvements.rake
│   │   ├── backfill_speaker_participation.rake
│   │   ├── cities.rake
│   │   ├── cleanup_ahoy_visits.rake
│   │   ├── contributors.rake
│   │   ├── db.rake
│   │   ├── download.rake
│   │   ├── dump.rake
│   │   ├── event_assets.rake
│   │   ├── geolocate.thor
│   │   ├── schema.rake
│   │   ├── search.rake
│   │   ├── seed.rake
│   │   ├── speakerdeck.rake
│   │   ├── speakers.rake
│   │   ├── thumbnails.rake
│   │   ├── topics.rake
│   │   ├── transcripts.rake
│   │   ├── update_video_statistics.rake
│   │   ├── users.rake
│   │   └── validate.rake
│   └── templates/
│       └── erb/
│           └── scaffold/
│               ├── _form.html.erb.tt
│               ├── edit.html.erb.tt
│               ├── index.html.erb.tt
│               ├── new.html.erb.tt
│               ├── partial.html.erb.tt
│               └── show.html.erb.tt
├── log/
│   └── .keep
├── package.json
├── postcss.config.js
├── public/
│   ├── 400.html
│   ├── 404.html
│   ├── 406-unsupported-browser.html
│   ├── 422.html
│   ├── 500.html
│   └── robots.txt
├── scripts/
│   ├── create_events.rb
│   ├── create_videos_yml.rb
│   ├── dump_speakers.rb
│   ├── dump_talks.rb
│   ├── extract_videos.rb
│   ├── import_event.rb
│   ├── prepare_series.rb
│   └── sort_speakers.rb
├── storage/
│   └── .keep
├── tailwind.config.js
├── test/
│   ├── application_system_test_case.rb
│   ├── channels/
│   │   └── application_cable/
│   │       └── connection_test.rb
│   ├── clients/
│   │   └── youtube/
│   │       ├── channels_test.rb
│   │       ├── playlist_items_test.rb
│   │       ├── playlists_test.rb
│   │       ├── transcript_test.rb
│   │       └── video_test.rb
│   ├── components/
│   │   ├── application_component_test.rb
│   │   ├── events/
│   │   │   ├── upcoming_event_banner_component/
│   │   │   │   └── helper_methods_test.rb
│   │   │   └── upcoming_event_banner_component_test.rb
│   │   ├── tito/
│   │   │   ├── button_component_test.rb
│   │   │   └── widget_component_test.rb
│   │   └── ui/
│   │       ├── avatar_component_test.rb
│   │       ├── badge_component_test.rb
│   │       ├── button_component_test.rb
│   │       └── stamp_component_test.rb
│   ├── controllers/
│   │   ├── analytics/
│   │   │   └── dashboards_controller_test.rb
│   │   ├── announcements_controller_test.rb
│   │   ├── cfp_controller_test.rb
│   │   ├── countries_controller_test.rb
│   │   ├── events/
│   │   │   ├── archive_controller_test.rb
│   │   │   ├── meetups_controller_test.rb
│   │   │   ├── participations_controller_test.rb
│   │   │   ├── related_talks_controller_test.rb
│   │   │   ├── schedule_controller_test.rb
│   │   │   ├── series_controller_test.rb
│   │   │   └── sponsors_controller_test.rb
│   │   ├── events_controller_test.rb
│   │   ├── favorite_users_controller_test.rb
│   │   ├── locations/
│   │   │   └── users_controller_test.rb
│   │   ├── organizations/
│   │   │   ├── logos_controller_test.rb
│   │   │   └── wrapped_controller_test.rb
│   │   ├── organizations_controller_test.rb
│   │   ├── page_controller_test.rb
│   │   ├── profiles/
│   │   │   ├── connect_controller_test.rb
│   │   │   ├── enhance_controller_test.rb
│   │   │   ├── involvements_controller_test.rb
│   │   │   ├── map_controller_test.rb
│   │   │   ├── notes_controller_test.rb
│   │   │   └── wrapped_controller_test.rb
│   │   ├── profiles_controller_test.rb
│   │   ├── recommendations_controller_test.rb
│   │   ├── sessions/
│   │   │   ├── omniauth_controller_test copy.rb
│   │   │   └── omniauth_controller_test.rb
│   │   ├── sessions_controller_test.rb
│   │   ├── speakers_controller_test.rb
│   │   ├── sponsors/
│   │   │   └── missing_controller_test.rb
│   │   ├── spotlight/
│   │   │   ├── events_controller_test.rb
│   │   │   ├── languages_controller_test.rb
│   │   │   ├── locations_controller_test.rb
│   │   │   ├── organizations_controller_test.rb
│   │   │   ├── series_controller_test.rb
│   │   │   ├── speakers_controller_test.rb
│   │   │   ├── talks_controller_test.rb
│   │   │   └── topics_controller_test.rb
│   │   ├── suggestions_controller_test.rb
│   │   ├── talks/
│   │   │   ├── recommendations_controller_test.rb
│   │   │   ├── slides_controller_test.rb
│   │   │   └── watched_talks_controller_test.rb
│   │   ├── talks_controller_test.rb
│   │   ├── topics_controller_test.rb
│   │   ├── watch_list_talks_controller_test.rb
│   │   ├── watch_lists_controller_test.rb
│   │   ├── watched_talks_controller_test.rb
│   │   └── wrapped_controller_test.rb
│   ├── fixtures/
│   │   ├── cfps.yml
│   │   ├── cities.yml
│   │   ├── connected_accounts.yml
│   │   ├── contributors.yml
│   │   ├── event_series.yml
│   │   ├── events.yml
│   │   ├── favorite_users.yml
│   │   ├── files/
│   │   │   └── .keep
│   │   ├── organizations.yml
│   │   ├── sponsors.yml
│   │   ├── suggestions.yml
│   │   ├── talk/
│   │   │   └── transcripts.yml
│   │   ├── talk_topics.yml
│   │   ├── talks.yml
│   │   ├── topics.yml
│   │   ├── user_talks.yml
│   │   ├── users.yml
│   │   ├── watch_lists.yml
│   │   └── watched_talks.yml
│   ├── helpers/
│   │   ├── event_tracking_helper.rb
│   │   └── icon_helper_test.rb
│   ├── integration/
│   │   └── .keep
│   ├── jobs/
│   │   ├── geocode_record_job_test.rb
│   │   └── recurring/
│   │       ├── rollup_job_test.rb
│   │       ├── youtube_thumbnail_validation_job_test.rb
│   │       ├── youtube_video_availability_job_test.rb
│   │       └── youtube_video_statistics_job_test.rb
│   ├── lib/
│   │   ├── download_sponsors_test.rb
│   │   ├── generators/
│   │   │   ├── cfp_generator_test.rb
│   │   │   ├── event_generator_test.rb
│   │   │   ├── schedule_generator_test.rb
│   │   │   ├── sponsors_generator_test.rb
│   │   │   ├── talk_generator_test.rb
│   │   │   └── venue_generator_test.rb
│   │   └── schema_export_test.rb
│   ├── models/
│   │   ├── ahoy/
│   │   │   └── visit_test.rb
│   │   ├── alias_test.rb
│   │   ├── announcement_test.rb
│   │   ├── cfp_test.rb
│   │   ├── city_test.rb
│   │   ├── concerns/
│   │   │   └── geocodeable_test.rb
│   │   ├── connected_account_test.rb
│   │   ├── continent_test.rb
│   │   ├── contributor_test.rb
│   │   ├── country_test.rb
│   │   ├── event/
│   │   │   ├── assets_test.rb
│   │   │   ├── static_metadata_test.rb
│   │   │   ├── tickets/
│   │   │   │   └── provider_detection_test.rb
│   │   │   ├── tickets_test.rb
│   │   │   └── videos_file_test.rb
│   │   ├── event_geocoding_test.rb
│   │   ├── event_participation_test.rb
│   │   ├── event_series_test.rb
│   │   ├── event_test.rb
│   │   ├── favorite_user_test.rb
│   │   ├── language_test.rb
│   │   ├── location_test.rb
│   │   ├── online_location_test.rb
│   │   ├── organization_test.rb
│   │   ├── rollup_test.rb
│   │   ├── search/
│   │   │   ├── backend/
│   │   │   │   ├── sqlite_fts/
│   │   │   │   │   └── indexer_test.rb
│   │   │   │   ├── sqlite_fts_test.rb
│   │   │   │   ├── typesense/
│   │   │   │   │   ├── indexer_test.rb
│   │   │   │   │   ├── language_indexer_test.rb
│   │   │   │   │   └── location_indexer_test.rb
│   │   │   │   └── typesense_test.rb
│   │   │   └── backend_test.rb
│   │   ├── sponsor_test.rb
│   │   ├── state_test.rb
│   │   ├── static/
│   │   │   ├── city_test.rb
│   │   │   └── event_test.rb
│   │   ├── suggestion_test.rb
│   │   ├── talk_test.rb
│   │   ├── talk_topic_test.rb
│   │   ├── template_test.rb
│   │   ├── topic_test.rb
│   │   ├── uk_nation_test.rb
│   │   ├── user/
│   │   │   ├── duplicate_detector_test.rb
│   │   │   ├── profiles_test.rb
│   │   │   ├── suspicion_detector_test.rb
│   │   │   └── talk_recommendations_test.rb
│   │   ├── user_geocoding_test.rb
│   │   ├── user_talk_test.rb
│   │   ├── user_test.rb
│   │   └── youtube/
│   │       ├── video_metadata_rails_worldtest.rb
│   │       └── video_metadata_test.rb
│   ├── system/
│   │   ├── call_for_papers_test.rb
│   │   ├── events_test.rb
│   │   ├── sessions_test.rb
│   │   ├── speakers_test.rb
│   │   ├── sponsors_test.rb
│   │   ├── spotlight_search_test.rb
│   │   └── talks_test.rb
│   ├── tasks/
│   │   ├── db_seed_test.rb
│   │   └── seed_test.rb
│   ├── test_helper.rb
│   ├── tools/
│   │   ├── cfp_create_tool_test.rb
│   │   ├── cfp_info_tool_test.rb
│   │   └── cfp_update_tool_test.rb
│   └── vcr_cassettes/
│       ├── profiles/
│       │   └── enhance_controller_test/
│       │       └── patch.yml
│       ├── recurring_youtube_statistics_job.yml
│       ├── sessions/
│       │   └── omniauth_controller_test/
│       │       └── creates_a_new_user_if_not_exists_github.yml
│       ├── talks/
│       │   ├── extract_topics.yml
│       │   ├── summarize.yml
│       │   └── transcript-enhancement.yml
│       ├── user/
│       │   └── enhance_profile_job_test.yml
│       ├── youtube/
│       │   ├── channels-scrapping.yml
│       │   ├── channels.yml
│       │   ├── playlist_items/
│       │   │   └── all.yml
│       │   ├── playlists/
│       │   │   └── all.yml
│       │   ├── transcript.yml
│       │   └── transcript_not_available.yml
│       ├── youtube_duration.yml
│       ├── youtube_statistics.yml
│       ├── youtube_statistics_invalid.yml
│       └── youtube_video_transcript.yml
├── tmp/
│   └── .keep
├── vendor/
│   └── .keep
├── vite.config.mjs
└── yaml/
    ├── enforce_strings.mjs
    └── formatter.mjs
Download .txt
Showing preview only (275K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (3552 symbols across 839 files)

FILE: app/avo/actions/approve_topic.rb
  class Avo::Actions::ApproveTopic (line 1) | class Avo::Actions::ApproveTopic < Avo::BaseAction
    method handle (line 4) | def handle(query:, fields:, current_user:, resource:, **args)

FILE: app/avo/actions/assign_canonical_event.rb
  class Avo::Actions::AssignCanonicalEvent (line 1) | class Avo::Actions::AssignCanonicalEvent < Avo::BaseAction
    method fields (line 7) | def fields
    method handle (line 13) | def handle(query:, fields:, current_user:, resource:, **args)

FILE: app/avo/actions/assign_canonical_speaker.rb
  class Avo::Actions::AssignCanonicalSpeaker (line 1) | class Avo::Actions::AssignCanonicalSpeaker < Avo::BaseAction
    method fields (line 7) | def fields
    method handle (line 13) | def handle(query:, fields:, current_user:, resource:, **args)

FILE: app/avo/actions/assign_canonical_topic.rb
  class Avo::Actions::AssignCanonicalTopic (line 1) | class Avo::Actions::AssignCanonicalTopic < Avo::BaseAction
    method fields (line 7) | def fields
    method handle (line 13) | def handle(query:, fields:, current_user:, resource:, **args)

FILE: app/avo/actions/assign_canonical_user.rb
  class Avo::Actions::AssignCanonicalUser (line 1) | class Avo::Actions::AssignCanonicalUser < Avo::BaseAction
    method fields (line 4) | def fields
    method handle (line 10) | def handle(query:, fields:, current_user:, resource:, **args)

FILE: app/avo/actions/clear_user.rb
  class Avo::Actions::ClearUser (line 1) | class Avo::Actions::ClearUser < Avo::BaseAction
    method handle (line 5) | def handle(query:, fields:, current_user:, resource:, **args)

FILE: app/avo/actions/enhance_transcript.rb
  class Avo::Actions::EnhanceTranscript (line 1) | class Avo::Actions::EnhanceTranscript < Avo::BaseAction
    method handle (line 3) | def handle(query:, fields:, current_user:, resource:, **args)

FILE: app/avo/actions/extract_topics.rb
  class Avo::Actions::ExtractTopics (line 1) | class Avo::Actions::ExtractTopics < Avo::BaseAction
    method handle (line 4) | def handle(query:, fields:, current_user:, resource:, **args)

FILE: app/avo/actions/fetch_duration.rb
  class Avo::Actions::FetchDuration (line 1) | class Avo::Actions::FetchDuration < Avo::BaseAction
    method handle (line 4) | def handle(query:, fields:, current_user:, resource:, **args)

FILE: app/avo/actions/find_topic_talks.rb
  class Avo::Actions::FindTopicTalks (line 1) | class Avo::Actions::FindTopicTalks < Avo::BaseAction
    method handle (line 4) | def handle(query:, fields:, current_user:, resource:, **args)

FILE: app/avo/actions/geocode_record.rb
  class Avo::Actions::GeocodeRecord (line 1) | class Avo::Actions::GeocodeRecord < Avo::BaseAction
    method handle (line 4) | def handle(query:, fields:, current_user:, resource:, records:, **args)

FILE: app/avo/actions/reject_topic.rb
  class Avo::Actions::RejectTopic (line 1) | class Avo::Actions::RejectTopic < Avo::BaseAction
    method handle (line 11) | def handle(query:, fields:, current_user:, resource:, **args)

FILE: app/avo/actions/summarize.rb
  class Avo::Actions::Summarize (line 1) | class Avo::Actions::Summarize < Avo::BaseAction
    method handle (line 4) | def handle(query:, fields:, current_user:, resource:, **args)

FILE: app/avo/actions/talk_index.rb
  class Avo::Actions::TalkIndex (line 1) | class Avo::Actions::TalkIndex < Avo::BaseAction
    method handle (line 5) | def handle(query:, fields:, current_user:, resource:, **args)

FILE: app/avo/actions/talk_ingest.rb
  class Avo::Actions::TalkIngest (line 1) | class Avo::Actions::TalkIngest < Avo::BaseAction
    method handle (line 4) | def handle(query:, fields:, current_user:, resource:, **args)

FILE: app/avo/actions/transcript.rb
  class Avo::Actions::Transcript (line 1) | class Avo::Actions::Transcript < Avo::BaseAction
    method handle (line 4) | def handle(query:, fields:, current_user:, resource:, **args)

FILE: app/avo/actions/update_from_yml.rb
  class Avo::Actions::UpdateFromYml (line 1) | class Avo::Actions::UpdateFromYml < Avo::BaseAction
    method handle (line 4) | def handle(query:, fields:, current_user:, resource:, **args)

FILE: app/avo/actions/user_fetch_github.rb
  class Avo::Actions::UserFetchGitHub (line 1) | class Avo::Actions::UserFetchGitHub < Avo::BaseAction
    method handle (line 4) | def handle(query:, fields:, current_user:, resource:, **args)

FILE: app/avo/cards/duplicates_summary.rb
  class Avo::Cards::DuplicatesSummary (line 1) | class Avo::Cards::DuplicatesSummary < Avo::Cards::PartialCard

FILE: app/avo/cards/reversed_name_duplicates_list.rb
  class Avo::Cards::ReversedNameDuplicatesList (line 1) | class Avo::Cards::ReversedNameDuplicatesList < Avo::Cards::PartialCard

FILE: app/avo/cards/reversed_name_duplicates_metric.rb
  class Avo::Cards::ReversedNameDuplicatesMetric (line 1) | class Avo::Cards::ReversedNameDuplicatesMetric < Avo::Cards::MetricCard
    method query (line 7) | def query

FILE: app/avo/cards/same_name_duplicates_list.rb
  class Avo::Cards::SameNameDuplicatesList (line 1) | class Avo::Cards::SameNameDuplicatesList < Avo::Cards::PartialCard

FILE: app/avo/cards/same_name_duplicates_metric.rb
  class Avo::Cards::SameNameDuplicatesMetric (line 1) | class Avo::Cards::SameNameDuplicatesMetric < Avo::Cards::MetricCard
    method query (line 7) | def query

FILE: app/avo/cards/suspicious_signals_breakdown.rb
  class Avo::Cards::SuspiciousSignalsBreakdown (line 1) | class Avo::Cards::SuspiciousSignalsBreakdown < Avo::Cards::PartialCard

FILE: app/avo/cards/suspicious_summary.rb
  class Avo::Cards::SuspiciousSummary (line 1) | class Avo::Cards::SuspiciousSummary < Avo::Cards::PartialCard

FILE: app/avo/cards/suspicious_users_list.rb
  class Avo::Cards::SuspiciousUsersList (line 1) | class Avo::Cards::SuspiciousUsersList < Avo::Cards::PartialCard

FILE: app/avo/cards/suspicious_users_metric.rb
  class Avo::Cards::SuspiciousUsersMetric (line 1) | class Avo::Cards::SuspiciousUsersMetric < Avo::Cards::MetricCard
    method query (line 7) | def query

FILE: app/avo/cards/unavailable_videos_by_event.rb
  class Avo::Cards::UnavailableVideosByEvent (line 1) | class Avo::Cards::UnavailableVideosByEvent < Avo::Cards::PartialCard

FILE: app/avo/cards/unavailable_videos_list.rb
  class Avo::Cards::UnavailableVideosList (line 1) | class Avo::Cards::UnavailableVideosList < Avo::Cards::PartialCard

FILE: app/avo/cards/unavailable_videos_metric.rb
  class Avo::Cards::UnavailableVideosMetric (line 1) | class Avo::Cards::UnavailableVideosMetric < Avo::Cards::MetricCard
    method query (line 7) | def query

FILE: app/avo/cards/unavailable_videos_summary.rb
  class Avo::Cards::UnavailableVideosSummary (line 1) | class Avo::Cards::UnavailableVideosSummary < Avo::Cards::PartialCard

FILE: app/avo/dashboards/default.rb
  class Avo::Dashboards::Default (line 1) | class Avo::Dashboards::Default < Avo::Dashboards::BaseDashboard
    method cards (line 7) | def cards

FILE: app/avo/dashboards/duplicates.rb
  class Avo::Dashboards::Duplicates (line 1) | class Avo::Dashboards::Duplicates < Avo::Dashboards::BaseDashboard
    method cards (line 7) | def cards

FILE: app/avo/dashboards/suspicious.rb
  class Avo::Dashboards::Suspicious (line 1) | class Avo::Dashboards::Suspicious < Avo::Dashboards::BaseDashboard
    method cards (line 7) | def cards

FILE: app/avo/dashboards/unavailable_videos.rb
  class Avo::Dashboards::UnavailableVideos (line 1) | class Avo::Dashboards::UnavailableVideos < Avo::Dashboards::BaseDashboard
    method cards (line 7) | def cards

FILE: app/avo/filters/aliasable_type.rb
  class Avo::Filters::AliasableType (line 1) | class Avo::Filters::AliasableType < Avo::Filters::SelectFilter
    method apply (line 4) | def apply(request, query, type)
    method options (line 12) | def options

FILE: app/avo/filters/attended_as.rb
  class Avo::Filters::AttendedAs (line 1) | class Avo::Filters::AttendedAs < Avo::Filters::SelectFilter
    method apply (line 4) | def apply(request, query, attended_as)
    method options (line 12) | def options

FILE: app/avo/filters/bio.rb
  class Avo::Filters::Bio (line 1) | class Avo::Filters::Bio < Avo::Filters::TextFilter
    method apply (line 5) | def apply(request, query, value)

FILE: app/avo/filters/bio_presence.rb
  class Avo::Filters::BioPresence (line 1) | class Avo::Filters::BioPresence < Avo::Filters::BooleanFilter
    method apply (line 7) | def apply(request, query, values)
    method options (line 13) | def options

FILE: app/avo/filters/canonical.rb
  class Avo::Filters::Canonical (line 1) | class Avo::Filters::Canonical < Avo::Filters::BooleanFilter
    method apply (line 7) | def apply(request, query, values)
    method options (line 17) | def options

FILE: app/avo/filters/enhanced_transcript.rb
  class Avo::Filters::EnhancedTranscript (line 1) | class Avo::Filters::EnhancedTranscript < Avo::Filters::BooleanFilter
    method apply (line 7) | def apply(request, query, values)
    method options (line 19) | def options

FILE: app/avo/filters/geocoded_presence.rb
  class Avo::Filters::GeocodedPresence (line 1) | class Avo::Filters::GeocodedPresence < Avo::Filters::BooleanFilter
    method apply (line 4) | def apply(request, query, values)
    method options (line 16) | def options

FILE: app/avo/filters/github.rb
  class Avo::Filters::GitHub (line 1) | class Avo::Filters::GitHub < Avo::Filters::BooleanFilter
    method apply (line 4) | def apply(request, query, values)
    method options (line 15) | def options

FILE: app/avo/filters/github_handle.rb
  class Avo::Filters::GitHubHandle (line 1) | class Avo::Filters::GitHubHandle < Avo::Filters::TextFilter
    method apply (line 4) | def apply(request, query, value)

FILE: app/avo/filters/github_handle_presence.rb
  class Avo::Filters::GitHubHandlePresence (line 1) | class Avo::Filters::GitHubHandlePresence < Avo::Filters::BooleanFilter
    method apply (line 4) | def apply(request, query, values)
    method options (line 15) | def options

FILE: app/avo/filters/has_duplicate.rb
  class Avo::Filters::HasDuplicate (line 1) | class Avo::Filters::HasDuplicate < Avo::Filters::BooleanFilter
    method apply (line 4) | def apply(request, query, values)
    method options (line 16) | def options

FILE: app/avo/filters/involvement_role.rb
  class Avo::Filters::InvolvementRole (line 1) | class Avo::Filters::InvolvementRole < Avo::Filters::SelectFilter
    method apply (line 4) | def apply(request, query, role)
    method options (line 12) | def options

FILE: app/avo/filters/language.rb
  class Avo::Filters::Language (line 1) | class Avo::Filters::Language < Avo::Filters::SelectFilter
    method apply (line 8) | def apply(request, query, language)
    method options (line 16) | def options

FILE: app/avo/filters/location_presence.rb
  class Avo::Filters::LocationPresence (line 1) | class Avo::Filters::LocationPresence < Avo::Filters::BooleanFilter
    method apply (line 4) | def apply(request, query, values)
    method options (line 16) | def options

FILE: app/avo/filters/name.rb
  class Avo::Filters::Name (line 1) | class Avo::Filters::Name < Avo::Filters::TextFilter
    method apply (line 5) | def apply(request, query, value)

FILE: app/avo/filters/provider.rb
  class Avo::Filters::Provider (line 1) | class Avo::Filters::Provider < Avo::Filters::SelectFilter
    method apply (line 4) | def apply(request, query, provider)
    method options (line 12) | def options

FILE: app/avo/filters/published.rb
  class Avo::Filters::Published (line 1) | class Avo::Filters::Published < Avo::Filters::BooleanFilter
    method apply (line 4) | def apply(request, query, values)
    method options (line 14) | def options

FILE: app/avo/filters/raw_transcript.rb
  class Avo::Filters::RawTranscript (line 1) | class Avo::Filters::RawTranscript < Avo::Filters::BooleanFilter
    method apply (line 7) | def apply(request, query, values)
    method options (line 19) | def options

FILE: app/avo/filters/slug.rb
  class Avo::Filters::Slug (line 1) | class Avo::Filters::Slug < Avo::Filters::TextFilter
    method apply (line 5) | def apply(request, query, value)

FILE: app/avo/filters/summary.rb
  class Avo::Filters::Summary (line 1) | class Avo::Filters::Summary < Avo::Filters::BooleanFilter
    method apply (line 4) | def apply(request, query, values)
    method options (line 16) | def options

FILE: app/avo/filters/suspicious.rb
  class Avo::Filters::Suspicious (line 1) | class Avo::Filters::Suspicious < Avo::Filters::BooleanFilter
    method apply (line 4) | def apply(request, query, values)
    method options (line 10) | def options

FILE: app/avo/filters/talk_event.rb
  class Avo::Filters::TalkEvent (line 1) | class Avo::Filters::TalkEvent < Avo::Filters::SelectFilter
    method apply (line 4) | def apply(request, query, values)
    method options (line 8) | def options

FILE: app/avo/filters/title.rb
  class Avo::Filters::Title (line 1) | class Avo::Filters::Title < Avo::Filters::TextFilter
    method apply (line 5) | def apply(request, query, value)

FILE: app/avo/filters/topic_talks.rb
  class Avo::Filters::TopicTalks (line 1) | class Avo::Filters::TopicTalks < Avo::Filters::BooleanFilter
    method apply (line 7) | def apply(request, query, values)
    method options (line 23) | def options

FILE: app/avo/filters/topics.rb
  class Avo::Filters::Topics (line 1) | class Avo::Filters::Topics < Avo::Filters::BooleanFilter
    method apply (line 7) | def apply(request, query, values)
    method options (line 19) | def options

FILE: app/avo/filters/video_availability.rb
  class Avo::Filters::VideoAvailability (line 1) | class Avo::Filters::VideoAvailability < Avo::Filters::BooleanFilter
    method apply (line 4) | def apply(request, query, values)
    method options (line 24) | def options

FILE: app/avo/filters/video_provider.rb
  class Avo::Filters::VideoProvider (line 1) | class Avo::Filters::VideoProvider < Avo::Filters::SelectFilter
    method apply (line 8) | def apply(request, query, provider)
    method options (line 16) | def options

FILE: app/avo/filters/without_talks.rb
  class Avo::Filters::WithoutTalks (line 1) | class Avo::Filters::WithoutTalks < Avo::Filters::BooleanFilter
    method apply (line 7) | def apply(request, query, values)
    method options (line 15) | def options

FILE: app/avo/resources/alias.rb
  class Avo::Resources::Alias (line 1) | class Avo::Resources::Alias < Avo::BaseResource
    method filters (line 10) | def filters
    method fields (line 14) | def fields
    method aliasable_link (line 31) | def self.aliasable_link(app, record)

FILE: app/avo/resources/city.rb
  class Avo::Resources::City (line 1) | class Avo::Resources::City < Avo::BaseResource
    method fields (line 34) | def fields
    method filters (line 48) | def filters
    method country_options (line 52) | def country_options

FILE: app/avo/resources/connected_account.rb
  class Avo::Resources::ConnectedAccount (line 11) | class Avo::Resources::ConnectedAccount < Avo::BaseResource
    method fields (line 18) | def fields
    method filters (line 31) | def filters

FILE: app/avo/resources/contributor.rb
  class Avo::Resources::Contributor (line 1) | class Avo::Resources::Contributor < Avo::BaseResource
    method fields (line 8) | def fields

FILE: app/avo/resources/event.rb
  class Avo::Resources::Event (line 1) | class Avo::Resources::Event < Avo::BaseResource
    method fields (line 17) | def fields
    method actions (line 44) | def actions
    method filters (line 49) | def filters
    method country_options (line 57) | def country_options

FILE: app/avo/resources/event_involvement.rb
  class Avo::Resources::EventInvolvement (line 1) | class Avo::Resources::EventInvolvement < Avo::BaseResource
    method fields (line 13) | def fields
    method filters (line 22) | def filters

FILE: app/avo/resources/event_participation.rb
  class Avo::Resources::EventParticipation (line 1) | class Avo::Resources::EventParticipation < Avo::BaseResource
    method fields (line 11) | def fields
    method filters (line 18) | def filters

FILE: app/avo/resources/event_series.rb
  class Avo::Resources::EventSeries (line 1) | class Avo::Resources::EventSeries < Avo::BaseResource
    method fields (line 17) | def fields
    method filters (line 34) | def filters

FILE: app/avo/resources/favorite_user.rb
  class Avo::Resources::FavoriteUser (line 1) | class Avo::Resources::FavoriteUser < Avo::BaseResource
    method fields (line 8) | def fields

FILE: app/avo/resources/geocode_result.rb
  class Avo::Resources::GeocodeResult (line 1) | class Avo::Resources::GeocodeResult < Avo::BaseResource
    method fields (line 9) | def fields

FILE: app/avo/resources/organization.rb
  class Avo::Resources::Organization (line 1) | class Avo::Resources::Organization < Avo::BaseResource
    method fields (line 19) | def fields

FILE: app/avo/resources/session.rb
  class Avo::Resources::Session (line 1) | class Avo::Resources::Session < Avo::BaseResource
    method fields (line 7) | def fields

FILE: app/avo/resources/sponsor.rb
  class Avo::Resources::Sponsor (line 1) | class Avo::Resources::Sponsor < Avo::BaseResource
    method fields (line 8) | def fields

FILE: app/avo/resources/suggestion.rb
  class Avo::Resources::Suggestion (line 1) | class Avo::Resources::Suggestion < Avo::BaseResource
    method fields (line 8) | def fields

FILE: app/avo/resources/talk.rb
  class Avo::Resources::Talk (line 1) | class Avo::Resources::Talk < Avo::BaseResource
    method fields (line 19) | def fields
    method actions (line 86) | def actions
    method filters (line 93) | def filters

FILE: app/avo/resources/talk_topic.rb
  class Avo::Resources::TalkTopic (line 1) | class Avo::Resources::TalkTopic < Avo::BaseResource
    method fields (line 8) | def fields

FILE: app/avo/resources/talk_transcript.rb
  class Avo::Resources::TalkTranscript (line 1) | class Avo::Resources::TalkTranscript < Avo::BaseResource
    method fields (line 9) | def fields
    method actions (line 18) | def actions

FILE: app/avo/resources/topic.rb
  class Avo::Resources::Topic (line 1) | class Avo::Resources::Topic < Avo::BaseResource
    method fields (line 19) | def fields
    method actions (line 34) | def actions
    method filters (line 41) | def filters

FILE: app/avo/resources/topic_gem.rb
  class Avo::Resources::TopicGem (line 1) | class Avo::Resources::TopicGem < Avo::BaseResource
    method name (line 10) | def self.name
    method fields (line 14) | def fields

FILE: app/avo/resources/user.rb
  class Avo::Resources::User (line 1) | class Avo::Resources::User < Avo::BaseResource
    method fields (line 22) | def fields
    method filters (line 62) | def filters
    method actions (line 74) | def actions

FILE: app/avo/resources/user_talk.rb
  class Avo::Resources::UserTalk (line 1) | class Avo::Resources::UserTalk < Avo::BaseResource
    method fields (line 8) | def fields

FILE: app/avo/resources/watch_list.rb
  class Avo::Resources::WatchList (line 1) | class Avo::Resources::WatchList < Avo::BaseResource
    method fields (line 5) | def fields

FILE: app/avo/resources/watch_list_talk.rb
  class Avo::Resources::WatchListTalk (line 1) | class Avo::Resources::WatchListTalk < Avo::BaseResource
    method fields (line 4) | def fields

FILE: app/channels/application_cable/channel.rb
  type ApplicationCable (line 1) | module ApplicationCable
    class Channel (line 2) | class Channel < ActionCable::Channel::Base

FILE: app/channels/application_cable/connection.rb
  type ApplicationCable (line 1) | module ApplicationCable
    class Connection (line 2) | class Connection < ActionCable::Connection::Base

FILE: app/clients/application_client.rb
  class ApplicationClient (line 1) | class ApplicationClient
    class Error (line 2) | class Error < StandardError; end
    class Forbidden (line 4) | class Forbidden < Error; end
    class Unauthorized (line 6) | class Unauthorized < Error; end
    class RateLimit (line 8) | class RateLimit < Error; end
    class NotFound (line 10) | class NotFound < Error; end
    class InternalError (line 12) | class InternalError < Error; end
    method initialize (line 17) | def initialize(token: nil)
    method default_headers (line 21) | def default_headers
    method content_type (line 28) | def content_type
    method authorization_header (line 32) | def authorization_header
    method default_query_params (line 36) | def default_query_params
    method get (line 40) | def get(path, headers: {}, query: nil)
    method post (line 44) | def post(path, headers: {}, query: nil, body: nil, form_data: nil)
    method patch (line 55) | def patch(path, headers: {}, query: nil, body: nil, form_data: nil)
    method put (line 66) | def put(path, headers: {}, query: nil, body: nil, form_data: nil)
    method delete (line 77) | def delete(path, headers: {}, query: nil, body: nil)
    method base_uri (line 81) | def base_uri
    method make_request (line 87) | def make_request(klass:, path:, headers: {}, body: nil, query: nil, fo...
    method handle_response (line 114) | def handle_response(response)
    method build_body (line 133) | def build_body(body)
    class Response (line 142) | class Response
      method initialize (line 155) | def initialize(original_response)
      method headers (line 159) | def headers
      method content_type (line 163) | def content_type
      method parsed_body (line 167) | def parsed_body

FILE: app/clients/blue_sky.rb
  function build (line 9) | def self.build(host = self.host, **options)
  function profile_metadata (line 17) | def profile_metadata(handle)

FILE: app/clients/github/client.rb
  type GitHub (line 1) | module GitHub
    class Client (line 2) | class Client < ApplicationClient
      method initialize (line 5) | def initialize
      method authorization_header (line 11) | def authorization_header
      method content_type (line 15) | def content_type
      method token (line 19) | def token

FILE: app/clients/github/contributors_client.rb
  type GitHub (line 1) | module GitHub
    class ContributorsClient (line 2) | class ContributorsClient < Client
      method fetch_all (line 6) | def fetch_all
      method fetch_contributors (line 13) | def fetch_contributors
      method enrich_with_user_data (line 31) | def enrich_with_user_data(contributors)

FILE: app/clients/github/user_client.rb
  type GitHub (line 1) | module GitHub
    class UserClient (line 2) | class UserClient < GitHub::Client
      method profile (line 3) | def profile(username)
      method social_accounts (line 7) | def social_accounts(username)
      method search (line 11) | def search(q, per_page: 10, page: 1)
      method emails (line 15) | def emails

FILE: app/clients/ruby_conferences/client.rb
  type RubyConferences (line 1) | module RubyConferences
    class Client (line 2) | class Client < ApplicationClient
      method conferences (line 5) | def conferences
      method conferences_cached (line 9) | def conferences_cached
      method content_type (line 17) | def content_type

FILE: app/clients/speakerdeck/client.rb
  type Speakerdeck (line 3) | module Speakerdeck
    class Client (line 4) | class Client < ApplicationClient
      method oembed (line 7) | def oembed(url)
      method normalize_url (line 14) | def normalize_url(url)
      method authorization_header (line 22) | def authorization_header

FILE: app/clients/youtube/channels.rb
  type YouTube (line 3) | module YouTube
    class Channels (line 4) | class Channels < YouTube::Client
      method id_by_name (line 5) | def id_by_name(channel_name:)
      method default_headers (line 12) | def default_headers
      method fallback_using_scrapping (line 18) | def fallback_using_scrapping(channel_name:)

FILE: app/clients/youtube/client.rb
  type YouTube (line 1) | module YouTube
    class Client (line 2) | class Client < ApplicationClient
      method all_items (line 7) | def all_items(path, query: {})
      method default_headers (line 20) | def default_headers
      method token (line 26) | def token

FILE: app/clients/youtube/playlist_items.rb
  type YouTube (line 1) | module YouTube
    class PlaylistItems (line 2) | class PlaylistItems < YouTube::Client
      method all (line 3) | def all(playlist_id:)

FILE: app/clients/youtube/playlists.rb
  type YouTube (line 1) | module YouTube
    class Playlists (line 2) | class Playlists < YouTube::Client
      method all (line 5) | def all(channel_id:, title_matcher: nil)
      method string_to_regex (line 34) | def string_to_regex(str)

FILE: app/clients/youtube/thumbnail.rb
  type YouTube (line 3) | module YouTube
    class Thumbnail (line 4) | class Thumbnail
      method initialize (line 18) | def initialize(video_id)
      method best_url (line 22) | def best_url
      method best_url_for (line 26) | def best_url_for(talk_size)
      method best_url_from (line 33) | def best_url_from(starting_size)
      method url_for (line 55) | def url_for(size)
      method default? (line 59) | def default?(url)
      method valid_aspect_ratio? (line 66) | def valid_aspect_ratio?(url)
      method content_length (line 86) | def content_length(url)

FILE: app/clients/youtube/transcript.rb
  type YouTube (line 3) | module YouTube
    class Transcript (line 4) | class Transcript
      method get (line 7) | def get(video_id)
      method get (line 31) | def self.get(video_id)
      method encode_message (line 37) | def encode_message(message, typedef)
      method get_base64_protobuf (line 42) | def get_base64_protobuf(message, typedef)

FILE: app/clients/youtube/video.rb
  type YouTube (line 1) | module YouTube
    class Video (line 2) | class Video < Client
      method available? (line 3) | def available?(video_id)
      method get_statistics (line 14) | def get_statistics(video_id)
      method duration (line 33) | def duration(video_id)

FILE: app/components/application_component.rb
  class ApplicationComponent (line 3) | class ApplicationComponent < ViewComponent::Base
    method initialize (line 9) | def initialize(*, **options)
    method render? (line 15) | def render?

FILE: app/components/events/upcoming_event_banner_component.rb
  class Events::UpcomingEventBannerComponent (line 3) | class Events::UpcomingEventBannerComponent < ApplicationComponent
    method render? (line 7) | def render?
    method upcoming_event (line 11) | def upcoming_event
    method background_style (line 19) | def background_style
    method background_color (line 26) | def background_color
    method text_color (line 31) | def text_color
    method should_show_banner? (line 37) | def should_show_banner?

FILE: app/components/hover_card/base_component.rb
  class HoverCard::BaseComponent (line 3) | class HoverCard::BaseComponent < ViewComponent::Base
    method initialize (line 8) | def initialize(record:, avatar_size: :sm)
    method frame_id (line 13) | def frame_id
    method hover_card_url (line 17) | def hover_card_url
    method render? (line 21) | def render?

FILE: app/components/hover_card/event_component.rb
  class HoverCard::EventComponent (line 3) | class HoverCard::EventComponent < HoverCard::BaseComponent
    method hover_card_url (line 4) | def hover_card_url

FILE: app/components/hover_card/user_component.rb
  class HoverCard::UserComponent (line 3) | class HoverCard::UserComponent < HoverCard::BaseComponent
    method hover_card_url (line 4) | def hover_card_url
    method render? (line 8) | def render?

FILE: app/components/tito/button_component.rb
  class Tito::ButtonComponent (line 3) | class Tito::ButtonComponent < ApplicationComponent
    method render? (line 7) | def render?
    method classes (line 11) | def classes

FILE: app/components/tito/widget_component.rb
  class Tito::WidgetComponent (line 3) | class Tito::WidgetComponent < ApplicationComponent
    method render? (line 7) | def render?
    method event_slug (line 11) | def event_slug

FILE: app/components/ui/avatar_component.rb
  class Ui::AvatarComponent (line 3) | class Ui::AvatarComponent < ApplicationComponent
    method show_hover_card? (line 40) | def show_hover_card?
    method show_link? (line 44) | def show_link?
    method link_path (line 48) | def link_path
    method avatar_classes (line 58) | def avatar_classes
    method initials (line 68) | def initials
    method has_custom_avatar? (line 73) | def has_custom_avatar?
    method avatar_url_for_size (line 77) | def avatar_url_for_size
    method image_size (line 83) | def image_size
    method text_size (line 87) | def text_size
    method kind_class (line 91) | def kind_class
    method suspicious? (line 95) | def suspicious?
    method show_custom_avatar? (line 99) | def show_custom_avatar?

FILE: app/components/ui/avatar_group_component.rb
  class Ui::AvatarGroupComponent (line 3) | class Ui::AvatarGroupComponent < ApplicationComponent
    method visible_avatarables (line 19) | def visible_avatarables
    method remaining_count (line 23) | def remaining_count
    method size_class (line 27) | def size_class

FILE: app/components/ui/badge_component.rb
  class Ui::BadgeComponent (line 3) | class Ui::BadgeComponent < ApplicationComponent
    method call (line 28) | def call
    method classes (line 36) | def classes
    method component_classes (line 40) | def component_classes
    method content (line 49) | def content

FILE: app/components/ui/button_component.rb
  class Ui::ButtonComponent (line 3) | class Ui::ButtonComponent < ApplicationComponent
    method call (line 32) | def call
    method classes (line 45) | def classes
    method component_classes (line 49) | def component_classes
    method content (line 60) | def content
    method button_kind (line 64) | def button_kind
    method default_method? (line 71) | def default_method?

FILE: app/components/ui/divider_component.rb
  class Ui::DividerComponent (line 3) | class Ui::DividerComponent < ApplicationComponent
    method call (line 12) | def call
    method classes (line 20) | def classes
    method component_classes (line 24) | def component_classes
    method content (line 31) | def content

FILE: app/components/ui/dropdown_component.rb
  class Ui::DropdownComponent (line 3) | class Ui::DropdownComponent < ApplicationComponent
    method before_render (line 41) | def before_render
    method classes (line 45) | def classes
    method component_classes (line 49) | def component_classes
    method content_classes (line 59) | def content_classes

FILE: app/components/ui/modal_component.rb
  class Ui::ModalComponent (line 3) | class Ui::ModalComponent < ApplicationComponent
    method before_render (line 25) | def before_render
    method classes (line 37) | def classes
    method component_classes (line 41) | def component_classes
    method size_class (line 48) | def size_class
    method content_classes (line 52) | def content_classes

FILE: app/components/ui/stamp_component.rb
  class Ui::StampComponent (line 3) | class Ui::StampComponent < ApplicationComponent
    method kind (line 19) | def kind
    method clickable? (line 31) | def clickable?
    method url (line 35) | def url
    method link_attributes (line 48) | def link_attributes
    method classes (line 52) | def classes
    method image_style (line 56) | def image_style
    method component_classes (line 64) | def component_classes

FILE: app/controllers/admin/suggestions_controller.rb
  type Admin (line 1) | module Admin
    class SuggestionsController (line 2) | class SuggestionsController < ApplicationController
      method index (line 5) | def index
      method update (line 9) | def update
      method destroy (line 15) | def destroy

FILE: app/controllers/analytics/dashboards_controller.rb
  class Analytics::DashboardsController (line 1) | class Analytics::DashboardsController < ApplicationController
    method daily_visits (line 5) | def daily_visits
    method daily_page_views (line 9) | def daily_page_views
    method monthly_visits (line 13) | def monthly_visits
    method monthly_page_views (line 17) | def monthly_page_views
    method yearly_conferences (line 21) | def yearly_conferences
    method yearly_talks (line 29) | def yearly_talks
    method top_referrers (line 33) | def top_referrers
    method top_landing_pages (line 45) | def top_landing_pages
    method top_searches (line 66) | def top_searches
    method admin_required (line 83) | def admin_required

FILE: app/controllers/announcements_controller.rb
  class AnnouncementsController (line 1) | class AnnouncementsController < ApplicationController
    method index (line 6) | def index
    method show (line 14) | def show
    method feed (line 24) | def feed
    method announcements (line 37) | def announcements
    method page_number (line 41) | def page_number
    method can_view_draft_articles? (line 45) | def can_view_draft_articles?
    method permitted_params (line 50) | def permitted_params
    method set_announcement_meta_tags (line 54) | def set_announcement_meta_tags

FILE: app/controllers/api/v1/embed/base_controller.rb
  type Api (line 3) | module Api
    type V1 (line 4) | module V1
      type Embed (line 5) | module Embed
        class BaseController (line 6) | class BaseController < ActionController::API
          method preflight (line 12) | def preflight
          method set_cors_headers (line 18) | def set_cors_headers
          method not_found (line 25) | def not_found
          method internal_error (line 29) | def internal_error(exception)
          method build_url (line 35) | def build_url(path)
          method avatar_url (line 39) | def avatar_url(user)
          method full_url (line 49) | def full_url(path)
          method event_avatar_url (line 55) | def event_avatar_url(event)
          method event_banner_url (line 63) | def event_banner_url(event)

FILE: app/controllers/api/v1/embed/events_controller.rb
  type Api (line 3) | module Api
    type V1 (line 4) | module V1
      type Embed (line 5) | module Embed
        class EventsController (line 6) | class EventsController < BaseController
          method index (line 7) | def index
          method show (line 30) | def show
          method participants (line 73) | def participants
          method participant_json (line 102) | def participant_json(user)
          method event_summary_json (line 110) | def event_summary_json(event)

FILE: app/controllers/api/v1/embed/profiles_controller.rb
  type Api (line 3) | module Api
    type V1 (line 4) | module V1
      type Embed (line 5) | module Embed
        class ProfilesController (line 6) | class ProfilesController < BaseController
          method index (line 7) | def index
          method show (line 17) | def show

FILE: app/controllers/api/v1/embed/speakers_controller.rb
  type Api (line 3) | module Api
    type V1 (line 4) | module V1
      type Embed (line 5) | module Embed
        class SpeakersController (line 6) | class SpeakersController < BaseController
          method index (line 7) | def index
          method show (line 16) | def show

FILE: app/controllers/api/v1/embed/stamps_controller.rb
  type Api (line 3) | module Api
    type V1 (line 4) | module V1
      type Embed (line 5) | module Embed
        class StampsController (line 6) | class StampsController < BaseController
          method show (line 7) | def show
          method stamp_json (line 28) | def stamp_json(stamp)
          method grouped_stamps (line 48) | def grouped_stamps(stamps)
          method stamp_image_url (line 60) | def stamp_image_url(stamp)

FILE: app/controllers/api/v1/embed/stickers_controller.rb
  type Api (line 3) | module Api
    type V1 (line 4) | module V1
      type Embed (line 5) | module Embed
        class StickersController (line 6) | class StickersController < BaseController
          method show (line 7) | def show
          method sticker_image_url (line 41) | def sticker_image_url(sticker)

FILE: app/controllers/api/v1/embed/talks_controller.rb
  type Api (line 3) | module Api
    type V1 (line 4) | module V1
      type Embed (line 5) | module Embed
        class TalksController (line 6) | class TalksController < BaseController
          method index (line 7) | def index
          method show (line 16) | def show

FILE: app/controllers/api/v1/embed/topics_controller.rb
  type Api (line 3) | module Api
    type V1 (line 4) | module V1
      type Embed (line 5) | module Embed
        class TopicsController (line 6) | class TopicsController < BaseController
          method show (line 7) | def show

FILE: app/controllers/application_controller.rb
  class ApplicationController (line 1) | class ApplicationController < ActionController::Base
    method default_watch_list (line 10) | def default_watch_list
    method redirect_to_ruby_events (line 16) | def redirect_to_ruby_events
    method sign_in (line 27) | def sign_in(user)

FILE: app/controllers/avo/aliases_controller.rb
  class Avo::AliasesController (line 3) | class Avo::AliasesController < Avo::ResourcesController

FILE: app/controllers/avo/cities_controller.rb
  class Avo::CitiesController (line 3) | class Avo::CitiesController < Avo::ResourcesController

FILE: app/controllers/avo/connected_accounts_controller.rb
  class Avo::ConnectedAccountsController (line 3) | class Avo::ConnectedAccountsController < Avo::ResourcesController

FILE: app/controllers/avo/contributors_controller.rb
  class Avo::ContributorsController (line 3) | class Avo::ContributorsController < Avo::ResourcesController

FILE: app/controllers/avo/event_involvements_controller.rb
  class Avo::EventInvolvementsController (line 3) | class Avo::EventInvolvementsController < Avo::ResourcesController

FILE: app/controllers/avo/event_participations_controller.rb
  class Avo::EventParticipationsController (line 3) | class Avo::EventParticipationsController < Avo::ResourcesController

FILE: app/controllers/avo/event_series_controller.rb
  class Avo::EventSeriesController (line 3) | class Avo::EventSeriesController < Avo::ResourcesController

FILE: app/controllers/avo/events_controller.rb
  class Avo::EventsController (line 3) | class Avo::EventsController < Avo::ResourcesController

FILE: app/controllers/avo/favorite_users_controller.rb
  class Avo::FavoriteUsersController (line 3) | class Avo::FavoriteUsersController < Avo::ResourcesController

FILE: app/controllers/avo/geocode_results_controller.rb
  class Avo::GeocodeResultsController (line 3) | class Avo::GeocodeResultsController < Avo::ResourcesController

FILE: app/controllers/avo/organizations_controller.rb
  class Avo::OrganizationsController (line 3) | class Avo::OrganizationsController < Avo::ResourcesController

FILE: app/controllers/avo/sessions_controller.rb
  class Avo::SessionsController (line 3) | class Avo::SessionsController < Avo::ResourcesController

FILE: app/controllers/avo/speaker_talks_controller.rb
  class Avo::SpeakerTalksController (line 3) | class Avo::SpeakerTalksController < Avo::ResourcesController

FILE: app/controllers/avo/speakers_controller.rb
  class Avo::SpeakersController (line 3) | class Avo::SpeakersController < Avo::ResourcesController

FILE: app/controllers/avo/sponsors_controller.rb
  class Avo::SponsorsController (line 3) | class Avo::SponsorsController < Avo::ResourcesController

FILE: app/controllers/avo/suggestions_controller.rb
  class Avo::SuggestionsController (line 3) | class Avo::SuggestionsController < Avo::ResourcesController

FILE: app/controllers/avo/talk_topics_controller.rb
  class Avo::TalkTopicsController (line 3) | class Avo::TalkTopicsController < Avo::ResourcesController

FILE: app/controllers/avo/talk_transcripts_controller.rb
  class Avo::TalkTranscriptsController (line 3) | class Avo::TalkTranscriptsController < Avo::ResourcesController

FILE: app/controllers/avo/talks_controller.rb
  class Avo::TalksController (line 3) | class Avo::TalksController < Avo::ResourcesController

FILE: app/controllers/avo/topic_gems_controller.rb
  class Avo::TopicGemsController (line 3) | class Avo::TopicGemsController < Avo::ResourcesController

FILE: app/controllers/avo/topics_controller.rb
  class Avo::TopicsController (line 3) | class Avo::TopicsController < Avo::ResourcesController

FILE: app/controllers/avo/user_talks_controller.rb
  class Avo::UserTalksController (line 3) | class Avo::UserTalksController < Avo::ResourcesController

FILE: app/controllers/avo/users_controller.rb
  class Avo::UsersController (line 3) | class Avo::UsersController < Avo::ResourcesController

FILE: app/controllers/avo/watch_list_talks_controller.rb
  class Avo::WatchListTalksController (line 3) | class Avo::WatchListTalksController < Avo::ResourcesController

FILE: app/controllers/avo/watch_lists_controller.rb
  class Avo::WatchListsController (line 3) | class Avo::WatchListsController < Avo::ResourcesController

FILE: app/controllers/browse_controller.rb
  class BrowseController (line 1) | class BrowseController < ApplicationController
    method index (line 16) | def index
    method show (line 22) | def show
    method instance_variables_for_section (line 32) | def instance_variables_for_section(section_name)
    method cache_key (line 66) | def cache_key(name)
    method load_featured_events (line 70) | def load_featured_events
    method load_event_rows (line 78) | def load_event_rows
    method load_continue_watching (line 96) | def load_continue_watching
    method load_newest_talks (line 106) | def load_newest_talks
    method load_recently_published (line 116) | def load_recently_published
    method load_trending (line 126) | def load_trending
    method load_for_you (line 136) | def load_for_you
    method load_from_bookmarks (line 142) | def load_from_bookmarks
    method load_favorite_rubyists (line 152) | def load_favorite_rubyists
    method load_events_attended (line 166) | def load_events_attended
    method load_unwatched_attended (line 179) | def load_unwatched_attended
    method load_favorite_speakers (line 195) | def load_favorite_speakers
    method load_popular (line 218) | def load_popular
    method load_popular_youtube (line 226) | def load_popular_youtube
    method load_most_bookmarked (line 234) | def load_most_bookmarked
    method load_quick_watches (line 242) | def load_quick_watches
    method load_deep_dives (line 250) | def load_deep_dives
    method load_hidden_gems (line 258) | def load_hidden_gems
    method load_evergreen (line 266) | def load_evergreen
    method load_beginner_friendly (line 274) | def load_beginner_friendly
    method load_mind_blowing (line 282) | def load_mind_blowing
    method load_inspiring (line 290) | def load_inspiring
    method load_most_liked (line 298) | def load_most_liked
    method load_recommended_community (line 306) | def load_recommended_community
    method load_popular_topics (line 314) | def load_popular_topics
    method load_talk_kinds (line 322) | def load_talk_kinds
    method load_topic_rows (line 328) | def load_topic_rows
    method load_language_rows (line 346) | def load_language_rows
    method featured_events_query (line 378) | def featured_events_query
    method recently_published_query (line 394) | def recently_published_query
    method newest_talks_query (line 401) | def newest_talks_query
    method trending_talks_query (line 408) | def trending_talks_query
    method popular_talks_query (line 417) | def popular_talks_query
    method popular_on_youtube_query (line 425) | def popular_on_youtube_query
    method most_bookmarked_query (line 432) | def most_bookmarked_query
    method quick_watches_query (line 440) | def quick_watches_query
    method deep_dives_query (line 447) | def deep_dives_query
    method hidden_gems_query (line 454) | def hidden_gems_query
    method evergreen_talks_query (line 464) | def evergreen_talks_query
    method beginner_friendly_query (line 474) | def beginner_friendly_query
    method mind_blowing_query (line 484) | def mind_blowing_query
    method inspiring_talks_query (line 494) | def inspiring_talks_query
    method most_liked_query (line 505) | def most_liked_query
    method recommended_by_community_query (line 515) | def recommended_by_community_query
    method popular_topics_query (line 525) | def popular_topics_query
    method talk_kinds_query (line 534) | def talk_kinds_query
    method build_topic_sections (line 541) | def build_topic_sections
    method build_event_sections (line 557) | def build_event_sections

FILE: app/controllers/cfp_controller.rb
  class CFPController (line 1) | class CFPController < ApplicationController
    method index (line 5) | def index

FILE: app/controllers/cities_controller.rb
  class CitiesController (line 1) | class CitiesController < ApplicationController
    method index (line 7) | def index
    method show (line 11) | def show
    method show_by_country (line 22) | def show_by_country
    method show_with_state (line 43) | def show_with_state
    method load_city_data (line 73) | def load_city_data
    method filter_events_by_time (line 121) | def filter_events_by_time(events)
    method continent_upcoming_events (line 125) | def continent_upcoming_events(exclude_country_codes: [])

FILE: app/controllers/concerns/analytics.rb
  type Analytics (line 1) | module Analytics
    function disable_analytics (line 9) | def disable_analytics
    function analytics_disabled? (line 16) | def analytics_disabled?
    function track_action (line 20) | def track_action

FILE: app/controllers/concerns/authenticable.rb
  type Authenticable (line 1) | module Authenticable
    function signed_in? (line 11) | def signed_in?
    function signed_in (line 15) | def signed_in(&block)
    function signed_out (line 19) | def signed_out(&block)
    function authenticate_user! (line 25) | def authenticate_user!
    function set_current_request_details (line 29) | def set_current_request_details

FILE: app/controllers/concerns/event_data.rb
  type EventData (line 1) | module EventData
    function set_event (line 6) | def set_event
    function set_event_meta_tags (line 11) | def set_event_meta_tags
    function set_participation (line 15) | def set_participation
    function set_participants (line 19) | def set_participants

FILE: app/controllers/concerns/event_map_markers.rb
  type EventMapMarkers (line 3) | module EventMapMarkers
    function event_map_markers (line 8) | def event_map_markers(events = Event.includes(:series).geocoded)
    function event_marker_data (line 24) | def event_marker_data(event)

FILE: app/controllers/concerns/favorite_users.rb
  type FavoriteUsers (line 1) | module FavoriteUsers
    function set_favorite_users (line 4) | def set_favorite_users

FILE: app/controllers/concerns/geo_map_layers.rb
  type GeoMapLayers (line 3) | module GeoMapLayers
    function build_sidebar_geo_layers (line 8) | def build_sidebar_geo_layers(events, include_broader_scope: true)
    function add_broader_layers (line 30) | def add_broader_layers(layers, current_events)
    function add_nearby_layer (line 45) | def add_nearby_layer(layers, city_events)
    function add_state_layer (line 54) | def add_state_layer(layers)
    function add_country_layer (line 60) | def add_country_layer(layers)
    function add_continent_layer (line 66) | def add_continent_layer(layers)
    function maybe_add_layer (line 72) | def maybe_add_layer(layers, id:, label:, emoji:, events:, bounds: nil)
    function build_layer (line 81) | def build_layer(id:, label:, emoji:, events: nil, markers: nil, bounds...
    function build_city_pin (line 95) | def build_city_pin(location)
    function set_first_visible_layer (line 101) | def set_first_visible_layer(layers)
    function filter_events_by_time (line 111) | def filter_events_by_time(events)

FILE: app/controllers/concerns/location_events.rb
  type LocationEvents (line 3) | module LocationEvents
    function location_events (line 8) | def location_events
    function upcoming_events (line 12) | def upcoming_events
    function past_events (line 16) | def past_events
    function country_upcoming_events (line 20) | def country_upcoming_events(exclude_ids: [])
    function continent_upcoming_events (line 29) | def continent_upcoming_events(exclude_country_codes: [])

FILE: app/controllers/concerns/metadata.rb
  type Metadata (line 3) | module Metadata
    function set_default_meta_tags (line 17) | def set_default_meta_tags

FILE: app/controllers/concerns/profile_data.rb
  type ProfileData (line 1) | module ProfileData
    function load_common_data (line 16) | def load_common_data
    function set_user (line 30) | def set_user
    function set_favorite_user (line 49) | def set_favorite_user
    function set_mutual_events (line 53) | def set_mutual_events
    function set_user_favorites (line 61) | def set_user_favorites
    function user_kind (line 67) | def user_kind

FILE: app/controllers/concerns/remote_modal.rb
  type RemoteModal (line 1) | module RemoteModal
    function respond_with_remote_modal (line 11) | def respond_with_remote_modal(options = {})
    function enable_remote_modal (line 19) | def enable_remote_modal
    function modal_options (line 23) | def modal_options
    function set_modal_options (line 27) | def set_modal_options(options)
    function define_layout (line 31) | def define_layout

FILE: app/controllers/concerns/spotlight_search.rb
  type SpotlightSearch (line 3) | module SpotlightSearch
    function search_backend_class (line 12) | def search_backend_class
    function search_backend (line 19) | def search_backend

FILE: app/controllers/concerns/turbo/force_response.rb
  type Turbo (line 3) | module Turbo
    type ForceResponse (line 4) | module ForceResponse
      function force_frame_response (line 8) | def force_frame_response(options = {})
      function force_stream_response (line 12) | def force_stream_response(options = {})
      function force_frame_response (line 17) | def force_frame_response
      function force_stream_response (line 23) | def force_stream_response

FILE: app/controllers/concerns/watched_talks.rb
  type WatchedTalks (line 1) | module WatchedTalks
    function user_watched_talks (line 10) | def user_watched_talks

FILE: app/controllers/continents/base_controller.rb
  class Continents::BaseController (line 3) | class Continents::BaseController < ApplicationController
    method set_continent (line 12) | def set_continent
    method continent_events (line 18) | def continent_events
    method upcoming_events (line 22) | def upcoming_events
    method past_events (line 26) | def past_events

FILE: app/controllers/continents/countries_controller.rb
  class Continents::CountriesController (line 3) | class Continents::CountriesController < Continents::BaseController
    method index (line 4) | def index

FILE: app/controllers/continents_controller.rb
  class ContinentsController (line 3) | class ContinentsController < ApplicationController
    method index (line 9) | def index
    method show (line 28) | def show

FILE: app/controllers/contributions_controller.rb
  class ContributionsController (line 1) | class ContributionsController < ApplicationController
    method index (line 10) | def index
    method show (line 48) | def show
    method speakers_without_github (line 58) | def speakers_without_github
    method talks_without_slides (line 63) | def talks_without_slides
    method events_without_videos (line 68) | def events_without_videos
    method events_without_location (line 76) | def events_without_location
    method events_without_dates (line 80) | def events_without_dates
    method talks_dates_out_of_bounds (line 84) | def talks_dates_out_of_bounds
    method missing_videos_cue (line 98) | def missing_videos_cue

FILE: app/controllers/coordinates_controller.rb
  class CoordinatesController (line 3) | class CoordinatesController < ApplicationController
    method index (line 8) | def index
    method show (line 22) | def show
    method load_location_data (line 35) | def load_location_data
    method build_geo_layers (line 52) | def build_geo_layers(events)

FILE: app/controllers/countries/base_controller.rb
  class Countries::BaseController (line 1) | class Countries::BaseController < ApplicationController
    method set_country (line 8) | def set_country
    method country_events (line 13) | def country_events
    method event_sort_date (line 17) | def event_sort_date(event)

FILE: app/controllers/countries/cities_controller.rb
  class Countries::CitiesController (line 1) | class Countries::CitiesController < Countries::BaseController
    method index (line 2) | def index

FILE: app/controllers/countries_controller.rb
  class CountriesController (line 1) | class CountriesController < ApplicationController
    method index (line 7) | def index
    method show (line 30) | def show
    method filter_events_by_time (line 68) | def filter_events_by_time(events)
    method find_nearby_users (line 72) | def find_nearby_users(country)
    method continent_upcoming_events (line 99) | def continent_upcoming_events(exclude_country_codes: [])

FILE: app/controllers/event_participations_controller.rb
  class EventParticipationsController (line 1) | class EventParticipationsController < ApplicationController
    method create (line 10) | def create
    method destroy (line 29) | def destroy
    method participation_params (line 43) | def participation_params

FILE: app/controllers/events/archive_controller.rb
  class Events::ArchiveController (line 1) | class Events::ArchiveController < ApplicationController
    method index (line 4) | def index

FILE: app/controllers/events/attendances_controller.rb
  class Events::AttendancesController (line 1) | class Events::AttendancesController < ApplicationController
    method index (line 6) | def index
    method show (line 30) | def show
    method set_event (line 51) | def set_event

FILE: app/controllers/events/cfp_controller.rb
  class Events::CFPController (line 1) | class Events::CFPController < ApplicationController
    method index (line 5) | def index
    method set_event (line 11) | def set_event

FILE: app/controllers/events/collectibles_controller.rb
  class Events::CollectiblesController (line 1) | class Events::CollectiblesController < ApplicationController
    method index (line 6) | def index
    method set_event (line 13) | def set_event

FILE: app/controllers/events/events_controller.rb
  class Events::EventsController (line 1) | class Events::EventsController < ApplicationController
    method index (line 5) | def index
    method show (line 9) | def show
    method set_event (line 15) | def set_event

FILE: app/controllers/events/involvements_controller.rb
  class Events::InvolvementsController (line 1) | class Events::InvolvementsController < ApplicationController
    method index (line 4) | def index

FILE: app/controllers/events/meetups_controller.rb
  class Events::MeetupsController (line 1) | class Events::MeetupsController < ApplicationController
    method index (line 5) | def index

FILE: app/controllers/events/participants_controller.rb
  class Events::ParticipantsController (line 1) | class Events::ParticipantsController < ApplicationController
    method index (line 11) | def index

FILE: app/controllers/events/past_controller.rb
  class Events::PastController (line 1) | class Events::PastController < ApplicationController
    method index (line 4) | def index

FILE: app/controllers/events/related_talks_controller.rb
  class Events::RelatedTalksController (line 1) | class Events::RelatedTalksController < ApplicationController
    method index (line 8) | def index
    method set_event (line 15) | def set_event
    method set_user_favorites (line 20) | def set_user_favorites

FILE: app/controllers/events/schedules_controller.rb
  class Events::SchedulesController (line 1) | class Events::SchedulesController < ApplicationController
    method index (line 5) | def index
    method show (line 15) | def show
    method set_event (line 23) | def set_event
    method set_talks (line 37) | def set_talks(day)

FILE: app/controllers/events/series_controller.rb
  class Events::SeriesController (line 1) | class Events::SeriesController < ApplicationController
    method index (line 9) | def index
    method show (line 14) | def show
    method reimport (line 29) | def reimport
    method reindex (line 41) | def reindex
    method set_event_series (line 56) | def set_event_series
    method require_admin! (line 65) | def require_admin!

FILE: app/controllers/events/speakers_controller.rb
  class Events::SpeakersController (line 1) | class Events::SpeakersController < ApplicationController
    method index (line 5) | def index
    method set_event (line 27) | def set_event

FILE: app/controllers/events/sponsors_controller.rb
  class Events::SponsorsController (line 1) | class Events::SponsorsController < ApplicationController
    method index (line 6) | def index
    method set_event (line 12) | def set_event

FILE: app/controllers/events/talks_controller.rb
  class Events::TalksController (line 1) | class Events::TalksController < ApplicationController
    method index (line 8) | def index
    method set_event (line 14) | def set_event
    method set_user_favorites (line 21) | def set_user_favorites

FILE: app/controllers/events/tickets_controller.rb
  class Events::TicketsController (line 1) | class Events::TicketsController < ApplicationController
    method show (line 5) | def show
    method set_event (line 10) | def set_event

FILE: app/controllers/events/todos_controller.rb
  class Events::TodosController (line 1) | class Events::TodosController < ApplicationController
    method index (line 5) | def index
    method set_event (line 13) | def set_event

FILE: app/controllers/events/upcoming_controller.rb
  class Events::UpcomingController (line 1) | class Events::UpcomingController < ApplicationController
    method index (line 4) | def index

FILE: app/controllers/events/venues_controller.rb
  class Events::VenuesController (line 1) | class Events::VenuesController < ApplicationController
    method show (line 5) | def show
    method set_event (line 16) | def set_event

FILE: app/controllers/events/videos_controller.rb
  class Events::VideosController (line 1) | class Events::VideosController < ApplicationController
    method index (line 8) | def index
    method set_event (line 15) | def set_event
    method set_user_favorites (line 20) | def set_user_favorites

FILE: app/controllers/events/years_controller.rb
  type Events (line 1) | module Events
    class YearsController (line 2) | class YearsController < ApplicationController
      method index (line 5) | def index

FILE: app/controllers/events_controller.rb
  class EventsController (line 1) | class EventsController < ApplicationController
    method index (line 11) | def index
    method show (line 18) | def show
    method edit (line 41) | def edit
    method update (line 45) | def update
    method reimport (line 56) | def reimport
    method reindex (line 68) | def reindex
    method set_event (line 80) | def set_event
    method event_params (line 92) | def event_params
    method set_user_favorites (line 96) | def set_user_favorites
    method require_admin! (line 102) | def require_admin!

FILE: app/controllers/favorite_users_controller.rb
  class FavoriteUsersController (line 1) | class FavoriteUsersController < ApplicationController
    method index (line 5) | def index
    method create (line 12) | def create
    method update (line 26) | def update
    method destroy (line 43) | def destroy
    method set_favorite_user (line 54) | def set_favorite_user
    method favorite_user_params (line 59) | def favorite_user_params

FILE: app/controllers/gems_controller.rb
  class GemsController (line 1) | class GemsController < ApplicationController
    method index (line 9) | def index
    method show (line 25) | def show
    method talks (line 34) | def talks
    method set_gem (line 49) | def set_gem
    method set_user_favorites (line 54) | def set_user_favorites
    method page_number (line 60) | def page_number

FILE: app/controllers/hotwire/native/v1/android/path_configurations_controller.rb
  class Hotwire::Native::V1::Android::PathConfigurationsController (line 1) | class Hotwire::Native::V1::Android::PathConfigurationsController < Actio...
    method show (line 2) | def show

FILE: app/controllers/hotwire/native/v1/ios/path_configurations_controller.rb
  class Hotwire::Native::V1::IOS::PathConfigurationsController (line 1) | class Hotwire::Native::V1::IOS::PathConfigurationsController < ActionCon...
    method show (line 2) | def show

FILE: app/controllers/hover_cards/events_controller.rb
  class HoverCards::EventsController (line 3) | class HoverCards::EventsController < ApplicationController
    method show (line 6) | def show

FILE: app/controllers/hover_cards/users_controller.rb
  class HoverCards::UsersController (line 3) | class HoverCards::UsersController < ApplicationController
    method show (line 8) | def show

FILE: app/controllers/leaderboard_controller.rb
  class LeaderboardController (line 1) | class LeaderboardController < ApplicationController
    method index (line 4) | def index

FILE: app/controllers/locations/base_controller.rb
  class Locations::BaseController (line 3) | class Locations::BaseController < ApplicationController
    method set_location (line 12) | def set_location
    method set_online (line 34) | def set_online
    method set_coordinates (line 38) | def set_coordinates
    method set_continent (line 46) | def set_continent
    method set_country (line 52) | def set_country
    method set_state (line 59) | def set_state
    method set_featured_city (line 69) | def set_featured_city
    method set_city_by_country (line 81) | def set_city_by_country
    method set_city_with_state (line 106) | def set_city_with_state
    method redirect_path_helper (line 139) | def redirect_path_helper
    method location_events (line 143) | def location_events
    method upcoming_events (line 147) | def upcoming_events
    method past_events (line 151) | def past_events
    method location_users (line 155) | def location_users
    method load_nearby_data (line 163) | def load_nearby_data
    method load_cities (line 171) | def load_cities
    method load_nearby_events (line 181) | def load_nearby_events
    method country_upcoming_events (line 191) | def country_upcoming_events(exclude_ids: [])
    method continent_upcoming_events (line 201) | def continent_upcoming_events(exclude_country_codes: [])
    method online? (line 211) | def online?
    method coordinate? (line 215) | def coordinate?
    method city? (line 219) | def city?
    method state? (line 223) | def state?
    method country? (line 227) | def country?
    method continent? (line 231) | def continent?
    method location_view_prefix (line 235) | def location_view_prefix
    method render_location_view (line 246) | def render_location_view(action)

FILE: app/controllers/locations/map_controller.rb
  class Locations::MapController (line 3) | class Locations::MapController < Locations::BaseController
    method index (line 4) | def index
    method build_time_filter_options (line 15) | def build_time_filter_options
    method build_geographic_layers (line 28) | def build_geographic_layers
    method select_default_visible_layer (line 47) | def select_default_visible_layer(layers)
    method build_continent_geo_layers (line 71) | def build_continent_geo_layers
    method build_country_geo_layers (line 95) | def build_country_geo_layers
    method build_state_geo_layers (line 130) | def build_state_geo_layers
    method build_city_geo_layers (line 178) | def build_city_geo_layers
    method build_coordinate_geo_layers (line 278) | def build_coordinate_geo_layers
    method fetch_online_events (line 358) | def fetch_online_events
    method redirect_path_helper (line 376) | def redirect_path_helper

FILE: app/controllers/locations/meetups_controller.rb
  class Locations::MeetupsController (line 3) | class Locations::MeetupsController < Locations::BaseController
    method index (line 4) | def index
    method redirect_path_helper (line 16) | def redirect_path_helper

FILE: app/controllers/locations/past_controller.rb
  class Locations::PastController (line 3) | class Locations::PastController < Locations::BaseController
    method index (line 6) | def index
    method filter_events_by_time (line 21) | def filter_events_by_time(events)
    method redirect_path_helper (line 25) | def redirect_path_helper

FILE: app/controllers/locations/stamps_controller.rb
  class Locations::StampsController (line 3) | class Locations::StampsController < Locations::BaseController
    method index (line 4) | def index
    method redirect_path_helper (line 12) | def redirect_path_helper

FILE: app/controllers/locations/users_controller.rb
  class Locations::UsersController (line 3) | class Locations::UsersController < Locations::BaseController
    method index (line 4) | def index
    method load_nearby_users (line 20) | def load_nearby_users
    method load_state_users (line 30) | def load_state_users
    method load_coordinate_nearby_users (line 39) | def load_coordinate_nearby_users
    method load_country_users (line 47) | def load_country_users
    method redirect_path_helper (line 54) | def redirect_path_helper

FILE: app/controllers/online_controller.rb
  class OnlineController (line 3) | class OnlineController < ApplicationController
    method show (line 6) | def show

FILE: app/controllers/organizations/logos_controller.rb
  class Organizations::LogosController (line 1) | class Organizations::LogosController < ApplicationController
    method show (line 5) | def show
    method update (line 9) | def update
    method set_organization (line 19) | def set_organization
    method ensure_admin! (line 24) | def ensure_admin!
    method organization_params (line 28) | def organization_params

FILE: app/controllers/organizations/wrapped_controller.rb
  class Organizations::WrappedController (line 1) | class Organizations::WrappedController < ApplicationController
    method index (line 8) | def index
    method og_image (line 63) | def og_image
    method set_organization (line 76) | def set_organization
    method set_wrapped_meta_tags (line 80) | def set_wrapped_meta_tags
    method ensure_card_generated (line 104) | def ensure_card_generated
    method wrapped_locals (line 135) | def wrapped_locals

FILE: app/controllers/organizations_controller.rb
  class OrganizationsController (line 1) | class OrganizationsController < ApplicationController
    method index (line 6) | def index
    method show (line 13) | def show
    method prepare_organization_statistics (line 31) | def prepare_organization_statistics
    method classify_event_size (line 50) | def classify_event_size(event)
    method set_organization (line 74) | def set_organization

FILE: app/controllers/page_controller.rb
  class PageController (line 1) | class PageController < ApplicationController
    method home (line 4) | def home
    method featured (line 92) | def featured
    method components (line 95) | def components
    method uses (line 98) | def uses
    method privacy (line 101) | def privacy
    method about (line 104) | def about
    method stickers (line 107) | def stickers
    method contributors (line 111) | def contributors
    method assets (line 115) | def assets

FILE: app/controllers/profiles/aliases_controller.rb
  class Profiles::AliasesController (line 1) | class Profiles::AliasesController < ApplicationController
    method index (line 6) | def index
    method require_admin! (line 12) | def require_admin!

FILE: app/controllers/profiles/claims_controller.rb
  class Profiles::ClaimsController (line 1) | class Profiles::ClaimsController < ApplicationController
    method create (line 2) | def create

FILE: app/controllers/profiles/connect_controller.rb
  class Profiles::ConnectController (line 1) | class Profiles::ConnectController < ApplicationController
    method index (line 4) | def index
    method show (line 8) | def show
    method current_user_passport? (line 23) | def current_user_passport?
    method passport_already_claimed? (line 29) | def passport_already_claimed?

FILE: app/controllers/profiles/enhance_controller.rb
  class Profiles::EnhanceController (line 1) | class Profiles::EnhanceController < ApplicationController
    method update (line 2) | def update

FILE: app/controllers/profiles/events_controller.rb
  class Profiles::EventsController (line 1) | class Profiles::EventsController < ApplicationController
    method index (line 4) | def index

FILE: app/controllers/profiles/involvements_controller.rb
  class Profiles::InvolvementsController (line 1) | class Profiles::InvolvementsController < ApplicationController
    method index (line 4) | def index

FILE: app/controllers/profiles/map_controller.rb
  class Profiles::MapController (line 1) | class Profiles::MapController < ApplicationController
    method index (line 5) | def index

FILE: app/controllers/profiles/mutual_events_controller.rb
  class Profiles::MutualEventsController (line 1) | class Profiles::MutualEventsController < ApplicationController
    method index (line 4) | def index

FILE: app/controllers/profiles/notes_controller.rb
  class Profiles::NotesController (line 4) | class Profiles::NotesController < ApplicationController
    method edit (line 9) | def edit
    method show (line 12) | def show
    method check_favorite_user_persisted? (line 17) | def check_favorite_user_persisted?

FILE: app/controllers/profiles/stamps_controller.rb
  class Profiles::StampsController (line 1) | class Profiles::StampsController < ApplicationController
    method index (line 4) | def index

FILE: app/controllers/profiles/stickers_controller.rb
  class Profiles::StickersController (line 1) | class Profiles::StickersController < ApplicationController
    method index (line 4) | def index

FILE: app/controllers/profiles/talks_controller.rb
  class Profiles::TalksController (line 1) | class Profiles::TalksController < ApplicationController
    method index (line 4) | def index

FILE: app/controllers/profiles/wrapped_controller.rb
  class Profiles::WrappedController (line 1) | class Profiles::WrappedController < ApplicationController
    method index (line 10) | def index
    method card (line 234) | def card
    method toggle_visibility (line 261) | def toggle_visibility
    method og_image (line 281) | def og_image
    method generate_card (line 294) | def generate_card
    method set_wrapped_meta_tags (line 313) | def set_wrapped_meta_tags
    method calculate_longest_streak (line 338) | def calculate_longest_streak
    method determine_personality (line 359) | def determine_personality
    method find_conference_buddies (line 422) | def find_conference_buddies
    method find_watch_twin (line 448) | def find_watch_twin
    method check_wrapped_access (line 472) | def check_wrapped_access
    method require_owner (line 481) | def require_owner
    method wrapped_locals (line 487) | def wrapped_locals

FILE: app/controllers/profiles_controller.rb
  class ProfilesController (line 1) | class ProfilesController < ApplicationController
    method show (line 16) | def show
    method edit (line 27) | def edit
    method update (line 32) | def update
    method reindex (line 42) | def reindex
    method require_admin! (line 51) | def require_admin!
    method load_profile_data_for_show (line 55) | def load_profile_data_for_show
    method user_kind (line 91) | def user_kind
    method set_user (line 100) | def set_user
    method user_params (line 119) | def user_params
    method set_favorite_user (line 136) | def set_favorite_user
    method set_mutual_events (line 140) | def set_mutual_events
    method set_user_favorites (line 148) | def set_user_favorites

FILE: app/controllers/recommendations_controller.rb
  class RecommendationsController (line 1) | class RecommendationsController < ApplicationController
    method index (line 4) | def index

FILE: app/controllers/sessions/omniauth_controller.rb
  class Sessions::OmniauthController (line 1) | class Sessions::OmniauthController < ApplicationController
    method create (line 5) | def create
    method failure (line 56) | def failure
    method omniauth_username (line 62) | def omniauth_username
    method initialize_user (line 66) | def initialize_user
    method email (line 76) | def email
    method github_email (line 84) | def github_email
    method token (line 88) | def token
    method redirect_to_path (line 92) | def redirect_to_path
    method username (line 96) | def username
    method omniauth_params (line 100) | def omniauth_params
    method omniauth (line 110) | def omniauth
    method query_params (line 114) | def query_params
    method state (line 118) | def state
    method fetch_github_email (line 122) | def fetch_github_email(oauth_token)

FILE: app/controllers/sessions_controller.rb
  class SessionsController (line 1) | class SessionsController < ApplicationController
    method new (line 8) | def new
    method create (line 15) | def create
    method destroy (line 26) | def destroy

FILE: app/controllers/settings_controller.rb
  class SettingsController (line 1) | class SettingsController < ApplicationController
    method show (line 4) | def show
    method update (line 7) | def update
    method settings_params (line 17) | def settings_params

FILE: app/controllers/sitemaps_controller.rb
  class SitemapsController (line 1) | class SitemapsController < ApplicationController
    method show (line 4) | def show
    method generate_sitemap_string (line 10) | def generate_sitemap_string
    class SitemapStringAdapter (line 45) | class SitemapStringAdapter
      method write (line 48) | def write(location, raw_data)

FILE: app/controllers/speakers_controller.rb
  class SpeakersController (line 1) | class SpeakersController < ApplicationController
    method index (line 6) | def index

FILE: app/controllers/sponsors/missing_controller.rb
  class Sponsors::MissingController (line 1) | class Sponsors::MissingController < ApplicationController
    method index (line 5) | def index

FILE: app/controllers/spotlight/events_controller.rb
  class Spotlight::EventsController (line 1) | class Spotlight::EventsController < ApplicationController
    method index (line 9) | def index
    method search_query (line 25) | def search_query

FILE: app/controllers/spotlight/kinds_controller.rb
  class Spotlight::KindsController (line 1) | class Spotlight::KindsController < ApplicationController
    method index (line 9) | def index
    method search_backend (line 24) | def search_backend
    method search_query (line 29) | def search_query

FILE: app/controllers/spotlight/languages_controller.rb
  class Spotlight::LanguagesController (line 1) | class Spotlight::LanguagesController < ApplicationController
    method index (line 9) | def index
    method search_query (line 25) | def search_query

FILE: app/controllers/spotlight/locations_controller.rb
  class Spotlight::LocationsController (line 1) | class Spotlight::LocationsController < ApplicationController
    method index (line 9) | def index
    method geocode_query (line 28) | def geocode_query(query)
    method search_query (line 46) | def search_query

FILE: app/controllers/spotlight/organizations_controller.rb
  class Spotlight::OrganizationsController (line 1) | class Spotlight::OrganizationsController < ApplicationController
    method index (line 9) | def index
    method search_query (line 25) | def search_query

FILE: app/controllers/spotlight/series_controller.rb
  class Spotlight::SeriesController (line 1) | class Spotlight::SeriesController < ApplicationController
    method index (line 9) | def index
    method search_query (line 25) | def search_query

FILE: app/controllers/spotlight/speakers_controller.rb
  class Spotlight::SpeakersController (line 1) | class Spotlight::SpeakersController < ApplicationController
    method index (line 9) | def index
    method search_query (line 28) | def search_query

FILE: app/controllers/spotlight/talks_controller.rb
  class Spotlight::TalksController (line 1) | class Spotlight::TalksController < ApplicationController
    method index (line 9) | def index
    method search_query (line 27) | def search_query

FILE: app/controllers/spotlight/topics_controller.rb
  class Spotlight::TopicsController (line 1) | class Spotlight::TopicsController < ApplicationController
    method index (line 9) | def index
    method search_query (line 25) | def search_query

FILE: app/controllers/stamps_controller.rb
  class StampsController (line 1) | class StampsController < ApplicationController
    method index (line 4) | def index

FILE: app/controllers/states/base_controller.rb
  class States::BaseController (line 3) | class States::BaseController < ApplicationController
    method set_state (line 10) | def set_state

FILE: app/controllers/states/cities_controller.rb
  class States::CitiesController (line 3) | class States::CitiesController < States::BaseController
    method index (line 4) | def index

FILE: app/controllers/states_controller.rb
  class StatesController (line 1) | class StatesController < ApplicationController
    method index (line 7) | def index
    method country_index (line 13) | def country_index
    method show (line 24) | def show
    method filter_events_by_time (line 69) | def filter_events_by_time(events)

FILE: app/controllers/talks/recommendations_controller.rb
  class Talks::RecommendationsController (line 1) | class Talks::RecommendationsController < ApplicationController
    method index (line 7) | def index
    method set_talk (line 15) | def set_talk

FILE: app/controllers/talks/slides_controller.rb
  class Talks::SlidesController (line 1) | class Talks::SlidesController < ApplicationController
    method show (line 8) | def show

FILE: app/controllers/talks/watched_talks_controller.rb
  class Talks::WatchedTalksController (line 1) | class Talks::WatchedTalksController < ApplicationController
    method new (line 11) | def new
    method create (line 16) | def create
    method destroy (line 27) | def destroy
    method toggle_attendance (line 36) | def toggle_attendance
    method toggle_online (line 62) | def toggle_online
    method update (line 89) | def update
    method watched_talk_params (line 124) | def watched_talk_params
    method set_talk (line 136) | def set_talk
    method should_auto_mark? (line 140) | def should_auto_mark?(progress_seconds)
    method broadcast_update_to_event_talks (line 148) | def broadcast_update_to_event_talks

FILE: app/controllers/talks_controller.rb
  class TalksController (line 1) | class TalksController < ApplicationController
    method index (line 16) | def index
    method show (line 25) | def show
    method edit (line 30) | def edit
    method update (line 35) | def update
    method search_backend (line 46) | def search_backend
    method search_options (line 50) | def search_options
    method sort_key (line 66) | def sort_key
    method order_by_key (line 75) | def order_by_key
    method filtered_search? (line 84) | def filtered_search?
    method explicit_ordering_requested? (line 88) | def explicit_ordering_requested?
    method created_after (line 92) | def created_after
    method talk_kind (line 98) | def talk_kind
    method set_talk (line 103) | def set_talk
    method talk_params (line 114) | def talk_params
    method search_params (line 119) | def search_params
    method set_user_favorites (line 123) | def set_user_favorites

FILE: app/controllers/templates_controller.rb
  class TemplatesController (line 1) | class TemplatesController < ApplicationController
    method new (line 8) | def new
    method create (line 12) | def create
    method new_child (line 22) | def new_child
    method delete_child (line 26) | def delete_child
    method speakers_search (line 29) | def speakers_search
    method speakers_search_chips (line 35) | def speakers_search_chips
    method search_query (line 46) | def search_query
    method talk_params (line 50) | def talk_params

FILE: app/controllers/todos_controller.rb
  class TodosController (line 1) | class TodosController < ApplicationController
    method index (line 6) | def index
    method group_by_type (line 25) | def group_by_type(matches)
    method group_by_series (line 38) | def group_by_series(todos)

FILE: app/controllers/topics_controller.rb
  class TopicsController (line 1) | class TopicsController < ApplicationController
    method index (line 8) | def index
    method show (line 14) | def show
    method set_user_favorites (line 28) | def set_user_favorites
    method page_number (line 36) | def page_number

FILE: app/controllers/watch_list_talks_controller.rb
  class WatchListTalksController (line 1) | class WatchListTalksController < ApplicationController
    method create (line 5) | def create
    method destroy (line 11) | def destroy
    method set_watch_list (line 19) | def set_watch_list

FILE: app/controllers/watch_lists_controller.rb
  class WatchListsController (line 1) | class WatchListsController < ApplicationController
    method index (line 7) | def index
    method show (line 12) | def show
    method new (line 15) | def new
    method create (line 19) | def create
    method edit (line 28) | def edit
    method update (line 31) | def update
    method destroy (line 39) | def destroy
    method set_watch_list (line 46) | def set_watch_list
    method watch_list_params (line 50) | def watch_list_params

FILE: app/controllers/watched_talks_controller.rb
  class WatchedTalksController (line 1) | class WatchedTalksController < ApplicationController
    method index (line 5) | def index
    method destroy (line 21) | def destroy

FILE: app/controllers/wrapped_controller.rb
  class WrappedController (line 1) | class WrappedController < ApplicationController
    method index (line 7) | def index
    method set_wrapped_meta_tags (line 133) | def set_wrapped_meta_tags
    method find_country_from_location (line 157) | def find_country_from_location(location_string)
    method country_codes_with_events (line 171) | def country_codes_with_events
    method events_by_attendees (line 179) | def events_by_attendees
    method events_by_sessions (line 190) | def events_by_sessions
    method languages (line 201) | def languages
    method most_watched_events (line 211) | def most_watched_events
    method most_watched_talks_slugs (line 220) | def most_watched_talks_slugs
    method new_speakers (line 231) | def new_speakers
    method open_cfps (line 240) | def open_cfps
    method people_involved (line 249) | def people_involved
    method rubyist_countries (line 258) | def rubyist_countries
    method top_organizations_slugs (line 268) | def top_organizations_slugs
    method top_topics_slugs (line 279) | def top_topics_slugs
    method total_page_views (line 290) | def total_page_views
    method total_visits (line 298) | def total_visits
    method unique_sponsors (line 306) | def unique_sponsors

FILE: app/helpers/application_helper.rb
  type ApplicationHelper (line 1) | module ApplicationHelper
    function back_path (line 4) | def back_path
    function back_to_from_request (line 8) | def back_to_from_request
    function active_link_to (line 15) | def active_link_to(text = nil, path = nil, active_class: "", **options...
    function footer_credits (line 26) | def footer_credits
    function canonical_url (line 43) | def canonical_url
    function sanitize_url (line 47) | def sanitize_url(url, fallback: "")

FILE: app/helpers/events/talks_helper.rb
  type Events::TalksHelper (line 1) | module Events::TalksHelper

FILE: app/helpers/events_helper.rb
  type EventsHelper (line 1) | module EventsHelper
    function event_date_display (line 2) | def event_date_display(event, day_name: false)
    function event_date_group_key (line 19) | def event_date_group_key(event)
    function group_events_by_date (line 32) | def group_events_by_date(events)
    function home_updated_text (line 48) | def home_updated_text(event)

FILE: app/helpers/icon_helper.rb
  type IconHelper (line 3) | module IconHelper
    function clear_cache (line 18) | def clear_cache
    function cached_inline_svg (line 23) | def cached_inline_svg(path, **options)
    function fontawesome (line 68) | def fontawesome(icon_name, size: :md, type: nil, style: :solid, **opti...
    function fab (line 73) | def fab(icon_name, **options)
    function fa (line 77) | def fa(icon_name, **options)
    function icon (line 81) | def icon(icon_name, size: :md, **options)

FILE: app/helpers/language_helper.rb
  type LanguageHelper (line 1) | module LanguageHelper
    function language_to_emoji (line 139) | def language_to_emoji(language)

FILE: app/helpers/location_helper.rb
  type LocationHelper (line 3) | module LocationHelper
    function location_path (line 4) | def location_path(location)
    function location_past_path (line 8) | def location_past_path(location)
    function location_users_path (line 12) | def location_users_path(location)
    function location_meetups_path (line 16) | def location_meetups_path(location)
    function location_countries_path (line 20) | def location_countries_path(location)
    function location_cities_path (line 24) | def location_cities_path(location)
    function location_stamps_path (line 28) | def location_stamps_path(location)
    function location_map_path (line 32) | def location_map_path(location)
    function location_has_routes? (line 36) | def location_has_routes?(location)

FILE: app/helpers/markdown_helper.rb
  type MarkdownHelper (line 1) | module MarkdownHelper
    class SyntaxHighlightedRenderer (line 3) | class SyntaxHighlightedRenderer < Redcarpet::Render::HTML
      method block_code (line 4) | def block_code(code, language)
    function markdown_to_html (line 13) | def markdown_to_html(markdown_content)
    function announcement_markdown_to_html (line 19) | def announcement_markdown_to_html(markdown_content)
    function process_mentions (line 40) | def process_mentions(html)
    function process_topics (line 55) | def process_topics(html)

FILE: app/helpers/page_helper.rb
  type PageHelper (line 1) | module PageHelper

FILE: app/helpers/speakers/enhance_helper.rb
  type Speakers::EnhanceHelper (line 1) | module Speakers::EnhanceHelper

FILE: app/helpers/speakers_helper.rb
  type SpeakersHelper (line 1) | module SpeakersHelper
    function form_title_for_user_kind (line 2) | def form_title_for_user_kind(user_kind)

FILE: app/helpers/spotlight_helper.rb
  type SpotlightHelper (line 1) | module SpotlightHelper
    function spotlight_resources (line 2) | def spotlight_resources
    function spotlight_main_resource (line 6) | def spotlight_main_resource
    function spotlight_main_resource_path (line 10) | def spotlight_main_resource_path
    function spotlight_search_backend (line 19) | def spotlight_search_backend
    function spotlight_can_search_locations? (line 23) | def spotlight_can_search_locations?
    function spotlight_can_search_languages? (line 27) | def spotlight_can_search_languages?
    function spotlight_can_search_series? (line 31) | def spotlight_can_search_series?

FILE: app/helpers/suggestions_helper.rb
  type SuggestionsHelper (line 1) | module SuggestionsHelper

FILE: app/helpers/talks_helper.rb
  type TalksHelper (line 1) | module TalksHelper
    function seconds_to_formatted_duration (line 2) | def seconds_to_formatted_duration(seconds)
    function ordering_title (line 6) | def ordering_title
    function resource_icon (line 17) | def resource_icon(resource)
    function resource_display_title (line 36) | def resource_display_title(resource)
    function resource_domain (line 40) | def resource_domain(resource)

FILE: app/helpers/view_component_helper.rb
  type ViewComponentHelper (line 1) | module ViewComponentHelper
    function ui_tooltip (line 18) | def ui_tooltip(text, **kwargs, &block)
    function external_link_to (line 24) | def external_link_to(text, url = nil, **attributes, &)

FILE: app/javascript/controllers/auto-click_controller.js
  method initialize (line 10) | initialize () {
  method appear (line 14) | appear () {

FILE: app/javascript/controllers/auto_submit_controller.js
  method initialize (line 7) | initialize () {
  method disconnect (line 14) | disconnect () {
  method submit (line 19) | submit () {

FILE: app/javascript/controllers/bridge/button_controller.js
  method connect (line 7) | connect () {
  method targetElement (line 15) | get targetElement () {
  method title (line 23) | get title () {

FILE: app/javascript/controllers/collapsible_controller.js
  method connect (line 9) | connect () {
  method toggle (line 13) | toggle () {
  method close (line 17) | close () {
  method open (line 21) | open () {
  method openValueChanged (line 25) | openValueChanged () {
  method updateVisibility (line 35) | updateVisibility () {

FILE: app/javascript/controllers/content_row_controller.js
  method connect (line 6) | connect () {
  method scrollLeft (line 10) | scrollLeft () {
  method scrollRight (line 15) | scrollRight () {
  method handleScroll (line 20) | handleScroll () {
  method updateButtonVisibility (line 24) | updateButtonVisibility () {
  method cardWidth (line 44) | get cardWidth () {

FILE: app/javascript/controllers/copy_to_clipboard_controller.js
  method copy (line 12) | async copy (event) {
  method fallbackCopy (line 30) | fallbackCopy (text) {
  method copied (line 39) | copied () {

FILE: app/javascript/controllers/dropdown_controller.js
  method connect (line 7) | connect () {
  method disconnect (line 12) | disconnect () {
  method clickOutside (line 17) | clickOutside (event) {
  method toggle (line 23) | toggle (event) {
  method #close (line 33) | #close (event) {

FILE: app/javascript/controllers/event_controller.js
  method dispatchEvent (line 9) | dispatchEvent (e) {

FILE: app/javascript/controllers/event_list_controller.js
  method connect (line 6) | connect () {
  method reveal (line 13) | reveal (event) {
  method hidePosters (line 20) | hidePosters () {
  method posterTargetFor (line 24) | posterTargetFor (eventId) {
  method updateGradients (line 28) | updateGradients () {

FILE: app/javascript/controllers/events_filter_controller.js
  method filter (line 7) | filter (event) {
  method currentValueChanged (line 11) | currentValueChanged () {
  method updateButtons (line 17) | updateButtons () {
  method filterEvents (line 24) | filterEvents () {
  method updateGroups (line 32) | updateGroups () {

FILE: app/javascript/controllers/events_view_switcher_controller.js
  method connect (line 7) | connect () {
  method showPreview (line 12) | showPreview () {
  method showList (line 16) | showList () {
  method switchTo (line 20) | switchTo (view) {

FILE: app/javascript/controllers/geolocation_controller.js
  method locate (line 6) | locate () {
  method success (line 27) | success (position) {
  method error (line 36) | error (error) {
  method showStatus (line 56) | showStatus (message) {

FILE: app/javascript/controllers/hover_card_controller.js
  method connect (line 8) | connect () {
  method reveal (line 12) | reveal () {
  method resize (line 21) | resize () {
  method scheduleAdjustPosition (line 28) | scheduleAdjustPosition () {
  method adjustPosition (line 32) | adjustPosition () {

FILE: app/javascript/controllers/lazy_loading_controller.js
  method initialize (line 11) | initialize () {
  method appear (line 15) | appear () {

FILE: app/javascript/controllers/map_controller.js
  method connect (line 18) | connect () {
  method #initTimeFilter (line 51) | #initTimeFilter () {
  method toggleLayer (line 64) | toggleLayer (event) {
  method filterByTime (line 74) | filterByTime (event) {
  method #applyTimeFilter (line 89) | #applyTimeFilter () {
  method #updateLayerBadgeCounts (line 139) | #updateLayerBadgeCounts (counts) {
  method #filterEventsByTime (line 153) | #filterEventsByTime (events, filter) {
  method #fitToVisibleBounds (line 161) | #fitToVisibleBounds (bounds) {
  method selectLayer (line 182) | selectLayer (event) {
  method #fitToLayerBounds (line 217) | #fitToLayerBounds (bounds) {
  method #updateLayerVisibility (line 226) | #updateLayerVisibility (layerId, visible) {
  method #updateButtonState (line 236) | #updateButtonState (input) {
  method #loadLayers (line 261) | #loadLayers () {
  method #fitToBounds (line 347) | #fitToBounds () {
  method #loadMarkers (line 365) | #loadMarkers () {
  method #loadEventMarkers (line 375) | #loadEventMarkers () {
  method #loadVenueMarkers (line 409) | #loadVenueMarkers () {
  method disconnect (line 435) | disconnect () {
  method #createMarkerElement (line 441) | #createMarkerElement (events) {
  method #createPopup (line 447) | #createPopup (events) {
  method #html (line 454) | #html (strings, ...values) {
  method #singleMarkerTemplate (line 460) | #singleMarkerTemplate (event) {
  method #groupMarkerTemplate (line 472) | #groupMarkerTemplate (events) {
  method #popupTemplate (line 505) | #popupTemplate (events) {
  method #createCityPinElement (line 525) | #createCityPinElement (name) {
  method #createCityPinPopup (line 536) | #createCityPinPopup (name) {
  method #createVenueMarkerElement (line 547) | #createVenueMarkerElement (marker) {
  method #createVenuePopup (line 570) | #createVenuePopup (marker) {
  method #venuePopupTemplate (line 577) | #venuePopupTemplate (marker) {

FILE: app/javascript/controllers/modal_controller.js
  method initialize (line 12) | initialize () {
  method connect (line 21) | connect () {
  method disconnect (line 27) | disconnect () {
  method clickOutside (line 31) | clickOutside (event) {
  method open (line 35) | open () {
  method close (line 40) | close (e) {
  method toggle (line 47) | get toggle () {

FILE: app/javascript/controllers/preserve_scroll_controller.js
  method connect (line 6) | async connect () {
  method updateLinkBackToWithScrollPosition (line 18) | updateLinkBackToWithScrollPosition (e) {
  method scrollTop (line 44) | get scrollTop () {

FILE: app/javascript/controllers/pronouns_select_controller.js
  method connect (line 9) | connect () {
  method change (line 13) | change () {
  method updateInputVisibility (line 23) | updateInputVisibility () {

FILE: app/javascript/controllers/scroll_controller.js
  method connect (line 6) | connect () {
  method checkScroll (line 10) | checkScroll () {
  method isAtEnd (line 18) | get isAtEnd () {

FILE: app/javascript/controllers/scroll_into_view_controller.js
  method connect (line 9) | connect () {
  method elementToScroll (line 13) | get elementToScroll () {

FILE: app/javascript/controllers/splide_controller.js
  method connect (line 7) | connect () {
  method disconnect (line 28) | disconnect () {
  method #reset (line 33) | #reset () {
  method #shouldUpdateNavbar (line 37) | #shouldUpdateNavbar () {
  method #updateNavbarColors (line 41) | #updateNavbarColors () {
  method splideOptions (line 60) | get splideOptions () {
  method hiddenSlides (line 70) | get hiddenSlides () {

FILE: app/javascript/controllers/spotlight_search_controller.js
  method initialize (line 28) | initialize () {
  method connect (line 37) | connect () {}
  method disconnect (line 39) | disconnect () {
  method search (line 46) | async search () {
  method navigate (line 156) | navigate () {
  method clear (line 168) | clear () {
  method setBackend (line 176) | setBackend (event) {
  method appear (line 190) | appear () {
  method #loadDefaults (line 196) | async #loadDefaults () {
  method #handleSearch (line 231) | #handleSearch (url, query, abortController) {
  method #clearResults (line 261) | #clearResults () {
  method #toggleClearing (line 343) | #toggleClearing () {
  method #initBackendToggle (line 352) | #initBackendToggle () {
  method #updateBackendBadges (line 358) | #updateBackendBadges (backend) {
  method dialog (line 380) | get dialog () {
  method selectedOption (line 384) | get selectedOption () {

FILE: app/javascript/controllers/tabs_controller.js
  method initialize (line 7) | initialize () {
  method showPanel (line 14) | showPanel (e) {
  method activeIndexValueChanged (line 19) | activeIndexValueChanged () {
  method #togglePanel (line 25) | #togglePanel () {
  method tabPanels (line 35) | get tabPanels () {
  method tabs (line 39) | get tabs () {
  method activeTab (line 43) | get activeTab () {

FILE: app/javascript/controllers/talks_filter_controller.js
  method connect (line 9) | connect () {
  method toggle (line 13) | toggle () {
  method hideWatchedValueChanged (line 17) | hideWatchedValueChanged () {
  method talks (line 21) | get talks () {
  method updateVisibility (line 25) | updateVisibility () {

FILE: app/javascript/controllers/talks_filter_pill_controller.js
  method selectKind (line 17) | selectKind (event) {
  method selectLanguage (line 26) | selectLanguage (event) {
  method kindValueChanged (line 35) | kindValueChanged () {
  method languageValueChanged (line 39) | languageValueChanged () {
  method updateFilterResult (line 43) | updateFilterResult () {

FILE: app/javascript/controllers/talks_navigation_controller.js
  method connect (line 7) | connect () {
  method setActive (line 11) | setActive (e) {
  method elementToScroll (line 18) | get elementToScroll () {

FILE: app/javascript/controllers/toggable_controller.js
  method connect (line 13) | connect () {
  method toggle (line 19) | toggle () {
  method nextToggleText (line 24) | get nextToggleText () {

FILE: app/javascript/controllers/tooltip_controller.js
  method connect (line 12) | connect () {

FILE: app/javascript/controllers/top_banner_controller.js
  constant ONE_MONTH (line 5) | const ONE_MONTH = 30 * 24 * 60 * 60 * 1000 // 30 days in milliseconds
  constant COOKIE_NAME (line 6) | const COOKIE_NAME = 'top_banner_dismissed'
  method connect (line 9) | connect () {
  method dismiss (line 15) | dismiss () {
  method #setCookie (line 20) | #setCookie (name, value, days) {
  method isDismissed (line 32) | get isDismissed () {

FILE: app/javascript/controllers/transition_controller.js
  method connect (line 21) | connect () {
  method elementToTransition (line 46) | get elementToTransition () {
  method isPreview (line 50) | get isPreview () {

FILE: app/javascript/controllers/video_player_controller.js
  method initialize (line 28) | initialize () {
  method connect (line 32) | connect () {
  method init (line 38) | init () {
  method dismissWatchedOverlay (line 47) | dismissWatchedOverlay () {
  method resumePlayback (line 54) | resumePlayback () {
  method startPlayback (line 60) | startPlayback () {
  method showLoadingState (line 66) | showLoadingState (overlay) {
  method removeOverlays (line 83) | removeOverlays () {
  method options (line 89) | get options () {
  method appear (line 136) | appear () {
  method disappear (line 141) | disappear () {
  method handlePlayerReady (line 146) | handlePlayerReady (player) {
  method setupYouTubeEventLogging (line 196) | setupYouTubeEventLogging (player) {
  method startProgressTracking (line 221) | async startProgressTracking () {
  method stopProgressTracking (line 240) | stopProgressTracking () {
  method handleVideoPaused (line 247) | async handleVideoPaused () {
  method handleVideoEnded (line 255) | async handleVideoEnded () {
  method isFullyWatched (line 264) | isFullyWatched () {
  method updateWatchedProgress (line 270) | updateWatchedProgress (progressSeconds) {
  method createPlaybackRateSelect (line 286) | createPlaybackRateSelect (options, player) {
  method seekTo (line 303) | seekTo (event) {
  method pause (line 313) | pause () {
  method disconnect (line 319) | disconnect () {
  method #togglePictureInPicturePlayer (line 323) | #togglePictureInPicturePlayer (enabled) {
  method isPlaying (line 343) | get isPlaying () {
  method isPreview (line 353) | get isPreview () {
  method getCurrentTime (line 357) | async getCurrentTime () {

FILE: app/javascript/controllers/watched_talk_form_controller.js
  method selectWatchedOn (line 10) | selectWatchedOn (event) {
  method select (line 20) | select () {
  method autoSubmit (line 24) | autoSubmit () {

FILE: app/javascript/controllers/wrapped_stories_controller.js
  method connect (line 7) | connect () {
  method disconnect (line 13) | disconnect () {
  method handleInitialHash (line 17) | handleInitialHash () {
  method handleHashChange (line 30) | handleHashChange () {
  method findPageIndexByName (line 43) | findPageIndexByName (name) {
  method updateHash (line 47) | updateHash () {
  method toggleMode (line 57) | toggleMode () {
  method updateMode (line 62) | updateMode () {
  method next (line 81) | next () {
  method previous (line 88) | previous () {
  method goToPage (line 95) | goToPage (event) {
  method handleClick (line 103) | handleClick (event) {
  method handleKeydown (line 117) | handleKeydown (event) {
  method showPage (line 131) | showPage () {

FILE: app/javascript/helpers/timing_helpers.js
  function nextEventLoopTick (line 1) | function nextEventLoopTick () {
  function onNextEventLoopTick (line 5) | function onNextEventLoopTick (callback) {
  function nextFrame (line 9) | function nextFrame () {
  function nextEventNamed (line 13) | function nextEventNamed (eventName, element = window) {
  function delay (line 17) | function delay (ms) {

FILE: app/jobs/application_job.rb
  class ApplicationJob (line 1) | class ApplicationJob < ActiveJob::Base
    method retries (line 11) | def self.retries(attempts, wait: :polynomially_longer)

FILE: app/jobs/generate_wrapped_screenshot_job.rb
  class GenerateWrappedScreenshotJob (line 1) | class GenerateWrappedScreenshotJob < ApplicationJob
    method perform (line 5) | def perform(user)

FILE: app/jobs/geocode_record_job.rb
  class GeocodeRecordJob (line 3) | class GeocodeRecordJob < ApplicationJob
    method perform (line 8) | def perform(record)
    method geocode_concurrency_key (line 15) | def geocode_concurrency_key(record)

FILE: app/jobs/recurring/fetch_contributors_job.rb
  class Recurring::FetchContributorsJob (line 1) | class Recurring::FetchContributorsJob < ApplicationJob
    method perform (line 4) | def perform

FILE: app/jobs/recurring/mark_suspicious_users_job.rb
  class Recurring::MarkSuspiciousUsersJob (line 1) | class Recurring::MarkSuspiciousUsersJob < ApplicationJob
    method perform (line 4) | def perform
    method refresh_github_metadata (line 16) | def refresh_github_metadata(user)

FILE: app/jobs/recurring/rollup_job.rb
  class Recurring::RollupJob (line 1) | class Recurring::RollupJob < ApplicationJob
    method perform (line 7) | def perform(*args)
    method cleanup_suspicious_recent_visits (line 19) | def cleanup_suspicious_recent_visits
    method find_suspicious_ips (line 31) | def find_suspicious_ips
    method delete_visits_for_ip_in_batches (line 41) | def delete_visits_for_ip_in_batches(ip)

FILE: app/jobs/recurring/youtube_thumbnail_validation_job.rb
  class Recurring::YouTubeThumbnailValidationJob (line 3) | class Recurring::YouTubeThumbnailValidationJob < ApplicationJob
    method perform (line 10) | def perform
    method talks_to_check (line 24) | def talks_to_check
    method validate_thumbnail (line 31) | def validate_thumbnail(talk)

FILE: app/jobs/recurring/youtube_video_availability_job.rb
  class Recurring::YouTubeVideoAvailabilityJob (line 3) | class Recurring::YouTubeVideoAvailabilityJob < ApplicationJob
    method perform (line 10) | def perform
    method talks_to_check (line 24) | def talks_to_check

FILE: app/jobs/recurring/youtube_video_duration_job.rb
  class Recurring::YouTubeVideoDurationJob (line 1) | class Recurring::YouTubeVideoDurationJob < ApplicationJob
    method perform (line 4) | def perform

FILE: app/jobs/recurring/youtube_video_statistics_job.rb
  class Recurring::YouTubeVideoStatisticsJob (line 1) | class Recurring::YouTubeVideoStatisticsJob < ApplicationJob
    method perform (line 4) | def perform

FILE: app/jobs/typesense_index_job.rb
  class TypesenseIndexJob (line 3) | class TypesenseIndexJob < ApplicationJob
    method perform (line 6) | def perform(record, method)

FILE: app/lib/command.rb
  class Command (line 1) | class Command
    method run (line 2) | def self.run(command)

FILE: app/lib/download_sponsors.rb
  class DownloadSponsors (line 6) | class DownloadSponsors
    method initialize (line 7) | def initialize
    method download_sponsors (line 22) | def download_sponsors(save_file:, base_url: nil, sponsors_url: nil, ht...
    method find_sponsor_page (line 39) | def find_sponsor_page(url)
    method download_sponsors_data (line 70) | def download_sponsors_data(url, save_file:)
    method download_sponsors_data_from_html (line 78) | def download_sponsors_data_from_html(html_content, save_file:)
    method extract_and_save_sponsors_data (line 84) | def extract_and_save_sponsors_data(html_content, save_file, url = nil)

FILE: app/lib/duration.rb
  class Duration (line 1) | class Duration
    method seconds_to_formatted_duration (line 2) | def self.seconds_to_formatted_duration(seconds, raise: true)

FILE: app/lib/router.rb
  type Router (line 1) | module Router
    function image_path (line 5) | def image_path(...)
    function image_url (line 9) | def image_url(...)

FILE: app/mailers/application_mailer.rb
  class ApplicationMailer (line 1) | class ApplicationMailer < ActionMailer::Base

FILE: app/models/active_record/sqlite/index.rb
  type ActiveRecord::SQLite::Index (line 1) | module ActiveRecord::SQLite::Index
    function attributes_for_create (line 18) | def attributes_for_create(attribute_names)

FILE: app/models/ahoy/event.rb
  class Ahoy::Event (line 21) | class Ahoy::Event < ApplicationRecord

FILE: app/models/ahoy/visit.rb
  class Ahoy::Visit (line 42) | class Ahoy::Visit < ApplicationRecord

FILE: app/models/alias.rb
  class Alias (line 20) | class Alias < ApplicationRecord
    method slug_globally_unique_except_same_aliasable (line 31) | def slug_globally_unique_except_same_aliasable
    method reindex (line 40) | def reindex

FILE: app/models/announcement.rb
  class Announcement (line 1) | class Announcement
    class Collection (line 5) | class Collection < Array
      method published (line 6) | def published
      method by_tag (line 10) | def by_tag(tag)
      method all_tags (line 14) | def all_tags
      method find_by_slug (line 18) | def find_by_slug(slug)
      method find_by_slug! (line 22) | def find_by_slug!(slug)
    method initialize (line 29) | def initialize(attributes = {})
    method all (line 43) | def all
    method published (line 49) | def published
    method by_tag (line 53) | def by_tag(tag)
    method all_tags (line 57) | def all_tags
    method find_by_slug (line 61) | def find_by_slug(slug)
    method find_by_slug! (line 65) | def find_by_slug!(slug)
    method reload! (line 69) | def reload!
    method load_all (line 76) | def load_all
    method parse_file (line 86) | def parse_file(file_path)
    method extract_frontmatter (line 106) | def extract_frontmatter(content)
    method slug_from_filename (line 118) | def slug_from_filename(file_path)
    method parse_date (line 123) | def parse_date(date)
    method published? (line 135) | def published?
    method author_user (line 139) | def author_user
    method to_param (line 145) | def to_param

FILE: app/models/application_record.rb
  class ApplicationRecord (line 1) | class ApplicationRecord < ActiveRecord::Base

FILE: app/models/cfp.rb
  class CFP (line 23) | class CFP < ApplicationRecord
    method open? (line 29) | def open?
    method open_ended? (line 36) | def open_ended?
    method closed? (line 40) | def closed?
    method future? (line 44) | def future?
    method past? (line 48) | def past?
    method status (line 52) | def status
    method days_remaining (line 62) | def days_remaining
    method days_until_open (line 69) | def days_until_open
    method days_since_close (line 77) | def days_since_close
    method present? (line 85) | def present?
    method formatted_open_date (line 89) | def formatted_open_date
    method formatted_close_date (line 93) | def formatted_close_date

FILE: app/models/city.rb
  class City (line 26) | class City < ApplicationRecord
    method country (line 62) | def country
    method state (line 66) | def state
    method path (line 72) | def path
    method past_path (line 82) | def past_path
    method users_path (line 92) | def users_path
    method meetups_path (line 102) | def meetups_path
    method stamps_path (line 112) | def stamps_path
    method map_path (line 122) | def map_path
    method to_param (line 132) | def to_param
    method geocoded? (line 136) | def geocoded?
    method geocodeable? (line 140) | def geocodeable?
    method needs_geocoding? (line 144) | def needs_geocoding?
    method geocode_query (line 148) | def geocode_query
    method coordinates (line 152) | def coordinates
    method location_string (line 158) | def location_string
    method to_location (line 166) | def to_location
    method alpha2 (line 170) | def alpha2
    method continent (line 174) | def continent
    method bounds (line 178) | def bounds
    method stamps (line 189) | def stamps
    method nearby_users (line 198) | def nearby_users(radius_km: 100, limit: 12, exclude_ids: [])
    method nearby_events (line 216) | def nearby_events(radius_km: 250, limit: 12, exclude_ids: [])
    method with_coordinates (line 239) | def with_coordinates
    method events_count (line 243) | def events_count
    method users_count (line 247) | def users_count
    method feature! (line 251) | def feature!
    method unfeature! (line 255) | def unfeature!
    method sync_aliases_from_list (line 259) | def sync_aliases_from_list(alias_names)
    method clear_unsupported_state_code (line 287) | def clear_unsupported_state_code
    method geocoded_as_city (line 293) | def geocoded_as_city
    method find_for (line 302) | def find_for(city:, country_code:, state_code: nil)
    method find_or_create_for (line 308) | def find_or_create_for(city:, country_code:, state_code: nil, latitude...
    method find_by_alias (line 331) | def find_by_alias(name, country_code:)
    method featured_slugs (line 348) | def featured_slugs
    method clear_cache! (line 352) | def clear_cache!
    method index_in_search (line 359) | def index_in_search
    method remove_from_search (line 363) | def remove_from_search

FILE: app/models/concerns/appsignal/admin_namespace.rb
  type Appsignal::AdminNamespace (line 1) | module Appsignal::AdminNamespace
    function set_appsignal_admin_namspace (line 8) | def set_appsignal_admin_namspace

FILE: app/models/concerns/geocodeable.rb
  type Geocodeable (line 3) | module Geocodeable
    function geocodeable (line 9) | def geocodeable(attribute = :location)
    function geocodeable? (line 41) | def geocodeable?
    function clear_geocode (line 45) | def clear_geocode
    function regeocode (line 54) | def regeocode
    function geocode! (line 59) | def geocode!
    function clear_geocode! (line 64) | def clear_geocode!
    function regeocode! (line 69) | def regeocode!
    function geocode_later (line 76) | def geocode_later

FILE: app/models/concerns/locatable.rb
  type Locatable (line 3) | module Locatable
    function location_type (line 6) | def location_type
    function continent? (line 10) | def continent?
    function country? (line 14) | def country?
    function city? (line 18) | def city?
    function state? (line 22) | def state?
    function has_sub_locations? (line 26) | def has_sub_locations?
    function sub_location_label (line 30) | def sub_location_label
    function to_location (line 36) | def to_location
    function has_routes? (line 40) | def has_routes?

FILE: app/models/concerns/rollupable.rb
  type Rollupable (line 1) | module Rollupable
    function rollup_default_column (line 7) | def rollup_default_column(column)
    function rollup (line 11) | def rollup(*args, **options, &block)

FILE: app/models/concerns/sluggable.rb
  type Sluggable (line 1) | module Sluggable
    function to_param (line 10) | def to_param
    function set_slug (line 16) | def set_slug
    function slug_source (line 28) | def slug_source
    function configure_slug (line 35) | def configure_slug(attribute:, auto_suffix_on_collision: false)

FILE: app/models/concerns/suggestable.rb
  type Suggestable (line 1) | module Suggestable
    function create_suggestion_from (line 8) | def create_suggestion_from(params:, user: Current.user)
    function managed_by? (line 16) | def managed_by?(visiting_user)
    function select_differences_for (line 21) | def select_differences_for(params)

FILE: app/models/concerns/todoable.rb
  type Todoable (line 1) | module Todoable
    function todos (line 4) | def todos
    function todos_count (line 8) | def todos_count
    function todos_data_path (line 14) | def todos_data_path
    function todos_file_prefix (line 18) | def todos_file_prefix

FILE: app/models/concerns/url_normalizable.rb
  type UrlNormalizable (line 3) | module UrlNormalizable
    function normalize_url_string (line 6) | def self.normalize_url_string(url)
    function normalize_url (line 24) | def normalize_url(field)

FILE: app/models/concerns/watchable.rb
  type Watchable (line 1) | module Watchable
    function mark_as_watched! (line 8) | def mark_as_watched!
    function unmark_as_watched! (line 12) | def unmark_as_watched!
    function watched? (line 16) | def watched?(user = Current.user)

FILE: app/models/concerns/yaml_file.rb
  type YAMLFile (line 3) | module YAMLFile
    function yaml_file (line 7) | def yaml_file(filename, data_method: :file)
    function file_path (line 13) | def file_path
    function exist? (line 17) | def exist?
    function file (line 21) | def file
    function entries (line 27) | def entries
    function reload (line 33) | def reload

FILE: app/models/connected_account.rb
  class ConnectedAccount (line 28) | class ConnectedAccount < ApplicationRecord

FILE: app/models/continent.rb
  class Continent (line 3) | class Continent
    method initialize (line 28) | def initialize(slug)
    method name (line 32) | def name
    method alpha2 (line 36) | def alpha2
    method emoji_flag (line 40) | def emoji_flag
    method path (line 44) | def path
    method past_path (line 48) | def past_path
    method users_path (line 52) | def users_path
    method countries_path (line 56) | def countries_path
    method stamps_path (line 60) | def stamps_path
    method map_path (line 64) | def map_path
    method to_param (line 68) | def to_param
    method bounds (line 72) | def bounds
    method latitude (line 76) | def latitude
    method longitude (line 82) | def longitude
    method coordinates (line 88) | def coordinates
    method countries (line 94) | def countries
    method country_codes (line 98) | def country_codes
    method events (line 102) | def events
    method users (line 106) | def users
    method stamps (line 110) | def stamps
    method == (line 114) | def ==(other)
    method eql? (line 118) | def eql?(other)
    method hash (line 122) | def hash
    method to_location (line 126) | def to_location
    method all (line 131) | def all
    method find (line 135) | def find(term)
    method find_by_name (line 144) | def find_by_name(name)
    method slugs (line 153) | def slugs
    method africa (line 157) | def africa = new("africa")
    method antarctica (line 158) | def antarctica = new("antarctica")
    method asia (line 159) | def asia = new("asia")
    method australia (line 160) | def australia = new("australia")
    method europe (line 161) | def europe = new("europe")
    method north_america (line 162) | def north_america = new("north-america")
    method south_america (line 163) | def south_america = new("south-america")
    method data (line 168) | def data

FILE: app/models/contributor.rb
  class Contributor (line 24) | class Contributor < ApplicationRecord
    method name (line 29) | def name

FILE: app/models/coordinate_location.rb
  class CoordinateLocation (line 3) | class CoordinateLocation
    method initialize (line 10) | def initialize(latitude:, longitude:)
    method name (line 16) | def name
    method full_name (line 20) | def full_name
    method slug (line 24) | def slug
    method emoji_flag (line 28) | def emoji_flag
    method path (line 32) | def path
    method past_path (line 36) | def past_path
    method users_path (line 40) | def users_path
    method cities_path (line 44) | def cities_path
    method stamps_path (line 48) | def stamps_path
    method map_path (line 52) | def map_path
    method has_routes? (line 56) | def has_routes?
    method events (line 60) | def events
    method users (line 64) | def users
    method stamps (line 68) | def stamps
    method events_count (line 72) | def events_count
    method users_count (line 76) | def users_count
    method geocoded? (line 80) | def geocoded?
    method coordinates (line 84) | def coordinates
    method to_coordinates (line 90) | def to_coordinates
    method bounds (line 94) | def bounds
    method to_location (line 105) | def to_location
    method alpha2 (line 116) | def alpha2
    method country_code (line 120) | def country_code
    method country (line 124) | def country
    method continent (line 130) | def continent
    method nearby_users (line 134) | def nearby_users(radius_km: 100, limit: 12, exclude_ids: [])
    method nearby_events (line 153) | def nearby_events(radius_km: 250, limit: 12, exclude_ids: [])
    method coordinates_param (line 176) | def coordinates_param
    method reverse_geocode_data (line 180) | def reverse_geocode_data
    method reverse_geocode_display_name (line 188) | def reverse_geocode_display_name
    method reverse_geocode_full_name (line 196) | def reverse_geocode_full_name
    method reverse_geocode_city (line 206) | def reverse_geocode_city
    method reverse_geocode_state (line 210) | def reverse_geocode_state
    method nearby_events_query (line 214) | def nearby_events_query
    method nearby_users_query (line 224) | def nearby_users_query
    method bounding_box_for_radius (line 234) | def bounding_box_for_radius(radius_km)
    method from_param (line 245) | def from_param(param)

FILE: app/models/country.rb
  class Country (line 1) | class Country
    method continent_name (line 15) | def continent_name
    method continent (line 19) | def continent
    method initialize (line 23) | def initialize(record)
    method name (line 27) | def name
    method slug (line 31) | def slug
    method path (line 35) | def path
    method past_path (line 39) | def past_path
    method users_path (line 43) | def users_path
    method meetups_path (line 47) | def meetups_path
    method cities_path (line 51) | def cities_path
    method stamps_path (line 55) | def stamps_path
    method map_path (line 59) | def map_path
    method to_location (line 63) | def to_location
    method code (line 67) | def code
    method latitude (line 71) | def latitude
    method longitude (line 75) | def longitude
    method coordinates (line 79) | def coordinates
    method bounds (line 84) | def bounds
    method to_param (line 94) | def to_param
    method == (line 98) | def ==(other)
    method eql? (line 102) | def eql?(other)
    method hash (line 106) | def hash
    method events (line 110) | def events
    method users (line 114) | def users
    method cities (line 118) | def cities
    method states (line 122) | def states
    method states? (line 126) | def states?
    method stamps (line 130) | def stamps
    method held_in_sentence (line 141) | def held_in_sentence
    method uk_nation? (line 149) | def uk_nation?
    method find (line 154) | def find(term)
    method find_by (line 176) | def find_by(country_code:)
    method all (line 183) | def all
    method all_with_uk_nations (line 187) | def all_with_uk_nations
    method uk_nations (line 191) | def uk_nations
    method valid_country_codes (line 195) | def valid_country_codes
    method all_by_slug (line 199) | def all_by_slug
    method slugs (line 203) | def slugs
    method select_options (line 207) | def select_options
    method search (line 211) | def search(query)
    method find_iso_record (line 225) | def find_iso_record(term)

FILE: app/models/cue.rb
  class Cue (line 1) | class Cue
    method initialize (line 4) | def initialize(start_time:, end_time:, text:)
    method to_s (line 10) | def to_s
    method to_h (line 14) | def to_h
    method start_time_in_seconds (line 22) | def start_time_in_seconds
    method time_string_to_seconds (line 26) | def time_string_to_seconds(time_string)
    method sound_descriptor? (line 36) | def sound_descriptor?

FILE: app/models/current.rb
  class Current (line 1) | class Current < ActiveSupport::CurrentAttributes
    method session= (line 5) | def session=(session)

FILE: app/models/email_verification_token.rb
  class EmailVerificationToken (line 19) | class EmailVerificationToken < ApplicationRecord

FILE: app/models/event.rb
  class Event (line 42) | class Event < ApplicationRecord
    method upcoming? (line 141) | def upcoming?
    method past? (line 145) | def past?
    method find_by_name_or_alias (line 149) | def self.find_by_name_or_alias(name)
    method find_by_slug_or_alias (line 159) | def self.find_by_slug_or_alias(slug)
    method grouped_by_country (line 169) | def self.grouped_by_country
    method sync_aliases_from_list (line 176) | def sync_aliases_from_list(alias_names)
    method assign_canonical_event! (line 203) | def assign_canonical_event!(canonical_event:)
    method managed_by? (line 213) | def managed_by?(user)
    method data_folder (line 217) | def data_folder
    method suggestion_summary (line 221) | def suggestion_summary
    method location_and_country_code (line 232) | def location_and_country_code
    method location_and_country_code_previously_changed? (line 238) | def location_and_country_code_previously_changed?
    method today? (line 242) | def today?
    method formatted_dates (line 250) | def formatted_dates
    method held_in_sentence (line 273) | def held_in_sentence
    method to_location (line 277) | def to_location
    method description (line 283) | def description
    method keynote_speakers_text (line 293) | def keynote_speakers_text
    method talks_text (line 297) | def talks_text
    method to_meta_tags (line 301) | def to_meta_tags
    method sort_date (line 327) | def sort_date
    method watchable_talks? (line 331) | def watchable_talks?
    method featurable? (line 335) | def featurable?
    method website (line 339) | def website
    method to_mobile_json (line 343) | def to_mobile_json(request)
    method todos_data_path (line 362) | def todos_data_path
    method todos_file_prefix (line 366) | def todos_file_prefix

FILE: app/models/event/assets.rb
  class Event::Assets (line 3) | class Event::Assets < ActiveRecord::AssociatedObject
    method event_image_path (line 9) | def event_image_path = assets.base_path
    method event_image_for (line 10) | def event_image_for(filename) = assets.image_path_if_exists(filename)
    method banner_image_path (line 11) | def banner_image_path = assets.banner_path
    method card_image_path (line 12) | def card_image_path = assets.card_path
    method avatar_image_path (line 13) | def avatar_image_path = assets.avatar_path
    method featured_image_path (line 14) | def featured_image_path = assets.featured_path
    method poster_image_path (line 15) | def poster_image_path = assets.poster_path
    method sticker_image_paths (line 16) | def sticker_image_paths = assets.sticker_paths
    method sticker_image_path (line 17) | def sticker_image_path = assets.sticker_path
    method stamp_image_paths (line 18) | def stamp_image_paths = assets.stamp_paths
    method stamp_image_path (line 19) | def stamp_image_path = assets.stamp_path
    method avatar_url (line 21) | def avatar_url
    method banner_url (line 27) | def banner_url
    method base_path (line 34) | def base_path
    method default_path (line 38) | def default_path
    method default_series_path (line 42) | def default_series_path
    method image_path_for (line 46) | def image_path_for(filename)
    method image_path_if_exists (line 57) | def image_path_if_exists(filename)
    method banner_path (line 63) | def banner_path
    method card_path (line 67) | def card_path
    method avatar_path (line 71) | def avatar_path
    method featured_path (line 75) | def featured_path
    method poster_path (line 79) | def poster_path
    method stickers (line 83) | def stickers
    method sticker_paths (line 87) | def sticker_paths
    method sticker_path (line 91) | def sticker_path
    method sticker? (line 95) | def sticker?
    method stamp_paths (line 99) | def stamp_paths
    method stamp_path (line 105) | def stamp_path
    method stamp? (line 109) | def stamp?

FILE: app/models/event/cfp_file.rb
  class Event::CFPFile (line 3) | class Event::CFPFile < ActiveRecord::AssociatedObject
    method find_by_link (line 8) | def find_by_link(link)
    method add (line 12) | def add(link:, open_date: nil, close_date: nil, name: nil)
    method update (line 21) | def update(link:, open_date: nil, close_date: nil, name: nil)
    method write (line 40) | def write(cfps)
    method build_entry (line 46) | def build_entry(link:, open_date:, close_date:, name:)

FILE: app/models/event/involvements_file.rb
  class Event::InvolvementsFile (line 3) | class Event::InvolvementsFile < ActiveRecord::AssociatedObject
    method roles (line 8) | def roles
    method users_for_role (line 12) | def users_for_role(role)
    method organisations_for_role (line 19) | def organisations_for_role(role)
    method all_users (line 26) | def all_users
    method all_organisations (line 30) | def all_organisations

FILE: app/models/event/schedule.rb
  class Event::Schedule (line 1) | class Event::Schedule < ActiveRecord::AssociatedObject
    method days (line 6) | def days
    method tracks (line 10) | def tracks
    method talk_offsets (line 14) | def talk_offsets

FILE: app/models/event/sponsors_file.rb
  class Event::SponsorsFile (line 2) | class Event::SponsorsFile < ActiveRecord::AssociatedObject
    method tier_names (line 7) | def tier_names
    method sponsors (line 13) | def sponsors
    method download (line 31) | def download(base_url: nil, sponsors_url: nil, html: nil)

FILE: app/models/event/static_metadata.rb
  class Event::StaticMetadata (line 1) | class Event::StaticMetadata < ActiveRecord::AssociatedObject
    method featured_metadata? (line 3) | def featured_metadata? = static_metadata.featured_background?
    method kind (line 8) | def kind
    method conference? (line 16) | def conference?
    method meetup? (line 20) | def meetup?
    method retreat? (line 24) | def retreat?
    method hackathon? (line 28) | def hackathon?
    method frequency (line 32) | def frequency
    method start_date (line 36) | def start_date
    method end_date (line 42) | def end_date
    method date_precision (line 48) | def date_precision
    method year (line 52) | def year
    method featured_background? (line 58) | def featured_background?
    method featured_background (line 64) | def featured_background
    method featured_color (line 73) | def featured_color
    method banner_background (line 80) | def banner_background
    method location (line 87) | def location
    method coordinates (line 91) | def coordinates
    method country (line 95) | def country
    method last_edition? (line 101) | def last_edition?
    method hybrid? (line 105) | def hybrid?
    method cancelled? (line 109) | def cancelled?
    method playlist (line 113) | def playlist
    method static_repository (line 119) | def static_repository

FILE: app/models/event/tickets.rb
  class Event::Tickets (line 5) | class Event::Tickets < ActiveRecord::AssociatedObject
    method tickets? (line 19) | def tickets?
    method next_upcoming_event_with_tickets (line 23) | def next_upcoming_event_with_tickets
    method url (line 34) | def url
    method exist? (line 38) | def exist?
    method available? (line 42) | def available?
    method tito_event_slug (line 46) | def tito_event_slug
    method provider (line 53) | def provider
    method provider_name (line 57) | def provider_name
    method tito? (line 61) | def tito? = provider.tito?
    method luma? (line 62) | def luma? = provider.luma?
    method meetup? (line 63) | def meetup? = provider.meetup?
    method ticket_url_host (line 67) | def ticket_url_host
    method host_is? (line 75) | def host_is?(*domains)
    method static_repository (line 82) | def static_repository

FILE: app/models/event/transcripts_file.rb
  class Event::TranscriptsFile (line 3) | class Event::TranscriptsFile < ActiveRecord::AssociatedObject
    method video_ids (line 8) | def video_ids
    method find_by_video_id (line 12) | def find_by_video_id(video_id)
    method cues_for_video (line 16) | def cues_for_video(video_id)

FILE: app/models/event/typesense_searchable.rb
  type Event::TypesenseSearchable (line 3) | module Event::TypesenseSearchable
    function trigger_typesense_job (line 151) | def trigger_typesense_job(record, remove)
    function typesense_search_events (line 155) | def typesense_search_events(query, options = {})
    function should_index? (line 198) | def should_index?

FILE: app/models/event/venue.rb
  class Event::Venue (line 1) | class Event::Venue < ActiveRecord::AssociatedObject
    method geocode (line 7) | def geocode
    method name (line 18) | def name
    method slug (line 22) | def slug
    method description (line 26) | def description
    method address (line 30) | def address
    method display_address (line 34) | def display_address
    method street (line 38) | def street
    method city (line 42) | def city
    method region (line 46) | def region
    method postal_code (line 50) | def postal_code
    method country (line 54) | def country
    method country_code (line 58) | def country_code
    method coordinates (line 62) | def coordinates
    method latitude (line 66) | def latitude
    method longitude (line 70) | def longitude
    method maps (line 74) | def maps
    method google_maps_url (line 78) | def google_maps_url
    method apple_maps_url (line 82) | def apple_maps_url
    method openstreetmap_url (line 86) | def openstreetmap_url
    method instructions (line 90) | def instructions
    method url (line 94) | def url
    method accessibility (line 98) | def accessibility
    method rooms (line 102) | def rooms
    method spaces (line 106) | def spaces
    method nearby (line 110) | def nearby
    method hotels (line 114) | def hotels
    method locations (line 118) | def locations
    method map_markers (line 122) | def map_markers

FILE: app/models/event/videos_file.rb
  class Event::VideosFile (line 3) | class Event::VideosFile < ActiveRecord::AssociatedObject
    method talks_in_running_order (line 9) | def talks_in_running_order(child_talks: true)
    method ids (line 14) | def ids(child_talks: true)
    method find_by_id (line 28) | def find_by_id(id)
    method count (line 32) | def count

FILE: app/models/event_involvement.rb
  class EventInvolvement (line 26) | class EventInvolvement < ApplicationRecord
    method name (line 35) | def name

FILE: app/models/event_participation.rb
  class EventParticipation (line 25) | class EventParticipation < ApplicationRecord
    method name (line 36) | def name

FILE: app/models/event_series.rb
  class EventSeries (line 29) | class EventSeries < ApplicationRecord
    method find_by_name_or_alias (line 52) | def self.find_by_name_or_alias(name)
    method find_by_slug_or_alias (line 62) | def self.find_by_slug_or_alias(slug)
    method sync_aliases_from_list (line 72) | def sync_aliases_from_list(alias_names)
    method title (line 92) | def title
    method next_upcoming_event_with_tickets (line 96) | def next_upcoming_event_with_tickets
    method description (line 100) | def description
    method to_meta_tags (line 123) | def to_meta_tags
    method todos_data_path (line 153) | def todos_data_path
    method todos_file_prefix (line 157) | def todos_file_prefix

FILE: app/models/event_series/static_metadata.rb
  class EventSeries::StaticMetadata (line 1) | class EventSeries::StaticMetadata < ActiveRecord::AssociatedObject
    method ended? (line 2) | def ended?
    method default_country_code (line 6) | def default_country_code
    method static_repository (line 12) | def static_repository

FILE: app/models/event_series/typesense_searchable.rb
  type EventSeries::TypesenseSearchable (line 3) | module EventSeries::TypesenseSearchable
    function trigger_typesense_job (line 82) | def trigger_typesense_job(record, remove)
    function typesense_search_series (line 86) | def typesense_search_series(query, options = {})
    function should_index? (line 118) | def should_index?

FILE: app/models/favorite_user.rb
  class FavoriteUser (line 23) | class FavoriteUser < ApplicationRecord
    method ruby_friend? (line 32) | def ruby_friend?
    method recommendations_for (line 38) | def self.recommendations_for(user)

FILE: app/models/geocode_result.rb
  class GeocodeResult (line 16) | class GeocodeResult < ApplicationRecord

FILE: app/models/language.rb
  class Language (line 1) | class Language
    method find (line 7) | def self.find(term)
    method find_by_code (line 14) | def self.find_by_code(code)
    method alpha2_codes (line 18) | def self.alpha2_codes
    method english_names (line 22) | def self.english_names
    method all (line 26) | def self.all
    method by_code (line 30) | def self.by_code(code)
    method used (line 34) | def self.used
    method talks (line 40) | def self.talks(code)
    method talks_count (line 44) | def self.talks_count(code)
    method native_name (line 48) | def self.native_name(code)
    method emoji_flag (line 52) | def self.emoji_flag(code)
    method synonyms_for (line 59) | def self.synonyms_for(code)
    method all_synonyms (line 85) | def self.all_synonyms

FILE: app/models/llm/client.rb
  class LLM::Client (line 1) | class LLM::Client
    method initialize (line 2) | def initialize(provider_client = OpenAI::Client.new)
    method chat (line 6) | def chat(parameters:, resource:, task_name:)

FILE: app/models/llm/request.rb
  class LLM::Request (line 23) | class LLM::Request < ApplicationRecord
    method find_or_create_by_request! (line 34) | def find_or_create_by_request!(request_params, resource:, task_name:, ...

FILE: app/models/location.rb
  class Location (line 3) | class Location
    method initialize (line 12) | def initialize(city: nil, state_code: nil, country_code: nil, latitude...
    method from_record (line 22) | def self.from_record(record)
    method from_string (line 34) | def self.from_string(location_string)
    method online (line 38) | def self.online
    method city_object (line 42) | def city_object
    method state (line 49) | def state
    method country (line 55) | def country
    method city_path (line 61) | def city_path
    method state_path (line 65) | def state_path
    method country_path (line 69) | def country_path
    method continent (line 73) | def continent
    method continent_name (line 77) | def continent_name
    method continent_path (line 81) | def continent_path
    method online_location (line 85) | def online_location
    method online_path (line 89) | def online_path
    method online? (line 93) | def online?
    method hybrid? (line 99) | def hybrid?
    method state_display_name (line 103) | def state_display_name
    method display_city (line 107) | def display_city
    method geocoded? (line 117) | def geocoded?
    method present? (line 121) | def present?
    method blank? (line 125) | def blank?
    method has_state? (line 129) | def has_state?
    method has_city? (line 133) | def has_city?
    method to_s (line 137) | def to_s
    method to_html (line 148) | def to_html(show_links: true, link_class: "link", upto: :country)
    method to_text (line 158) | def to_text(upto: :country)
    method text_upto (line 173) | def text_upto(upto)
    method render_online (line 177) | def render_online(show_links:, link_class:)
    method render_upto (line 181) | def render_upto(upto:, show_links:, link_class:)
    method location_parts (line 189) | def location_parts(upto:)
    method append_hybrid_html (line 206) | def append_hybrid_html(result, show_links:, link_class:)
    method link_or_text (line 212) | def link_or_text(text, path, show_links:, link_class:)
    method join_parts (line 222) | def join_parts(parts, separator)

FILE: app/models/online_location.rb
  class OnlineLocation (line 3) | class OnlineLocation
    method name (line 7) | def name
    method slug (line 11) | def slug
    method emoji_flag (line 15) | def emoji_flag
    method path (line 19) | def path
    method past_path (line 23) | def past_path
    method users_path (line 27) | def users_path
    method cities_path (line 31) | def cities_path
    method stamps_path (line 35) | def stamps_path
    method map_path (line 39) | def map_path
    method has_routes? (line 43) | def has_routes?
    method events (line 47) | def events
    method users (line 51) | def users
    method stamps (line 55) | def stamps
    method events_count (line 59) | def events_count
    method users_count (line 63) | def users_count
    method geocoded? (line 67) | def geocoded?
    method coordinates (line 71) | def coordinates
    method to_coordinates (line 75) | def to_coordinates
    method bounds (line 79) | def bounds
    method to_location (line 83) | def to_location
    method instance (line 88) | def instance

FILE: app/models/organization.rb
  class Organization (line 25) | class Organization < ApplicationRecord
    method find_by_name_or_alias (line 49) | def self.find_by_name_or_alias(name)
    method find_by_slug_or_alias (line 59) | def self.find_by_slug_or_alias(slug)
    method organization_image_path (line 71) | def organization_image_path
    method default_organization_image_path (line 75) | def default_organization_image_path
    method organization_image_or_default_for (line 79) | def organization_image_or_default_for(filename)
    method organization_image_for (line 90) | def organization_image_for(filename)
    method avatar_image_path (line 96) | def avatar_image_path
    method banner_image_path (line 100) | def banner_image_path
    method logo_image_path (line 104) | def logo_image_path
    method has_logo_image? (line 115) | def has_logo_image?
    method logo_background_class (line 119) | def logo_background_class
    method logo_border_class (line 130) | def logo_border_class
    method add_logo_url (line 141) | def add_logo_url(url)
    method ensure_unique_logo_urls (line 152) | def ensure_unique_logo_urls

FILE: app/models/organization/typesense_searchable.rb
  type Organization::TypesenseSearchable (line 3) | module Organization::TypesenseSearchable
    function trigger_typesense_job (line 53) | def trigger_typesense_job(record, remove)
    function typesense_search_organizations (line 57) | def typesense_search_organizations(query, options = {})
    function should_index? (line 89) | def should_index?

FILE: app/models/organization/wrapped_screenshot_generator.rb
  class Organization::WrappedScreenshotGenerator (line 3) | class Organization::WrappedScreenshotGenerator
    method initialize (line 13) | def initialize(organization)
    method save_to_storage (line 17) | def save_to_storage(locals)
    method generate_horizontal_card (line 33) | def generate_horizontal_card(locals)
    method browser_options (line 58) | def browser_options(dimensions)
    method chrome_ws_url (line 80) | def chrome_ws_url
    method render_card_html (line 92) | def render_card_html(locals)
    method wrap_in_html_document (line 101) | def wrap_in_html_document(partial_html, locals)

FILE: app/models/password_reset_token.rb
  class PasswordResetToken (line 19) | class PasswordResetToken < ApplicationRecord

FILE: app/models/prompts/base.rb
  type Prompts (line 1) | module Prompts
    class Base (line 2) | class Base
      method to_params (line 5) | def to_params
      method model (line 16) | def model
      method response_format (line 20) | def response_format
      method messages (line 24) | def messages
      method system_message (line 31) | def system_message
      method prompt (line 35) | def prompt
      method service_tier (line 39) | def service_tier

FILE: app/models/prompts/talk/enhance_transcript.rb
  type Prompts (line 1) | module Prompts
    type Talk (line 2) | module Talk
      class EnhanceTranscript (line 3) | class EnhanceTranscript < Prompts::Base
        method initialize (line 6) | def initialize(talk:)
        method system_message (line 15) | def system_message
        method prompt (line 19) | def prompt
        method response_format (line 69) | def response_format

FILE: app/models/prompts/talk/summary.rb
  type Prompts (line 1) | module Prompts
    type Talk (line 2) | module Talk
      class Summary (line 3) | class Summary < Prompts::Base
        method initialize (line 6) | def initialize(talk:)
        method system_message (line 15) | def system_message
        method prompt (line 19) | def prompt
        method response_format (line 74) | def response_format

FILE: app/models/prompts/talk/topics.rb
  type Prompts (line 1) | module Prompts
    type Talk (line 2) | module Talk
      class Topics (line 3) | class Topics < Prompts::Base
        method initialize (line 6) | def initialize(talk:)
        method system_message (line 15) | def system_message
        method prompt (line 19) | def prompt
        method response_format (line 76) | def response_format

FILE: app/models/prompts/topic/match_talks.rb
  type Prompts (line 1) | module Prompts
    type Topic (line 2) | module Topic
      class MatchTalks (line 3) | class MatchTalks < Prompts::Base
        method initialize (line 6) | def initialize(topic:, talks:)
        method system_message (line 15) | def system_message
        method prompt (line 22) | def prompt
        method talks_info (line 59) | def talks_info
        method response_format (line 72) | def response_format

FILE: app/models/prompts/topic/suggest_gems.rb
  type Prompts (line 1) | module Prompts
    type Topic (line 2) | module Topic
      class SuggestGems (line 3) | class SuggestGems < Prompts::Base
        method initialize (line 6) | def initialize(topics:)
        method system_message (line 14) | def system_message
        method prompt (line 21) | def prompt
        method response_format (line 73) | def response_format

FILE: app/models/rollup.rb
  class Rollup (line 17) | class Rollup < ApplicationRecord
    method time_zone (line 47) | def time_zone
    method series (line 51) | def series(name, interval: "day", dimensions: {})
    method list (line 62) | def list
    method rename (line 69) | def rename(old_name, new_name)
    method make_series (line 75) | def make_series(result, interval)
    method inspect (line 100) | def inspect
    method time (line 108) | def time
    class Aggregator (line 120) | class Aggregator
      method initialize (line 121) | def initialize(klass)
      method rollup (line 125) | def rollup(name, column: nil, interval: "day", dimension_names: nil,...
      method validate_column (line 147) | def validate_column(column)
      method perform_group (line 157) | def perform_group(name, column:, interval:, time_zone:, current:, la...
      method set_dimension_names (line 219) | def set_dimension_names(dimension_names, relation)
      method determine_dimension_name (line 232) | def determine_dimension_name(group)
      method perform_calculation (line 248) | def perform_calculation(relation, &block)
      method prepare_result (line 256) | def prepare_result(result, name, dimension_names, interval)
      method maybe_clear (line 291) | def maybe_clear(clear, name, interval)
      method save_records (line 302) | def save_records(records)
    type Utils (line 317) | module Utils
      function time_sql (line 321) | def time_sql(interval)
      function date_interval? (line 329) | def date_interval?(interval)

FILE: app/models/search/backend.rb
  type Search::Backend (line 3) | module Search::Backend
    function without_indexing (line 9) | def without_indexing(&block)
    function backends (line 17) | def backends
    function available_backends (line 24) | def available_backends
    function resolve (line 28) | def resolve(preferred = nil)
    function default_backend (line 37) | def default_backend
    function default_backend_key (line 41) | def default_backend_key
    function index (line 51) | def index(record)
    function remove (line 61) | def remove(record)
    function reindex_all (line 69) | def reindex_all

FILE: app/models/search/backend/sqlite_fts.rb
  class Search::Backend::SQLiteFTS (line 3) | class Search::Backend::SQLiteFTS
    method search_talks (line 5) | def search_talks(query, limit:, **options)
    method search_talks_with_pagy (line 28) | def search_talks_with_pagy(query, pagy_backend:, **options)
    method search_speakers (line 57) | def search_speakers(query, limit:)
    method search_events (line 64) | def search_events(query, limit:)
    method search_topics (line 71) | def search_topics(query, limit:)
    method search_series (line 79) | def search_series(query, limit:)
    method search_organizations (line 87) | def search_organizations(query, limit:)
    method search_languages (line 95) | def search_languages(query, limit:)
    method search_locations (line 125) | def search_locations(query, limit:)
    method search_continents (line 129) | def search_continents(query, limit:)
    method search_countries (line 133) | def search_countries(query, limit:)
    method search_states (line 137) | def search_states(query, limit:)
    method search_cities (line 141) | def search_cities(query, limit:)
    method search_kinds (line 145) | def search_kinds(query, limit:)
    method available? (line 149) | def available?
    method name (line 153) | def name
    method indexer (line 157) | def indexer
    method reset_cache! (line 161) | def reset_cache!
    method apply_sort (line 175) | def apply_sort(talks, query, sort)
    method languages_with_talks (line 186) | def languages_with_talks

FILE: app/models/search/backend/sqlite_fts/indexer.rb
  class Search::Backend::SQLiteFTS (line 3) | class Search::Backend::SQLiteFTS
    class Indexer (line 4) | class Indexer
      method index (line 6) | def index(record)
      method remove (line 17) | def remove(record)
      method reindex_all (line 28) | def reindex_all
      method reindex_talks (line 34) | def reindex_talks
      method reindex_users (line 41) | def reindex_users
      method reindex_events (line 48) | def reindex_events
      method index_talk (line 55) | def index_talk(talk)
      method remove_talk (line 63) | def remove_talk(talk)
      method index_user (line 67) | def index_user(user)
      method remove_user (line 75) | def remove_user(user)
      method index_event (line 79) | def index_event(event)
      method remove_event (line 83) | def remove_event(event)

FILE: app/models/search/backend/typesense.rb
  class Search::Backend::Typesense (line 3) | class Search::Backend::Typesense
    method search_talks (line 8) | def search_talks(query, limit:, **options)
    method search_talks_with_pagy (line 15) | def search_talks_with_pagy(query, pagy_backend: nil, **options)
    method search_speakers (line 19) | def search_speakers(query, limit:)
    method search_events (line 25) | def search_events(query, limit:)
    method search_topics (line 31) | def search_topics(query, limit:)
    method search_series (line 37) | def search_series(query, limit:)
    method search_organizations (line 43) | def search_organizations(query, limit:)
    method search_languages (line 49) | def search_languages(query, limit:)
    method search_locations (line 55) | def search_locations(query, limit:)
    method search_continents (line 61) | def search_continents(query, limit:)
    method search_countries (line 67) | def search_countries(query, limit:)
    method search_states (line 73) | def search_states(query, limit:)
    method search_cities (line 79) | def search_cities(query, limit:)
    method search_kinds (line 85) | def search_kinds(query, limit:)
    method available? (line 91) | def available?
    method name (line 101) | def name
    method indexer (line 105) | def indexer
    method perform_search (line 111) | def perform_search(type, query)
    method circuit_breaker (line 121) | def circuit_breaker

FILE: app/models/search/backend/typesense/circuit_breaker.rb
  class Search::Backend::Typesense (line 3) | class Search::Backend::Typesense
    class CircuitBreaker (line 4) | class CircuitBreaker
      method initialize (line 5) | def initialize(ttl:)
      method call (line 13) | def call

FILE: app/models/search/backend/typesense/indexer.rb
  class Search::Backend::Typesense (line 3) | class Search::Backend::Typesense
    class Indexer (line 4) | class Indexer
      method index (line 6) | def index(record)
      method remove (line 16) | def remove(record)
      method reindex_all (line 26) | def reindex_all
      method reindex_talks (line 38) | def reindex_talks
      method reindex_users (line 42) | def reindex_users
      method reindex_events (line 46) | def reindex_events
      method reindex_topics (line 50) | def reindex_topics
      method reindex_series (line 54) | def reindex_series
      method reindex_organizations (line 58) | def reindex_organizations
      method reindex_languages (line 62) | def reindex_languages
      method reindex_locations (line 66) | def reindex_locations
      method reindex_kinds (line 70) | def reindex_kinds
      method should_index? (line 76) | def should_index?(record)

FILE: app/models/search/backend/typesense/kind_indexer.rb
  class Search::Backend::Typesense (line 3) | class Search::Backend::Typesense
    class KindIndexer (line 4) | class KindIndexer
      method collection_schema (line 33) | def collection_schema
      method client (line 49) | def client
      method collection (line 53) | def collection
      method ensure_collection! (line 57) | def ensure_collection!
      method reindex_all (line 63) | def reindex_all
      method drop_collection! (line 73) | def drop_collection!
      method index_talk_kinds (line 79) | def index_talk_kinds
      method index_event_kinds (line 87) | def index_event_kinds
      method search (line 95) | def search(query, category: nil, limit: 10)
      method build_talk_kind_documents (line 117) | def build_talk_kind_documents
      method build_event_kind_documents (line 134) | def build_event_kind_documents

FILE: app/models/search/backend/typesense/language_indexer.rb
  class Search::Backend::Typesense (line 3) | class Search::Backend::Typesense
    class LanguageIndexer (line 4) | class LanguageIndexer
      method collection_schema (line 8) | def collection_schema
      method client (line 24) | def client
      method collection (line 28) | def collection
      method ensure_collection! (line 32) | def ensure_collection!
      method reindex_all (line 38) | def reindex_all
      method create_synonyms! (line 47) | def create_synonyms!
      method drop_collection! (line 59) | def drop_collection!
      method index_languages (line 65) | def index_languages
      method search (line 73) | def search(query, limit: 10)
      method build_language_documents (line 93) | def build_language_documents
      method languages_with_talks (line 108) | def languages_with_talks

FILE: app/models/search/backend/typesense/location_indexer.rb
  class Search::Backend::Typesense (line 3) | class Search::Backend::Typesense
    class LocationIndexer (line 4) | class LocationIndexer
      method collection_schema (line 8) | def collection_schema
      method client (line 31) | def client
      method collection (line 35) | def collection
      method ensure_collection! (line 39) | def ensure_collection!
      method reindex_all (line 45) | def reindex_all
      method create_synonyms! (line 60) | def create_synonyms!
      method city_synonyms (line 72) | def city_synonyms
      method online_synonyms (line 81) | def online_synonyms
      method drop_collection! (line 89) | def drop_collection!
      method index_continents (line 95) | def index_continents = index_documents("continents", build_continent...
      method index_countries (line 96) | def index_countries = index_documents("countries", build_country_doc...
      method index_states (line 97) | def index_states = index_documents("states", build_state_documents)
      method index_uk_nations (line 98) | def index_uk_nations = index_documents("UK nations", build_uk_nation...
      method index_cities (line 99) | def index_cities = index_documents("cities", build_city_documents)
      method index_online (line 100) | def index_online = index_documents("online location", [build_online_...
      method index_city (line 102) | def index_city(city)
      method remove_city (line 113) | def remove_city(city)
      method index_documents (line 123) | def index_documents(name, documents)
      method search (line 130) | def search(query, type: nil, limit: 10)
      method build_online_document (line 152) | def build_online_document
      method build_continent_documents (line 167) | def build_continent_documents
      method build_country_documents (line 196) | def build_country_documents
      method build_state_documents (line 218) | def build_state_documents
      method build_uk_nation_documents (line 253) | def build_uk_nation_documents
      method build_city_documents (line 273) | def build_city_documents
      method build_city_document (line 277) | def build_city_document(city)
      method normalize_coordinates (line 296) | def normalize_coordinates(coords)
      method countries_with_events (line 303) | def countries_with_events
      method states_with_events (line 309) | def states_with_events
      method states_with_users (line 318) | def states_with_users
      method coordinates_for_state (line 327) | def coordinates_for_state(country_code, state_code)
      method coordinates_for_location (line 331) | def coordinates_for_location(events_scope)

FILE: app/models/session.rb
  class Session (line 23) | class Session < ApplicationRecord
    method sign_out_siblings! (line 31) | def sign_out_siblings!

FILE: app/models/speaker.rb
  class Speaker (line 38) | class Speaker < ApplicationRecord
    method title (line 39) | def title

FILE: app/models/sponsor.rb
  class Sponsor (line 26) | class Sponsor < ApplicationRecord
    method normalize_tier (line 36) | def normalize_tier

FILE: app/models/stamp.rb
  class Stamp (line 1) | class Stamp
    method all (line 15) | def all
    method country_stamps (line 19) | def country_stamps
    method event_stamps (line 23) | def event_stamps
    method contributor_stamp (line 27) | def contributor_stamp
    method passport_stamp (line 31) | def passport_stamp
    method triathlon_2025_stamp (line 35) | def triathlon_2025_stamp
    method conference_speaker_stamp (line 39) | def conference_speaker_stamp
    method meetup_speaker_stamp (line 43) | def meetup_speaker_stamp
    method attend_one_event_stamp (line 47) | def attend_one_event_stamp
    method ruby_30th_anniversary (line 51) | def ruby_30th_anniversary
    method online_stamp (line 55) | def online_stamp
    method for (line 59) | def for(country_code: nil, state_code: nil, events: nil)
    method for_user (line 90) | def for_user(user)
    method for_event (line 128) | def for_event(event)
    method user_attended_triathlon_2025? (line 139) | def user_attended_triathlon_2025?(user)
    method user_spoke_at_conference? (line 146) | def user_spoke_at_conference?(user)
    method user_spoke_at_meetup? (line 150) | def user_spoke_at_meetup?(user)
    method user_attended_conference? (line 154) | def user_attended_conference?(user)
    method user_attended_online_event? (line 158) | def user_attended_online_event?(user)
    method grouped_by_continent (line 162) | def grouped_by_continent
    method missing_for_events (line 171) | def missing_for_events
    method asset_path (line 183) | def asset_path
    method has_country? (line 193) | def has_country?
    method has_event? (line 197) | def has_event?
    method event (line 201) | def event
    method load_stamps_from_filesystem (line 207) | def self.load_stamps_from_filesystem
    method create_stamp_from_code (line 227) | def self.create_stamp_from_code(stamp_code)
    method create_stamp_from_event_file (line 260) | def self.create_stamp_from_event_file(file, images_directory)
    method uk_subdivisions_covered? (line 290) | def self.uk_subdivisions_covered?

FILE: app/models/state.rb
  class State (line 1) | class State
    method initialize (line 8) | def initialize(country:, record:)
    method name (line 13) | def name
    method code (line 17) | def code
    method slug (line 21) | def slug
    method abbreviation (line 25) | def abbreviation
    method display_name (line 29) | def display_name
    method path (line 37) | def path
    method past_path (line 45) | def past_path
    method users_path (line 49) | def users_path
    method meetups_path (line 53) | def meetups_path
    method cities_path (line 57) | def cities_path
    method stamps_path (line 61) | def stamps_path
    method map_path (line 65) | def map_path
    method has_routes? (line 69) | def has_routes?
    method to_param (line 73) | def to_param
    method == (line 77) | def ==(other)
    method eql? (line 81) | def eql?(other)
    method hash (line 85) | def hash
    method events (line 89) | def events
    method users (line 93) | def users
    method cities (line 97) | def cities
    method stamps (line 101) | def stamps
    method alpha2 (line 106) | def alpha2
    method country_code (line 110) | def country_code
    method geocoded? (line 114) | def geocoded?
    method bounds (line 118) | def bounds
    method to_location (line 122) | def to_location
    method supported_country? (line 127) | def supported_country?(country)
    method find (line 133) | def find(country:, term:)
    method find_by_slug (line 148) | def find_by_slug(slug)
    method find_by_code (line 154) | def find_by_code(code, country: nil)
    method find_by_name (line 170) | def find_by_name(name, country: nil)
    method all (line 186) | def all
    method for_country (line 190) | def for_country(country)
    method select_options (line 198) | def select_options(country: nil)

FILE: app/models/static/backends/array_backend.rb
  type Static::Backends (line 1) | module Static::Backends
    class ArrayBackend (line 2) | class ArrayBackend < FileBackend
      method load (line 3) | def load(...)

FILE: app/models/static/backends/file_backend.rb
  type Static::Backends (line 1) | module Static::Backends
    class FileBackend (line 2) | class FileBackend
      method initialize (line 3) | def initialize(file_path, backend: FrozenRecord::Backends::Yaml)
      method filename (line 8) | def filename(_model_name = nil)
      method load (line 12) | def load(file_path = @file_path)

FILE: app/models/static/backends/multi_file_backend.rb
  type Static::Backends (line 1) | module Static::Backends
    class MultiFileBackend (line 2) | class MultiFileBackend
      method initialize (line 3) | def initialize(glob, backend: FrozenRecord::Backends::Yaml)
      method filename (line 8) | def filename(_model_name = nil)
      method load (line 12) | def load(file_path = @glob)

FILE: app/models/static/city.rb
  type Static (line 3) | module Static
    class City (line 4) | class City < FrozenRecord::Base
      method import_all! (line 10) | def self.import_all!(index: SEARCH_INDEX_ON_IMPORT_DEFAULT)
      method import! (line 14) | def import!(index: SEARCH_INDEX_ON_IMPORT_DEFAULT)
      method find_by_yaml_aliases (line 46) | def find_by_yaml_aliases

FILE: app/models/static/event.rb
  type Static (line 1) | module Static
    class Event (line 2) | class Event < FrozenRecord::Base
      method find_by_slug (line 11) | def find_by_slug(slug)
      method import_all! (line 16) | def import_all!(index: SEARCH_INDEX_ON_IMPORT_DEFAULT)
      method import_meetups! (line 20) | def import_meetups!(index: SEARCH_INDEX_ON_IMPORT_DEFAULT)
      method import_recent! (line 24) | def import_recent!(index: SEARCH_INDEX_ON_IMPORT_DEFAULT)
      method create (line 29) | def create(
      method featured? (line 129) | def featured?
      method today? (line 133) | def today?
      method within_next_days? (line 153) | def within_next_days?
      method past? (line 175) | def past?
      method conference? (line 185) | def conference?
      method meetup? (line 189) | def meetup?
      method retreat? (line 193) | def retreat?
      method hackathon? (line 197) | def hackathon?
      method slug (line 201) | def slug
      method imported? (line 209) | def imported?
      method event_record (line 213) | def event_record
      method start_date (line 217) | def start_date
      method end_date (line 223) | def end_date
      method published_date (line 229) | def published_date
      method country (line 235) | def country
      method city (line 241) | def city
      method home_sort_date (line 248) | def home_sort_date(event_record: nil)
      method static_series (line 274) | def static_series
      method import! (line 278) | def import!(index: SEARCH_INDEX_ON_IMPORT_DEFAULT)
      method import_event! (line 294) | def import_event!
      method import_cfps! (line 334) | def import_cfps!(event)
      method import_videos! (line 352) | def import_videos!(event, index: SEARCH_INDEX_ON_IMPORT_DEFAULT)
      method import_sponsors! (line 376) | def import_sponsors!(event)
      method import_involvements! (line 427) | def import_involvements!(event)
      method import_transcripts! (line 506) | def import_transcripts!(event)
      method series_slug (line 538) | def series_slug
      method __file_path (line 542) | def __file_path

FILE: app/models/static/event_series.rb
  type Static (line 1) | module Static
    class EventSeries (line 2) | class EventSeries < FrozenRecord::Base
      method find_by_slug (line 9) | def find_by_slug(slug)
      method import_all! (line 14) | def import_all!(index: SEARCH_INDEX_ON_IMPORT_DEFAULT)
      method import_all_series! (line 18) | def import_all_series!(index: SEARCH_INDEX_ON_IMPORT_DEFAULT)
      method create (line 22) | def create(
      method slug (line 99) | def slug
      method event_series_record (line 103) | def event_series_record
      method import_series! (line 107) | def import_series!(index: SEARCH_INDEX_ON_IMPORT_DEFAULT)
      method import! (line 129) | def import!(index: SEARCH_INDEX_ON_IMPORT_DEFAULT)
      method events (line 135) | def events

FILE: app/models/static/speaker.rb
  type Static (line 3) | module Static
    class Speaker (line 4) | class Speaker < FrozenRecord::Base
      method import_all! (line 10) | def self.import_all!(index: SEARCH_INDEX_ON_IMPORT_DEFAULT)
      method import! (line 26) | def import!(index: SEARCH_INDEX_ON_IMPORT_DEFAULT)

FILE: app/models/static/sponsor.rb
  type Static (line 1) | module Static
    class Sponsor (line 2) | class Sponsor < FrozenRecord::Base

FILE: app/models/static/topic.rb
  type Static (line 1) | module Static
    class Topic (line 2) | class Topic < FrozenRecord::Base
      method import_all! (line 8) | def self.import_all!(index: SEARCH_INDEX_ON_IMPORT_DEFAULT)
      method name (line 14) | def name
      method import! (line 18) | def import!(index: SEARCH_INDEX_ON_IMPORT_DEFAULT)

FILE: app/models/static/transcript.rb
  type Static (line 1) | module Static
    class Transcript (line 2) | class Transcript < FrozenRecord::Base
      method find_by_video_id (line 9) | def find_by_video_id(video_id)
      method import_all! (line 14) | def import_all!(index: SEARCH_INDEX_ON_IMPORT_DEFAULT)
      method video_id (line 19) | def video_id
      method cues (line 23) | def cues
      method to_transcript (line 27) | def to_transcript
      method import! (line 41) | def import!(index: SEARCH_INDEX_ON_IMPORT_DEFAULT)
      method event_slug (line 53) | def event_slug
      method series_slug (line 59) | def series_slug
      method __file_path (line 65) | def __file_path

FILE: app/models/static/video.rb
  type Static (line 1) | module Static
    class Video (line 2) | class Video < FrozenRecord::Base
      method child_talks (line 8) | def self.child_talks
      method child_talks_map (line 12) | def self.child_talks_map
      method all_talks (line 16) | def self.all_talks
      method all_talks_map (line 20) | def self.all_talks_map
      method find_child_talk_by_id (line 24) | def self.find_child_talk_by_id(id)
      method find_by_static_id (line 28) | def self.find_by_static_id(id)
      method where_event_slug (line 32) | def self.where_event_slug(event_slug)
      method import_all! (line 36) | def self.import_all!(index: SEARCH_INDEX_ON_IMPORT_DEFAULT)
      method raw_title (line 40) | def raw_title
      method description (line 44) | def description
      method start_cue (line 48) | def start_cue
      method end_cue (line 52) | def end_cue
      method thumbnail_cue (line 56) | def thumbnail_cue
      method duration_fs (line 60) | def duration_fs
      method duration_to_formatted_cue (line 64) | def duration_to_formatted_cue(duration)
      method duration (line 68) | def duration
      method duration_in_seconds (line 72) | def duration_in_seconds
      method start_cue_in_seconds (line 76) | def start_cue_in_seconds
      method end_cue_in_seconds (line 80) | def end_cue_in_seconds
      method thumbnail_cue_in_seconds (line 84) | def thumbnail_cue_in_seconds
      method convert_cue_to_seconds (line 88) | def convert_cue_to_seconds(cue)
      method speakers (line 96) | def speakers
      method talks (line 102) | def talks
      method meta_talk? (line 110) | def meta_talk?
      method import! (line 114) | def import!(event: nil, parent_talk: nil, index: SEARCH_INDEX_ON_IMP...
      method find_event (line 140) | def find_event
      method __file_path (line 147) | def __file_path

FILE: app/models/sticker.rb
  class Sticker (line 1) | class Sticker
    method all (line 11) | def self.all
    method for_event (line 15) | def self.for_event(event)
    method asset_path (line 26) | def asset_path
    method event (line 30) | def event
    method load_stickers_from_filesystem (line 36) | def self.load_stickers_from_filesystem
    method create_sticker_from_event_file (line 46) | def self.create_sticker_from_event_file(file, images_directory)

FILE: app/models/suggestion.rb
  class Suggestion (line 30) | class Suggestion < ApplicationRecord
    method approved! (line 47) | def approved!(approver:)
    method notice (line 54) | def notice

FILE: app/models/talk.rb
  class Talk (line 63) | class Talk < ApplicationRecord
    method speaker_role_titles (line 151) | def self.speaker_role_titles
    method find_by_slug_or_alias (line 169) | def self.find_by_slug_or_alias(slug)
    method formatted_kind (line 179) | def formatted_kind
    method managed_by? (line 247) | def managed_by?(visiting_user)
    method published? (line 254) | def published?
    method video_available? (line 258) | def video_available?
    method video_unavailable? (line 262) | def video_unavailable?
    method check_video_availability! (line 266) | def check_video_availability!
    method validate_thumbnail! (line 288) | def validate_thumbnail!
    method to_meta_tags (line 305) | def to_meta_tags
    method thumbnail_xs (line 331) | def thumbnail_xs
    method thumbnail_sm (line 335) | def thumbnail_sm
    method thumbnail_md (line 339) | def thumbnail_md
    method thumbnail_lg (line 343) | def thumbnail_lg
    method thumbnail_xl (line 347) | def thumbnail_xl
    method thumbnail_classes (line 351) | def thumbnail_classes
    method fallback_thumbnail (line 355) | def fallback_thumbnail
    method thumbnail_url (line 359) | def thumbnail_url(size:, request:)
    method thumbnail (line 369) | def thumbnail(size = :thumbnail_lg)
    method external_player_utm_params (line 417) | def external_player_utm_params
    method external_player_url (line 426) | def external_player_url
    method provider_url (line 437) | def provider_url
    method related_talks (line 460) | def related_talks(limit: 6)
    method formatted_date (line 468) | def formatted_date
    method formatted_duration (line 472) | def formatted_duration
    method duration (line 476) | def duration
    method speakers (line 482) | def speakers
    method feedback_allowed? (line 488) | def feedback_allowed?
    method feedback_allowed_for? (line 492) | def feedback_allowed_for?(user)
    method speaker? (line 499) | def speaker?(user)
    method speaker_names (line 505) | def speaker_names
    method event_names (line 509) | def event_names
    method language_name (line 523) | def language_name
    method location (line 527) | def location
    method to_location (line 531) | def to_location
    method slug_candidates (line 539) | def slug_candidates
    method unused_slugs (line 553) | def unused_slugs
    method event_name (line 561) | def event_name
    method fetch_and_update_raw_transcript! (line 567) | def fetch_and_update_raw_transcript!
    method fetch_duration_from_youtube! (line 576) | def fetch_duration_from_youtube!
    method update_from_yml_metadata! (line 583) | def update_from_yml_metadata!(event: nil)
    method static_metadata (line 647) | def static_metadata
    method suggestion_summary (line 651) | def suggestion_summary
    method set_kind (line 659) | def set_kind
    method to_mobile_json (line 701) | def to_mobile_json(request)
    method parent_talk_id_cannot_be_self (line 716) | def parent_talk_id_cannot_be_self

FILE: app/models/talk/agents.rb
  class Talk::Agents (line 1) | class Talk::Agents < ActiveRecord::AssociatedObject
    method improve_transcript (line 8) | def improve_transcript
    method summarize (line 22) | def summarize
    method analyze_topics (line 36) | def analyze_topics
    method ingest (line 58) | def ingest
    method client (line 67) | def client

FILE: app/models/talk/downloader.rb
  class Talk::Downloader (line 1) | class Talk::Downloader < ActiveRecord::AssociatedObject
    method bin (line 2) | def bin
    method download_path (line 6) | def download_path
    method downloaded? (line 10) | def downloaded?
    method downloadable? (line 14) | def downloadable?
    method download! (line 18) | def download!

FILE: app/models/talk/index.rb
  class Talk::Index (line 1) | class Talk::Index < ApplicationRecord
    method search (line 10) | def self.search(query)
    method snippets (line 21) | def self.snippets(**)
    method snippet (line 25) | def self.snippet(column, tag: "mark", omission: "…", limit: 32)
    method reindex (line 30) | def reindex
    method remove_invalid_search_characters (line 39) | def self.remove_invalid_search_characters(query)
    method remove_unbalanced_quotes (line 43) | def self.remove_unbalanced_quotes(query)

FILE: app/models/talk/similar_recommender.rb
  class Talk::SimilarRecommender (line 1) | class Talk::SimilarRecommender < ActiveRecord::AssociatedObject
    method talks (line 2) | def talks(limit: 12)
    method topic_ids (line 19) | def topic_ids
    method topics (line 23) | def topics

FILE: app/models/talk/sqlite_fts_searchable.rb
  type Talk::SQLiteFTSSearchable (line 3) | module Talk::SQLiteFTSSearchable
    function title_with_snippet (line 33) | def title_with_snippet
    function fts_index (line 37) | def fts_index
    function reindex_fts (line 41) | def reindex_fts

FILE: app/models/talk/thumbnails.rb
  class Talk::Thumbnails (line 1) | class Talk::Thumbnails < ActiveRecord::AssociatedObject
    method path (line 2) | def path
    method extractable? (line 6) | def extractable?
    method start_cues (line 10) | def start_cues
    method extracted? (line 14) | def extracted?
    method extract! (line 18) | def extract!(force: false, download: false)
    method extract_thumbnail (line 58) | def extract_thumbnail(timestamp, input_file, output_file)
    method directory (line 64) | def directory

FILE: app/models/talk/transcript.rb
  class Talk::Transcript (line 21) | class Talk::Transcript < ApplicationRecord
    method transcript (line 29) | def transcript

FILE: app/models/talk/typesense_searchable.rb
  type Talk::TypesenseSearchable (line 3) | module Talk::TypesenseSearchable
    function typesense_synonyms_from_aliases (line 289) | def typesense_synonyms_from_aliases
    function trigger_typesense_job (line 307) | def trigger_typesense_job(record, remove)
    function typesense_search_talks (line 311) | def typesense_search_talks(query, options = {})
    function should_index? (line 372) | def should_index?

FILE: app/models/talk_topic.rb
  class TalkTopic (line 25) | class TalkTopic < ApplicationRecord
    method reset_topic_counter_cache (line 31) | def reset_topic_counter_cache

FILE: app/models/template.rb
  class Template (line 1) | class Template
    method initialize (line 40) | def initialize(attributes = {})
    method persisted? (line 45) | def persisted?
    method to_param (line 49) | def to_param
    method children_attributes= (line 53) | def children_attributes=(attributes)
    method valid? (line 59) | def valid?
    method has_children? (line 71) | def has_children?
    method to_hash (line 75) | def to_hash
    method transform_attributes (line 81) | def transform_attributes(hash)
    method to_yaml (line 92) | def to_yaml
    method time_to_cue (line 98) | def time_to_cue(time)
    method parse_speakers (line 104) | def parse_speakers(data)

FILE: app/models/todo.rb
  class Todo (line 3) | class Todo < Data.define(:file, :line, :column, :content)
    method all (line 6) | def self.all
    method for_path (line 10) | def self.for_path(path, prefix: nil)
    method url (line 33) | def url
    method git_ref (line 41) | def git_ref
    method github_url (line 45) | def github_url
    method local_url (line 52) | def local_url
    method normalized_content (line 58) | def normalized_content
    method series_slug (line 66) | def series_slug
    method event_slug (line 70) | def event_slug

FILE: app/models/topic.rb
  class Topic (line 30) | class Topic < ApplicationRecord
    method create_from_list (line 63) | def self.create_from_list(topics, status: :pending)
    method assign_canonical_topic! (line 70) | def assign_canonical_topic!(canonical_topic:)
    method primary_topic (line 86) | def primary_topic
    method to_meta_tags (line 90) | def to_meta_tags
    method rejected! (line 110) | def rejected!

FILE: app/models/topic/agents.rb
  class Topic::Agents (line 1) | class Topic::Agents < ActiveRecord::AssociatedObject
    method find_talks (line 6) | def find_talks
    method find_candidate_talks (line 27) | def find_candidate_talks
    method name_variants (line 38) | def name_variants
    method filter_with_ai (line 57) | def filter_with_ai(candidates)
    method client (line 79) | def client

FILE: app/models/topic/gem_info.rb
  class Topic::GemInfo (line 1) | class Topic::GemInfo < ActiveRecord::AssociatedObject
    method gems (line 2) | def gems
    method gem? (line 6) | def gem?
    method primary_gem (line 10) | def primary_gem

FILE: app/models/topic/typesense_searchable.rb
  type Topic::TypesenseSearchable (line 3) | module Topic::TypesenseSearchable
    function trigger_typesense_job (line 58) | def trigger_typesense_job(record, remove)
    function typesense_search_topics (line 62) | def typesense_search_topics(query, options = {})
    function should_index? (line 93) | def should_index?

FILE: app/models/topic_gem.rb
  class TopicGem (line 21) | class TopicGem < ApplicationRecord
    method info (line 26) | def info
    method downloads (line 32) | def downloads
    method version (line 36) | def version
    method version_created_at (line 40) | def version_created_at
    method authors (line 47) | def authors
    method author_names (line 51) | def author_names
    method author_users (line 57) | def author_users
    method owners (line 63) | def owners
    method owner_handles (line 69) | def owner_handles
    method owner_users (line 73) | def owner_users
    method maintainers (line 79) | def maintainers
    method summary (line 84) | def summary
    method licenses (line 88) | def licenses
    method license (line 92) | def license
    method homepage_url (line 96) | def homepage_url
    method source_code_url (line 100) | def source_code_url
    method documentation_url (line 104) | def documentation_url
    method changelog_url (line 108) | def changelog_url
    method bug_tracker_url (line 112) | def bug_tracker_url
    method mailing_list_url (line 116) | def mailing_list_url
    method wiki_url (line 120) | def wiki_url
    method funding_url (line 124) | def funding_url
    method runtime_dependencies (line 128) | def runtime_dependencies
    method development_dependencies (line 132) | def development_dependencies
    method rubygems_url (line 136) | def rubygems_url
    method github_repo (line 140) | def github_repo
    method github_url (line 148) | def github_url
    method fetch_gem_info (line 156) | def fetch_gem_info
    method fetch_owners (line 163) | def fetch_owners
    method cache_key (line 170) | def cache_key
    method owners_cache_key (line 174) | def owners_cache_key

FILE: app/models/transcript.rb
  class Transcript (line 1) | class Transcript
    method initialize (line 6) | def initialize(cues: [])
    method add_cue (line 10) | def add_cue(cue)
    method to_h (line 14) | def to_h
    method to_json (line 18) | def to_json
    method to_text (line 22) | def to_text
    method to_vtt (line 26) | def to_vtt
    method presence (line 35) | def presence
    method present? (line 39) | def present?
    method each (line 43) | def each(&)
    method create_from_vtt (line 48) | def create_from_vtt(vtt_content)
    method create_from_youtube_transcript (line 106) | def create_from_youtube_transcript(youtube_transcript)
    method create_from_json (line 119) | def create_from_json(json)
    method format_time (line 128) | def format_time(ms)

FILE: app/models/uk_nation.rb
  class UKNation (line 1) | class UKNation
    method initialize (line 4) | def initialize(slug)
    method find_by_code (line 11) | def self.find_by_code(code)
    method name (line 28) | def name
    method alpha2 (line 32) | def alpha2
    method alpha3 (line 36) | def alpha3
    method continent (line 40) | def continent
    method continent_name (line 44) | def continent_name
    method emoji_flag (line 48) | def emoji_flag
    method path (line 52) | def path
    method past_path (line 56) | def past_path
    method users_path (line 60) | def users_path
    method meetups_path (line 64) | def meetups_path
    method cities_path (line 68) | def cities_path
    method stamps_path (line 72) | def stamps_path
    method map_path (line 76) | def map_path
    method has_routes? (line 80) | def has_routes?
    method code (line 84) | def code
    method country_code (line 88) | def country_code
    method to_param (line 92) | def to_param
    method == (line 96) | def ==(other)
    method eql? (line 100) | def eql?(other)
    method hash (line 104) | def hash
    method events (line 108) | def events
    method users (line 112) | def users
    method cities (line 116) | def cities
    method stamps (line 120) | def stamps
    method bounds (line 124) | def bounds
    method held_in_sentence (line 128) | def held_in_sentence
    method uk_nation? (line 132) | def uk_nation?
    method states? (line 136) | def states?
    method parent_country (line 140) | def parent_country
    method to_location (line 144) | def to_location

FILE: app/models/user.rb
  class User (line 53) | class User < ApplicationRecord
    method normalize_github_handle (line 205) | def self.normalize_github_handle(value)
    method reset_talks_counts (line 212) | def self.reset_talks_counts
    method find_by_github_handle (line 218) | def self.find_by_github_handle(handle)
    method find_by_name_or_alias (line 223) | def self.find_by_name_or_alias(name)
    method find_by_slug_or_alias (line 233) | def self.find_by_slug_or_alias(slug)
    method default_watch_list (line 244) | def default_watch_list
    method main_participation_to (line 248) | def main_participation_to(event)
    method title (line 253) | def title
    method country (line 257) | def country
    method to_location (line 263) | def to_location
    method canonical_slug (line 267) | def canonical_slug
    method verified? (line 271) | def verified?
    method indexable? (line 275) | def indexable?
    method ruby_passport_claimed? (line 282) | def ruby_passport_claimed?
    method possessive_pronoun (line 286) | def possessive_pronoun
    method contributor? (line 290) | def contributor?
    method managed_by? (line 294) | def managed_by?(visiting_user)
    method avatar_url (line 301) | def avatar_url(...)
    method avatar_rank (line 305) | def avatar_rank
    method custom_avatar? (line 312) | def custom_avatar?
    method bsky_avatar_url (line 316) | def bsky_avatar_url(...)
    method github_avatar_url (line 320) | def github_avatar_url(size: 200)
    method fallback_avatar_url (line 330) | def fallback_avatar_url(size: 200)
    method broadcast_header (line 336) | def broadcast_header
    method to_meta_tags (line 340) | def to_meta_tags
    method to_combobox_display (line 366) | def to_combobox_display
    method meta_description (line 370) | def meta_description
    method assign_canonical_speaker! (line 384) | def assign_canonical_speaker!(canonical_speaker:)
    method primary_speaker (line 388) | def primary_speaker
    method suggestion_summary (line 392) | def suggestion_summary
    method to_mobile_json (line 402) | def to_mobile_json(request)
    method assign_canonical_user! (line 412) | def assign_canonical_user!(canonical_user:)
    method set_slug (line 449) | def set_slug
    method create_alias_for_previous_name (line 454) | def create_alias_for_previous_name
    method speakerdeck_user_from_slides_url (line 467) | def speakerdeck_user_from_slides_url
    method to_param (line 477) | def to_param

FILE: app/models/user/duplicate_detector.rb
  class User::DuplicateDetector (line 1) | class User::DuplicateDetector < ActiveRecord::AssociatedObject
    method reversed_name_duplicates (line 3) | def reversed_name_duplicates
    method same_name_duplicates (line 15) | def same_name_duplicates
    method reversed_name (line 37) | def reversed_name
    method normalized_name (line 43) | def normalized_name
    method potential_duplicates_by_reversed_name (line 49) | def potential_duplicates_by_reversed_name
    method potential_duplicates_by_normalized_name (line 53) | def potential_duplicates_by_normalized_name
    method has_reversed_name_duplicate? (line 64) | def has_reversed_name_duplicate?
    method has_same_name_duplicate? (line 68) | def has_same_name_duplicate?
    method has_any_duplicate? (line 72) | def has_any_duplicate?
    method reversed_name_duplicate_ids (line 114) | def self.reversed_name_duplicate_ids
    method same_name_duplicate_ids (line 158) | def self.same_name_duplicate_ids
    method all_duplicate_ids (line 162) | def self.all_duplicate_ids
    method find_all_reversed_name_duplicates (line 184) | def self.find_all_reversed_name_duplicates
    method find_all_same_name_duplicates (line 211) | def self.find_all_same_name_duplicates
    method report (line 219) | def self.report

FILE: app/models/user/index.rb
  class User::Index (line 1) | class User::Index < ApplicationRecord
    method search (line 10) | def self.search(query)
    method snippets (line 21) | def self.snippets(**)
    method snippet (line 25) | def self.snippet(column, tag: "mark", omission: "…", limit: 32)
    method reindex (line 30) | def reindex
    method remove_invalid_search_characters (line 34) | def self.remove_invalid_search_characters(query)
    method remove_unbalanced_quotes (line 38) | def self.remove_unbalanced_quotes(query)

FILE: app/models/user/profiles.rb
  class User::Profiles (line 1) | class User::Profiles < ActiveRecord::AssociatedObject
    method enhance_all_later (line 4) | def enhance_all_later
    method enhance_with_github (line 9) | def enhance_with_github
    method enhance_with_bsky (line 33) | def enhance_with_bsky(force: false)
    method github_client (line 42) | def github_client

FILE: app/models/user/speakerdeck_feed.rb
  class User::SpeakerdeckFeed (line 4) | class User::SpeakerdeckFeed < ActiveRecord::AssociatedObject
    method username (line 5) | def username
    method has_feed? (line 9) | def has_feed?
    method feed (line 13) | def feed
    method decks (line 19) | def decks
    method unused_decks (line 25) | def unused_decks
    class FeedData (line 33) | class FeedData
      method initialize (line 36) | def initialize(username)
      method fetch! (line 42) | def fetch!
      method decks (line 67) | def decks
      method decks_count (line 73) | def decks_count
      method find_unused_decks (line 79) | def find_unused_decks
    class Deck (line 88) | class Deck
      method initialize (line 91) | def initialize(rss_item)
      method to_h (line 99) | def to_h

FILE: app/models/user/sqlite_fts_searchable.rb
  type User::SQLiteFTSSearchable (line 3) | module User::SQLiteFTSSearchable
    function name_with_snippet (line 24) | def name_with_snippet
    function fts_index (line 28) | def fts_index
    function reindex_fts (line 32) | def reindex_fts

FILE: app/models/user/suspicion_detector.rb
  class User::SuspicionDetector (line 1) | class User::SuspicionDetector < ActiveRecord::AssociatedObject
    method suspicious? (line 26) | def suspicious?
    method suspicion_cleared? (line 30) | def suspicion_cleared?
    method mark_suspicious! (line 34) | def mark_suspicious!
    method clear_suspicion! (line 41) | def clear_suspicion!
    method unclear_suspicion! (line 45) | def unclear_suspicion!
    method github_account_newer_than? (line 49) | def github_account_newer_than?(duration)
    method calculate_suspicious? (line 59) | def calculate_suspicious?
    method signals (line 67) | def signals
    method signal_count (line 77) | def signal_count
    method github_account_new? (line 81) | def github_account_new?
    method no_talks? (line 90) | def no_talks?
    method no_watched_talks? (line 94) | def no_watched_talks?
    method bio_contains_url? (line 98) | def bio_contains_url?
    method github_account_empty? (line 104) | def github_account_empty?

FILE: app/models/user/talk_recommender.rb
  class User::TalkRecommender (line 1) | class User::TalkRecommender < ActiveRecord::AssociatedObject
    method talks (line 2) | def talks(limit: 4)
    method watched_talk_ids (line 12) | def watched_talk_ids
    method collaborative_filtering_recommendations (line 16) | def collaborative_filtering_recommendations(limit:)
    method content_based_recommendations (line 35) | def content_based_recommendations(limit:)

FILE: app/models/user/typesense_searchable.rb
  type User::TypesenseSearchable (line 3) | module User::TypesenseSearchable
    function typesense_synonyms_from_aliases (line 107) | def typesense_synonyms_from_aliases
    function trigger_typesense_job (line 125) | def trigger_typesense_job(record, remove)
    function typesense_search_speakers (line 129) | def typesense_search_speakers(query, options = {})
    function should_index? (line 165) | def should_index?

FILE: app/models/user/watched_talk_seeder.rb
  class User::WatchedTalkSeeder (line 1) | class User::WatchedTalkSeeder < ActiveRecord::AssociatedObject
    method seed_development_data (line 2) | def seed_development_data
    method seed_overlapping_patterns (line 16) | def seed_overlapping_patterns(watchable_talks, existing_users)

FILE: app/models/user/wrapped_image_generator.rb
  class User::WrappedImageGenerator (line 4) | class User::WrappedImageGenerator
    method initialize (line 11) | def initialize(user)
    method generate (line 15) | def generate
    method save_to_storage (line 49) | def save_to_storage
    method exists? (line 65) | def exists?
    method render_html (line 71) | def render_html
    method wrap_in_html_document (line 80) | def wrap_in_html_document(partial_html)

FILE: app/models/user/wrapped_screenshot_generator.rb
  class User::WrappedScreenshotGenerator (line 3) | class User::WrappedScreenshotGenerator
    method initialize (line 14) | def initialize(user, orientation: :vertical)
    method generate (line 19) | def generate
    method save_to_storage (line 42) | def save_to_storage
    method exists? (line 60) | def exists?
    method generate_all (line 68) | def self.generate_all(user)
    method render_card_html (line 78) | def render_card_html
    method build_assigns (line 86) | def build_assigns
    method render_partial (line 144) | def render_partial(partial_name, locals)
    method wrap_in_html_document (line 151) | def wrap_in_html_document(partial_html)
    method wrap_horizontal_html_document (line 168) | def wrap_horizontal_html_document(partial_html)
    method wrap_vertical_html_document (line 274) | def wrap_vertical_html_document(partial_html)
    method browser_options (line 400) | def browser_options(dimensions)
    method chrome_ws_url (line 422) | def chrome_ws_url
    method determine_personality (line 434) | def determine_personality(top_topics)

FILE: app/models/user_talk.rb
  class UserTalk (line 24) | class UserTalk < ApplicationRecord
    method update_user_talks_count (line 39) | def update_user_talks_count

FILE: app/models/watch_list.rb
  class WatchList (line 20) | class WatchList < ApplicationRecord

FILE: app/models/watch_list_talk.rb
  class WatchListTalk (line 25) | class WatchListTalk < ApplicationRecord
    method reset_watch_list_counter_cache (line 32) | def reset_watch_list_counter_cache

FILE: app/models/watched_talk.rb
  class WatchedTalk (line 24) | class WatchedTalk < ApplicationRecord
    method set_default_watched_at (line 86) | def set_default_watched_at
    method progress_percentage (line 92) | def progress_percentage
    method has_feedback? (line 99) | def has_feedback?
    method has_rating_feedback? (line 103) | def has_rating_feedback?
    method in_progress? (line 109) | def in_progress?
    method watched_on_options_for (line 113) | def self.watched_on_options_for(talk)

FILE: app/models/youtube/null_parser.rb
  type YouTube (line 3) | module YouTube
    class NullParser (line 4) | class NullParser
      method initialize (line 5) | def initialize(metadata:, event_name:, options: {})
      method cleaned (line 10) | def cleaned

FILE: app/models/youtube/video_metadata.rb
  type YouTube (line 8) | module YouTube
    class VideoMetadata (line 9) | class VideoMetadata
      method initialize (line 13) | def initialize(metadata:, event_name:, options: {})
      method cleaned (line 18) | def cleaned
      method keynote? (line 35) | def keynote?
      method lighting? (line 39) | def lighting?
      method extract_info_from_title (line 45) | def extract_info_from_title
      method speakers (line 56) | def speakers
      method raw_title (line 63) | def raw_title
      method title_without_event_name (line 67) | def title_without_event_name
      method remove_leading_and_trailing_separators_from (line 74) | def remove_leading_and_trailing_separators_from(title)
      method title (line 80) | def title
      method description (line 91) | def description

FILE: app/models/youtube/video_metadata_baltic_ruby_2024.rb
  type YouTube (line 1) | module YouTube
    class VideoMetadataBalticRuby2024 (line 2) | class VideoMetadataBalticRuby2024
      method initialize (line 6) | def initialize(metadata:, event_name:, options: {})
      method cleaned (line 11) | def cleaned
      method keynote? (line 26) | def keynote?
      method speakers (line 32) | def speakers
      method raw_title (line 46) | def raw_title
      method title_without_event_name (line 50) | def title_without_event_name
      method remove_leading_and_trailing_separators_from (line 54) | def remove_leading_and_trailing_separators_from(title)
      method title (line 62) | def title
      method raw_description (line 68) | def raw_description
      method description_without_speaker (line 72) | def description_without_speaker

FILE: app/models/youtube/video_metadata_kaigi_on_rails.rb
  type YouTube (line 1) | module YouTube
    class VideoMetadataKaigiOnRails (line 2) | class VideoMetadataKaigiOnRails < VideoMetadata
      method title (line 4) | def title
      method speakers (line 14) | def speakers
      method title_parts (line 20) | def title_parts

FILE: app/models/youtube/video_metadata_rails_world.rb
  type YouTube (line 8) | module YouTube
    class VideoMetadataRailsWorld (line 9) | class VideoMetadataRailsWorld
      method initialize (line 13) | def initialize(metadata:, event_name:, options: {})
      method cleaned (line 18) | def cleaned
      method keynote? (line 33) | def keynote?
      method extract_info_from_title (line 39) | def extract_info_from_title
      method speakers (line 50) | def speakers
      method raw_title (line 54) | def raw_title
      method title_without_event_name (line 58) | def title_without_event_name
      method remove_leading_and_trailing_separators_from (line 65) | def remove_leading_and_trailing_separators_from(title)
      method title (line 73) | def title
      method description (line 77) | def description
      method raw_title_parts (line 81) | def raw_title_parts

FILE: app/schemas/address_schema.rb
  class AddressSchema (line 3) | class AddressSchema < RubyLLM::Schema

FILE: app/schemas/cfp_schema.rb
  class CFPSchema (line 3) | class CFPSchema < RubyLLM::Schema

FILE: app/schemas/coordinates_schema.rb
  class CoordinatesSchema (line 3) | class CoordinatesSchema < RubyLLM::Schema

FILE: app/schemas/event_schema.rb
  class EventSchema (line 3) | class EventSchema < RubyLLM::Schema

FILE: app/schemas/featured_city_schema.rb
  class FeaturedCitySchema (line 3) | class FeaturedCitySchema < RubyLLM::Schema
    method to_json_schema (line 12) | def to_json_schema

FILE: app/schemas/hotel_schema.rb
  class HotelSchema (line 3) | class HotelSchema < RubyLLM::Schema

FILE: app/schemas/involvement_schema.rb
  class InvolvementSchema (line 3) | class InvolvementSchema < RubyLLM::Schema

FILE: app/schemas/location_schema.rb
  class LocationSchema (line 3) | class LocationSchema < RubyLLM::Schema

FILE: app/schemas/maps_schema.rb
  class MapsSchema (line 3) | class MapsSchema < RubyLLM::Schema

FILE: app/schemas/schedule_schema.rb
  class ScheduleSchema (line 3) | class ScheduleSchema < RubyLLM::Schema

FILE: app/schemas/series_schema.rb
  class SeriesSchema (line 3) | class SeriesSchema < RubyLLM::Schema

FILE: app/schemas/speaker_schema.rb
  class SpeakerSchema (line 3) | class SpeakerSchema < RubyLLM::Schema

FILE: app/schemas/sponsors_schema.rb
  class SponsorsSchema (line 3) | class SponsorsSchema < RubyLLM::Schema

FILE: app/schemas/transcript_schema.rb
  class TranscriptSchema (line 3) | class TranscriptSchema < RubyLLM::Schema

FILE: app/schemas/venue_schema.rb
  class VenueSchema (line 3) | class VenueSchema < RubyLLM::Schema

FILE: app/schemas/video_schema.rb
  class VideoSchema (line 3) | class VideoSchema < RubyLLM::Schema

FILE: app/serializers/transcript_serializer.rb
  class TranscriptSerializer (line 1) | class TranscriptSerializer
    method dump (line 2) | def self.dump(transcript)
    method load (line 8) | def self.load(transcript_json)

FILE: app/tools/cfp_create_tool.rb
  class CFPCreateTool (line 3) | class CFPCreateTool < RubyLLM::Tool
    method execute (line 12) | def execute(event_query:, link:, open_date: nil, close_date: nil, name...
    method find_event (line 37) | def find_event(query)

FILE: app/tools/cfp_info_tool.rb
  class CFPInfoTool (line 3) | class CFPInfoTool < RubyLLM::Tool
    method execute (line 8) | def execute(event_query:)
    method find_event (line 27) | def find_event(query)
    method format_cfp (line 34) | def format_cfp(cfp)
    method cfp_status (line 44) | def cfp_status(cfp)

FILE: app/tools/cfp_update_tool.rb
  class CFPUpdateTool (line 3) | class CFPUpdateTool < RubyLLM::Tool
    method execute (line 12) | def execute(event_query:, link:, open_date: nil, close_date: nil, name...
    method find_event (line 37) | def find_event(query)

FILE: app/tools/event_create_tool.rb
  class EventCreateTool (line 3) | class EventCreateTool < RubyLLM::Tool
    method execute (line 20) | def execute(**params)

FILE: app/tools/event_lookup_tool.rb
  class EventLookupTool (line 3) | class EventLookupTool < RubyLLM::Tool
    method execute (line 7) | def execute(query:)
    method event_to_hash (line 26) | def event_to_hash(event)

FILE: app/tools/event_series_create_tool.rb
  class EventSeriesCreateTool (line 3) | class EventSeriesCreateTool < RubyLLM::Tool
    method execute (line 19) | def execute(**params)

FILE: app/tools/event_series_events_tool.rb
  class EventSeriesEventsTool (line 3) | class EventSeriesEventsTool < RubyLLM::Tool
    method execute (line 7) | def execute(query:)
    method event_to_hash (line 31) | def event_to_hash(event, series)

FILE: app/tools/event_series_lookup_tool.rb
  class EventSeriesLookupTool (line 3) | class EventSeriesLookupTool < RubyLLM::Tool
    method execute (line 7) | def execute(query:)
    method series_to_hash (line 26) | def series_to_hash(series)

FILE: app/tools/event_talks_tool.rb
  class EventTalksTool (line 3) | class EventTalksTool < RubyLLM::Tool
    method execute (line 7) | def execute(query:)
    method video_to_hash (line 38) | def video_to_hash(video)

FILE: app/tools/geocode_tool.rb
  class GeocodeTool (line 3) | class GeocodeTool < RubyLLM::Tool
    method execute (line 7) | def execute(location:)

FILE: app/tools/github_profile_tool.rb
  class GitHubProfileTool (line 3) | class GitHubProfileTool < RubyLLM::Tool
    method execute (line 7) | def execute(username:)
    method client (line 20) | def client

FILE: app/tools/speaker_lookup_tool.rb
  class SpeakerLookupTool (line 3) | class SpeakerLookupTool < RubyLLM::Tool
    method execute (line 7) | def execute(query:)
    method user_to_hash (line 31) | def user_to_hash(user)

FILE: app/tools/speaker_talks_tool.rb
  class SpeakerTalksTool (line 3) | class SpeakerTalksTool < RubyLLM::Tool
    method execute (line 8) | def execute(name: nil, id: nil)
    method find_user (line 28) | def find_user(name:, id:)
    method talk_to_hash (line 38) | def talk_to_hash(talk)

FILE: app/tools/speakerdeck_deck_tool.rb
  class SpeakerdeckDeckTool (line 3) | class SpeakerdeckDeckTool < RubyLLM::Tool
    method execute (line 7) | def execute(url:)
    method client (line 29) | def client
    method normalize_url (line 33) | def normalize_url(url)

FILE: app/tools/speakerdeck_user_decks_tool.rb
  class SpeakerdeckUserDecksTool (line 3) | class SpeakerdeckUserDecksTool < RubyLLM::Tool
    method execute (line 7) | def execute(name:)
    method deck_to_hash (line 34) | def deck_to_hash(deck)

FILE: app/tools/venue_create_tool.rb
  class VenueCreateTool (line 3) | class VenueCreateTool < RubyLLM::Tool
    method execute (line 11) | def execute(event_query:, venue_name:, address: nil, source_url: nil)
    method find_event (line 76) | def find_event(query)

FILE: app/tools/vimeo_video_tool.rb
  class VimeoVideoTool (line 3) | class VimeoVideoTool < RubyLLM::Tool
    method execute (line 9) | def execute(id:)
    method format_duration (line 39) | def format_duration(seconds)

FILE: a
Copy disabled (too large) Download .json
Condensed preview — 3709 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (16,930K chars).
[
  {
    "path": ".annotaterb.yml",
    "chars": 1277,
    "preview": "---\n:position: before\n:position_in_additional_file_patterns: before\n:position_in_class: before\n:position_in_factory: bef"
  },
  {
    "path": ".cursor/commands/plan_commands.md",
    "chars": 1508,
    "preview": "The user will provide a feature description. Your job is to:\n\n1. Create a technical plan that concisely describes the fe"
  },
  {
    "path": ".cursor/rules/cursorrules.mdc",
    "chars": 8581,
    "preview": "---\nalwaysApply: true\n---\n\n# RubyVideo Rails 8 Project - Cursor Rules\n\nYou are working on RubyVideo, a modern Ruby on Ra"
  },
  {
    "path": ".cursor/rules/viewcomponents.mdc",
    "chars": 10083,
    "preview": "---\nalwaysApply: false\n---\n\n# RubyVideo ViewComponents - UI Component Rules\n\n> **Main Project Rules**: See [cursorrules."
  },
  {
    "path": ".devcontainer/Dockerfile",
    "chars": 1181,
    "preview": "ARG RUBY_VERSION=4.0.1\nFROM docker.io/library/ruby:$RUBY_VERSION\n\n# Rails app lives here\nWORKDIR /rails\n\n# Install base "
  },
  {
    "path": ".devcontainer/devcontainer.json",
    "chars": 1000,
    "preview": "{\n  \"name\": \"RubyEvents Dev\",\n  \"dockerComposeFile\": \"./docker-compose.yml\",\n  \"service\": \"rails-app\",\n  \"workspaceFolde"
  },
  {
    "path": ".devcontainer/docker-compose.yml",
    "chars": 1148,
    "preview": "name: \"RubyEvents\"\n\nservices:\n  rails-app:\n    build:\n      context: ..\n      dockerfile: .devcontainer/Dockerfile\n    c"
  },
  {
    "path": ".dockerignore",
    "chars": 757,
    "preview": "# See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files.\n\n# Ignore git d"
  },
  {
    "path": ".erb_lint.yml",
    "chars": 1183,
    "preview": "---\nEnableDefaultLinters: true\nglob: \"**/*.{html}{+*,}.erb\"\nexclude:\n  - vendor/bundle/**/*\n  - node_modules/**/*\n  - tm"
  },
  {
    "path": ".eslintignore",
    "chars": 36,
    "preview": "app/javascript/controllers/index.js\n"
  },
  {
    "path": ".eslintrc",
    "chars": 26,
    "preview": "{ \"extends\": \"standard\" }\n"
  },
  {
    "path": ".gitattributes",
    "chars": 348,
    "preview": "# See https://git-scm.com/docs/gitattributes for more about git attribute files.\n\n# Mark the database schema as having b"
  },
  {
    "path": ".github/pull_request_template.md",
    "chars": 383,
    "preview": "## Description\n<!-- Please describe your changes. -->\n\n## Screenshots\n<!-- Add screenshots or GIFs if applicable. -->\n\n#"
  },
  {
    "path": ".github/skills/event-data/SKILL.md",
    "chars": 3077,
    "preview": "---\nname: event-data\ndescription: Guide for handling event data. Use when asked to update event data such as CFPs, Talks"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 6094,
    "preview": "name: CI\n\non:\n  pull_request:\n    branches: [\"*\"]\n  push:\n    branches: [main]\n\nconcurrency:\n  group: ci-${{ github.ref "
  },
  {
    "path": ".github/workflows/copilot-setup-steps.yml",
    "chars": 1303,
    "preview": "name: Setup Development Environment for GitHub Copilot\n\n\n# Automatically run the setup steps when they are changed to al"
  },
  {
    "path": ".github/workflows/deploy-staging.yml",
    "chars": 1378,
    "preview": "name: Deploy to Staging\n\non: workflow_dispatch\n\njobs:\n  deploy-staging:\n    name: Deploy to Staging\n    runs-on: ubuntu-"
  },
  {
    "path": ".github/workflows/migrate-production.yml",
    "chars": 586,
    "preview": "name: Migrate Production\n\non: workflow_dispatch\n\njobs:\n  migrate-production:\n    name: Migrate Production\n    runs-on: u"
  },
  {
    "path": ".github/workflows/migrate-staging.yml",
    "chars": 585,
    "preview": "name: Migrate Staging\n\non: workflow_dispatch\n\njobs:\n  migrate-staging:\n    name: Migrate Staging\n    runs-on: ubuntu-lat"
  },
  {
    "path": ".github/workflows/release-lock-production.yml",
    "chars": 563,
    "preview": "name: Release Lock Production\n\non: workflow_dispatch\n\njobs:\n  release-lock-production:\n    name: Release Lock Production"
  },
  {
    "path": ".github/workflows/release-lock-staging.yml",
    "chars": 568,
    "preview": "name: Release Lock Staging\n\non: workflow_dispatch\n\njobs:\n  release-lock-staging:\n    name: Release Lock Staging\n    runs"
  },
  {
    "path": ".github/workflows/seed-production.yml",
    "chars": 580,
    "preview": "name: Seed Production\n\non: workflow_dispatch\n\njobs:\n  seed-production:\n    name: Seed Production\n    runs-on: ubuntu-lat"
  },
  {
    "path": ".github/workflows/seed-staging.yml",
    "chars": 578,
    "preview": "name: Seed Staging\n\non: workflow_dispatch\n\njobs:\n  seed-staging:\n    name: Seed Staging\n    runs-on: ubuntu-latest\n    t"
  },
  {
    "path": ".gitignore",
    "chars": 1650,
    "preview": "# See https://help.github.com/articles/ignoring-files for more about ignoring files.\n#\n# If you find yourself ignoring t"
  },
  {
    "path": ".herb.yml",
    "chars": 664,
    "preview": "# This file configures Herb for your project and team.\n# Settings here take precedence over individual editor preference"
  },
  {
    "path": ".kamal/hooks/docker-setup.sample",
    "chars": 51,
    "preview": "#!/bin/sh\n\necho \"Docker set up on $KAMAL_HOSTS...\"\n"
  },
  {
    "path": ".kamal/hooks/post-deploy.sample",
    "chars": 318,
    "preview": "#!/bin/sh\n\n# A sample post-deploy hook\n#\n# These environment variables are available:\n# KAMAL_RECORDED_AT\n# KAMAL_PERFOR"
  },
  {
    "path": ".kamal/hooks/post-proxy-reboot.sample",
    "chars": 55,
    "preview": "#!/bin/sh\n\necho \"Rebooted kamal-proxy on $KAMAL_HOSTS\"\n"
  },
  {
    "path": ".kamal/hooks/pre-build.sample",
    "chars": 1102,
    "preview": "#!/bin/sh\n\n# A sample pre-build hook\n#\n# Checks:\n# 1. We have a clean checkout\n# 2. A remote is configured\n# 3. The bran"
  },
  {
    "path": ".kamal/hooks/pre-connect.sample",
    "chars": 1038,
    "preview": "#!/usr/bin/env ruby\n\n# A sample pre-connect check\n#\n# Warms DNS before connecting to hosts in parallel\n#\n# These environ"
  },
  {
    "path": ".kamal/hooks/pre-deploy.sample",
    "chars": 2523,
    "preview": "#!/usr/bin/env ruby\n\n# A sample pre-deploy hook\n#\n# Checks the Github status of the build, waiting for a pending build t"
  },
  {
    "path": ".kamal/hooks/pre-proxy-reboot.sample",
    "chars": 59,
    "preview": "#!/bin/sh\n\necho \"Rebooting kamal-proxy on $KAMAL_HOSTS...\"\n"
  },
  {
    "path": ".kamal/secrets",
    "chars": 1171,
    "preview": "# Secrets defined here are available for reference under registry/password, env/secret, builder/secrets,\n# and accessori"
  },
  {
    "path": ".kamal/secrets.staging",
    "chars": 1091,
    "preview": "# Secrets defined here are available for reference under registry/password, env/secret, builder/secrets,\n# and accessori"
  },
  {
    "path": ".mcp.json",
    "chars": 126,
    "preview": "{\n  \"mcpServers\": {\n    \"rubyevents\": {\n      \"command\": \"bin/mcp_server\",\n      \"args\": [],\n      \"tools\": [\"*\"]\n    }\n"
  },
  {
    "path": ".node-version",
    "chars": 8,
    "preview": "22.15.1\n"
  },
  {
    "path": ".prettierignore",
    "chars": 16,
    "preview": "transcripts.yml\n"
  },
  {
    "path": ".ruby-version",
    "chars": 6,
    "preview": "4.0.1\n"
  },
  {
    "path": ".standard.yml",
    "chars": 0,
    "preview": ""
  },
  {
    "path": ".vscode/extensions.json",
    "chars": 213,
    "preview": "{\n  \"recommendations\": [\n    \"dbaeumer.vscode-eslint\",\n    \"esbenp.prettier-vscode\",\n    \"bradlc.vscode-tailwindcss\",\n  "
  },
  {
    "path": ".vscode/settings.json",
    "chars": 1484,
    "preview": "{\n  \"editor.detectIndentation\": false,\n  \"editor.formatOnPaste\": true,\n  \"editor.formatOnSave\": true,\n  \"editor.minimap."
  },
  {
    "path": "CLAUDE.md",
    "chars": 3733,
    "preview": "# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## "
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 9877,
    "preview": "# Welcome to RubyEvents.org!\n\nWelcome to RubyEvents.org, and thank you for contributing your time and energy to improvin"
  },
  {
    "path": "Dockerfile",
    "chars": 2931,
    "preview": "# syntax=docker/dockerfile:1\n# check=error=true\n\n# This Dockerfile is designed for production, not development. Use with"
  },
  {
    "path": "Gemfile",
    "chars": 7804,
    "preview": "source \"https://rubygems.org\"\ngit_source(:github) { |repo| \"https://github.com/#{repo}.git\" }\n\nruby file: \".ruby-version"
  },
  {
    "path": "Guardfile",
    "chars": 522,
    "preview": "# Guardfile for watching YAML files in data/ and auto-importing them\n\nrequire_relative \"lib/guard/data_import\"\n\nguard :d"
  },
  {
    "path": "Procfile.dev",
    "chars": 112,
    "preview": "web: bin/rails server -b 0.0.0.0\nvite: bin/vite dev\njobs: bin/jobs\n# guard: bundle exec guard --no-interactions\n"
  },
  {
    "path": "README.md",
    "chars": 2461,
    "preview": "# RubyEvents.org (formerly RubyVideo.dev)\n\n[RubyEvents.org](https://www.rubyevents.org) (formerly RubyVideo.dev), inspir"
  },
  {
    "path": "Rakefile",
    "chars": 227,
    "preview": "# Add your own tasks in files placed in lib/tasks ending in .rake,\n# for example lib/tasks/capistrano.rake, and they wil"
  },
  {
    "path": "app/assets/builds/.keep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "app/assets/stylesheets/application.css",
    "chars": 844,
    "preview": "@import \"tailwindcss/base\";\n@import \"tailwindcss/components\";\n@import \"tailwindcss/utilities\";\n\n@import \"components/butt"
  },
  {
    "path": "app/assets/stylesheets/bridge/components.css",
    "chars": 145,
    "preview": "html[data-bridge-platform] {\n  user-select: none;\n}\n\n[data-bridge-components~=\"button\"] [data-controller~=\"bridge--butto"
  },
  {
    "path": "app/assets/stylesheets/components/button.css",
    "chars": 900,
    "preview": "@layer components {\n  .btn {\n    @apply fill-current;\n  }\n\n  .btn:not(.btn-sm) {\n    height: 2.5rem;\n    min-height: 2.5"
  },
  {
    "path": "app/assets/stylesheets/components/diff.css",
    "chars": 121,
    "preview": "@layer components {\n  .diff {\n    del {\n      @apply text-error;\n    }\n\n    ins {\n      @apply text-success;\n    }\n  }\n}"
  },
  {
    "path": "app/assets/stylesheets/components/dropdown.css",
    "chars": 479,
    "preview": "@layer components {\n  details > summary {\n    list-style: none;\n  }\n\n  /* fix the dropdown button to links, by default d"
  },
  {
    "path": "app/assets/stylesheets/components/event.css",
    "chars": 89,
    "preview": "@layer components {\n  .event-card.cancelled,\n  .card.cancelled {\n    opacity: 0.5;\n  }\n}\n"
  },
  {
    "path": "app/assets/stylesheets/components/form.css",
    "chars": 271,
    "preview": "@layer components {\n  label {\n    @apply font-semibold;\n  }\n\n  /* because setting --rounded-btn to 1.9rem makes also all"
  },
  {
    "path": "app/assets/stylesheets/components/hotwire-combobox.css",
    "chars": 630,
    "preview": "@layer components {\n  .hw-combobox__main__wrapper {\n    @apply min-h-12;\n  }\n\n  .hw-combobox__main__wrapper:has(input:fo"
  },
  {
    "path": "app/assets/stylesheets/components/iframe.css",
    "chars": 83,
    "preview": "@layer components {\n  .responsive-iframe-container iframe {\n    width: 100%;\n  }\n}\n"
  },
  {
    "path": "app/assets/stylesheets/components/markdown.css",
    "chars": 2217,
    "preview": "@layer components {\n  .markdown {\n    p {\n      @apply mb-2;\n    }\n\n    h1,\n    h2,\n    h3,\n    h4,\n    h5,\n    h6 {\n   "
  },
  {
    "path": "app/assets/stylesheets/components/modal.css",
    "chars": 199,
    "preview": "@layer components {\n  .modal-box {\n    @apply bg-white;\n  }\n\n  .modal-top.spotlight {\n    .modal-box {\n      @apply abso"
  },
  {
    "path": "app/assets/stylesheets/components/nav.css",
    "chars": 433,
    "preview": "@layer components {\n  .desktop-menu {\n    @apply hidden gap-6 md:flex;\n\n    li,\n    title {\n      @apply m-0 inline-bloc"
  },
  {
    "path": "app/assets/stylesheets/components/pagination.css",
    "chars": 250,
    "preview": "@layer components {\n  nav.pagy.nav {\n    @apply mx-auto flex justify-normal gap-4 bg-transparent text-base-content sm:ga"
  },
  {
    "path": "app/assets/stylesheets/components/skeleton.css",
    "chars": 68,
    "preview": "@layer components {\n  .skeleton {\n    border-radius: inherit;\n  }\n}\n"
  },
  {
    "path": "app/assets/stylesheets/components/spotlight.css",
    "chars": 143,
    "preview": "@layer components {\n  .modal-box.spotlight {\n    @apply max-w-full;\n  }\n\n  [role=\"option\"][aria-selected=\"true\"] {\n    @"
  },
  {
    "path": "app/assets/stylesheets/components/tabs.css",
    "chars": 211,
    "preview": "@layer components {\n  /* https://github.com/saadeghi/daisyui/issues/2988 */\n  .tabs {\n    display: flex;\n    flex-wrap: "
  },
  {
    "path": "app/assets/stylesheets/components/transition.css",
    "chars": 950,
    "preview": "@layer components {\n  ::view-transition-group(root) {\n    animation: none;\n    mix-blend-mode: normal;\n  }\n\n  .navbar {\n"
  },
  {
    "path": "app/assets/stylesheets/components/typography.css",
    "chars": 760,
    "preview": "@import url(\"https://fonts.googleapis.com/css2?family=Nunito:wght@200..1000&display=swap\");\n\n:root {\n  font-family: Inte"
  },
  {
    "path": "app/assets/stylesheets/components/video.css",
    "chars": 779,
    "preview": "@layer components {\n  .banner-img .v-vlite {\n    --vlite-controlsColor: #ffffff;\n    --vlite-controlsOpacity: 1;\n    --v"
  },
  {
    "path": "app/avo/actions/approve_topic.rb",
    "chars": 214,
    "preview": "class Avo::Actions::ApproveTopic < Avo::BaseAction\n  self.name = \"Publish Topic\"\n\n  def handle(query:, fields:, current_"
  },
  {
    "path": "app/avo/actions/assign_canonical_event.rb",
    "chars": 722,
    "preview": "class Avo::Actions::AssignCanonicalEvent < Avo::BaseAction\n  self.name = \"Assign Canonical Event\"\n  # self.visible = -> "
  },
  {
    "path": "app/avo/actions/assign_canonical_speaker.rb",
    "chars": 785,
    "preview": "class Avo::Actions::AssignCanonicalSpeaker < Avo::BaseAction\n  self.name = \"Assign Canonical Speaker\"\n  # self.visible ="
  },
  {
    "path": "app/avo/actions/assign_canonical_topic.rb",
    "chars": 731,
    "preview": "class Avo::Actions::AssignCanonicalTopic < Avo::BaseAction\n  self.name = \"Assign Canonical Topic\"\n  # self.visible = -> "
  },
  {
    "path": "app/avo/actions/assign_canonical_user.rb",
    "chars": 693,
    "preview": "class Avo::Actions::AssignCanonicalUser < Avo::BaseAction\n  self.name = \"Assign Canonical User\"\n\n  def fields\n    field "
  },
  {
    "path": "app/avo/actions/clear_user.rb",
    "chars": 352,
    "preview": "class Avo::Actions::ClearUser < Avo::BaseAction\n  self.name = \"Clear Suspicion\"\n  self.message = \"Mark this user as manu"
  },
  {
    "path": "app/avo/actions/enhance_transcript.rb",
    "chars": 302,
    "preview": "class Avo::Actions::EnhanceTranscript < Avo::BaseAction\n  self.name = \"Enhance Transcript\"\n  def handle(query:, fields:,"
  },
  {
    "path": "app/avo/actions/extract_topics.rb",
    "chars": 230,
    "preview": "class Avo::Actions::ExtractTopics < Avo::BaseAction\n  self.name = \"Extract Topics\"\n\n  def handle(query:, fields:, curren"
  },
  {
    "path": "app/avo/actions/fetch_duration.rb",
    "chars": 296,
    "preview": "class Avo::Actions::FetchDuration < Avo::BaseAction\n  self.name = \"Fetch duration\"\n\n  def handle(query:, fields:, curren"
  },
  {
    "path": "app/avo/actions/find_topic_talks.rb",
    "chars": 295,
    "preview": "class Avo::Actions::FindTopicTalks < Avo::BaseAction\n  self.name = \"Find Talks\"\n\n  def handle(query:, fields:, current_u"
  },
  {
    "path": "app/avo/actions/geocode_record.rb",
    "chars": 865,
    "preview": "class Avo::Actions::GeocodeRecord < Avo::BaseAction\n  self.name = \"Geocode location\"\n\n  def handle(query:, fields:, curr"
  },
  {
    "path": "app/avo/actions/reject_topic.rb",
    "chars": 311,
    "preview": "class Avo::Actions::RejectTopic < Avo::BaseAction\n  self.name = \"Reject Topic\"\n  # self.visible = -> do\n  #   true\n  # e"
  },
  {
    "path": "app/avo/actions/summarize.rb",
    "chars": 216,
    "preview": "class Avo::Actions::Summarize < Avo::BaseAction\n  self.name = \"Summarize\"\n\n  def handle(query:, fields:, current_user:, "
  },
  {
    "path": "app/avo/actions/talk_index.rb",
    "chars": 429,
    "preview": "class Avo::Actions::TalkIndex < Avo::BaseAction\n  self.name = \"Talk Reindex\"\n  self.standalone = true\n\n  def handle(quer"
  },
  {
    "path": "app/avo/actions/talk_ingest.rb",
    "chars": 339,
    "preview": "class Avo::Actions::TalkIngest < Avo::BaseAction\n  self.name = \"Ingest talk (fetch transcript, enhance transcript, summa"
  },
  {
    "path": "app/avo/actions/transcript.rb",
    "chars": 305,
    "preview": "class Avo::Actions::Transcript < Avo::BaseAction\n  self.name = \"Fetch raw transcript\"\n\n  def handle(query:, fields:, cur"
  },
  {
    "path": "app/avo/actions/update_from_yml.rb",
    "chars": 300,
    "preview": "class Avo::Actions::UpdateFromYml < Avo::BaseAction\n  self.name = \"Update talk from yml metadata\"\n\n  def handle(query:, "
  },
  {
    "path": "app/avo/actions/user_fetch_github.rb",
    "chars": 353,
    "preview": "class Avo::Actions::UserFetchGitHub < Avo::BaseAction\n  self.name = \"Fetch GitHub profile\"\n\n  def handle(query:, fields:"
  },
  {
    "path": "app/avo/cards/duplicates_summary.rb",
    "chars": 281,
    "preview": "class Avo::Cards::DuplicatesSummary < Avo::Cards::PartialCard\n  self.id = \"duplicates_summary\"\n  self.label = \"Duplicate"
  },
  {
    "path": "app/avo/cards/reversed_name_duplicates_list.rb",
    "chars": 299,
    "preview": "class Avo::Cards::ReversedNameDuplicatesList < Avo::Cards::PartialCard\n  self.id = \"reversed_name_duplicates_list\"\n  sel"
  },
  {
    "path": "app/avo/cards/reversed_name_duplicates_metric.rb",
    "chars": 345,
    "preview": "class Avo::Cards::ReversedNameDuplicatesMetric < Avo::Cards::MetricCard\n  self.id = \"reversed_name_duplicates_metric\"\n  "
  },
  {
    "path": "app/avo/cards/same_name_duplicates_list.rb",
    "chars": 305,
    "preview": "class Avo::Cards::SameNameDuplicatesList < Avo::Cards::PartialCard\n  self.id = \"same_name_duplicates_list\"\n  self.label "
  },
  {
    "path": "app/avo/cards/same_name_duplicates_metric.rb",
    "chars": 302,
    "preview": "class Avo::Cards::SameNameDuplicatesMetric < Avo::Cards::MetricCard\n  self.id = \"same_name_duplicates_metric\"\n  self.lab"
  },
  {
    "path": "app/avo/cards/suspicious_signals_breakdown.rb",
    "chars": 318,
    "preview": "class Avo::Cards::SuspiciousSignalsBreakdown < Avo::Cards::PartialCard\n  self.id = \"suspicious_signals_breakdown\"\n  self"
  },
  {
    "path": "app/avo/cards/suspicious_summary.rb",
    "chars": 274,
    "preview": "class Avo::Cards::SuspiciousSummary < Avo::Cards::PartialCard\n  self.id = \"suspicious_summary\"\n  self.label = \"Suspiciou"
  },
  {
    "path": "app/avo/cards/suspicious_users_list.rb",
    "chars": 298,
    "preview": "class Avo::Cards::SuspiciousUsersList < Avo::Cards::PartialCard\n  self.id = \"suspicious_users_list\"\n  self.label = \"Susp"
  },
  {
    "path": "app/avo/cards/suspicious_users_metric.rb",
    "chars": 270,
    "preview": "class Avo::Cards::SuspiciousUsersMetric < Avo::Cards::MetricCard\n  self.id = \"suspicious_users_metric\"\n  self.label = \"S"
  },
  {
    "path": "app/avo/cards/unavailable_videos_by_event.rb",
    "chars": 289,
    "preview": "class Avo::Cards::UnavailableVideosByEvent < Avo::Cards::PartialCard\n  self.id = \"unavailable_videos_by_event\"\n  self.la"
  },
  {
    "path": "app/avo/cards/unavailable_videos_list.rb",
    "chars": 299,
    "preview": "class Avo::Cards::UnavailableVideosList < Avo::Cards::PartialCard\n  self.id = \"unavailable_videos_list\"\n  self.label = \""
  },
  {
    "path": "app/avo/cards/unavailable_videos_metric.rb",
    "chars": 285,
    "preview": "class Avo::Cards::UnavailableVideosMetric < Avo::Cards::MetricCard\n  self.id = \"unavailable_videos_metric\"\n  self.label "
  },
  {
    "path": "app/avo/cards/unavailable_videos_summary.rb",
    "chars": 299,
    "preview": "class Avo::Cards::UnavailableVideosSummary < Avo::Cards::PartialCard\n  self.id = \"unavailable_videos_summary\"\n  self.lab"
  },
  {
    "path": "app/avo/dashboards/default.rb",
    "chars": 338,
    "preview": "class Avo::Dashboards::Default < Avo::Dashboards::BaseDashboard\n  self.id = \"default\"\n  self.name = \"Dashboard\"\n  self.d"
  },
  {
    "path": "app/avo/dashboards/duplicates.rb",
    "chars": 422,
    "preview": "class Avo::Dashboards::Duplicates < Avo::Dashboards::BaseDashboard\n  self.id = \"duplicates\"\n  self.name = \"Duplicate Det"
  },
  {
    "path": "app/avo/dashboards/suspicious.rb",
    "chars": 368,
    "preview": "class Avo::Dashboards::Suspicious < Avo::Dashboards::BaseDashboard\n  self.id = \"suspicious\"\n  self.name = \"Suspicious Us"
  },
  {
    "path": "app/avo/dashboards/unavailable_videos.rb",
    "chars": 398,
    "preview": "class Avo::Dashboards::UnavailableVideos < Avo::Dashboards::BaseDashboard\n  self.id = \"unavailable_videos\"\n  self.name ="
  },
  {
    "path": "app/avo/filters/aliasable_type.rb",
    "chars": 378,
    "preview": "class Avo::Filters::AliasableType < Avo::Filters::SelectFilter\n  self.name = \"Aliasable Type\"\n\n  def apply(request, quer"
  },
  {
    "path": "app/avo/filters/attended_as.rb",
    "chars": 295,
    "preview": "class Avo::Filters::AttendedAs < Avo::Filters::SelectFilter\n  self.name = \"Attended as\"\n\n  def apply(request, query, att"
  },
  {
    "path": "app/avo/filters/bio.rb",
    "chars": 210,
    "preview": "class Avo::Filters::Bio < Avo::Filters::TextFilter\n  self.name = \"Bio\"\n  self.button_label = \"Filter by bio (contains)\"\n"
  },
  {
    "path": "app/avo/filters/bio_presence.rb",
    "chars": 317,
    "preview": "class Avo::Filters::BioPresence < Avo::Filters::BooleanFilter\n  self.name = \"Bio presence\"\n  # self.visible = -> do\n  # "
  },
  {
    "path": "app/avo/filters/canonical.rb",
    "chars": 495,
    "preview": "class Avo::Filters::Canonical < Avo::Filters::BooleanFilter\n  self.name = \"Canonical\"\n  # self.visible = -> do\n  #   tru"
  },
  {
    "path": "app/avo/filters/enhanced_transcript.rb",
    "chars": 635,
    "preview": "class Avo::Filters::EnhancedTranscript < Avo::Filters::BooleanFilter\n  self.name = \"Enhanced transcript\"\n  # self.visibl"
  },
  {
    "path": "app/avo/filters/geocoded_presence.rb",
    "chars": 435,
    "preview": "class Avo::Filters::GeocodedPresence < Avo::Filters::BooleanFilter\n  self.name = \"Geocoded\"\n\n  def apply(request, query,"
  },
  {
    "path": "app/avo/filters/github.rb",
    "chars": 483,
    "preview": "class Avo::Filters::GitHub < Avo::Filters::BooleanFilter\n  self.name = \"GitHub handle\"\n\n  def apply(request, query, valu"
  },
  {
    "path": "app/avo/filters/github_handle.rb",
    "chars": 217,
    "preview": "class Avo::Filters::GitHubHandle < Avo::Filters::TextFilter\n  self.name = \"GitHub handle (contains)\"\n\n  def apply(reques"
  },
  {
    "path": "app/avo/filters/github_handle_presence.rb",
    "chars": 520,
    "preview": "class Avo::Filters::GitHubHandlePresence < Avo::Filters::BooleanFilter\n  self.name = \"GitHub handle presence\"\n\n  def app"
  },
  {
    "path": "app/avo/filters/has_duplicate.rb",
    "chars": 607,
    "preview": "class Avo::Filters::HasDuplicate < Avo::Filters::BooleanFilter\n  self.name = \"Has duplicate\"\n\n  def apply(request, query"
  },
  {
    "path": "app/avo/filters/involvement_role.rb",
    "chars": 298,
    "preview": "class Avo::Filters::InvolvementRole < Avo::Filters::SelectFilter\n  self.name = \"Role\"\n\n  def apply(request, query, role)"
  },
  {
    "path": "app/avo/filters/language.rb",
    "chars": 306,
    "preview": "class Avo::Filters::Language < Avo::Filters::SelectFilter\n  self.name = \"Language\"\n\n  # self.visible = -> do\n  #   true\n"
  },
  {
    "path": "app/avo/filters/location_presence.rb",
    "chars": 504,
    "preview": "class Avo::Filters::LocationPresence < Avo::Filters::BooleanFilter\n  self.name = \"Location presence\"\n\n  def apply(reques"
  },
  {
    "path": "app/avo/filters/name.rb",
    "chars": 214,
    "preview": "class Avo::Filters::Name < Avo::Filters::TextFilter\n  self.name = \"Name\"\n  self.button_label = \"Filter by name (contains"
  },
  {
    "path": "app/avo/filters/provider.rb",
    "chars": 274,
    "preview": "class Avo::Filters::Provider < Avo::Filters::SelectFilter\n  self.name = \"Provider\"\n\n  def apply(request, query, provider"
  },
  {
    "path": "app/avo/filters/published.rb",
    "chars": 442,
    "preview": "class Avo::Filters::Published < Avo::Filters::BooleanFilter\n  self.name = \"Approved Status\"\n\n  def apply(request, query,"
  },
  {
    "path": "app/avo/filters/raw_transcript.rb",
    "chars": 551,
    "preview": "class Avo::Filters::RawTranscript < Avo::Filters::BooleanFilter\n  self.name = \"Raw transcript\"\n  # self.visible = -> do\n"
  },
  {
    "path": "app/avo/filters/slug.rb",
    "chars": 214,
    "preview": "class Avo::Filters::Slug < Avo::Filters::TextFilter\n  self.name = \"Slug\"\n  self.button_label = \"Filter by slug (contains"
  },
  {
    "path": "app/avo/filters/summary.rb",
    "chars": 448,
    "preview": "class Avo::Filters::Summary < Avo::Filters::BooleanFilter\n  self.name = \"Summary\"\n\n  def apply(request, query, values)\n "
  },
  {
    "path": "app/avo/filters/suspicious.rb",
    "chars": 272,
    "preview": "class Avo::Filters::Suspicious < Avo::Filters::BooleanFilter\n  self.name = \"Suspicious\"\n\n  def apply(request, query, val"
  },
  {
    "path": "app/avo/filters/talk_event.rb",
    "chars": 283,
    "preview": "class Avo::Filters::TalkEvent < Avo::Filters::SelectFilter\n  self.name = \"Talk event\"\n\n  def apply(request, query, value"
  },
  {
    "path": "app/avo/filters/title.rb",
    "chars": 218,
    "preview": "class Avo::Filters::Title < Avo::Filters::TextFilter\n  self.name = \"Title\"\n  self.button_label = \"Filter by title (conta"
  },
  {
    "path": "app/avo/filters/topic_talks.rb",
    "chars": 723,
    "preview": "class Avo::Filters::TopicTalks < Avo::Filters::BooleanFilter\n  self.name = \"Topic talks\"\n  # self.visible = -> do\n  #   "
  },
  {
    "path": "app/avo/filters/topics.rb",
    "chars": 480,
    "preview": "class Avo::Filters::Topics < Avo::Filters::BooleanFilter\n  self.name = \"Topics\"\n  # self.visible = -> do\n  #   true\n  # "
  },
  {
    "path": "app/avo/filters/video_availability.rb",
    "chars": 674,
    "preview": "class Avo::Filters::VideoAvailability < Avo::Filters::BooleanFilter\n  self.name = \"Video Availability\"\n\n  def apply(requ"
  },
  {
    "path": "app/avo/filters/video_provider.rb",
    "chars": 323,
    "preview": "class Avo::Filters::VideoProvider < Avo::Filters::SelectFilter\n  self.name = \"Video Provider\"\n\n  # self.visible = -> do\n"
  },
  {
    "path": "app/avo/filters/without_talks.rb",
    "chars": 328,
    "preview": "class Avo::Filters::WithoutTalks < Avo::Filters::BooleanFilter\n  self.name = \"Without talks\"\n  # self.visible = -> do\n  "
  },
  {
    "path": "app/avo/resources/alias.rb",
    "chars": 1639,
    "preview": "class Avo::Resources::Alias < Avo::BaseResource\n  self.includes = [:aliasable]\n  self.search = {\n    query: -> { query.w"
  },
  {
    "path": "app/avo/resources/city.rb",
    "chars": 1408,
    "preview": "class Avo::Resources::City < Avo::BaseResource\n  self.model_class = ::City\n  self.title = :name\n  self.includes = []\n  s"
  },
  {
    "path": "app/avo/resources/connected_account.rb",
    "chars": 1013,
    "preview": "# id           :integer\n# uid          :string\n# provider     :string\n# username     :string\n# user_id      :integer\n# a"
  },
  {
    "path": "app/avo/resources/contributor.rb",
    "chars": 372,
    "preview": "class Avo::Resources::Contributor < Avo::BaseResource\n  # self.includes = []\n  # self.attachments = []\n  # self.search ="
  },
  {
    "path": "app/avo/resources/event.rb",
    "chars": 1969,
    "preview": "class Avo::Resources::Event < Avo::BaseResource\n  self.includes = []\n  # self.search = {\n  #   query: -> { query.ransack"
  },
  {
    "path": "app/avo/resources/event_involvement.rb",
    "chars": 1063,
    "preview": "class Avo::Resources::EventInvolvement < Avo::BaseResource\n  self.includes = [:involvementable, :event]\n\n  self.search ="
  },
  {
    "path": "app/avo/resources/event_participation.rb",
    "chars": 658,
    "preview": "class Avo::Resources::EventParticipation < Avo::BaseResource\n  self.includes = [:user, :event]\n  # self.attachments = []"
  },
  {
    "path": "app/avo/resources/event_series.rb",
    "chars": 1172,
    "preview": "class Avo::Resources::EventSeries < Avo::BaseResource\n  self.single_includes = [:events]\n  # self.search = {\n  #   query"
  },
  {
    "path": "app/avo/resources/favorite_user.rb",
    "chars": 329,
    "preview": "class Avo::Resources::FavoriteUser < Avo::BaseResource\n  # self.includes = []\n  # self.attachments = []\n  # self.search "
  },
  {
    "path": "app/avo/resources/geocode_result.rb",
    "chars": 549,
    "preview": "class Avo::Resources::GeocodeResult < Avo::BaseResource\n  self.model_class = ::GeocodeResult\n  self.title = :query\n  sel"
  },
  {
    "path": "app/avo/resources/organization.rb",
    "chars": 797,
    "preview": "class Avo::Resources::Organization < Avo::BaseResource\n  # self.includes = []\n  # self.attachments = []\n  # self.search "
  },
  {
    "path": "app/avo/resources/session.rb",
    "chars": 534,
    "preview": "class Avo::Resources::Session < Avo::BaseResource\n  self.includes = []\n  # self.search = {\n  #   query: -> { query.ransa"
  },
  {
    "path": "app/avo/resources/sponsor.rb",
    "chars": 388,
    "preview": "class Avo::Resources::Sponsor < Avo::BaseResource\n  # self.includes = []\n  # self.attachments = []\n  # self.search = {\n "
  },
  {
    "path": "app/avo/resources/suggestion.rb",
    "chars": 735,
    "preview": "class Avo::Resources::Suggestion < Avo::BaseResource\n  # self.includes = []\n  # self.attachments = []\n  # self.search = "
  },
  {
    "path": "app/avo/resources/talk.rb",
    "chars": 4157,
    "preview": "class Avo::Resources::Talk < Avo::BaseResource\n  self.includes = [:event, :speakers, :topics]\n  self.find_record_method "
  },
  {
    "path": "app/avo/resources/talk_topic.rb",
    "chars": 407,
    "preview": "class Avo::Resources::TalkTopic < Avo::BaseResource\n  self.includes = [:talk, :topic]\n  # self.attachments = []\n  # self"
  },
  {
    "path": "app/avo/resources/talk_transcript.rb",
    "chars": 728,
    "preview": "class Avo::Resources::TalkTranscript < Avo::BaseResource\n  # self.includes = []\n  # self.attachments = []\n  self.model_c"
  },
  {
    "path": "app/avo/resources/topic.rb",
    "chars": 1399,
    "preview": "class Avo::Resources::Topic < Avo::BaseResource\n  # self.includes = []\n  # self.attachments = []\n  self.search = {\n    q"
  },
  {
    "path": "app/avo/resources/topic_gem.rb",
    "chars": 487,
    "preview": "class Avo::Resources::TopicGem < Avo::BaseResource\n  self.title = :gem_name\n  self.search = {\n    query: -> { query.wher"
  },
  {
    "path": "app/avo/resources/user.rb",
    "chars": 3179,
    "preview": "class Avo::Resources::User < Avo::BaseResource\n  self.title = :name\n  self.includes = []\n  self.find_record_method = -> "
  },
  {
    "path": "app/avo/resources/user_talk.rb",
    "chars": 316,
    "preview": "class Avo::Resources::UserTalk < Avo::BaseResource\n  # self.includes = []\n  # self.attachments = []\n  # self.search = {\n"
  },
  {
    "path": "app/avo/resources/watch_list.rb",
    "chars": 299,
    "preview": "class Avo::Resources::WatchList < Avo::BaseResource\n  self.title = :name\n  self.includes = []\n\n  def fields\n    field :i"
  },
  {
    "path": "app/avo/resources/watch_list_talk.rb",
    "chars": 252,
    "preview": "class Avo::Resources::WatchListTalk < Avo::BaseResource\n  self.includes = [:talk, :watch_list]\n\n  def fields\n    field :"
  },
  {
    "path": "app/channels/application_cable/channel.rb",
    "chars": 79,
    "preview": "module ApplicationCable\n  class Channel < ActionCable::Channel::Base\n  end\nend\n"
  },
  {
    "path": "app/channels/application_cable/connection.rb",
    "chars": 85,
    "preview": "module ApplicationCable\n  class Connection < ActionCable::Connection::Base\n  end\nend\n"
  },
  {
    "path": "app/clients/application_client.rb",
    "chars": 4275,
    "preview": "class ApplicationClient\n  class Error < StandardError; end\n\n  class Forbidden < Error; end\n\n  class Unauthorized < Error"
  },
  {
    "path": "app/clients/blue_sky.rb",
    "chars": 615,
    "preview": "# frozen_string_literal: true\n\nBlueSky = DelegateClass(Minisky) do\n  alias_method :client, :__getobj__\n\n  singleton_clas"
  },
  {
    "path": "app/clients/github/client.rb",
    "chars": 426,
    "preview": "module GitHub\n  class Client < ApplicationClient\n    BASE_URI = \"https://api.github.com\"\n\n    def initialize\n      super"
  },
  {
    "path": "app/clients/github/contributors_client.rb",
    "chars": 1404,
    "preview": "module GitHub\n  class ContributorsClient < Client\n    OWNER = \"rubyevents\"\n    REPO = \"rubyevents\"\n\n    def fetch_all\n  "
  },
  {
    "path": "app/clients/github/user_client.rb",
    "chars": 391,
    "preview": "module GitHub\n  class UserClient < GitHub::Client\n    def profile(username)\n      get(\"/users/#{username}\")\n    end\n\n   "
  },
  {
    "path": "app/clients/ruby_conferences/client.rb",
    "chars": 502,
    "preview": "module RubyConferences\n  class Client < ApplicationClient\n    BASE_URI = \"https://raw.githubusercontent.com/ruby-confere"
  },
  {
    "path": "app/clients/speakerdeck/client.rb",
    "chars": 457,
    "preview": "# frozen_string_literal: true\n\nmodule Speakerdeck\n  class Client < ApplicationClient\n    BASE_URI = \"https://speakerdeck"
  },
  {
    "path": "app/clients/youtube/channels.rb",
    "chars": 834,
    "preview": "require \"open-uri\"\n\nmodule YouTube\n  class Channels < YouTube::Client\n    def id_by_name(channel_name:)\n      response ="
  },
  {
    "path": "app/clients/youtube/client.rb",
    "chars": 765,
    "preview": "module YouTube\n  class Client < ApplicationClient\n    BASE_URI = \"https://youtube.googleapis.com/youtube/v3\"\n\n    privat"
  },
  {
    "path": "app/clients/youtube/playlist_items.rb",
    "chars": 1107,
    "preview": "module YouTube\n  class PlaylistItems < YouTube::Client\n    def all(playlist_id:)\n      all_items(\"/playlistItems\", query"
  },
  {
    "path": "app/clients/youtube/playlists.rb",
    "chars": 1350,
    "preview": "module YouTube\n  class Playlists < YouTube::Client\n    DEFAULT_METADATA_PARSER = \"YouTube::VideoMetadata\"\n\n    def all(c"
  },
  {
    "path": "app/clients/youtube/thumbnail.rb",
    "chars": 2306,
    "preview": "# frozen_string_literal: true\n\nmodule YouTube\n  class Thumbnail\n    SIZES = %w[maxresdefault sddefault hqdefault mqdefau"
  },
  {
    "path": "app/clients/youtube/transcript.rb",
    "chars": 1114,
    "preview": "require \"protobuf/message_type\"\n\nmodule YouTube\n  class Transcript\n    attr_reader :response\n\n    def get(video_id)\n    "
  },
  {
    "path": "app/clients/youtube/video.rb",
    "chars": 1093,
    "preview": "module YouTube\n  class Video < Client\n    def available?(video_id)\n      path = \"/videos\"\n      query = {\n        part: "
  },
  {
    "path": "app/components/application_component.rb",
    "chars": 396,
    "preview": "# frozen_string_literal: true\n\nclass ApplicationComponent < ViewComponent::Base\n  extend Dry::Initializer\n\n  attr_access"
  },
  {
    "path": "app/components/events/upcoming_event_banner_component.html.erb",
    "chars": 1061,
    "preview": "<a href=\"<%= helpers.event_tickets_path(upcoming_event) %>\" data-turbo-frame=\"_top\" class=\"rounded-xl group border hover"
  },
  {
    "path": "app/components/events/upcoming_event_banner_component.rb",
    "chars": 981,
    "preview": "# frozen_string_literal: true\n\nclass Events::UpcomingEventBannerComponent < ApplicationComponent\n  option :event, option"
  },
  {
    "path": "app/components/hover_card/base_component.html.erb",
    "chars": 314,
    "preview": "<div class=\"absolute left-1/2 -translate-x-1/2 bottom-full mb-2 w-80 opacity-0 invisible group-hover/card:opacity-100 gr"
  },
  {
    "path": "app/components/hover_card/base_component.rb",
    "chars": 456,
    "preview": "# frozen_string_literal: true\n\nclass HoverCard::BaseComponent < ViewComponent::Base\n  include Turbo::FramesHelper\n\n  att"
  },
  {
    "path": "app/components/hover_card/event_component.rb",
    "chars": 174,
    "preview": "# frozen_string_literal: true\n\nclass HoverCard::EventComponent < HoverCard::BaseComponent\n  def hover_card_url\n    Route"
  },
  {
    "path": "app/components/hover_card/user_component.rb",
    "chars": 252,
    "preview": "# frozen_string_literal: true\n\nclass HoverCard::UserComponent < HoverCard::BaseComponent\n  def hover_card_url\n    Router"
  },
  {
    "path": "app/components/tito/button_component.html.erb",
    "chars": 72,
    "preview": "<%= link_to label, helpers.event_tickets_path(event), class: classes %>\n"
  },
  {
    "path": "app/components/tito/button_component.rb",
    "chars": 276,
    "preview": "# frozen_string_literal: true\n\nclass Tito::ButtonComponent < ApplicationComponent\n  option :event\n  option :label, defau"
  },
  {
    "path": "app/components/tito/widget_component.html.erb",
    "chars": 368,
    "preview": "<% content_for :head do %>\n  <script src=\"https://js.tito.io/v2\" async></script>\n<% end %>\n\n<% if wrapper %>\n  <div clas"
  },
  {
    "path": "app/components/tito/widget_component.rb",
    "chars": 275,
    "preview": "# frozen_string_literal: true\n\nclass Tito::WidgetComponent < ApplicationComponent\n  option :event\n  option :wrapper, def"
  },
  {
    "path": "app/components/ui/avatar_component.html.erb",
    "chars": 1019,
    "preview": "<% avatar_markup = capture do %>\n  <div class=\"avatar placeholder\">\n    <div class=\"<%= avatar_classes %>\">\n      <% if "
  },
  {
    "path": "app/components/ui/avatar_component.rb",
    "chars": 2306,
    "preview": "# frozen_string_literal: true\n\nclass Ui::AvatarComponent < ApplicationComponent\n  SIZE_MAPPING = {\n    xs: {\n      size_"
  },
  {
    "path": "app/components/ui/avatar_group_component.html.erb",
    "chars": 399,
    "preview": "<div class=\"avatar-group <%= overlap %> rtl:space-x-reverse\">\n  <% visible_avatarables.each do |avatarable| %>\n    <%= r"
  },
  {
    "path": "app/components/ui/avatar_group_component.rb",
    "chars": 797,
    "preview": "# frozen_string_literal: true\n\nclass Ui::AvatarGroupComponent < ApplicationComponent\n  SIZE_MAPPING = {\n    sm: \"w-8\",\n "
  },
  {
    "path": "app/components/ui/badge_component.rb",
    "chars": 1184,
    "preview": "# frozen_string_literal: true\n\nclass Ui::BadgeComponent < ApplicationComponent\n  KIND_MAPPING = {\n    neutral: \"badge-ne"
  },
  {
    "path": "app/components/ui/button_component.rb",
    "chars": 2270,
    "preview": "# frozen_string_literal: true\n\nclass Ui::ButtonComponent < ApplicationComponent\n  KIND_MAPPING = {\n    primary: \"btn-pri"
  },
  {
    "path": "app/components/ui/divider_component.rb",
    "chars": 651,
    "preview": "# frozen_string_literal: true\n\nclass Ui::DividerComponent < ApplicationComponent\n  KIND_MAPPING = {\n    horizontal: \"div"
  },
  {
    "path": "app/components/ui/dropdown_component.html.erb",
    "chars": 533,
    "preview": "<%= content_tag :details, class: classes, **attributes do %>\n  <summary class=\"flex after:hidden\">\n    <% if toggle_open"
  },
  {
    "path": "app/components/ui/dropdown_component.rb",
    "chars": 1793,
    "preview": "# frozen_string_literal: true\n\nclass Ui::DropdownComponent < ApplicationComponent\n  renders_many :menu_items, types: {\n "
  },
  {
    "path": "app/components/ui/modal_component.html.erb",
    "chars": 423,
    "preview": "<%= content_tag :dialog, role: :dialog, aria: {modal: true}, class: classes, **attributes do %>\n  <div class=\"modal-box "
  },
  {
    "path": "app/components/ui/modal_component.rb",
    "chars": 1567,
    "preview": "# frozen_string_literal: true\n\nclass Ui::ModalComponent < ApplicationComponent\n  POSITION_MAPPING = {\n    top: \"modal-to"
  },
  {
    "path": "app/components/ui/stamp_component.html.erb",
    "chars": 480,
    "preview": "<% if interactive && clickable? %>\n  <%= link_to(url, **link_attributes.deep_merge(data: {turbo_frame: \"_top\"})) do %>\n "
  },
  {
    "path": "app/components/ui/stamp_component.rb",
    "chars": 1678,
    "preview": "# frozen_string_literal: true\n\nclass Ui::StampComponent < ApplicationComponent\n  SIZE_MAPPING = {\n    unset: \"\",\n    ful"
  },
  {
    "path": "app/controllers/admin/suggestions_controller.rb",
    "chars": 512,
    "preview": "module Admin\n  class SuggestionsController < ApplicationController\n    include Pagy::Backend\n\n    def index\n      @pagy,"
  },
  {
    "path": "app/controllers/analytics/dashboards_controller.rb",
    "chars": 3757,
    "preview": "class Analytics::DashboardsController < ApplicationController\n  skip_before_action :authenticate_user!\n  before_action :"
  },
  {
    "path": "app/controllers/announcements_controller.rb",
    "chars": 2237,
    "preview": "class AnnouncementsController < ApplicationController\n  include Pagy::Backend\n\n  skip_before_action :authenticate_user!\n"
  },
  {
    "path": "app/controllers/api/v1/embed/base_controller.rb",
    "chars": 2029,
    "preview": "# frozen_string_literal: true\n\nmodule Api\n  module V1\n    module Embed\n      class BaseController < ActionController::AP"
  },
  {
    "path": "app/controllers/api/v1/embed/events_controller.rb",
    "chars": 4378,
    "preview": "# frozen_string_literal: true\n\nmodule Api\n  module V1\n    module Embed\n      class EventsController < BaseController\n   "
  }
]

// ... and 3509 more files (download for full content)

About this extraction

This page contains the full source code of the adrienpoly/rubyvideo GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 3709 files (15.1 MB), approximately 4.1M tokens, and a symbol index with 3552 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!