`, and ``.
+// $font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace !default;
+// $font-family-base: $font-family-sans-serif !default;
+
+// $font-size-base: 14px !default;
+// $font-size-large: ceil(($font-size-base * 1.25)) !default; // ~18px
+// $font-size-small: ceil(($font-size-base * 0.85)) !default; // ~12px
+
+// $font-size-h1: floor(($font-size-base * 2.6)) !default; // ~36px
+// $font-size-h2: floor(($font-size-base * 2.15)) !default; // ~30px
+// $font-size-h3: ceil(($font-size-base * 1.7)) !default; // ~24px
+// $font-size-h4: ceil(($font-size-base * 1.25)) !default; // ~18px
+// $font-size-h5: $font-size-base !default;
+// $font-size-h6: ceil(($font-size-base * 0.85)) !default; // ~12px
+
+// //** Unit-less `line-height` for use in components like buttons.
+// $line-height-base: 1.428571429 !default; // 20/14
+// //** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
+// $line-height-computed: floor(($font-size-base * $line-height-base)) !default; // ~20px
+
+// //** By default, this inherits from the ``.
+// $headings-font-family: inherit !default;
+// $headings-font-weight: 500 !default;
+// $headings-line-height: 1.1 !default;
+// $headings-color: inherit !default;
+
+
+// //== Iconography
+// //
+// //## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
+
+// //** Load fonts from this directory.
+
+// // [converter] If $bootstrap-sass-asset-helper if used, provide path relative to the assets load path.
+// // [converter] This is because some asset helpers, such as Sprockets, do not work with file-relative paths.
+// $icon-font-path: if($bootstrap-sass-asset-helper, "bootstrap/", "../fonts/bootstrap/") !default;
+
+// //** File name for all font files.
+// $icon-font-name: "glyphicons-halflings-regular" !default;
+// //** Element ID within SVG icon file.
+// $icon-font-svg-id: "glyphicons_halflingsregular" !default;
+
+
+// //== Components
+// //
+// //## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
+
+// $padding-base-vertical: 6px !default;
+// $padding-base-horizontal: 12px !default;
+
+// $padding-large-vertical: 10px !default;
+// $padding-large-horizontal: 16px !default;
+
+// $padding-small-vertical: 5px !default;
+// $padding-small-horizontal: 10px !default;
+
+// $padding-xs-vertical: 1px !default;
+// $padding-xs-horizontal: 5px !default;
+
+// $line-height-large: 1.3333333 !default; // extra decimals for Win 8.1 Chrome
+// $line-height-small: 1.5 !default;
+
+// $border-radius-base: 4px !default;
+// $border-radius-large: 6px !default;
+// $border-radius-small: 3px !default;
+
+// //** Global color for active items (e.g., navs or dropdowns).
+// $component-active-color: #fff !default;
+// //** Global background color for active items (e.g., navs or dropdowns).
+// $component-active-bg: $brand-primary !default;
+
+// //** Width of the `border` for generating carets that indicator dropdowns.
+// $caret-width-base: 4px !default;
+// //** Carets increase slightly in size for larger components.
+// $caret-width-large: 5px !default;
+
+
+// //== Tables
+// //
+// //## Customizes the `.table` component with basic values, each used across all table variations.
+
+// //** Padding for ``s and ` `s.
+// $table-cell-padding: 8px !default;
+// //** Padding for cells in `.table-condensed`.
+// $table-condensed-cell-padding: 5px !default;
+
+// //** Default background color used for all tables.
+// $table-bg: transparent !default;
+// //** Background color used for `.table-striped`.
+// $table-bg-accent: #f9f9f9 !default;
+// //** Background color used for `.table-hover`.
+// $table-bg-hover: #f5f5f5 !default;
+// $table-bg-active: $table-bg-hover !default;
+
+// //** Border color for table and cell borders.
+// $table-border-color: #ddd !default;
+
+
+// //== Buttons
+// //
+// //## For each of Bootstrap's buttons, define text, background and border color.
+
+// $btn-font-weight: normal !default;
+
+// $btn-default-color: #333 !default;
+// $btn-default-bg: #fff !default;
+// $btn-default-border: #ccc !default;
+
+// $btn-primary-color: #fff !default;
+// $btn-primary-bg: $brand-primary !default;
+
+// $btn-success-color: #fff !default;
+// $btn-success-bg: $brand-success !default;
+// $btn-success-border: darken($btn-success-bg, 5%) !default;
+
+// $btn-info-color: #fff !default;
+// $btn-info-bg: $brand-info !default;
+// $btn-info-border: darken($btn-info-bg, 5%) !default;
+
+// $btn-warning-color: #fff !default;
+// $btn-warning-bg: $brand-warning !default;
+// $btn-warning-border: darken($btn-warning-bg, 5%) !default;
+
+// $btn-danger-color: #fff !default;
+// $btn-danger-bg: $brand-danger !default;
+// $btn-danger-border: darken($btn-danger-bg, 5%) !default;
+
+// $btn-link-disabled-color: $gray-light !default;
+
+// // Allows for customizing button radius independently from global border radius
+// $btn-border-radius-base: $border-radius-base !default;
+$btn-border-radius-base: 3px;
+// $btn-border-radius-large: $border-radius-large !default;
+// $btn-border-radius-small: $border-radius-small !default;
+
+
+// //== Forms
+// //
+// //##
+
+// //** ` ` background color
+// $input-bg: #fff !default;
+// //** ` ` background color
+// $input-bg-disabled: $gray-lighter !default;
+
+// //** Text color for ` `s
+// $input-color: $gray !default;
+// //** ` ` border color
+// $input-border: #ccc !default;
+$input-border: #d4d4d4;
+
+// // TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4
+// //** Default `.form-control` border radius
+// // This has no effect on ``s in some browsers, due to the limited stylability of ``s in CSS.
+// $input-border-radius: $border-radius-base !default;
+$input-border-radius: 3px;
+// //** Large `.form-control` border radius
+// $input-border-radius-large: $border-radius-large !default;
+// //** Small `.form-control` border radius
+// $input-border-radius-small: $border-radius-small !default;
+
+// //** Border color for inputs on focus
+// $input-border-focus: #66afe9 !default;
+$input-border-focus: $theme-color;
+
+// //** Placeholder text color
+// $input-color-placeholder: #999 !default;
+
+// //** Default `.form-control` height
+// $input-height-base: ($line-height-computed + ($padding-base-vertical * 2) + 2) !default;
+$input-height-base: 44px;
+// //** Large `.form-control` height
+// $input-height-large: (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2) !default;
+// //** Small `.form-control` height
+// $input-height-small: (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2) !default;
+
+// //** `.form-group` margin
+// $form-group-margin-bottom: 15px !default;
+$form-group-margin-bottom: 24px;
+
+// $legend-color: $gray-dark !default;
+// $legend-border-color: #e5e5e5 !default;
+
+// //** Background color for textual input addons
+// $input-group-addon-bg: $gray-lighter !default;
+// //** Border color for textual input addons
+// $input-group-addon-border-color: $input-border !default;
+
+// //** Disabled cursor for form controls and buttons.
+// $cursor-disabled: not-allowed !default;
+
+
+// //== Dropdowns
+// //
+// //## Dropdown menu container and contents.
+
+// //** Background for the dropdown menu.
+// $dropdown-bg: #fff !default;
+// //** Dropdown menu `border-color`.
+// $dropdown-border: rgba(0,0,0,.15) !default;
+// //** Dropdown menu `border-color` **for IE8**.
+// $dropdown-fallback-border: #ccc !default;
+// //** Divider color for between dropdown items.
+// $dropdown-divider-bg: #e5e5e5 !default;
+
+// //** Dropdown link text color.
+// $dropdown-link-color: $gray-dark !default;
+$dropdown-link-color: $theme-color;
+// //** Hover color for dropdown links.
+// $dropdown-link-hover-color: darken($gray-dark, 5%) !default;
+$dropdown-link-hover-color: $theme-color;
+// //** Hover background for dropdown links.
+// $dropdown-link-hover-bg: #f5f5f5 !default;
+$dropdown-link-hover-bg: #f3f3f3;
+
+// //** Active dropdown menu item text color.
+$dropdown-link-active-color: $theme-color;
+// //** Active dropdown menu item background color.
+// $dropdown-link-active-bg: $component-active-bg !default;
+$dropdown-link-active-bg: #e3e3e3;
+
+// //** Disabled dropdown menu item background color.
+// $dropdown-link-disabled-color: $gray-light !default;
+
+// //** Text color for headers within dropdown menus.
+// $dropdown-header-color: $gray-light !default;
+
+// //** Deprecated `$dropdown-caret-color` as of v3.1.0
+// $dropdown-caret-color: #000 !default;
+
+
+// //-- Z-index master list
+// //
+// // Warning: Avoid customizing these values. They're used for a bird's eye view
+// // of components dependent on the z-axis and are designed to all work together.
+// //
+// // Note: These variables are not generated into the Customizer.
+
+// $zindex-navbar: 1000 !default;
+// $zindex-dropdown: 1000 !default;
+// $zindex-popover: 1060 !default;
+// $zindex-tooltip: 1070 !default;
+// $zindex-navbar-fixed: 1030 !default;
+// $zindex-modal-background: 1040 !default;
+// $zindex-modal: 1050 !default;
+
+
+// //== Media queries breakpoints
+// //
+// //## Define the breakpoints at which your layout will change, adapting to different screen sizes.
+
+// // Extra small screen / phone
+// //** Deprecated `$screen-xs` as of v3.0.1
+// $screen-xs: 480px !default;
+// //** Deprecated `$screen-xs-min` as of v3.2.0
+// $screen-xs-min: $screen-xs !default;
+// //** Deprecated `$screen-phone` as of v3.0.1
+// $screen-phone: $screen-xs-min !default;
+
+// // Small screen / tablet
+// //** Deprecated `$screen-sm` as of v3.0.1
+// $screen-sm: 768px !default;
+// $screen-sm-min: $screen-sm !default;
+// //** Deprecated `$screen-tablet` as of v3.0.1
+// $screen-tablet: $screen-sm-min !default;
+
+// // Medium screen / desktop
+// //** Deprecated `$screen-md` as of v3.0.1
+// $screen-md: 992px !default;
+// $screen-md-min: $screen-md !default;
+// //** Deprecated `$screen-desktop` as of v3.0.1
+// $screen-desktop: $screen-md-min !default;
+
+// // Large screen / wide desktop
+// //** Deprecated `$screen-lg` as of v3.0.1
+// $screen-lg: 1200px !default;
+// $screen-lg: 1140;
+// $screen-lg-min: $screen-lg !default;
+// //** Deprecated `$screen-lg-desktop` as of v3.0.1
+// $screen-lg-desktop: $screen-lg-min !default;
+
+// // So media queries don't overlap when required, provide a maximum
+// $screen-xs-max: ($screen-sm-min - 1) !default;
+// $screen-sm-max: ($screen-md-min - 1) !default;
+// $screen-md-max: ($screen-lg-min - 1) !default;
+
+
+// //== Grid system
+// //
+// //## Define your custom responsive grid.
+
+// //** Number of columns in the grid.
+// $grid-columns: 12 !default;
+// //** Padding between columns. Gets divided in half for the left and right.
+// $grid-gutter-width: 30px !default;
+// // Navbar collapse
+// //** Point at which the navbar becomes uncollapsed.
+// $grid-float-breakpoint: $screen-sm-min !default;
+// //** Point at which the navbar begins collapsing.
+// $grid-float-breakpoint-max: ($grid-float-breakpoint - 1) !default;
+
+
+// //== Container sizes
+// //
+// //## Define the maximum width of `.container` for different screen sizes.
+
+// // Small screen / tablet
+// $container-tablet: (720px + $grid-gutter-width) !default;
+// //** For `$screen-sm-min` and up.
+// $container-sm: $container-tablet !default;
+
+// // Medium screen / desktop
+// $container-desktop: (940px + $grid-gutter-width) !default;
+// //** For `$screen-md-min` and up.
+// $container-md: $container-desktop !default;
+
+// // Large screen / wide desktop
+// $container-large-desktop: (1140px + $grid-gutter-width) !default;
+// //** For `$screen-lg-min` and up.
+// $container-lg: $container-large-desktop !default;
+
+
+// //== Navbar
+// //
+// //##
+
+// // Basics of a navbar
+// $navbar-height: 50px !default;
+$navbar-margin-bottom: 0 !default;
+// $navbar-border-radius: $border-radius-base !default;
+$navbar-border-radius: 0;
+// $navbar-padding-horizontal: floor(($grid-gutter-width / 2)) !default;
+// $navbar-padding-vertical: (($navbar-height - $line-height-computed) / 2) !default;
+// $navbar-collapse-max-height: 340px !default;
+
+// $navbar-default-color: #777 !default;
+// $navbar-default-bg: #f8f8f8 !default;
+$navbar-default-bg: $theme-color;
+// $navbar-default-border: darken($navbar-default-bg, 6.5%) !default;
+
+// // Navbar links
+$navbar-default-link-color: #fff !default;
+$navbar-default-link-hover-color: #ccc !default;
+// $navbar-default-link-hover-bg: transparent !default;
+$navbar-default-link-active-color: #dedede !default;
+// $navbar-default-link-active-bg: darken($navbar-default-bg, 6.5%) !default;
+$navbar-default-link-active-bg: transparent;
+$navbar-default-link-disabled-color: #aaa !default;
+// $navbar-default-link-disabled-bg: transparent !default;
+
+// // Navbar brand label
+// $navbar-default-brand-color: $navbar-default-link-color !default;
+// $navbar-default-brand-hover-color: darken($navbar-default-brand-color, 10%) !default;
+// $navbar-default-brand-hover-bg: transparent !default;
+
+// // Navbar toggle
+// $navbar-default-toggle-hover-bg: #ddd !default;
+$navbar-default-toggle-hover-bg: transparent;
+// $navbar-default-toggle-icon-bar-bg: #888 !default;
+$navbar-default-toggle-icon-bar-bg: #fff;
+// $navbar-default-toggle-border-color: #ddd !default;
+$navbar-default-toggle-border-color: transparent;
+
+
+// //=== Inverted navbar
+// // Reset inverted navbar basics
+// $navbar-inverse-color: lighten($gray-light, 15%) !default;
+// $navbar-inverse-bg: #222 !default;
+// $navbar-inverse-border: darken($navbar-inverse-bg, 10%) !default;
+
+// // Inverted navbar links
+// $navbar-inverse-link-color: lighten($gray-light, 15%) !default;
+// $navbar-inverse-link-hover-color: #fff !default;
+// $navbar-inverse-link-hover-bg: transparent !default;
+// $navbar-inverse-link-active-color: $navbar-inverse-link-hover-color !default;
+// $navbar-inverse-link-active-bg: darken($navbar-inverse-bg, 10%) !default;
+// $navbar-inverse-link-disabled-color: #444 !default;
+// $navbar-inverse-link-disabled-bg: transparent !default;
+
+// // Inverted navbar brand label
+// $navbar-inverse-brand-color: $navbar-inverse-link-color !default;
+// $navbar-inverse-brand-hover-color: #fff !default;
+// $navbar-inverse-brand-hover-bg: transparent !default;
+
+// // Inverted navbar toggle
+// $navbar-inverse-toggle-hover-bg: #333 !default;
+// $navbar-inverse-toggle-icon-bar-bg: #fff !default;
+// $navbar-inverse-toggle-border-color: #333 !default;
+
+
+// //== Navs
+// //
+// //##
+
+// //=== Shared nav styles
+// $nav-link-padding: 10px 15px !default;
+// $nav-link-hover-bg: $gray-lighter !default;
+
+// $nav-disabled-link-color: $gray-light !default;
+// $nav-disabled-link-hover-color: $gray-light !default;
+
+// //== Tabs
+// $nav-tabs-border-color: #ddd !default;
+
+// $nav-tabs-link-hover-border-color: $gray-lighter !default;
+
+// $nav-tabs-active-link-hover-bg: $body-bg !default;
+// $nav-tabs-active-link-hover-color: $gray !default;
+// $nav-tabs-active-link-hover-border-color: #ddd !default;
+
+// $nav-tabs-justified-link-border-color: #ddd !default;
+// $nav-tabs-justified-active-link-border-color: $body-bg !default;
+
+// //== Pills
+// $nav-pills-border-radius: $border-radius-base !default;
+// $nav-pills-active-link-hover-bg: $component-active-bg !default;
+// $nav-pills-active-link-hover-color: $component-active-color !default;
+
+
+// //== Pagination
+// //
+// //##
+
+// $pagination-color: $link-color !default;
+// $pagination-bg: #fff !default;
+// $pagination-border: #ddd !default;
+
+// $pagination-hover-color: $link-hover-color !default;
+// $pagination-hover-bg: $gray-lighter !default;
+// $pagination-hover-border: #ddd !default;
+
+// $pagination-active-color: #fff !default;
+// $pagination-active-bg: $brand-primary !default;
+// $pagination-active-border: $brand-primary !default;
+
+// $pagination-disabled-color: $gray-light !default;
+// $pagination-disabled-bg: #fff !default;
+// $pagination-disabled-border: #ddd !default;
+
+
+// //== Pager
+// //
+// //##
+
+// $pager-bg: $pagination-bg !default;
+// $pager-border: $pagination-border !default;
+// $pager-border-radius: 15px !default;
+
+// $pager-hover-bg: $pagination-hover-bg !default;
+
+// $pager-active-bg: $pagination-active-bg !default;
+// $pager-active-color: $pagination-active-color !default;
+
+// $pager-disabled-color: $pagination-disabled-color !default;
+
+
+// //== Jumbotron
+// //
+// //##
+
+// $jumbotron-padding: 30px !default;
+// $jumbotron-color: inherit !default;
+// $jumbotron-bg: $gray-lighter !default;
+// $jumbotron-heading-color: inherit !default;
+// $jumbotron-font-size: ceil(($font-size-base * 1.5)) !default;
+// $jumbotron-heading-font-size: ceil(($font-size-base * 4.5)) !default;
+
+
+// //== Form states and alerts
+// //
+// //## Define colors for form feedback states and, by default, alerts.
+
+// $state-success-text: #3c763d !default;
+// $state-success-bg: #dff0d8 !default;
+// $state-success-border: darken(adjust-hue($state-success-bg, -10), 5%) !default;
+
+// $state-info-text: #31708f !default;
+// $state-info-bg: #d9edf7 !default;
+// $state-info-border: darken(adjust-hue($state-info-bg, -10), 7%) !default;
+
+// $state-warning-text: #8a6d3b !default;
+// $state-warning-bg: #fcf8e3 !default;
+// $state-warning-border: darken(adjust-hue($state-warning-bg, -10), 5%) !default;
+
+// $state-danger-text: #a94442 !default;
+$state-danger-text: #f15a39;
+// $state-danger-bg: #f2dede !default;
+// $state-danger-border: darken(adjust-hue($state-danger-bg, -10), 5%) !default;
+
+
+// //== Tooltips
+// //
+// //##
+
+// //** Tooltip max width
+// $tooltip-max-width: 200px !default;
+// //** Tooltip text color
+// $tooltip-color: #fff !default;
+// //** Tooltip background color
+// $tooltip-bg: #000 !default;
+// $tooltip-opacity: .9 !default;
+
+// //** Tooltip arrow width
+// $tooltip-arrow-width: 5px !default;
+// //** Tooltip arrow color
+// $tooltip-arrow-color: $tooltip-bg !default;
+
+
+// //== Popovers
+// //
+// //##
+
+// //** Popover body background color
+// $popover-bg: #fff !default;
+// //** Popover maximum width
+// $popover-max-width: 276px !default;
+// //** Popover border color
+// $popover-border-color: rgba(0,0,0,.2) !default;
+// //** Popover fallback border color
+// $popover-fallback-border-color: #ccc !default;
+
+// //** Popover title background color
+// $popover-title-bg: darken($popover-bg, 3%) !default;
+
+// //** Popover arrow width
+// $popover-arrow-width: 10px !default;
+// //** Popover arrow color
+// $popover-arrow-color: $popover-bg !default;
+
+// //** Popover outer arrow width
+// $popover-arrow-outer-width: ($popover-arrow-width + 1) !default;
+// //** Popover outer arrow color
+// $popover-arrow-outer-color: fade_in($popover-border-color, 0.05) !default;
+// //** Popover outer arrow fallback color
+// $popover-arrow-outer-fallback-color: darken($popover-fallback-border-color, 20%) !default;
+
+
+// //== Labels
+// //
+// //##
+
+// //** Default label background color
+// $label-default-bg: $gray-light !default;
+// //** Primary label background color
+// $label-primary-bg: $brand-primary !default;
+// //** Success label background color
+// $label-success-bg: $brand-success !default;
+// //** Info label background color
+// $label-info-bg: $brand-info !default;
+// //** Warning label background color
+// $label-warning-bg: $brand-warning !default;
+// //** Danger label background color
+// $label-danger-bg: $brand-danger !default;
+
+// //** Default label text color
+// $label-color: #fff !default;
+// //** Default text color of a linked label
+// $label-link-hover-color: #fff !default;
+
+
+// //== Modals
+// //
+// //##
+
+// //** Padding applied to the modal body
+// $modal-inner-padding: 15px !default;
+
+// //** Padding applied to the modal title
+// $modal-title-padding: 15px !default;
+// //** Modal title line-height
+// $modal-title-line-height: $line-height-base !default;
+
+// //** Background color of modal content area
+$modal-content-bg: #46467A !default;
+// //** Modal content border color
+// $modal-content-border-color: rgba(0,0,0,.2) !default;
+// //** Modal content border color **for IE8**
+// $modal-content-fallback-border-color: #999 !default;
+
+// //** Modal backdrop background color
+// $modal-backdrop-bg: #000 !default;
+// //** Modal backdrop opacity
+// $modal-backdrop-opacity: .5 !default;
+// //** Modal header border color
+// $modal-header-border-color: #e5e5e5 !default;
+// //** Modal footer border color
+// $modal-footer-border-color: $modal-header-border-color !default;
+
+// $modal-lg: 900px !default;
+// $modal-md: 600px !default;
+// $modal-sm: 300px !default;
+
+
+// //== Alerts
+// //
+// //## Define alert colors, border radius, and padding.
+
+// $alert-padding: 15px !default;
+// $alert-border-radius: $border-radius-base !default;
+// $alert-link-font-weight: bold !default;
+
+// $alert-success-bg: $state-success-bg !default;
+// $alert-success-text: $state-success-text !default;
+// $alert-success-border: $state-success-border !default;
+
+// $alert-info-bg: $state-info-bg !default;
+// $alert-info-text: $state-info-text !default;
+// $alert-info-border: $state-info-border !default;
+
+// $alert-warning-bg: $state-warning-bg !default;
+// $alert-warning-text: $state-warning-text !default;
+// $alert-warning-border: $state-warning-border !default;
+
+// $alert-danger-bg: $state-danger-bg !default;
+// $alert-danger-text: $state-danger-text !default;
+// $alert-danger-border: $state-danger-border !default;
+
+
+// //== Progress bars
+// //
+// //##
+
+// //** Background color of the whole progress component
+// $progress-bg: #f5f5f5 !default;
+// //** Progress bar text color
+$progress-bar-color: #333 !default;
+// //** Variable for setting rounded corners on progress bar.
+// $progress-border-radius: $border-radius-base !default;
+
+// //** Default progress bar color
+// $progress-bar-bg: $brand-primary !default;
+// //** Success progress bar color
+// $progress-bar-success-bg: $brand-success !default;
+// //** Warning progress bar color
+// $progress-bar-warning-bg: $brand-warning !default;
+// //** Danger progress bar color
+// $progress-bar-danger-bg: $brand-danger !default;
+// //** Info progress bar color
+// $progress-bar-info-bg: $brand-info !default;
+
+
+// //== List group
+// //
+// //##
+
+// //** Background color on `.list-group-item`
+// $list-group-bg: #fff !default;
+// //** `.list-group-item` border color
+// $list-group-border: #ddd !default;
+// //** List group border radius
+// $list-group-border-radius: $border-radius-base !default;
+
+// //** Background color of single list items on hover
+// $list-group-hover-bg: #f5f5f5 !default;
+// //** Text color of active list items
+// $list-group-active-color: $component-active-color !default;
+// //** Background color of active list items
+// $list-group-active-bg: $component-active-bg !default;
+// //** Border color of active list elements
+// $list-group-active-border: $list-group-active-bg !default;
+// //** Text color for content within active list items
+// $list-group-active-text-color: lighten($list-group-active-bg, 40%) !default;
+
+// //** Text color of disabled list items
+// $list-group-disabled-color: $gray-light !default;
+// //** Background color of disabled list items
+// $list-group-disabled-bg: $gray-lighter !default;
+// //** Text color for content within disabled list items
+// $list-group-disabled-text-color: $list-group-disabled-color !default;
+
+// $list-group-link-color: #555 !default;
+// $list-group-link-hover-color: $list-group-link-color !default;
+// $list-group-link-heading-color: #333 !default;
+
+
+// //== Panels
+// //
+// //##
+
+// $panel-bg: #fff !default;
+// $panel-body-padding: 15px !default;
+// $panel-heading-padding: 10px 15px !default;
+// $panel-footer-padding: $panel-heading-padding !default;
+// $panel-border-radius: $border-radius-base !default;
+
+// //** Border color for elements within panels
+// $panel-inner-border: #ddd !default;
+// $panel-footer-bg: #f5f5f5 !default;
+
+// $panel-default-text: $gray-dark !default;
+// $panel-default-border: #ddd !default;
+// $panel-default-heading-bg: #f5f5f5 !default;
+
+// $panel-primary-text: #fff !default;
+// $panel-primary-border: $brand-primary !default;
+// $panel-primary-heading-bg: $brand-primary !default;
+
+// $panel-success-text: $state-success-text !default;
+// $panel-success-border: $state-success-border !default;
+// $panel-success-heading-bg: $state-success-bg !default;
+
+// $panel-info-text: $state-info-text !default;
+// $panel-info-border: $state-info-border !default;
+// $panel-info-heading-bg: $state-info-bg !default;
+
+// $panel-warning-text: $state-warning-text !default;
+// $panel-warning-border: $state-warning-border !default;
+// $panel-warning-heading-bg: $state-warning-bg !default;
+
+// $panel-danger-text: $state-danger-text !default;
+// $panel-danger-border: $state-danger-border !default;
+// $panel-danger-heading-bg: $state-danger-bg !default;
+
+
+// //== Thumbnails
+// //
+// //##
+
+// //** Padding around the thumbnail image
+// $thumbnail-padding: 4px !default;
+// //** Thumbnail background color
+// $thumbnail-bg: $body-bg !default;
+// //** Thumbnail border color
+// $thumbnail-border: #ddd !default;
+// //** Thumbnail border radius
+// $thumbnail-border-radius: $border-radius-base !default;
+
+// //** Custom text color for thumbnail captions
+// $thumbnail-caption-color: $text-color !default;
+// //** Padding around the thumbnail caption
+// $thumbnail-caption-padding: 9px !default;
+
+
+// //== Wells
+// //
+// //##
+
+// $well-bg: #f5f5f5 !default;
+// $well-border: darken($well-bg, 7%) !default;
+
+
+// //== Badges
+// //
+// //##
+
+// $badge-color: #fff !default;
+// //** Linked badge text color on hover
+// $badge-link-hover-color: #fff !default;
+// $badge-bg: $gray-light !default;
+
+// //** Badge text color in active nav link
+// $badge-active-color: $link-color !default;
+// //** Badge background color in active nav link
+// $badge-active-bg: #fff !default;
+
+// $badge-font-weight: bold !default;
+// $badge-line-height: 1 !default;
+// $badge-border-radius: 10px !default;
+
+
+// //== Breadcrumbs
+// //
+// //##
+
+// $breadcrumb-padding-vertical: 8px !default;
+// $breadcrumb-padding-horizontal: 15px !default;
+// //** Breadcrumb background color
+// $breadcrumb-bg: #f5f5f5 !default;
+// //** Breadcrumb text color
+// $breadcrumb-color: #ccc !default;
+// //** Text color of current page in the breadcrumb
+// $breadcrumb-active-color: $gray-light !default;
+// //** Textual separator for between breadcrumb elements
+// $breadcrumb-separator: "/" !default;
+
+
+// //== Carousel
+// //
+// //##
+
+// $carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6) !default;
+
+// $carousel-control-color: #fff !default;
+// $carousel-control-width: 15% !default;
+// $carousel-control-opacity: .5 !default;
+// $carousel-control-font-size: 20px !default;
+
+// $carousel-indicator-active-bg: #fff !default;
+// $carousel-indicator-border-color: #fff !default;
+
+// $carousel-caption-color: #fff !default;
+
+
+// //== Close
+// //
+// //##
+
+// $close-font-weight: bold !default;
+$close-color: #fff !default;
+// $close-text-shadow: 0 1px 0 #fff !default;
+
+
+// //== Code
+// //
+// //##
+
+// $code-color: #c7254e !default;
+// $code-bg: #f9f2f4 !default;
+
+// $kbd-color: #fff !default;
+// $kbd-bg: #333 !default;
+
+// $pre-bg: #f5f5f5 !default;
+// $pre-color: $gray-dark !default;
+// $pre-border-color: #ccc !default;
+// $pre-scrollable-max-height: 340px !default;
+
+
+// //== Type
+// //
+// //##
+
+// //** Horizontal offset for forms and lists.
+// $component-offset-horizontal: 180px !default;
+// //** Text muted color
+// $text-muted: $gray-light !default;
+// //** Abbreviations and acronyms border color
+// $abbr-border-color: $gray-light !default;
+// //** Headings small color
+// $headings-small-color: $gray-light !default;
+// //** Blockquote small color
+// $blockquote-small-color: $gray-light !default;
+// //** Blockquote font size
+// $blockquote-font-size: ($font-size-base * 1.25) !default;
+// //** Blockquote border color
+// $blockquote-border-color: $gray-lighter !default;
+// //** Page header border color
+// $page-header-border-color: $gray-lighter !default;
+// //** Width of horizontal description list titles
+// $dl-horizontal-offset: $component-offset-horizontal !default;
+// //** Horizontal line color.
+// $hr-border: $gray-lighter !default;
diff --git a/src/static/pycontw-2024/_includes/base/_variables.scss b/src/static/pycontw-2024/_includes/base/_variables.scss
new file mode 100644
index 000000000..0133d965a
--- /dev/null
+++ b/src/static/pycontw-2024/_includes/base/_variables.scss
@@ -0,0 +1,86 @@
+@import './../../pycontw-2024/styles/_palette.scss';
+
+$static_root: "./../../";
+
+$theme-color: $egyptian-blue;
+$theme-focus: $maize;
+
+$quote-color: $theme-focus;
+
+// section
+$section__heading-color: $theme-color;
+
+// schedule
+$schedule-color: #F58454;
+$schedule__title-color: #ADCDFF;
+
+// intro
+$intro__heading-color: $theme-color;
+$intro-color: #686868;
+
+// community
+$community-bg: $theme-focus;
+$community-color: #6B4C00;
+
+// footer
+$footer-bg: #F9FCFF;
+$footer-color: $theme-color;
+
+// keynotes
+$keynotes-bg: $theme-color;
+$keynote-speaker-bg: #fff;
+$keynote-speaker__url-color: #3C3C3C;
+$keynote-speaker__bio-color: #4A4A4A;
+
+// sprints
+$sprints-bg: $theme-color;
+$sprint-event-bg: #fff;
+$sprint-event__url-color: #3C3C3C;
+$sprint-event__info-color: #4A4A4A;
+
+// sponsors
+$sponsor-bg: $theme-color;
+$sponsor-bronze-color: #c37141;
+$sponsor-silver-color: #a1a1a1;
+$sponsor-gold-color: #ffc525;
+$sponsor-platinum-color: #eddcad;
+
+// Buttons
+
+$btn-primary-bg: $ultramarine-blue;
+$btn-primary-hover-bg: lighter($ultramarine-blue);
+
+$btn-focus-color: $white;
+$btn-focus-bg: $light-indigo;
+$btn-focus-border: $light-indigo;
+$btn-focus-hover-bg: lighter($light-indigo);
+
+$btn-negative-color: #fff;
+$btn-negative-bg: #D4D4D4;
+$btn-negative-border: #D4D4D4;
+$btn-negative-hover-bg: #f5bb1b;
+
+$btn-natural-color: $azure;
+$btn-natural-bg: #f8f8f8;
+$btn-natural-border: #eee;
+$btn-natural-hover-bg: #f3f3f3;
+
+$btn-logout-color: #f0ebf5;
+$btn-logout-bg: transparent;
+$btn-logout-border: transparent;
+$btn-logout-hover-bg: #f3f3f3;
+
+$btn-action-color: #fff;
+$btn-action-bg:#f08e57;
+$btn-action-border: transparent;
+
+$btn-link-color: $theme-color;
+
+$proposals-alert-warning-bg: $maize;
+
+$navbar-em-bg: $btn-primary-bg;
+
+
+// Fonts.
+
+$font-family-sans-serif: $header-font-family !default;
diff --git a/src/static/pycontw-2024/assets/2024-py-logo.svg b/src/static/pycontw-2024/assets/2024-py-logo.svg
new file mode 100644
index 000000000..035facc5c
--- /dev/null
+++ b/src/static/pycontw-2024/assets/2024-py-logo.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/static/pycontw-2024/assets/bg-dashboard.svg b/src/static/pycontw-2024/assets/bg-dashboard.svg
new file mode 100644
index 000000000..f8220b77a
--- /dev/null
+++ b/src/static/pycontw-2024/assets/bg-dashboard.svg
@@ -0,0 +1,424 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/static/pycontw-2024/assets/bg-window-1-black.svg b/src/static/pycontw-2024/assets/bg-window-1-black.svg
new file mode 100644
index 000000000..064be9c9e
--- /dev/null
+++ b/src/static/pycontw-2024/assets/bg-window-1-black.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/static/pycontw-2024/assets/bg-window-2-brick.svg b/src/static/pycontw-2024/assets/bg-window-2-brick.svg
new file mode 100644
index 000000000..363175732
--- /dev/null
+++ b/src/static/pycontw-2024/assets/bg-window-2-brick.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/static/pycontw-2024/assets/button-hover-bg.svg b/src/static/pycontw-2024/assets/button-hover-bg.svg
new file mode 100644
index 000000000..4b1190584
--- /dev/null
+++ b/src/static/pycontw-2024/assets/button-hover-bg.svg
@@ -0,0 +1,269 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/static/pycontw-2024/assets/deco-a-1.svg b/src/static/pycontw-2024/assets/deco-a-1.svg
new file mode 100644
index 000000000..002d1784a
--- /dev/null
+++ b/src/static/pycontw-2024/assets/deco-a-1.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/static/pycontw-2024/assets/deco-a-2.svg b/src/static/pycontw-2024/assets/deco-a-2.svg
new file mode 100644
index 000000000..8c69f70cd
--- /dev/null
+++ b/src/static/pycontw-2024/assets/deco-a-2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/static/pycontw-2024/assets/deco-a-3.svg b/src/static/pycontw-2024/assets/deco-a-3.svg
new file mode 100644
index 000000000..e32b3f849
--- /dev/null
+++ b/src/static/pycontw-2024/assets/deco-a-3.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/static/pycontw-2024/assets/deco-b-1.svg b/src/static/pycontw-2024/assets/deco-b-1.svg
new file mode 100644
index 000000000..9dd42de15
--- /dev/null
+++ b/src/static/pycontw-2024/assets/deco-b-1.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/static/pycontw-2024/assets/deco-b-2.svg b/src/static/pycontw-2024/assets/deco-b-2.svg
new file mode 100644
index 000000000..0b35e332b
--- /dev/null
+++ b/src/static/pycontw-2024/assets/deco-b-2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/static/pycontw-2024/assets/discord-0.jpg b/src/static/pycontw-2024/assets/discord-0.jpg
new file mode 100644
index 000000000..76e4324e0
Binary files /dev/null and b/src/static/pycontw-2024/assets/discord-0.jpg differ
diff --git a/src/static/pycontw-2024/assets/discord-1.png b/src/static/pycontw-2024/assets/discord-1.png
new file mode 100644
index 000000000..dc6bb8c90
Binary files /dev/null and b/src/static/pycontw-2024/assets/discord-1.png differ
diff --git a/src/static/pycontw-2024/assets/discord-2.png b/src/static/pycontw-2024/assets/discord-2.png
new file mode 100644
index 000000000..161533577
Binary files /dev/null and b/src/static/pycontw-2024/assets/discord-2.png differ
diff --git a/src/static/pycontw-2024/assets/favicon-inverted/favicon-16x16.png b/src/static/pycontw-2024/assets/favicon-inverted/favicon-16x16.png
new file mode 100644
index 000000000..982de36b0
Binary files /dev/null and b/src/static/pycontw-2024/assets/favicon-inverted/favicon-16x16.png differ
diff --git a/src/static/pycontw-2024/assets/favicon-inverted/favicon-192x192.png b/src/static/pycontw-2024/assets/favicon-inverted/favicon-192x192.png
new file mode 100644
index 000000000..cfa454cd9
Binary files /dev/null and b/src/static/pycontw-2024/assets/favicon-inverted/favicon-192x192.png differ
diff --git a/src/static/pycontw-2024/assets/favicon-inverted/favicon-32x32.png b/src/static/pycontw-2024/assets/favicon-inverted/favicon-32x32.png
new file mode 100644
index 000000000..6433c37b7
Binary files /dev/null and b/src/static/pycontw-2024/assets/favicon-inverted/favicon-32x32.png differ
diff --git a/src/static/pycontw-2024/assets/favicon-inverted/favicon.ico b/src/static/pycontw-2024/assets/favicon-inverted/favicon.ico
new file mode 100644
index 000000000..9c26f19a9
Binary files /dev/null and b/src/static/pycontw-2024/assets/favicon-inverted/favicon.ico differ
diff --git a/src/static/pycontw-2024/assets/favicon/favicon-16x16.png b/src/static/pycontw-2024/assets/favicon/favicon-16x16.png
new file mode 100644
index 000000000..925a10a8d
Binary files /dev/null and b/src/static/pycontw-2024/assets/favicon/favicon-16x16.png differ
diff --git a/src/static/pycontw-2024/assets/favicon/favicon-192x192.png b/src/static/pycontw-2024/assets/favicon/favicon-192x192.png
new file mode 100644
index 000000000..28a2b9298
Binary files /dev/null and b/src/static/pycontw-2024/assets/favicon/favicon-192x192.png differ
diff --git a/src/static/pycontw-2024/assets/favicon/favicon-32x32.png b/src/static/pycontw-2024/assets/favicon/favicon-32x32.png
new file mode 100644
index 000000000..a572a9f56
Binary files /dev/null and b/src/static/pycontw-2024/assets/favicon/favicon-32x32.png differ
diff --git a/src/static/pycontw-2024/assets/favicon/favicon.ico b/src/static/pycontw-2024/assets/favicon/favicon.ico
new file mode 100644
index 000000000..d4d7a9a80
Binary files /dev/null and b/src/static/pycontw-2024/assets/favicon/favicon.ico differ
diff --git a/src/static/pycontw-2024/assets/footer-image.svg b/src/static/pycontw-2024/assets/footer-image.svg
new file mode 100644
index 000000000..5eb428357
--- /dev/null
+++ b/src/static/pycontw-2024/assets/footer-image.svg
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/static/pycontw-2024/assets/grass-blue.svg b/src/static/pycontw-2024/assets/grass-blue.svg
new file mode 100644
index 000000000..02aa7a041
--- /dev/null
+++ b/src/static/pycontw-2024/assets/grass-blue.svg
@@ -0,0 +1,31 @@
+
+
+
+ Group 12
+ Created with Sketch.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/static/pycontw-2024/assets/grass-green.svg b/src/static/pycontw-2024/assets/grass-green.svg
new file mode 100644
index 000000000..8536d1b36
--- /dev/null
+++ b/src/static/pycontw-2024/assets/grass-green.svg
@@ -0,0 +1,31 @@
+
+
+
+ Group 12
+ Created with Sketch.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/static/pycontw-2024/assets/grass-group.svg b/src/static/pycontw-2024/assets/grass-group.svg
new file mode 100644
index 000000000..337f52c0c
--- /dev/null
+++ b/src/static/pycontw-2024/assets/grass-group.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/static/pycontw-2024/assets/grass-yellow.svg b/src/static/pycontw-2024/assets/grass-yellow.svg
new file mode 100644
index 000000000..1bf862874
--- /dev/null
+++ b/src/static/pycontw-2024/assets/grass-yellow.svg
@@ -0,0 +1,31 @@
+
+
+
+ Group 12
+ Created with Sketch.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/static/pycontw-2024/assets/icon-about.svg b/src/static/pycontw-2024/assets/icon-about.svg
new file mode 100644
index 000000000..b66a1953c
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-about.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/static/pycontw-2024/assets/icon-clock.svg b/src/static/pycontw-2024/assets/icon-clock.svg
new file mode 100644
index 000000000..34ad90ecc
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-clock.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/static/pycontw-2024/assets/icon-grass-group.svg b/src/static/pycontw-2024/assets/icon-grass-group.svg
new file mode 100644
index 000000000..337f52c0c
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-grass-group.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/static/pycontw-2024/assets/icon-language-enen.svg b/src/static/pycontw-2024/assets/icon-language-enen.svg
new file mode 100644
index 000000000..4cc654432
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-language-enen.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/static/pycontw-2024/assets/icon-language-zhen.svg b/src/static/pycontw-2024/assets/icon-language-zhen.svg
new file mode 100644
index 000000000..0f165c4a6
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-language-zhen.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/static/pycontw-2024/assets/icon-language-zhzh.svg b/src/static/pycontw-2024/assets/icon-language-zhzh.svg
new file mode 100644
index 000000000..b5f938b06
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-language-zhzh.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/static/pycontw-2024/assets/icon-level-1.svg b/src/static/pycontw-2024/assets/icon-level-1.svg
new file mode 100644
index 000000000..62185f6c3
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-level-1.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/static/pycontw-2024/assets/icon-level-2.svg b/src/static/pycontw-2024/assets/icon-level-2.svg
new file mode 100644
index 000000000..8f72bdc6e
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-level-2.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/static/pycontw-2024/assets/icon-level-3.svg b/src/static/pycontw-2024/assets/icon-level-3.svg
new file mode 100644
index 000000000..c16c7feff
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-level-3.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/static/pycontw-2024/assets/icon-location.svg b/src/static/pycontw-2024/assets/icon-location.svg
new file mode 100644
index 000000000..1fd27e401
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-location.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/static/pycontw-2024/assets/icon-map-main.png b/src/static/pycontw-2024/assets/icon-map-main.png
new file mode 100644
index 000000000..9439596a2
Binary files /dev/null and b/src/static/pycontw-2024/assets/icon-map-main.png differ
diff --git a/src/static/pycontw-2024/assets/icon-map-main@2x.png b/src/static/pycontw-2024/assets/icon-map-main@2x.png
new file mode 100644
index 000000000..cf62a438e
Binary files /dev/null and b/src/static/pycontw-2024/assets/icon-map-main@2x.png differ
diff --git a/src/static/pycontw-2024/assets/icon-map-tutorial.png b/src/static/pycontw-2024/assets/icon-map-tutorial.png
new file mode 100644
index 000000000..1c56c8974
Binary files /dev/null and b/src/static/pycontw-2024/assets/icon-map-tutorial.png differ
diff --git a/src/static/pycontw-2024/assets/icon-map-tutorial@2x.png b/src/static/pycontw-2024/assets/icon-map-tutorial@2x.png
new file mode 100644
index 000000000..f540a6229
Binary files /dev/null and b/src/static/pycontw-2024/assets/icon-map-tutorial@2x.png differ
diff --git a/src/static/pycontw-2024/assets/icon-no-recording.svg b/src/static/pycontw-2024/assets/icon-no-recording.svg
new file mode 100644
index 000000000..c10dd7339
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-no-recording.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/static/pycontw-2024/assets/icon-registration.svg b/src/static/pycontw-2024/assets/icon-registration.svg
new file mode 100644
index 000000000..423fbcce4
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-registration.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/static/pycontw-2024/assets/icon-room-R0.svg b/src/static/pycontw-2024/assets/icon-room-R0.svg
new file mode 100644
index 000000000..92a1a97aa
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-room-R0.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/static/pycontw-2024/assets/icon-room-R1.svg b/src/static/pycontw-2024/assets/icon-room-R1.svg
new file mode 100644
index 000000000..f12c29530
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-room-R1.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/static/pycontw-2024/assets/icon-room-R2.svg b/src/static/pycontw-2024/assets/icon-room-R2.svg
new file mode 100644
index 000000000..008fef617
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-room-R2.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/static/pycontw-2024/assets/icon-room-R3.svg b/src/static/pycontw-2024/assets/icon-room-R3.svg
new file mode 100644
index 000000000..a904b68ba
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-room-R3.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/static/pycontw-2024/assets/icon-snake.svg b/src/static/pycontw-2024/assets/icon-snake.svg
new file mode 100644
index 000000000..b1a3d8806
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-snake.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/static/pycontw-2024/assets/icon-speaking.svg b/src/static/pycontw-2024/assets/icon-speaking.svg
new file mode 100644
index 000000000..0889c1145
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-speaking.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/static/pycontw-2024/assets/icon-sponsor.svg b/src/static/pycontw-2024/assets/icon-sponsor.svg
new file mode 100644
index 000000000..d5023ee39
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-sponsor.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/static/pycontw-2024/assets/icon-tag.svg b/src/static/pycontw-2024/assets/icon-tag.svg
new file mode 100644
index 000000000..3f0008c39
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-tag.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/static/pycontw-2024/assets/icon-venue.svg b/src/static/pycontw-2024/assets/icon-venue.svg
new file mode 100644
index 000000000..fd04cc7ae
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-venue.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/static/pycontw-2024/assets/icon-volunteering.svg b/src/static/pycontw-2024/assets/icon-volunteering.svg
new file mode 100644
index 000000000..eb38b4e56
--- /dev/null
+++ b/src/static/pycontw-2024/assets/icon-volunteering.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/static/pycontw-2024/assets/logo-icon-yellow.svg b/src/static/pycontw-2024/assets/logo-icon-yellow.svg
new file mode 100644
index 000000000..3b61ecf3a
--- /dev/null
+++ b/src/static/pycontw-2024/assets/logo-icon-yellow.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/static/pycontw-2024/assets/logo-py-white.svg b/src/static/pycontw-2024/assets/logo-py-white.svg
new file mode 100755
index 000000000..211e2d1e3
--- /dev/null
+++ b/src/static/pycontw-2024/assets/logo-py-white.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
diff --git a/src/static/pycontw-2024/assets/one-grass-yellow.svg b/src/static/pycontw-2024/assets/one-grass-yellow.svg
new file mode 100644
index 000000000..8d2d5f2e8
--- /dev/null
+++ b/src/static/pycontw-2024/assets/one-grass-yellow.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/static/pycontw-2024/assets/perspective-desktop.svg b/src/static/pycontw-2024/assets/perspective-desktop.svg
new file mode 100755
index 000000000..fa3933536
--- /dev/null
+++ b/src/static/pycontw-2024/assets/perspective-desktop.svg
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/static/pycontw-2024/assets/perspective-mobile.svg b/src/static/pycontw-2024/assets/perspective-mobile.svg
new file mode 100755
index 000000000..bcf67668d
--- /dev/null
+++ b/src/static/pycontw-2024/assets/perspective-mobile.svg
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/static/pycontw-2024/assets/snake-icon-dark.svg b/src/static/pycontw-2024/assets/snake-icon-dark.svg
new file mode 100644
index 000000000..e154e35fd
--- /dev/null
+++ b/src/static/pycontw-2024/assets/snake-icon-dark.svg
@@ -0,0 +1 @@
+
diff --git a/src/static/pycontw-2024/assets/snake-icon.svg b/src/static/pycontw-2024/assets/snake-icon.svg
new file mode 100644
index 000000000..d8c81302c
--- /dev/null
+++ b/src/static/pycontw-2024/assets/snake-icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/static/pycontw-2024/assets/twicon/twicon.css b/src/static/pycontw-2024/assets/twicon/twicon.css
new file mode 100644
index 000000000..8fa3fa56c
--- /dev/null
+++ b/src/static/pycontw-2024/assets/twicon/twicon.css
@@ -0,0 +1,576 @@
+/*!
+* @package twicon
+* @version 1.001
+* @author twicon https://twicon.page
+* @copyright Copyright (c) 2020 twicon
+* @license - https://twicon.page/license/
+*/
+@font-face {
+ font-family: twicon;
+ font-weight: 400;
+ font-style: Regular;
+ src: url(twicon.woff2) format("woff2"),
+ url(twicon.woff) format("woff");
+}
+[class*=" twicon-"],
+[class^="twicon-"] {
+ font-family: twicon !important;
+ speak: none;
+ font-style: normal;
+ font-weight: 400;
+ font-variant: normal;
+ text-transform: none;
+ white-space: nowrap;
+ word-wrap: normal;
+ direction: ltr;
+ line-height: 1;
+ -webkit-font-feature-settings: "liga";
+ -webkit-font-smoothing: antialiased;
+}
+
+.twicon-td-flag:before {
+ content: "\a000";
+}
+.twicon-roc-flag:before {
+ content: "\a001";
+}
+.twicon-main-island:before {
+ content: "\a002";
+}
+.twicon-penghu-islands:before {
+ content: "\a003";
+}
+.twicon-kinmen-island:before {
+ content: "\a004";
+}
+.twicon-green-island:before {
+ content: "\a005";
+}
+.twicon-lamay-island:before {
+ content: "\a006";
+}
+.twicon-gueishan-island:before {
+ content: "\a007";
+}
+.twicon-orchid-island:before {
+ content: "\a008";
+}
+.twicon-grave-sense:before {
+ content: "\a009";
+}
+.twicon-cks-hall:before {
+ content: "\a00a";
+}
+.twicon-gate-cks:before {
+ content: "\a00b";
+}
+.twicon-president-office:before {
+ content: "\a00c";
+}
+.twicon-taipei101:before {
+ content: "\a00d";
+}
+.twicon-np-mus:before {
+ content: "\a00e";
+}
+.twicon-shrine-tp:before {
+ content: "\a00f";
+}
+.twicon-longshan-tmp:before {
+ content: "\a010";
+}
+.twicon-sys-hall:before {
+ content: "\a011";
+}
+.twicon-confucius-tmp:before {
+ content: "\a012";
+}
+.twicon-xingtian-tmp:before {
+ content: "\a013";
+}
+.twicon-nt-mus:before {
+ content: "\a014";
+}
+.twicon-grand-hotel:before {
+ content: "\a015";
+}
+.twicon-228-park:before {
+ content: "\a016";
+}
+.twicon-san-domingo:before {
+ content: "\a017";
+}
+.twicon-raohe-nm:before {
+ content: "\a018";
+}
+.twicon-red-house:before {
+ content: "\a019";
+}
+.twicon-beimen:before {
+ content: "\a01a";
+}
+.twicon-xiaonanmen:before {
+ content: "\a01b";
+}
+.twicon-taipei-stn:before {
+ content: "\a01c";
+}
+.twicon-zeelandia:before {
+ content: "\a01d";
+}
+.twicon-eg-castle:before {
+ content: "\a01e";
+}
+.twicon-provintia:before {
+ content: "\a01f";
+}
+.twicon-hy-statue:before {
+ content: "\a020";
+}
+.twicon-85tower:before {
+ content: "\a021";
+}
+.twicon-fb-stn:before {
+ content: "\a022";
+}
+.twicon-dt-pagoda:before {
+ content: "\a023";
+}
+.twicon-rosary-church:before {
+ content: "\a024";
+}
+.twicon-longteng-brg:before {
+ content: "\a025";
+}
+.twicon-ly-mus:before {
+ content: "\a026";
+}
+.twicon-lovers-brg:before {
+ content: "\a027";
+}
+.twicon-hotspring-mus:before {
+ content: "\a028";
+}
+.twicon-tunghai-uni:before {
+ content: "\a029";
+}
+.twicon-taichung-park:before {
+ content: "\a02a";
+}
+.twicon-queens-head:before {
+ content: "\a02b";
+}
+.twicon-ntc-theater:before {
+ content: "\a02c";
+}
+.twicon-bagua:before {
+ content: "\a02d";
+}
+.twicon-foguangshan:before {
+ content: "\a02e";
+}
+.twicon-vase-rock:before {
+ content: "\a02f";
+}
+.twicon-tropic-cancer:before {
+ content: "\a030";
+}
+.twicon-fuguijiao-lh:before {
+ content: "\a031";
+}
+.twicon-yuweng-lh:before {
+ content: "\a032";
+}
+.twicon-eluanbi-lh:before {
+ content: "\a033";
+}
+.twicon-kano-staue:before {
+ content: "\a034";
+}
+.twicon-ershawan:before {
+ content: "\a035";
+}
+.twicon-dahu-park:before {
+ content: "\a036";
+}
+.twicon-balloon:before {
+ content: "\a037";
+}
+.twicon-taiwan-rw:before {
+ content: "\a038";
+}
+.twicon-taipei-mrt:before {
+ content: "\a039";
+}
+.twicon-alishan-rw:before {
+ content: "\a03a";
+}
+.twicon-high-speed-rail:before {
+ content: "\a03b";
+}
+.twicon-gondola:before {
+ content: "\a03c";
+}
+.twicon-youbike:before {
+ content: "\a03d";
+}
+.twicon-yami-boat:before {
+ content: "\a03e";
+}
+.twicon-dragon-boat:before {
+ content: "\a03f";
+}
+.twicon-lantern1:before {
+ content: "\a040";
+}
+.twicon-lantern2:before {
+ content: "\a041";
+}
+.twicon-sky-lantern:before {
+ content: "\a042";
+}
+.twicon-taiwanese-bag:before {
+ content: "\a043";
+}
+.twicon-postbox1:before {
+ content: "\a044";
+}
+.twicon-postbox2:before {
+ content: "\a045";
+}
+.twicon-jug:before {
+ content: "\a046";
+}
+.twicon-tea-pot:before {
+ content: "\a047";
+}
+.twicon-tapioca:before {
+ content: "\a048";
+}
+.twicon-beer:before {
+ content: "\a049";
+}
+.twicon-apple-cider:before {
+ content: "\a04a";
+}
+.twicon-couplets:before {
+ content: "\a04b";
+}
+.twicon-fortune:before {
+ content: "\a04c";
+}
+.twicon-electric-pot:before {
+ content: "\a04d";
+}
+.twicon-slipper:before {
+ content: "\a04e";
+}
+.twicon-flying-fish:before {
+ content: "\a04f";
+}
+.twicon-black-bear:before {
+ content: "\a050";
+}
+.twicon-trash:before {
+ content: "\a052";
+}
+.twicon-recycling:before {
+ content: "\a051";
+}
+.twicon-queue-box:before {
+ content: "\a053";
+}
+.twicon-bicycle-lane:before {
+ content: "\a054";
+}
+.twicon-red-man:before {
+ content: "\a055";
+}
+.twicon-green-man:before {
+ content: "\a056";
+}
+.twicon-l-nh-insurance:before {
+ content: "\a057";
+}
+.twicon-l-pixnet:before {
+ content: "\a058";
+}
+.twicon-l-17live:before {
+ content: "\a059";
+}
+.twicon-l-wemo:before {
+ content: "\a05a";
+}
+.twicon-l-dcard:before {
+ content: "\a05b";
+}
+.twicon-l-easy-card:before {
+ content: "\a05c";
+}
+.twicon-l-ipass:before {
+ content: "\a05d";
+}
+.twicon-l-youbike:before {
+ content: "\a05e";
+}
+.twicon-l-luxgen:before {
+ content: "\a05f";
+}
+.twicon-l-post:before {
+ content: "\a060";
+}
+.twicon-l-taiwan-rw:before {
+ content: "\a061";
+}
+.twicon-l-taipei-mrt:before {
+ content: "\a062";
+}
+.twicon-l-kaoxiong-mrt:before {
+ content: "\a063";
+}
+.twicon-xs {
+ font-size: 0.5em;
+}
+.twicon-sm {
+ font-size: 0.75em;
+}
+.twicon-md {
+ font-size: 1.25em;
+}
+.twicon-lg {
+ font-size: 1.5em;
+}
+.twicon-1x {
+ font-size: 1em;
+}
+.twicon-2x {
+ font-size: 2em;
+}
+.twicon-3x {
+ font-size: 3em;
+}
+.twicon-4x {
+ font-size: 4em;
+}
+.twicon-5x {
+ font-size: 5em;
+}
+.twicon-6x {
+ font-size: 6em;
+}
+.twicon-7x {
+ font-size: 7em;
+}
+.twicon-8x {
+ font-size: 8em;
+}
+.twicon-9x {
+ font-size: 9em;
+}
+.twicon-10x {
+ font-size: 10em;
+}
+.twicon-fw {
+ text-align: center;
+ width: 1.25em;
+}
+.twicon-ul {
+ list-style-type: none;
+ padding-left: 0;
+ margin-left: 0;
+}
+.twicon-ul > li {
+ position: relative;
+ line-height: 2em;
+}
+.twicon-ul > li .twicon {
+ display: inline-block;
+ vertical-align: middle;
+}
+.twicon-border {
+ border: solid 0.08em #f1f1f1;
+ border-radius: 0.1em;
+ padding: 0.2em 0.25em 0.15em;
+}
+.twicon-pull-left {
+ float: left;
+}
+.twicon-pull-right {
+ float: right;
+}
+.twicon.twicon-pull-left {
+ margin-right: 0.3em;
+}
+.twicon.twicon-pull-right {
+ margin-left: 0.3em;
+}
+.twicon-spin {
+ -webkit-animation: twicon-spin 2s infinite linear;
+ animation: twicon-spin 2s infinite linear;
+ display: inline-block;
+}
+.twicon-pulse {
+ -webkit-animation: twicon-spin 1s infinite steps(8);
+ animation: twicon-spin 1s infinite steps(8);
+ display: inline-block;
+}
+@-webkit-keyframes twicon-spin {
+ 0% {
+ -webkit-transform: rotate(0);
+ transform: rotate(0);
+ }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+}
+@keyframes twicon-spin {
+ 0% {
+ -webkit-transform: rotate(0);
+ transform: rotate(0);
+ }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
+}
+.twicon-rotate-90 {
+ -webkit-transform: rotate(90deg);
+ transform: rotate(90deg);
+}
+.twicon-rotate-180 {
+ -webkit-transform: rotate(180deg);
+ transform: rotate(180deg);
+}
+.twicon-rotate-270 {
+ -webkit-transform: rotate(270deg);
+ transform: rotate(270deg);
+}
+.twicon-flip-horizontal {
+ -webkit-transform: scale(-1, 1);
+ transform: scale(-1, 1);
+}
+.twicon-flip-vertical {
+ -webkit-transform: scale(1, -1);
+ transform: scale(1, -1);
+}
+.twicon-flip-horizontal.twicon-flip-vertical {
+ -webkit-transform: scale(-1, -1);
+ transform: scale(-1, -1);
+}
+:root .twicon-flip-horizontal,
+:root .twicon-flip-vertical,
+:root .twicon-rotate-180,
+:root .twicon-rotate-270,
+:root .twicon-rotate-90 {
+ -webkit-filter: none;
+ filter: none;
+ display: inline-block;
+}
+.twicon-inverse {
+ color: #fff;
+}
+/*
+.sr-only {
+ border: 0;
+ clip: rect(0, 0, 0, 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+.sr-only-focusable:active,
+.sr-only-focusable:focus {
+ clip: auto;
+ height: auto;
+ margin: 0;
+ overflow: visible;
+ position: static;
+ width: auto;
+}
+*/
+/* NEW */
+/* GLOBAL STYLES */
+
+/*
+.main-nav {
+ max-width: 1200px;
+}
+
+.navigation ul {
+ background: #fff;
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: flex;
+}
+
+.navigation li {
+ flex: 3;
+}
+
+.navigation .user {
+ flex: 1;
+}
+*/
+
+
+/* HEADER */
+
+/*
+* {
+ box-sizing: border-box;
+}
+
+body {
+ margin: 0;
+}
+
+.header {
+ overflow: hidden;
+ padding: 16px 10px;
+}
+
+.header a {
+ float: left;
+ text-align: center;
+ padding: 14px;
+ text-decoration: none;
+ font-size: 18px;
+ line-height: 23px;
+ border-radius: 4px;
+ margin-right: 10px;
+}
+
+.header a.logo {
+ font-size: 22px;
+}
+
+.header a:hover {
+ background-color: #ddd;
+}
+
+.header a.active {
+ background-color: rgb(110, 172, 125);
+ color: white;
+}
+
+.header-right {
+ float: right;
+}
+
+@media screen and (max-width: 550px) {
+ .header a {
+ padding: 8px;
+ font-size: 12px;
+ line-height: 15px;
+ margin-right: 2px;
+ }
+ .header a.logo {
+ font-size: 18px;
+ font-weight: bold;
+ }
+}
+*/
diff --git a/src/static/pycontw-2024/assets/twicon/twicon.otf b/src/static/pycontw-2024/assets/twicon/twicon.otf
new file mode 100644
index 000000000..60bf47ccc
Binary files /dev/null and b/src/static/pycontw-2024/assets/twicon/twicon.otf differ
diff --git a/src/static/pycontw-2024/assets/twicon/twicon.svg b/src/static/pycontw-2024/assets/twicon/twicon.svg
new file mode 100644
index 000000000..8535ec67c
--- /dev/null
+++ b/src/static/pycontw-2024/assets/twicon/twicon.svg
@@ -0,0 +1,2105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/static/pycontw-2024/assets/twicon/twicon.woff b/src/static/pycontw-2024/assets/twicon/twicon.woff
new file mode 100644
index 000000000..7398ff947
Binary files /dev/null and b/src/static/pycontw-2024/assets/twicon/twicon.woff differ
diff --git a/src/static/pycontw-2024/assets/twicon/twicon.woff2 b/src/static/pycontw-2024/assets/twicon/twicon.woff2
new file mode 100644
index 000000000..8fbac37b7
Binary files /dev/null and b/src/static/pycontw-2024/assets/twicon/twicon.woff2 differ
diff --git a/src/static/pycontw-2024/assets/venue-button.png b/src/static/pycontw-2024/assets/venue-button.png
new file mode 100644
index 000000000..9a45fcd95
Binary files /dev/null and b/src/static/pycontw-2024/assets/venue-button.png differ
diff --git a/src/static/pycontw-2024/assets/venue-icon.png b/src/static/pycontw-2024/assets/venue-icon.png
new file mode 100644
index 000000000..8537a24e0
Binary files /dev/null and b/src/static/pycontw-2024/assets/venue-icon.png differ
diff --git a/src/static/pycontw-2024/assets/venue.png b/src/static/pycontw-2024/assets/venue.png
new file mode 100644
index 000000000..249820e3e
Binary files /dev/null and b/src/static/pycontw-2024/assets/venue.png differ
diff --git a/src/static/pycontw-2024/scripts/app.js b/src/static/pycontw-2024/scripts/app.js
new file mode 100644
index 000000000..5c098c41a
--- /dev/null
+++ b/src/static/pycontw-2024/scripts/app.js
@@ -0,0 +1,13 @@
+import './polyfills'
+
+import {Application} from 'stimulus'
+import {MediaPopupController} from './controllers/popup'
+import {MenuController} from './controllers/menu'
+import {TabbingController} from './controllers/tabbing'
+import {TopNavController} from './controllers/nav'
+
+const application = Application.start()
+application.register('mediaPopup', MediaPopupController)
+application.register('menu', MenuController)
+application.register('tabbing', TabbingController)
+application.register('topNav', TopNavController)
diff --git a/src/static/pycontw-2024/scripts/community-track.js b/src/static/pycontw-2024/scripts/community-track.js
new file mode 100644
index 000000000..b5bdbd5e7
--- /dev/null
+++ b/src/static/pycontw-2024/scripts/community-track.js
@@ -0,0 +1,13 @@
+import 'blueimp-gallery/js/blueimp-gallery.min.js'
+
+let galleryArr=document.getElementsByClassName('links')
+Array.prototype.forEach.call(galleryArr,el=>{
+ el.onclick = function (event) {
+ event = event || window.event
+ var target = event.target || event.srcElement,
+ link = target.src ? target.parentNode : target,
+ options = { index: link, event: event },
+ links = this.getElementsByTagName('a')
+ blueimp.Gallery(links, options)
+ }
+})
\ No newline at end of file
diff --git a/src/static/pycontw-2024/scripts/controllers/menu.js b/src/static/pycontw-2024/scripts/controllers/menu.js
new file mode 100644
index 000000000..95684bff2
--- /dev/null
+++ b/src/static/pycontw-2024/scripts/controllers/menu.js
@@ -0,0 +1,67 @@
+import {Controller} from 'stimulus'
+
+export class MenuController extends Controller {
+
+ static targets = ['item', 'checker']
+
+ connect() {
+ // Click anywhere on the page to close the menu.
+ document.documentElement.addEventListener('click', event => {
+ // Don't run if the event originates from the menu, to avoid triggering
+ // the handler twice when clicking on a menu item. Otherwise a menu item
+ // will not be able to uncheck itself. Also notice we intentionally
+ // exclude label elements to avoid it triggering the input's event.
+ if (event.target.tagName !== 'LABEL' &&
+ !this.checkerTargets.includes(event.target)) {
+ this.exclude(event)
+ }
+ })
+ }
+
+ open(event) {
+ const id = event.target.getAttribute('for')
+ if (id) {
+ document.getElementById(id).checked = true
+ }
+ }
+
+ // Given an element, find the menu item surrounding it (if any).
+ _getMenuItem(target) {
+ let element = target
+ while (element) {
+ if (this.itemTargets.includes(element)) {
+ return element
+ }
+ element = element.parentNode
+ }
+ return null
+ }
+
+ close(event) {
+ // Don't close menu if the current element under cursor is a descendant of
+ // the current menu item. This prevents the menu from being closed when
+ // the mouse is leaving parent to hover onto the submenu.
+ setTimeout(() => {
+ const item = this._getMenuItem(event.target)
+ for (const el of document.querySelectorAll(':hover')) {
+ let element = el
+ while (element) {
+ if (element === item) {
+ return
+ }
+ element = element.parentNode
+ }
+ }
+ item.querySelector('input').checked = false
+ }, 1) // Fraction delay to make sure the mouse leaves the menu item.
+ }
+
+ exclude(event) {
+ // Close all menus except the one triggering this event.
+ for (const target of this.checkerTargets) {
+ if (target !== event.target) {
+ target.checked = false
+ }
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/scripts/controllers/nav.js b/src/static/pycontw-2024/scripts/controllers/nav.js
new file mode 100644
index 000000000..b2c7b8b6b
--- /dev/null
+++ b/src/static/pycontw-2024/scripts/controllers/nav.js
@@ -0,0 +1,18 @@
+import {Controller} from 'stimulus'
+
+export class TopNavController extends Controller {
+
+ static targets = ['menu', 'toggler']
+
+ connect() {
+ this.menuTarget.classList.remove('no-script')
+ this.togglerTarget.classList.remove('no-script')
+ }
+
+ toggle() {
+ this.menuTarget.classList.toggle('open')
+ const curr = this.menuTarget.classList.contains('open')
+ this.togglerTarget.setAttribute('aria-expanded', curr.toString())
+ document.body.classList.toggle('overlay-open', curr)
+ }
+}
diff --git a/src/static/pycontw-2024/scripts/controllers/popup.js b/src/static/pycontw-2024/scripts/controllers/popup.js
new file mode 100644
index 000000000..8fe6b7822
--- /dev/null
+++ b/src/static/pycontw-2024/scripts/controllers/popup.js
@@ -0,0 +1,40 @@
+import {Controller} from 'stimulus'
+
+export class MediaPopupController extends Controller {
+
+ static targets = ['presenter', 'popup']
+
+ _toggle(target, value) {
+ target.classList.toggle('open', value)
+
+ }
+
+ open(event) {
+ event.preventDefault()
+ for (const target of this.popupTargets) {
+ target.classList.toggle('open', false)
+ }
+
+ let target = null
+ for (let e = event.target; !!e; e = e.parentElement) {
+ const index = this.presenterTargets.indexOf(e)
+ if (index >= 0) {
+ target = this.popupTargets[index]
+ break
+ }
+ }
+
+ if (target) {
+ target.classList.toggle('open', true)
+ document.body.classList.toggle('overlay-open', true)
+ }
+ }
+
+ close(event) {
+ event.preventDefault()
+ for (const target of this.popupTargets) {
+ target.classList.toggle('open', false)
+ }
+ document.body.classList.toggle('overlay-open', false)
+ }
+}
diff --git a/src/static/pycontw-2024/scripts/controllers/tabbing.js b/src/static/pycontw-2024/scripts/controllers/tabbing.js
new file mode 100644
index 000000000..8fc58e758
--- /dev/null
+++ b/src/static/pycontw-2024/scripts/controllers/tabbing.js
@@ -0,0 +1,99 @@
+import {Controller} from 'stimulus'
+
+let controllerID = 0
+
+function formatTabStorageKey(tabKey) {
+ return `${window.location.pathname}-tabbing-${tabKey}`
+}
+
+function setTabState(tabKey, value) {
+ if (!window.localStorage) {
+ return
+ }
+ window.localStorage.setItem(formatTabStorageKey(tabKey), value)
+}
+
+function getTabState(tabKey) {
+ if (!window.localStorage) {
+ return null
+ }
+ let value = Number(window.localStorage.getItem(formatTabStorageKey(tabKey)))
+ if (isNaN(value)) {
+ value = 0
+ }
+ return value
+}
+
+export class TabbingController extends Controller {
+
+ static targets = ['tab', 'pane']
+
+ _activateTab(tab) {
+ let index = -1
+
+ // Find a tab to activate.
+ for (const [i, t] of this.tabTargets.entries()) {
+ if (t === tab) {
+ t.classList.add('active')
+ index = i
+ } else {
+ t.classList.remove('active')
+ }
+ }
+
+ // Find the corresponding pane to show.
+ for (const [i, p] of this.paneTargets.entries()) {
+ if (i === index) {
+ p.classList.remove('hidden')
+ } else {
+ p.classList.add('hidden')
+ }
+ }
+
+ // Record this into local storage.
+ setTabState(this.data.get('id'), index.toString())
+ }
+
+ _ensureSingleActive(tabs) {
+ if (tabs.length < 1) {
+ return
+ }
+
+ // Find an initial tab to show with the following priority:
+ // 1. Check if the user has already set it in the local storage.
+ // 2. Look for a tab marked as "active" in HTML.
+ let activeTabs = []
+ const state = Number(getTabState(this.data.get('id')))
+ if (Number.isInteger(state) && state >= 0 && state < tabs.length) {
+ activeTabs.push(tabs[state])
+ } else {
+ for (const tab of tabs) {
+ if (tab.classList.contains('active')) {
+ activeTabs.push(tab)
+ }
+ }
+ }
+
+ // If an initial tab is found, use it; otherwise activate the first tab.
+ if (activeTabs.length < 1) {
+ this._activateTab(tabs[0])
+ } else {
+ this._activateTab(activeTabs[0])
+ }
+ }
+
+ connect() {
+ this.element.classList.add('enabled')
+ this._ensureSingleActive(this.tabTargets)
+ }
+
+ initialize() {
+ // Give this tabbing group an ID, to be used when saving to local storage.
+ this.data.set('id', controllerID.toString())
+ controllerID += 1
+ }
+
+ activate(event) {
+ this._activateTab(event.target)
+ }
+}
diff --git a/src/static/pycontw-2024/scripts/polyfills.js b/src/static/pycontw-2024/scripts/polyfills.js
new file mode 100644
index 000000000..7dc1e9540
--- /dev/null
+++ b/src/static/pycontw-2024/scripts/polyfills.js
@@ -0,0 +1,51 @@
+// https://tc39.github.io/ecma262/#sec-array.prototype.includes
+if (!Array.prototype.includes) {
+ Object.defineProperty(Array.prototype, 'includes', {
+ value: function(searchElement, fromIndex) {
+
+ if (this == null) {
+ throw new TypeError('"this" is null or not defined');
+ }
+
+ // 1. Let O be ? ToObject(this value).
+ var o = Object(this);
+
+ // 2. Let len be ? ToLength(? Get(O, "length")).
+ var len = o.length >>> 0;
+
+ // 3. If len is 0, return false.
+ if (len === 0) {
+ return false;
+ }
+
+ // 4. Let n be ? ToInteger(fromIndex).
+ // (If fromIndex is undefined, this step produces the value 0.)
+ var n = fromIndex | 0;
+
+ // 5. If n ≥ 0, then
+ // a. Let k be n.
+ // 6. Else n < 0,
+ // a. Let k be len + n.
+ // b. If k < 0, let k be 0.
+ var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
+
+ function sameValueZero(x, y) {
+ return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));
+ }
+
+ // 7. Repeat, while k < len
+ while (k < len) {
+ // a. Let elementK be the result of ? Get(O, ! ToString(k)).
+ // b. If SameValueZero(searchElement, elementK) is true, return true.
+ if (sameValueZero(o[k], searchElement)) {
+ return true;
+ }
+ // c. Increase k by 1.
+ k++;
+ }
+
+ // 8. Return false
+ return false;
+ }
+ });
+}
diff --git a/src/static/pycontw-2024/scripts/schedule.js b/src/static/pycontw-2024/scripts/schedule.js
new file mode 100644
index 000000000..478756338
--- /dev/null
+++ b/src/static/pycontw-2024/scripts/schedule.js
@@ -0,0 +1,32 @@
+// Schedule generation.
+const form = document.querySelector('.generation-form')
+if (form) {
+ const html = document.querySelector('.schedule-content').innerHTML
+ form.querySelector('input[name="html"]').value = html
+ form.style.display = 'block'
+}
+
+
+// Replace localed URL with current locale prefix.
+const I18N = JSON.parse(document.getElementById('i18n_variables').textContent)
+function findPrefix(u) {
+ const possiblePrefixes = []
+ for (const prefix of I18N.LANGUAGE_PREFIXES) {
+ if (u.startsWith(prefix)) {
+ return prefix
+ }
+ }
+ return ''
+}
+for (const el of document.querySelectorAll('.localed-url')) {
+ const original = el.getAttribute('href')
+ if (!original) {
+ continue
+ }
+ const prefix = findPrefix(original)
+ if (!prefix) {
+ continue
+ }
+ const sub = original.substr(prefix.length)
+ el.setAttribute('href', `${I18N.LANGUAGE_PREFIX}${sub}`)
+}
diff --git a/src/static/pycontw-2024/scripts/token.js b/src/static/pycontw-2024/scripts/token.js
new file mode 100644
index 000000000..3d82a2ed7
--- /dev/null
+++ b/src/static/pycontw-2024/scripts/token.js
@@ -0,0 +1,22 @@
+// Tom 2020-08-22:
+// This is a hack to inject the token to the next parameter
+// The current implementation of the language switcher does not
+// support query parameters, which means all query paremeters
+// will be lost after switching language.
+
+// However, the token parameter is required in this page,
+// So we find the "next" field which is used to redirect
+// to the destination page after switching language,
+// and then inject the token parameter inside
+// so the page won't be broken after language switch
+
+if (window.TOKEN) {
+ var next = document.querySelector("[name='next']");
+ var params = new URLSearchParams();
+ params.append('token', window.TOKEN);
+
+ // Cannot use next.value += ...
+ // Because when you refresh the page, the input value is preserved
+ // So there would be a lot of concated ?token=... in next.value
+ next.value = `${next.value.split('?')[0]}?${params.toString()}`;
+}
diff --git a/src/static/pycontw-2024/scripts/venue.js b/src/static/pycontw-2024/scripts/venue.js
new file mode 100644
index 000000000..86d77c505
--- /dev/null
+++ b/src/static/pycontw-2024/scripts/venue.js
@@ -0,0 +1,75 @@
+import L from 'leaflet'
+import 'leaflet-easybutton'
+
+const venue = L.layerGroup()
+
+// Marker style and layer definition.
+window.MARKERS.forEach(function(entry) {
+ L.marker(entry.coord, {
+ icon: L.icon({
+ iconUrl: entry.icon,
+ iconSize: [41, 42],
+ iconAnchor: [33, 15],
+ }),
+ })
+ .addTo(venue)
+ .bindTooltip(entry.name, {
+ offset: [-4, 20],
+ direction: 'bottom',
+ })
+ .openTooltip()
+});
+
+// Tile attributions.
+const mbAttr1 = 'Tiles by Stamen Design . Data © OpenStreetMap contributors.'
+const mbUrl1 = 'http://{s}.sm.mapstack.stamen.com/((toner-background,$fff[@20],$000[hsl-color])[@90],(toner-lines,$fff[@80],$fff[hsl-saturation@20],$502526[hsl-color]),(toner-labels,$fff[@30]))/{z}/{x}/{y}.png'
+const mbAttr2 = 'Maps © Thunderforest , Data © OpenStreetMap contributors.'
+const mbUrl2 = 'https://{s}.tile.thunderforest.com/transport/{z}/{x}/{y}.png?apikey=6170aad10dfd42a38d4d8c709a536f38'
+
+
+const stamen = L.tileLayer(mbUrl1, {attribution: mbAttr1})
+const transport = L.tileLayer(mbUrl2, {attribution: mbAttr2})
+
+// Initialize map.
+const pymap = L.map('venue-map', {
+ center: window.MARKERS[0].coord,
+ zoom: 15,
+ layers: [stamen, venue],
+ scrollWheelZoom: false,
+ zoomControl: false,
+})
+L.control.zoom({position: 'topright'}).addTo(pymap)
+
+// Adjust map to center the icon in the non-covered area.
+function centerMap() {
+ const mapw = document.getElementById('venue-map').clientWidth
+ const ovlw = document.getElementById('venue-info-overlay').clientWidth
+
+ let lng = window.MARKERS[0].coord[1]
+ if (ovlw && mapw > ovlw) {
+ const bs = pymap.getBounds()
+ lng -= (bs.getEast() - bs.getWest()) * ovlw / mapw / 2
+ }
+ pymap.panTo([window.MARKERS[0].coord[0], lng])
+}
+centerMap()
+window.map = pymap
+
+// Icon for venue.
+L.easyButton(
+ ` `,
+ centerMap,
+ {position: 'topright'},
+).addTo(pymap)
+
+// Layers and functionalities.
+const baseLayers = {
+ 'Stamen': stamen,
+ 'Transport': transport,
+}
+const overlays = {
+ 'Venue': venue
+}
+
+// Layers and functionalities.
+L.control.layers(baseLayers, overlays, {position: 'bottomright'}).addTo(pymap)
diff --git a/src/static/pycontw-2024/styles/_box.scss b/src/static/pycontw-2024/styles/_box.scss
new file mode 100644
index 000000000..edbe55743
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_box.scss
@@ -0,0 +1,50 @@
+$box-content-padding-x: 32px;
+$box-content-padding-y: 16px;
+
+.box {
+ $box-border: solid 1px $brown;
+
+ border: $box-border;
+ border-radius: 5px;
+ overflow: hidden;
+
+ .box-title {
+ margin: 0;
+ padding: (2rem / 3) 1rem;
+ background-color: $brown;
+ color: $white;
+ line-height: 150%;
+ font-size: 1.25rem;
+ font-weight: 400;
+ }
+
+ .box-content {
+ padding: $box-content-padding-y $box-content-padding-x;
+ }
+
+ .box-control {
+ color:$jinger-bread;
+ display: flex;
+ overflow: hidden;
+
+ > * {
+ @include header(1.25rem);
+ @include no-underline();
+
+ flex: 1;
+ border-top: solid 1px $jinger-bread;
+ line-height: 48px;
+ text-align: center;
+ font-family: "Philosopher", "Noto Sans TC", "sans-serif";
+ }
+
+ > * + * {
+ border-left: $box-border;
+ }
+
+ > a:hover {
+ background: $brown;
+ color: $white;
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/_breakpoints.scss b/src/static/pycontw-2024/styles/_breakpoints.scss
new file mode 100644
index 000000000..fed71375d
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_breakpoints.scss
@@ -0,0 +1,23 @@
+@import 'breakpoint-sass/stylesheets/breakpoint';
+
+$mobile-max: 768px;
+
+@mixin on-desktop {
+ @include breakpoint($mobile-max) {
+ @content;
+ }
+}
+
+html {
+ font-size: 80%;
+
+ @include breakpoint(350px) {
+ font-size: 85%;
+ }
+ @include breakpoint(600px) {
+ font-size: 90%;
+ }
+ @include breakpoint(900px) {
+ font-size: 100%;
+ }
+}
diff --git a/src/static/pycontw-2024/styles/_button.scss b/src/static/pycontw-2024/styles/_button.scss
new file mode 100644
index 000000000..bd7c190fd
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_button.scss
@@ -0,0 +1,46 @@
+@mixin button($angle, $color1, $color2, $base-color:$white, $hover-color:$white) {
+ @include gradient-hover($angle, $color1, $color2);
+ @include link($base-color, $hover-color);
+ @include no-underline;
+ font-weight: 500;
+ margin: auto;
+
+ @include on-desktop {
+ max-width: 336px;
+ }
+}
+
+@mixin outline-button($color) {
+ @include button(0, $color, $color);
+ border: 2px solid $color;
+ background: transparent;
+ color: $color;
+}
+
+@mixin bgimg-hover-button($color, $image, $text-color:$white){
+ @include link($text-color, $text-color);
+ @include no-underline;
+ margin: auto;
+ font-weight: 300;
+ background-color: $color;
+ &:hover{
+ background-image: $image;
+ }
+ @include on-desktop {
+ max-width: 480px;
+ }
+}
+
+.button-round {
+ @include text($text-font-size);
+ @include text-light;
+ @include no-underline;
+
+ padding-top: 16px;
+ padding-bottom: 16px;
+ padding-left: 32px;
+ padding-right: 32px;
+ border: none;
+ border-radius: 4px;
+ text-align: center;
+}
diff --git a/src/static/pycontw-2024/styles/_index-hero.scss b/src/static/pycontw-2024/styles/_index-hero.scss
new file mode 100644
index 000000000..2bddf4cd2
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_index-hero.scss
@@ -0,0 +1,195 @@
+@mixin aspect-ratio($width, $height) {
+ position: relative;
+ &:before {
+ display: block;
+ content: "";
+ width: 100%;
+ padding-top: ($height / $width) * 100%;
+ }
+ > .content {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ }
+}
+
+$hero-desktop-margin: 40px;
+
+.index-hero-outer {
+ @include on-desktop {
+ margin: 0 $hero-desktop-margin 0px;
+ }
+}
+
+.index-hero {
+ margin: 40px auto 10px;
+ max-width: 1160px;
+ font-size: 100%;
+
+ .welcome-text {
+ font-size: 1.5rem;
+ font-family: $text-font-family;
+ color: $jinger-bread;
+ margin-bottom: 10px;
+ margin-left: 12px;
+
+ @include on-desktop {
+ margin-left: 0;
+ }
+ }
+
+ .banner {
+ // 2020-hero-bg.svg, 799x333
+ @include aspect-ratio(799, 333);
+ //background: url('../assets/2020-hero-bg.svg');
+ background-color: black;
+ background-repeat: no-repeat;
+ background-size: 100% 100%;
+ margin-bottom: 60px;
+
+ @include on-desktop {
+ box-shadow: 7px 7px 5px rgba(26, 19, 17, 0.5);
+ margin-bottom: 0;
+ }
+
+ position: relative;
+
+ .logo {
+ position: absolute;
+ left: 49.9%;
+ transform: translate(-50%, -50%);
+
+ width: calc(100% * 600/799);
+ top: 50%;
+
+ @include on-desktop {
+ // 2020-logo.svg, 391x55
+ width: calc(100% * 391/799);
+ top: 51%;
+ }
+ }
+
+ .time-location {
+ width: calc(100% * 450/799);
+ position: absolute;
+ left: 50%;
+ top: 80%;
+ transform: translate(-50%, -50%);
+ text {
+ font-size: 22px;
+ fill: white;
+ font-family: $text-font-family;
+ }
+
+
+ @include on-desktop {
+ width: calc(100% * 220/799);
+ top: 69%;
+ }
+ }
+
+ .icon {
+ width: calc(100% * 70/799);
+
+ position: absolute;
+ left: 49.9%;
+ top: 105%;
+ transform: translate(-50%, 0);
+
+ &.desktop {
+ display: none;
+ }
+
+ @include on-desktop {
+ // snake-icon.svg, 50x50
+ width: calc(100% * 50/799);
+ top: auto;
+ bottom: 6.5%;
+
+ &.desktop {
+ display: block;
+ }
+
+ &.mobile {
+ display: none;
+ }
+ }
+ }
+ }
+}
+
+.index-hero-old {
+ $padding-top-mobile: calc(12.5vh + #{$top-navbar-offset * 7 / 8});
+ $padding-top-desktop: 100px;
+ $heading-aspect: 528 / 95;
+ $heading-width-mobile: 70vw;
+ $heading-height-mobile: $heading-width-mobile / $heading-aspect;
+ $heading-width-desktop: 20vw;
+ $heading-margin-left-desktop: 100vw - $heading-width-desktop;
+ max-width:100%;
+ height:100vh;
+ margin: 0 40px;
+
+ @mixin hero-text($font-size) {
+ color: $white;
+ font-family: $header-font-family;
+ font-size: $font-size;
+ font-style: italic;
+ font-weight: 100;
+ }
+
+ display: flex;
+ flex-direction: column;
+ margin-top: 0;
+ // padding-top: $padding-top-mobile;
+ height: calc(100vh - #{$padding-top-mobile});
+ max-height: 130vw;
+
+ background: url('../assets/landingpage-mobile.png');
+ background-repeat: no-repeat;
+ background-size: 100vw;
+ @include on-desktop {
+ background: url('../assets/2020-hero-bg.svg');
+ background-repeat: no-repeat;
+ background-size: 100vw;
+ background-position-y: -30px;
+
+ $menu-overlap: $menu-desktop-height / 2;
+ height: calc(60vw - #{$padding-top-desktop + $menu-overlap});
+ max-height: auto;
+
+ }
+ .hero-logo{
+ width: 100vw;
+ max-width:100%;
+ margin-top: 0-$padding-top-desktop;
+ @include on-desktop{
+ }
+ }
+ header {
+ height:100%;
+ flex: 1;
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+ position: relative;
+ background-position: center;
+
+ }
+
+ blockquote {
+ @include hero-text(1rem);
+ margin: 0 12px 12px 0;
+ border: none;
+ text-align: right;
+ font-size: 1.2rem;
+
+ @include on-desktop {
+ margin-right: $menu-desktop-margin-x + $menu-desktop-border-radius;
+ margin-bottom: 20px;
+ font-size: 1.25rem;
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/_index-mixins.scss b/src/static/pycontw-2024/styles/_index-mixins.scss
new file mode 100644
index 000000000..5812d4ee6
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_index-mixins.scss
@@ -0,0 +1,68 @@
+$menu-desktop-border-radius: 8px;
+
+@mixin index-section {
+ @include content-section;
+ margin: 0 auto;
+ max-width: 1160px;
+
+ h2 {
+ @include h1();
+ &:first-child {
+ margin-top: 24px;
+ }
+ }
+ h3 {
+ @include h2();
+ }
+ article {
+ margin-bottom: 64px;
+ &:last-child {
+ margin-bottom: 0;
+ }
+ }
+}
+
+// Apply this to any section to get a logo background after it.
+@mixin logo-background-section {
+ padding-bottom: calc(50vw + 35px);
+ background: url('../assets/logo-py-indigo.svg') center 103% no-repeat;
+ background-size: auto 50vw;
+
+ @include on-desktop {
+ padding-bottom: 264px;
+ background-size: 42%;
+ background-position: -10% 110%;
+ }
+}
+
+// Apply this to any section to get a grey background with circle decoration.
+@mixin circle-background-section {
+ padding: 42px 28px 42px 28px;
+ background: $white;
+
+ > article {
+ padding: 32px 12px 54px 12px;
+ }
+
+ @include on-desktop {
+ position: relative;
+ overflow: hidden;
+ padding: 80px 0 80px 0;
+
+ > * {
+ $padding-x: (976px - $container-max-width) / 2;
+ padding: 16px $padding-x 48px $padding-x;
+ position: relative;
+ }
+ }
+}
+
+@mixin grass-python-logo($url, $size: 200px) {
+ content: '';
+ display: block;
+ background-image: url($url);
+ background-size: cover;
+ background-repeat: no-repeat;
+ width: $size;
+ height: $size;
+}
diff --git a/src/static/pycontw-2024/styles/_index-partners.scss b/src/static/pycontw-2024/styles/_index-partners.scss
new file mode 100644
index 000000000..bad5a93dd
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_index-partners.scss
@@ -0,0 +1,128 @@
+@import 'index-mixins';
+
+h2 {
+ margin: auto auto;
+}
+
+.index-partners {
+ @include index-section();
+ margin: 0 auto;
+ max-width: 1160px;
+ padding: 0;
+ margin-bottom: 100px;
+ position: relative;
+
+ > .container {
+
+ [class*=" deco-"],
+ [class^="deco-"] {
+ position: absolute;
+ z-index: -1;
+ }
+
+ .deco-a-1 {
+ top: 2%;
+ right: 2%;
+ }
+
+ .deco-a-2 {
+ top: 50%;
+ left: -6%;
+ }
+
+ .deco-a-3 {
+ bottom: -1%;
+ right: 3%;
+ }
+
+ @include on-desktop {
+ .deco-a-1 {
+ top: 0%;
+ right: 15%;
+ }
+
+ .deco-a-2 {
+ top: 50%;
+ left: -6%;
+ }
+
+ .deco-a-3 {
+ bottom: -1%;
+ right: 20%;
+ }
+ }
+ @include container(904px);
+ max-width: max-content;
+ margin: 0 auto;
+ padding-bottom: 8px;
+ > .grid-layout {
+ display: grid;
+ grid-template-columns: repeat(3, 290px);
+ @media (max-width: 770px) {
+ grid-template-columns: repeat(1, 270px);
+ }
+ column-gap: 2vw;
+ row-gap: 3vh;
+ margin: 4vw;
+ > .partner-container {
+ background-color: #ffffff6e;
+ border: 1px solid #ffffff00;
+ display: flex;
+ height: 268px;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+ padding: 5px;
+ position: relative;
+ overflow: hidden;
+ > span {
+ position: absolute;
+ top: 0.7em;
+ left: 0.7em;
+ text-shadow: 1px 1px 1px #ffffff;
+ font-weight: bolder;
+ }
+ > span.platinum {
+ color: black;
+ }
+ > span.gold {
+ color: $imperial;
+ }
+ > span.silver {
+ color: #262727;
+ }
+ > span.bronze {
+ color: #502526;
+ }
+ > span.special {
+ color: #502526;
+ }
+ > a {
+ text-align: center;
+ .logo {
+ background-size: contain;
+ background-repeat: no-repeat;
+ background-position: center;
+ z-index: $background-deco-index + 1;
+ width: 240px;
+ height: 185px;
+ }
+ > span {
+ margin: 40px 0px;
+ position: relative;
+ z-index: $background-deco-index + 1;
+ max-width: 180px;
+ max-height: 125px;
+ line-height: 64px;
+ vertical-align: middle;
+ font-size: 175%;
+
+ @include on-desktop() {
+ max-width: 100%;
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/_layout.scss b/src/static/pycontw-2024/styles/_layout.scss
new file mode 100644
index 000000000..e769ff289
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_layout.scss
@@ -0,0 +1,91 @@
+$container-max-width: 720px;
+
+@mixin container($max-width: $container-max-width) {
+ max-width: $max-width;
+ margin: 0;
+ @include on-desktop {
+ margin: auto;
+ }
+}
+
+.container {
+ @include container;
+}
+
+$content-section-padding: 20px 40px 80px 40px;
+
+@mixin content-section {
+ padding: $content-section-padding;
+}
+
+footer {
+ @include text-light;
+
+ padding: 80px 0 10px;
+ background-color: $jinger-bread;
+ flex-shrink: 0; // Fix for sticky footer
+
+ .footer-logos{
+ display: flex;
+ flex-direction: row;
+ align-items: flex-end;
+ justify-content: center;
+ .footer-logo {
+ width: 59px;
+ height: 38px;
+ background: url('../assets/2024-py-logo.svg') center no-repeat;
+ }
+ }
+
+ a, p, ul {
+ @include no-underline;
+ text-align: center;
+ }
+ ul {
+ @include menu-items;
+ padding-left: 0;
+ line-height: 48px;
+ a:hover {
+ color: $imperial;
+ }
+ }
+
+ .copyright {
+ border-top: 1px solid $brick;
+ padding-top: 8px;
+ max-width: 1160px;
+ margin: 20px auto;
+ color: $brick;
+ font-family: "Quicksand";
+ }
+}
+
+// Applied when a fullscreen popup is open to disable scrolling.
+body.overlay-open {
+ max-width: 100vw;
+ max-height: 100vh;
+ overflow: hidden;
+
+ @include on-desktop {
+ max-width: none;
+ max-height: none;
+ }
+}
+
+$background-deco-index: 0;
+$overlay-index: 99;
+
+
+// Fix for sticky footer
+html, body {
+ height: 100%;
+}
+
+body {
+ display: flex;
+ flex-direction: column;
+}
+
+body.scroll-x {
+ overflow-x: scroll;
+}
diff --git a/src/static/pycontw-2024/styles/_media.scss b/src/static/pycontw-2024/styles/_media.scss
new file mode 100644
index 000000000..0e5fac645
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_media.scss
@@ -0,0 +1,33 @@
+.media {
+ > header {
+ > figure {
+ $image-size: 136px;
+
+ display: flex;
+ flex-direction: column;
+
+ img {
+ align-self: center;
+ width: $image-size;
+ height: $image-size;
+ border-radius: $image-size / 2;
+ object-fit: cover;
+ object-position: center;
+ }
+
+ figcaption {
+ @include header(1.125rem); // ~ 18px.
+ margin-top: 32px;
+ }
+ }
+
+ .title {
+ @include header(1.125rem); // ~ 18px.
+ margin-top: 16px;
+ }
+ }
+
+ > * + * {
+ margin-top: 32px;
+ }
+}
diff --git a/src/static/pycontw-2024/styles/_menu-desktop.scss b/src/static/pycontw-2024/styles/_menu-desktop.scss
new file mode 100644
index 000000000..a62b716c1
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_menu-desktop.scss
@@ -0,0 +1,156 @@
+$menu-desktop-margin-x: 48px;
+$menu-desktop-height: 70px;
+
+@mixin menu-navbar-desktop($logo, $decocolor1, $decocolor2, $top-item-color) {
+ display: none;
+
+ @include on-desktop {
+ display: flex;
+ flex-direction: row;
+ height: $menu-desktop-height;
+ margin: 0px $menu-desktop-margin-x 100px $menu-desktop-margin-x;
+ padding: 0px 40px;
+ position: relative;
+ }
+ .menu-logo {
+ width: 221.4px;
+ height: 35.5px;
+ background: $logo center no-repeat;
+ }
+ .menu {
+ @include container(100%);
+ @include menu($top-item-color, $top-item-color);
+
+ $menu-item-spacing: 25px;
+ $menu-item-height: $menu-desktop-height / 2;
+
+ display: inline-block;
+ height: $menu-item-height;
+
+ > li {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ float: left;
+ padding: 0 $menu-item-spacing / 2;
+
+ #{$menu-item-types} {
+ width: 100%;
+ // TODO: This only works for single-line text, and is a hack anyway
+ // because we're relying on the half-logo/half-item nature of the
+ // menubar. Real vertical centering would require additional markup.
+ // The minus 1px is the bottom border decoration.
+ line-height: $menu-item-height - 1px;
+ font-weight: normal;
+ color: $jinger-bread;
+
+ &.active::after {
+ content: "";
+ display: block;
+ width: 100%;
+ height: 1px;
+ margin: 0px auto auto auto;
+ background: linear-gradient(119deg, $decocolor1, $decocolor2);
+ }
+
+ &:not(.active)::after {
+ content: "";
+ display: block;
+ width: 0;
+ height: 1px;
+ margin: 0px auto auto auto;
+ background: linear-gradient(119deg, $decocolor1, $decocolor2);
+ transition: width 0.25s ease-in-out;
+ }
+
+ &:hover::after {
+ width: 100%;
+ }
+ }
+
+ > input:checked ~ .dropdown > .submenu {
+ opacity: 1;
+ transform: scaleY(1);
+ }
+
+ // This requires the input to be *before* the label element in markup.
+ > input:checked ~ label::after {
+ width: 100%;
+ }
+
+ &.dashboard-item {
+ position: absolute;
+ right: 0;
+ padding-right: 8px;
+
+ a {
+ font-family: "Quicksand";
+ text-transform: uppercase;
+
+ line-height: 1;
+ border: 1px solid $jinger-bread;
+ border-radius: 7px;
+ padding: 4px 6px;
+
+ transition: background 100ms linear, border 100ms linear;
+
+ &:hover {
+ background-color: $salmon;
+ border-color: transparent;
+ }
+ }
+
+ > a, > label {
+ &::after {
+ display: none;
+ }
+ }
+ }
+ }
+
+ .dropdown {
+ min-width: 100%;
+ min-height: 40px; // Arbitrary; enough to fill gap under menu item.
+ }
+
+ .submenu {
+ $width: 140px;
+ $item-padding: 5px;
+
+ position: absolute;
+ top: $menu-item-height;
+ left: calc(50% - #{$width / 2});
+ min-width: $width;
+ background: transparentize($salmon-dark, 0.05);
+ text-align: center;
+ opacity: 0;
+ transform: scaleY(0);
+ transform-origin: top;
+ transition: transform 0.25s ease-in-out, opacity 0.25s ease-in-out;
+
+ &.submenu-wide {
+ $width: 180px;
+ left: calc(50% - #{$width / 2});
+ min-width: $width;
+ }
+
+ li {
+ display: flex;
+ flex-direction: column;
+ align-content: stretch;
+
+ @include menu-item($jinger-bread, $imperial) {
+ flex: 1;
+ padding: $item-padding;
+ }
+
+ &:first-child > *:first-child {
+ padding-top: 2 * $item-padding;
+ }
+ &:last-child > *:first-child {
+ padding-bottom: 2 * $item-padding;
+ }
+ }
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/_menu-mobile.scss b/src/static/pycontw-2024/styles/_menu-mobile.scss
new file mode 100644
index 000000000..d006cfef4
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_menu-mobile.scss
@@ -0,0 +1,80 @@
+.menu-navbar-mobile {
+ position: fixed;
+ top: $top-navbar-offset;
+ z-index: $overlay-index;
+
+ width: 100vw;
+ height: 0;
+ // background-color: lighten($jinger-bread, 10%);
+ background-color: $jinger-bread;
+ transition: 0.25s ease-in-out;
+ overflow: auto;
+
+ @include on-desktop {
+ display: none;
+ }
+
+ .shadow {
+ position: absolute;
+ left: 99px;
+ top: -62px;
+ margin: 0 !important;
+ font-size: 52px;
+ transform: scaleY(-1) skew(45deg, 0);
+ transform-origin: bottom;
+ color: rgba(0, 0, 0, 0.3);
+ // height: 42px;
+ filter: blur(1px);
+ line-height: 52px;
+ display: none;
+ }
+
+ &.no-script {
+ position: relative;
+ z-index: -1;
+ top: 0 - $top-navbar-offset;
+ height: auto;
+ border-bottom: $top-navbar-border-bottom;
+
+ .menu {
+ padding: $top-navbar-offset + 24px 16px 0 16px;
+ }
+ }
+
+ &.open {
+ height: calc(100vh - #{$top-navbar-offset});
+ }
+
+ > * {
+ margin: 11vh 0;
+
+ &:first-child {
+ margin-top: 11vh;
+ }
+ &:last-child {
+ margin-bottom: 11vh;
+ }
+ }
+
+ .menu {
+ @include menu($brick, $imperial);
+
+ > li {
+ margin: 32px 0;
+ }
+
+ .submenu {
+ background: $brown;
+ border-radius: 0;
+ border: none;
+ padding: 1px;
+ margin-top: 20px;
+
+ text-align: center;
+
+ li {
+ margin: 24px 8px;
+ }
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/_menu.scss b/src/static/pycontw-2024/styles/_menu.scss
new file mode 100644
index 000000000..1b1f72897
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_menu.scss
@@ -0,0 +1,62 @@
+@mixin list-reset() {
+ list-style: none;
+ padding: 0;
+
+ > li::before { // Override custom list bullet.
+ content: none;
+ }
+}
+
+$menu-item-types: '> a, > label';
+
+@mixin menu-item($base-color, $hover-color) {
+ #{$menu-item-types} {
+ @include no-underline;
+ color: $base-color;
+ &:hover {
+ cursor: pointer;
+ color: $hover-color;
+ }
+ @content;
+ }
+}
+
+@mixin menu($top-item-color, $top-item-hover-color) {
+ @include list-reset;
+
+ li { // General menu item styling.
+ > input:checked ~ .dropdown, > .dropdown:hover {
+ height: auto;
+ overflow: visible;
+ }
+ @include menu-item($top-item-color, $top-item-hover-color) {
+ font-weight: 300;
+ }
+ }
+
+ > li { // Styling specific to top-level menu items.
+ position: relative;
+ text-align: center;
+
+ #{$menu-item-types} {
+ font-family: $header-font-family;
+ font-size: 1.125rem;
+ }
+ }
+
+ .dropdown {
+ height: 0;
+ overflow: hidden;
+ }
+
+ .submenu {
+ @include list-reset;
+ @include text(0.975rem);
+ margin-top: 6px;
+ border-radius: 5.36px;
+ z-index: 10;
+ }
+}
+
+@import 'menu-mobile';
+@import 'menu-desktop';
diff --git a/src/static/pycontw-2024/styles/_nav.scss b/src/static/pycontw-2024/styles/_nav.scss
new file mode 100644
index 000000000..d229df0cf
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_nav.scss
@@ -0,0 +1,248 @@
+$top-navbar-background-color: $brick;
+$top-navbar-height: 48px;
+$top-navbar-margin-y: 10px;
+$top-navbar-logo-height: 24px;
+$top-navbar-border-bottom: solid 2px $jinger-bread;
+
+.top-navbar {
+ background-color: $top-navbar-background-color;
+ position: relative;
+ z-index: $background-deco-index + 1;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ height: $top-navbar-height;
+ border-bottom: $top-navbar-border-bottom;
+ overflow: hidden;
+ margin: $top-navbar-margin-y 0;
+
+ @include on-desktop {
+ margin: $top-navbar-margin-y 40px 0;
+ }
+
+
+ .navbar-logo {
+ margin-top: ($top-navbar-height - $top-navbar-logo-height) / 2;
+
+ @include on-desktop {
+ display: none;
+ }
+ }
+}
+
+$top-navbar-offset: $top-navbar-height + $top-navbar-margin-y;
+
+.navbar-centerbox {
+ position: absolute;
+ left: 50%;
+ width: 160px;
+ margin-left: -80px;
+ height: $top-navbar-height;
+ overflow: hidden;
+}
+
+.navbar-logo {
+ display: block;
+ width: 100%;
+ height: 100%;
+ background: url('../assets/2019whitelogo.svg') no-repeat 50% top / 80%;
+}
+
+.navbar-left {
+ display: flex;
+ align-items: center;
+ position: relative;
+ bottom: -2px;
+ margin-left: 12px;
+}
+
+.navbar-provintia {
+ font-size: 52px;
+ position: relative;
+ bottom: -5px;
+ color: $jinger-bread;
+ left: 0px;
+}
+
+.navbar-brand {
+ font-size: 20px;
+ font-family: $classic-font-family;
+ padding-left: 7px;
+ color: $jinger-bread;
+
+ @include no-underline;
+ &:hover {
+ color: $imperial;
+ }
+}
+
+.navbar-lang-switch {
+ @include no-underline;
+ margin: 0 0px;
+
+ > button {
+ $size: 36px;
+
+ font-family: $classic-font-family;
+ width: $size;
+ height: $size;
+ // margin: #{($top-navbar-height - $size) / 2} 2px;
+ padding: 0;
+ border: none;
+ background: none;
+ color: $jinger-bread;
+ font-weight: 500;
+ font-size: 20px;
+ text-align: center;
+ text-transform: uppercase;
+ cursor: pointer;
+
+ &:disabled {
+ border-radius: 8px;
+ background: $salmon;
+ color: $jinger-bread;
+ cursor: default;
+ }
+ &:not(:disabled):hover {
+ color: $imperial;
+ }
+ }
+}
+
+.navbar-toggler {
+ $size: $top-navbar-height;
+
+ display: flex;
+ justify-content: center;
+ margin-left: auto;
+ width: $size;
+ // Fix firefox style problem
+ // if you set height here, the hamberger would be misplaced
+ // height: $size;
+ padding: 0;
+ border: none;
+ background-color: transparent;
+
+ $icon-width: 28px;
+ $icon-height: 20px;
+ $bar-thickness: 3px;
+
+ &.no-script {
+ display: none;
+ }
+
+ > div {
+ position: relative;
+ z-index: $background-deco-index;
+ width: $icon-width;
+ height: $icon-height;
+ transform: rotate(0deg);
+ cursor: pointer;
+
+ > span {
+ display: block;
+ position: absolute;
+ height: $bar-thickness;
+ width: 100%;
+ background: $jinger-bread;
+ border-radius: 8px;
+ opacity: 1;
+ left: 0;
+ transform: rotate(0deg);
+ transform-origin: left center;
+ transition: 0.25s ease-in-out;
+
+ &:nth-child(1) {
+ top: 0;
+ }
+ &:nth-child(2) {
+ top: ($icon-height - $bar-thickness) / 2;
+ }
+ &:nth-child(3) {
+ top: $icon-height - $bar-thickness;
+ }
+ }
+ }
+
+ &[aria-expanded="true"] > div {
+ // Cross the bars correctly.
+ $offset: $icon-width * (2 - $sqrt-2) / 4;
+
+ // Move the cross to the center of the button.
+ $fix-x: (2 - $sqrt-2) * $icon-width / 8;
+ $fix-y: $fix-x + ($icon-width - $icon-height) / 2;
+
+ > span:nth-child(1) {
+ transform: rotate(45deg);
+ top: $offset - $fix-y;
+ left: $offset + $fix-x;
+ }
+ > span:nth-child(2) {
+ width: 0%;
+ opacity: 0;
+ }
+ > span:nth-child(3) {
+ transform: rotate(-45deg);
+ top: $icon-width - $offset - $fix-y;
+ left: $offset + $fix-x;
+ }
+ }
+
+ @include on-desktop {
+ display: none;
+ }
+}
+
+@mixin navbar-social-icon($font-size, $base-color, $hover-color) {
+ @include no-underline;
+ color: $base-color;
+ font-size: $font-size;
+
+ // Visually compensate for icon size.
+ &.fa-book {
+ font-size: $font-size * 1.075;
+ padding-right: $font-size * 0.175;
+ }
+ &.fa-twitter {
+ font-size: $font-size * 1.1;
+ }
+ &.fa-envelope {
+ font-size: $font-size * 0.9;
+ }
+
+ &:hover {
+ color: $hover-color;
+ // text-shadow: 0 2px 4px rgba(135, 135, 135, 0.5);
+ text-shadow: 0 2px 4px transparentize($imperial, 0.5);
+ }
+}
+
+.navbar-social-desktop {
+ display: none;
+
+ @include on-desktop {
+ display: flex;
+ align-content: center;
+ margin-right: 8px;
+
+ .fa {
+ @include navbar-social-icon(1.375rem, $jinger-bread, $imperial);
+ margin: 0 16px 0 12px;
+ line-height: $top-navbar-height;
+ }
+ }
+}
+
+.navbar-social-mobile {
+ display: flex;
+ justify-content: center;
+
+ .fa {
+ @include navbar-social-icon(1.5rem, $brick, $imperial);
+ margin: 0 20px;
+ }
+
+ @include on-desktop {
+ display: none;
+ }
+}
diff --git a/src/static/pycontw-2024/styles/_normalize.scss b/src/static/pycontw-2024/styles/_normalize.scss
new file mode 100644
index 000000000..6e7abef85
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_normalize.scss
@@ -0,0 +1,78 @@
+@import 'normalize-scss/sass/normalize';
+
+body { // Remove WebKit body padding.
+ margin: 0;
+ padding: 0;
+}
+
+/* Apply default styling. */
+
+h1 {
+ @include h1;
+}
+
+h2 {
+ @include h2;
+}
+
+h3 {
+ @include h3;
+}
+
+h4 {
+ @include h4;
+}
+
+h5 {
+ @include h5;
+}
+
+h6 {
+ @include h6;
+}
+
+blockquote, button, dl, label, ol, p, ul, th, td {
+ @include text($text-font-size);
+ outline: none;
+}
+
+dl, ol, p, ul {
+ line-height: 160%;
+ // letter-spacing: 0.075ex;
+ letter-spacing: 0.05ex;
+ text-align: justify;
+}
+
+a {
+ @include link-dark;
+}
+
+blockquote {
+ margin-left: 0;
+ padding-left: 2rem;
+ border-left: solid 8px rgba($link-dark, 0.5);
+}
+
+code {
+ margin: 0;
+ padding: 0.2rem 0.4rem;
+ border-radius: 4px;
+ background: rgba(27, 31, 35, 0.05);
+ letter-spacing: 0;
+ font-family: 'Consolas', 'Liberation Mono', 'Menlo', 'Courier', monospace;
+ font-size: 85%;
+}
+
+pre {
+ overflow: auto;
+ background: rgba(27, 31, 35, 0.05);
+ padding: 1rem;
+ border: 1px solid $white-35;
+ border-radius: 4px;
+ line-height: 120%;
+
+ code {
+ padding: 0;
+ background: transparent;
+ }
+}
diff --git a/src/static/pycontw-2024/styles/_palette.scss b/src/static/pycontw-2024/styles/_palette.scss
new file mode 100644
index 000000000..b742641c0
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_palette.scss
@@ -0,0 +1,163 @@
+/* Color palette. */
+$indigo: #3b097b;
+$dark-slate-blue: #192660;
+$dark-peach: #e57b5c;
+$maize: #eec850;
+$azure: #2bb1f7;
+$ultramarine-blue: #3000d1;
+$black: #333333;
+$white: #ffffff;
+$pale-grey: #f7f5fa;
+$dark-indigo: #280454;
+$dark-violet: #280356;
+$purple: #521f93;
+$light-indigo: #875bcd;
+$bluey-grey: #9997b7;
+$white-two: #e6e6e6;
+$pinkish-grey: #c9c9c9;
+$white-35: rgba(255, 255, 255, 0.35);
+$strong-violet:#7200d6;
+$portica:#F4D35E;
+$elf-green:#169B64;
+$egyptian-blue:#224398;
+$waikawa-grey: #616e86;
+$light-grayish-yellow: #FDF6DF;
+$gold-yellow: #fad443;
+$forest-green: #009f5f;
+$light-gray: #868686;
+$dark-orange: #e6851a;
+$jungle-green: #2CB57C;
+$ghost-gray: #f8f8f8;
+
+/* 2020 */
+$brick: white;
+$salmon: rgb(216, 204, 204);
+$jinger-bread: #502526;
+$dark-gray: #262626;
+$imperial: #E23728;
+$salmon-dark: #F6B197;
+$brown: #6A3F3B;
+$my-pink: #D0908A;
+$jazz: #612D2E;
+
+
+/* Some extra styles not in the Zepplin palette. */
+$white-65: rgba(255, 255, 255, 0.65);
+
+
+/* Header styles. */
+
+$header-font-family: 'Philosopher', 'Noto Sans TC', 'sans-serif';
+
+@mixin header($font-size) {
+ color: $jinger-bread;
+ font-family: $header-font-family;
+ font-size: $font-size;
+ font-weight: normal;
+ text-align: center;
+}
+
+@mixin header-geometry($margin-top, $margin-bottom: 24px) {
+ margin-top: $margin-top;
+ margin-bottom: $margin-bottom;
+ + * {
+ margin-top: 0;
+ }
+}
+
+@mixin h1 {
+ @include header(1.875rem); // ~ 30px.
+ @include header-geometry(48px);
+ line-height: 150%;
+}
+
+@mixin h2 {
+ @include header(1.75rem); // ~ 24px.
+ @include header-geometry(72px);
+}
+
+@mixin h3($margin-top: 24px) {
+ @include header(1.25rem); // ~ 20px.
+ @include header-geometry($margin-top);
+}
+
+@mixin h4() {
+ @include header(1.25rem); // ~ 20px.
+ @include header-geometry(16px);
+}
+
+@mixin h5() {
+ @include header(1.125rem); // ~ 18px.
+ @include header-geometry(16px);
+}
+
+@mixin h5() {
+ @include header(1.125rem); // ~ 18px.
+ @include header-geometry(8px);
+}
+
+@mixin h6() {
+ @include header(1.125rem); // ~ 18px.
+ @include header-geometry(0);
+}
+
+
+/* Content styles. */
+
+$text-font-family: 'Quicksand', 'Microsoft Jhenghei', 'Noto Sans TC', 'sans-serif';
+
+$classic-font-family: 'Philosopher', 'Noto Sans TC', 'sans-serif';
+
+$text-font-size: 1.125rem; // ~ 18px.
+$text-font-size-small: 0.75rem; // ~ 12px.
+
+$text-light: $white;
+$text-dark: $black;
+
+$link-dark: lighten($jinger-bread, 25%);
+$link-hover-dark: $waikawa-grey;
+$link-light: $brick;
+$link-hover-light: $waikawa-grey;
+
+@mixin link($base-color, $hover-color) {
+ color: $base-color;
+ text-decoration: none;
+ transition: color 100ms linear, text-decoartion 100ms linear;
+
+ &:hover {
+ color: $hover-color;
+ text-decoration: underline;
+ }
+}
+
+@mixin link-dark {
+ @include link($link-dark, $imperial);
+}
+
+@mixin link-light {
+ @include link($link-light, $link-light);
+}
+
+@mixin text($font-size) {
+ color: $text-dark;
+ font-family: $text-font-family;
+ font-weight: 200;
+ font-size: $font-size;
+
+ strong {
+ font-weight: 400;
+ }
+ em { // Do not use slant.
+ font-style: normal;
+ font-weight: 400;
+ }
+}
+
+@mixin text-light {
+ a {
+ @include link-light;
+ }
+ button, dl, p, ul, ol, th, td {
+ color: $text-light;
+ }
+}
diff --git a/src/static/pycontw-2024/styles/_popup.scss b/src/static/pycontw-2024/styles/_popup.scss
new file mode 100644
index 000000000..ee70268f2
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_popup.scss
@@ -0,0 +1,176 @@
+.popup {
+ position: fixed;
+ z-index: $overlay-index;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ transform: scale(0, 0);
+ opacity: 0;
+ transition: transform 0.25s ease-in-out, opacity 0.25s ease-in-out;
+
+ &.open {
+ transform: scale(1, 1);
+ opacity: 1;
+ }
+
+ @mixin card($spacing) {
+ top: $spacing;
+ bottom: $spacing;
+ left: $spacing;
+ right: $spacing;
+ }
+
+ > .card {
+ @include card(16px);
+ position: fixed;
+ border-radius: 5px;
+ background-color: rgba(255, 255, 255, 0.95);
+ box-shadow: 0 0 14px 0 rgba(39, 39, 39, 1);
+ border: solid 1px $imperial;
+
+ @include on-desktop() {
+ @include card(48px);
+ }
+ }
+
+ .popup-close {
+ position: absolute;
+ top: 16px;
+ right: 16px;
+ width: 30px;
+ height: 30px;
+ max-width: 10vmin;
+ max-height: 10vmin;
+ margin: 0;
+ padding: 5px;
+ border: none;
+ background: $imperial;
+ border-radius: 50%;
+
+ &:hover {
+ cursor: pointer;
+
+ > span {
+ border-color: #535353;
+ }
+ }
+
+ > span {
+ display: block;
+ width: 100%;
+ border: 1px solid #fdfbfb;
+ transform-origin: center;
+
+ &:first-child {
+ transform: rotate(45deg) translate(#{$sqrt-2}px, #{$sqrt-2}px);
+ }
+ &:last-child {
+ transform: rotate(-45deg);
+ }
+ }
+ }
+}
+
+@mixin link-to-website($button-color) {
+ @include button(0, $button-color, $button-color, $white, $imperial);
+ @include on-desktop{
+ max-width: 225px;
+ }
+ border-radius: 30px;
+ padding: 12px 45px;
+ margin: 0px;
+ font-weight: normal;
+ line-height: normal;
+ letter-spacing: normal;
+ text-align: center;
+ margin-left: auto;
+}
+
+.popup .card-content {
+ @mixin card-content($spacing, $extra-top-padding, $overflow) {
+ overflow: $overflow;
+ width: calc(100% - #{2 * $spacing});
+ height: calc(100% - #{2 * $spacing + $extra-top-padding});
+ padding: $spacing + $extra-top-padding $spacing $spacing $spacing;
+
+ > * {
+ padding: $spacing;
+ }
+ }
+
+ @include card-content(16px, 16px, auto);
+
+ .logo {
+ display: block;
+
+ img {
+ max-width: 256px;
+ max-height: 38px;
+ }
+ }
+
+ .name {
+ @include header(1.5rem);
+ @include header-geometry(0, 16px);
+ color: $imperial;
+ }
+ .name, .description .description * {
+ text-align: center;
+ }
+ .horizontal-rule {
+ border: 1px solid $imperial;
+ width: 15%;
+ }
+
+ @include on-desktop() {
+ @include card-content(32px, 0, visible);
+ display: flex;
+ flex-direction: column;
+
+ > * {
+ max-height: 100%;
+ }
+
+ .logo {
+ display: flex;
+ }
+
+ .text {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+
+ article {
+ display: flex;
+ flex-direction: column;
+ max-height: 100%;
+
+ .name {
+ flex: 0;
+ }
+
+ .description {
+ flex: 1;
+ max-height: 560px;
+ word-wrap: break-word;
+ overflow: auto;
+ margin: 28px 0px;
+
+ &, * {
+ text-align: left;
+ }
+ }
+
+ .link-to-website {
+ @include link-to-website($imperial);
+
+ &:hover{
+ @include link-to-website(transparent);
+ border: 1px solid $imperial;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/_pycontw-year-ribbon.scss b/src/static/pycontw-2024/styles/_pycontw-year-ribbon.scss
new file mode 100644
index 000000000..8703e9046
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_pycontw-year-ribbon.scss
@@ -0,0 +1,31 @@
+.year-ribbon {
+ flex: 1 0 auto; // Fix for sticky footer
+ display: flex;
+ align-content: center;
+ align-items: center;
+ justify-content: center;
+ flex-wrap: wrap;
+ height: 125px;
+ margin: 0;
+ padding: 0 2rem;
+ // background-image: url(/static/pycontw-2019/assets/button-hover-bg.svg);
+
+ li {
+ @include menu-items();
+ @include h3(0);
+ margin: 0;
+ line-height: 2rem;
+
+ &:not(:first-of-type) {
+ margin-left: 1rem;
+ }
+ &:not(:last-of-type)::after {
+ content: '/';
+ margin-left: 1rem;
+ }
+ color: $black;
+ a {
+ color: $jungle-green;
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/_slido.scss b/src/static/pycontw-2024/styles/_slido.scss
new file mode 100644
index 000000000..7b7afd297
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_slido.scss
@@ -0,0 +1,10 @@
+iframe {
+ &.slido {
+ height: 100%;
+ width: 100%;
+ height: 500px;
+ @include on-desktop() {
+ height: 700px;
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/_tabbing.scss b/src/static/pycontw-2024/styles/_tabbing.scss
new file mode 100644
index 000000000..62e284278
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_tabbing.scss
@@ -0,0 +1,69 @@
+.tabbing {
+ $background-color: adjust-color($imperial, $alpha: -0.9);
+
+ &:not(.enabled) {
+ > .tabs {
+ height: 0;
+ }
+ > *:not(.tabs) > *:first-child {
+ margin-top: -16px;
+ }
+ }
+ &.enabled {
+ > .tabs ~ * {
+ border-top: 2px solid $my-pink;
+ }
+ .tab-title {
+ display: none;
+ }
+ }
+
+ > .tabs {
+ $item-spacing: 8px;
+
+ @include list-reset();
+ display: flex;
+ overflow-x: auto;
+ overflow-y: hidden;
+ margin: 0 #{0 - $item-spacing / 2};
+
+ > li {
+ flex: 1 1 112px;
+ min-width: 64px;
+ margin: 0 $item-spacing / 2;
+ padding: 8px 0;
+ border-radius: 2px 2px 0 0;
+ background: $background-color;
+ text-indent: 0;
+ text-align: center;
+ font-weight: normal;
+ color: $jazz;
+
+ @include on-desktop() {
+ flex-grow: 0;
+ }
+
+ &.active {
+ background: $imperial;
+ color: $white;
+ }
+
+ &:not(.active) {
+ cursor: pointer;
+ &:hover {
+ background: $imperial;
+ color: $white;
+ }
+ }
+ }
+ }
+
+ > *:not(.tabs) {
+ padding: 32px 24px;
+ background: white;
+
+ > .hidden {
+ display: none;
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/_tag.scss b/src/static/pycontw-2024/styles/_tag.scss
new file mode 100644
index 000000000..ec6bd7c8f
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_tag.scss
@@ -0,0 +1,18 @@
+.tag {
+ @include text($text-font-size);
+
+ display: inline-block;
+ margin: 3px 1px;
+ padding: 4px 12px;
+ border-radius: 2px;
+ background: $imperial;
+ color: $white;
+ text-align: center;
+ transition: background-color 150ms linear;
+
+ &:hover {
+ background-color: $jinger-bread;
+ color: $white;
+ text-decoration: none;
+ }
+}
diff --git a/src/static/pycontw-2024/styles/_utils.scss b/src/static/pycontw-2024/styles/_utils.scss
new file mode 100644
index 000000000..a57313393
--- /dev/null
+++ b/src/static/pycontw-2024/styles/_utils.scss
@@ -0,0 +1,41 @@
+$sqrt-2: 1.4142;
+
+@mixin menu-items {
+ list-style: none inside;
+}
+
+@mixin no-underline {
+ text-decoration: none;
+ &:hover {
+ text-decoration: none;
+ }
+}
+
+dl.inline {
+ overflow: auto;
+
+ dt, dd {
+ float: left;
+ }
+ dt {
+ clear: left;
+ }
+ dd {
+ margin-left: 1rem;
+ }
+}
+
+.center {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+@mixin gradient-hover($angle, $color1, $color2) {
+ background: linear-gradient($angle, $color2, $color1, $color2) 0 / 200% 100%;
+ transition: background-position-x 0.5s ease-in-out;
+
+ &:hover {
+ background-position-x: 100%;
+ }
+}
diff --git a/src/static/pycontw-2024/styles/ccip-discord.scss b/src/static/pycontw-2024/styles/ccip-discord.scss
new file mode 100644
index 000000000..a71da491f
--- /dev/null
+++ b/src/static/pycontw-2024/styles/ccip-discord.scss
@@ -0,0 +1,19 @@
+@import "page";
+
+.discord-page {
+ main {
+ p {
+ text-align: left;
+ }
+
+ $margin: 20px;
+ width: calc(100% - 2*#{$margin});
+ margin: $margin;
+ padding: 0;
+ max-width: none;
+
+ .entry {
+ margin-top: 20px;
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/ccip-live.scss b/src/static/pycontw-2024/styles/ccip-live.scss
new file mode 100644
index 000000000..bc9a4f9cf
--- /dev/null
+++ b/src/static/pycontw-2024/styles/ccip-live.scss
@@ -0,0 +1,17 @@
+@import "page";
+
+.live-page {
+ main {
+ $margin: 20px;
+ width: calc(100% - 2*#{$margin});
+ margin: $margin;
+ padding: 0;
+ max-width: none;
+
+ .entry {
+ &:first-child {
+ margin-top: 0;
+ }
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/ccip-sponsors.scss b/src/static/pycontw-2024/styles/ccip-sponsors.scss
new file mode 100644
index 000000000..5fa6a85e8
--- /dev/null
+++ b/src/static/pycontw-2024/styles/ccip-sponsors.scss
@@ -0,0 +1,9 @@
+@import "site";
+
+@import "index-mixins";
+@import "index-hero";
+@import "index-partners";
+
+body {
+ background-color: $brick;
+}
diff --git a/src/static/pycontw-2024/styles/ccip-staff.scss b/src/static/pycontw-2024/styles/ccip-staff.scss
new file mode 100644
index 000000000..54c816a0a
--- /dev/null
+++ b/src/static/pycontw-2024/styles/ccip-staff.scss
@@ -0,0 +1,10 @@
+@import "site";
+@import "pages/staff";
+
+body {
+ background-color: $brick;
+}
+
+.staff-list {
+ margin: auto auto 10px auto;
+}
diff --git a/src/static/pycontw-2024/styles/gallery.scss b/src/static/pycontw-2024/styles/gallery.scss
new file mode 100644
index 000000000..cfaee96ed
--- /dev/null
+++ b/src/static/pycontw-2024/styles/gallery.scss
@@ -0,0 +1,63 @@
+@import 'site';
+
+.my-gallery {
+ width: 100%;
+ float: left;
+}
+.my-gallery img {
+ width: 100%;
+ height: auto;
+}
+.my-gallery figure {
+ display: block;
+ float: left;
+ margin: 0 5px 5px 0;
+ width: 150px;
+}
+.my-gallery figcaption {
+ display: none;
+
+}
+.links{
+ margin-left: -0.5em;
+ text-align:center;
+ display:flex;
+ flex-wrap: wrap;
+ > .frame-square{
+ flex:0 0 calc(50% - 14px - 0.5em);
+ margin-left: 0.5em;
+
+ @include on-desktop {
+ flex:0 0 calc(25% - 14px - 0.5em);
+ }
+ }
+}
+.frame-square {
+ background: rgba(0,0,0, 0.1);
+ border: 2px solid #000;
+ vertical-align: top;
+ padding: 5px;
+ width: 130px;
+ height: 130px;
+ margin-bottom: .5em;
+ .crop{
+ height: 100%;
+ overflow: hidden;
+ position: relative;
+ img {
+ display: block;
+ min-width: 100%;
+ min-height: 100%;
+ margin: auto;
+ position: absolute;
+ top: -100%;
+ right: -100%;
+ bottom: -100%;
+ left: -100%;
+ }
+ }
+}
+main > .gallery{
+ margin-top: 0;
+ margin-bottom: 0;
+}
\ No newline at end of file
diff --git a/src/static/pycontw-2024/styles/index.scss b/src/static/pycontw-2024/styles/index.scss
new file mode 100644
index 000000000..f50a91036
--- /dev/null
+++ b/src/static/pycontw-2024/styles/index.scss
@@ -0,0 +1,252 @@
+@import 'site';
+@import 'index-mixins';
+@import 'index-hero';
+@import 'index-partners';
+@import 'pycontw-year-ribbon';
+
+body {
+ background-color: $top-navbar-background-color;
+ background: rgb(242, 236, 236);
+}
+
+footer {
+ background: #4e4b4b;
+}
+
+.top-navbar {
+ background: rgb(242, 236, 236);
+}
+
+
+.portal {
+ @include index-section;
+
+ @include on-desktop {
+ margin-top: 0 - $menu-desktop-height / 2;
+ }
+
+ .portal-container {
+ display: flex;
+ flex-flow: wrap;
+ align-items: center;
+ justify-content: space-around;
+ height: 260px;
+ @include on-desktop {
+ flex-flow: wrap;
+ height: 100px;
+ }
+ }
+
+ .card {
+ display: flex;
+ margin-bottom: 15px;
+ width: 156px;
+ height: 50px;
+ justify-content: center;
+ align-items: center;
+ border-radius: 4px;
+ border: solid 2px white;
+ a {
+ display: flex;
+ width: 100%;
+ height: 100%;
+ align-items: center;
+ justify-content: center;
+ /*color: #502526;*/
+ font-size: 16px;
+ font-weight: normal;
+ letter-spacing: -0.08px;
+ }
+ &:hover {
+ border: solid 2px #E23728;
+ }
+ }
+}
+
+.top-navbar {
+ .navbar-brand {
+ // Tom: Don't display "PyCon TW20" at navbar in index
+ // It collides with the hero image
+ display: none;
+ }
+}
+
+.menu-navbar-desktop-outer {
+ @include on-desktop {
+ margin: 0 $hero-desktop-margin;
+ }
+}
+
+.menu-navbar-desktop {
+ @include menu-navbar-desktop(
+ url('../assets/logo-strong-violet.svg'), $jinger-bread, $jinger-bread, $jinger-bread);
+
+ @include on-desktop {
+ // Align with hero-image-bg
+ margin: 0 auto 50px;
+ max-width: 1160px;
+ padding: 0;
+ }
+}
+
+@mixin big-button-color($color-name, $color) {
+ &.color-#{$color-name} {
+ background-color: $color;
+ border: 2px solid $color;
+
+ &:hover {
+ color: $color;
+ background-color: transparentize($brick, 0.3);
+ text-decoration: none;
+ .icon {
+ background-color: $color;
+ }
+ }
+ }
+}
+
+@mixin big-button-icon($name) {
+ .icon-#{$name} {
+ mask: url('../assets/icon-#{$name}.svg');
+ mask-size: 100% 100%;
+ }
+}
+
+.index-big-button {
+ width: 100%;
+ height: 70px;
+ border-radius: 35px;
+ font-size: 1.6rem;
+ margin: 30px auto;
+ max-width: 100%;
+
+ @include on-desktop {
+ width: 510px;
+ height: 113px;
+ border-radius: 57px;
+ font-size: 1.875rem;
+ margin: 50px auto;
+ }
+
+ text-decoration: none;
+ color: $brick;
+ position: relative;
+ text-align: center;
+ display: flex;
+ align-items: center;
+ transition: background 150ms linear, border 150ms linear;
+
+ @include big-button-color(jinger-bread, $jinger-bread);
+ @include big-button-color(imperial, $imperial);
+ @include big-button-color(dark-gray, $dark-gray);
+
+ .icon {
+ width: 35px;
+ height: 35px;
+ margin-left: 5.493%;
+ background-repeat: no-repeat;
+ background-color: $brick;
+
+ @include on-desktop {
+ width: 50px;
+ height: 50px;
+ margin-left: 5.493%;
+ }
+ }
+
+ > div {
+ flex-grow: 1;
+ margin-right: 9.805%;
+ }
+
+ @include big-button-icon(speaking);
+ @include big-button-icon(volunteering);
+ @include big-button-icon(sponsor);
+}
+
+.index-introduction {
+ @include index-section;
+
+ @include on-desktop {
+ margin-top: 0 - $menu-desktop-height / 2;
+ }
+
+ .my-pycon {
+ @include button(276deg, $dark-peach, $maize);
+ margin-top: 40px;
+ }
+}
+
+.index-actions {
+ @include index-section;
+
+ padding: 0 40px 80px;
+ font-family: 'Noto Sans TC';
+
+ @include on-desktop {
+ margin-top: 0 - $menu-desktop-height / 2;
+ }
+}
+
+.index-volunteer-container {
+ @include container(960px);
+ display: flex;
+ flex-flow: row wrap;
+ background: rgba(253, 246, 223, 0.6);;
+ border-radius: 12px;
+ justify-content: center;
+ align-items:flex-end;
+ margin-bottom: 60px;
+
+ .index-volunteer, .index-cfp {
+ flex: 1 1 0;
+ }
+
+ .index-volunteer {
+ @include index-section;
+ margin-top: 40px;
+
+ article:first-of-type {
+ margin-top: 0;
+ }
+ h2, p {
+ color: $egyptian-blue;
+ }
+
+ .volunteer {
+ @include bgimg-hover-button($portica, url('../assets/button-hover-bg.svg'), $egyptian-blue);
+ margin-top: 40px;
+ font-size: 1.75rem;
+ }
+ }
+
+ .index-cfp {
+ @include index-section;
+ padding: 120px;
+ background-color: $egyptian-blue;
+
+ article:first-of-type {
+ margin-top: 0;
+ }
+ h2, p {
+ color: $white;
+ }
+
+ .volunteer {
+ @include outline-button($portica);
+ margin-top: 40px;
+ }
+ }
+}
+
+.main-content {
+ flex: 1 0 auto; // Fix for sticky footer
+ position: relative;
+ overflow: hidden;
+ background: white;
+
+ @include on-desktop {
+ margin: 0;
+ padding-top: 80px;
+ }
+}
diff --git a/src/static/pycontw-2024/styles/page.scss b/src/static/pycontw-2024/styles/page.scss
new file mode 100644
index 000000000..7c9b94569
--- /dev/null
+++ b/src/static/pycontw-2024/styles/page.scss
@@ -0,0 +1,416 @@
+@import "site";
+
+body {
+ // Fix the fancy h1 overflowing width (because 100vw includes scrollbar).
+ overflow-x: hidden;
+ background-color: $top-navbar-background-color;
+}
+
+.page-hero {
+ background-color: $top-navbar-background-color;
+ height: $menu-desktop-height - 20;
+ @include on-desktop;
+}
+
+.menu-navbar-desktop {
+ @include menu-navbar-desktop(url("../assets/2019bluelogo.svg"), $jinger-bread, $jinger-bread, $jinger-bread);
+
+ .menu {
+ height: $menu-desktop-height - 20;
+ margin: 0 auto;
+ }
+
+ @include on-desktop {
+ margin: 0 40px;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0;
+ }
+}
+
+// Expand to full width, ignoring container.
+@mixin full-width() {
+ margin-left: calc(50% - 50vw);
+ margin-right: calc(50% - 50vw);
+}
+
+main {
+ @include content-section;
+ @include container(100%);
+
+ @include on-desktop {
+ @include container;
+ padding-left: 0;
+ padding-right: 0;
+ }
+
+ position: relative;
+ flex: 1 0 auto; // Fix for sticky footer
+
+ // Fancy h1 that merges into the navbar.
+ > h1:first-child {
+ @mixin fill-vw($p) {
+ width: calc(100vw - #{$p * 2});
+ padding: 0 $p 32px $p;
+ }
+
+ // @include shove-left();
+ // @include fill-vw(2rem);
+
+ // 2020
+ // background-color: $white;
+
+ @include on-desktop {
+ // @include fill-vw(6rem);
+ }
+ }
+
+ @mixin container-block($margin-top, $margin-bottom) {
+ margin-top: $margin-top;
+ margin-bottom: $margin-bottom;
+
+ // Cancel terminal margins for nested blocks.
+ > *:first-child {
+ margin-top: 0;
+ }
+ > *:last-child {
+ margin-bottom: 0;
+ }
+ }
+
+ // Most content blocks are 48px apart.
+ > * {
+ @include container-block(48px, 20px);
+ }
+
+ // p elements are 20px apart.
+ p + p {
+ margin-top: 20px;
+ }
+ h3 {
+ text-align: left;
+
+ &::before {
+ // content: url('../assets/snake-icon-dark.svg');
+ content: "";
+ display: inline-block;
+ width: 30px;
+ height: 30px;
+ background-image: url("../assets/snake-icon-dark.svg");
+ background-repeat: no-repeat;
+ background-size: 110% 110%;
+ background-position: 50% 50%;
+ margin-right: 5px;
+ position: relative;
+ top: 8px;
+
+ @include on-desktop {
+ background-size: 125% 125%;
+ }
+ }
+ }
+ // Custom UL bullets.
+ ul {
+ $mark-indent: 1.125rem;
+ $text-indent: 2.125rem;
+
+ list-style: none;
+ padding-left: $text-indent;
+ text-indent: $mark-indent - $text-indent;
+
+ > li {
+ &.event-info {
+ margin-top: 1em;
+ }
+
+ &::before {
+ content: "•";
+ display: block;
+ float: left;
+ width: $text-indent - $mark-indent;
+ }
+
+ > p {
+ margin-top: 0;
+ }
+ }
+
+ // Different styles:
+ &.square {
+ $mark-indent: 0.8rem;
+ $text-indent: 2.125rem;
+
+ padding-left: $text-indent;
+ text-indent: $mark-indent - $text-indent;
+
+ > li {
+ &::before {
+ content: "▪";
+ width: $text-indent - $mark-indent;
+ }
+ }
+ }
+
+ &.white-circle {
+ $mark-indent: 0.6rem;
+ $text-indent: 2.125rem;
+
+ padding-left: $text-indent;
+ text-indent: $mark-indent - $text-indent;
+
+ > li {
+ &::before {
+ content: "◦";
+ width: $text-indent - $mark-indent;
+ }
+ }
+ }
+ }
+
+ > table:not([class]),
+ table.table,
+ .table > table {
+ min-width: 100%;
+ text-align: center;
+ border-collapse: collapse;
+
+ tr {
+ > th,
+ > td {
+ height: 3.5rem;
+ padding: 4px 8px;
+ border-bottom: solid thin $indigo;
+ font-size: 1rem;
+ font-weight: 400;
+ }
+ > th {
+ color: $indigo;
+ }
+ }
+ }
+ .table {
+ width: 100%;
+ overflow: auto;
+ }
+ .closing-para {
+ text-align: right;
+ }
+
+ .no-top-margin {
+ margin-top: 0;
+ }
+}
+
+.decoration {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ z-index: -1;
+
+ // Prevent scrolling on mobile devices
+ overflow: hidden;
+
+ @include on-desktop {
+ overflow: visible;
+ }
+}
+
+[class*=" deco-"],
+[class^="deco-"] {
+ position: absolute;
+ z-index: -1;
+ opacity: 0.4;
+}
+
+.deco-b-1 {
+ top: 16%;
+ right: -2%;
+}
+
+.deco-b-2 {
+ bottom: 14%;
+ left: -8%;
+}
+
+.deco-c-1 {
+ top: 15.2%;
+ right: -15%;
+ transform: rotate(42deg);
+ width: 145px;
+ opacity: 0.15;
+}
+
+.deco-c-2 {
+ bottom: 18%;
+ left: -31%;
+ transform: rotate(42deg);
+ width: 250px;
+ opacity: 0.05;
+}
+
+.deco-c-3 {
+ bottom: 12.2%;
+ left: -32%;
+ transform: rotate(42deg);
+ width: 190px;
+ opacity: 0.1;
+}
+
+@include on-desktop {
+ // margin: 0 $hero-desktop-margin 0px;
+ .deco-b-1 {
+ top: 16%;
+ right: -20%;
+ }
+
+ .deco-b-2 {
+ bottom: 14%;
+ left: -20%;
+ }
+
+ .deco-c-1 {
+ top: 15.1%;
+ right: -20%;
+ }
+}
+
+@mixin big-button-icon($name) {
+ .icon-#{$name} {
+ mask: url("../assets/icon-#{$name}.svg");
+ mask-size: 100% 100%;
+ }
+}
+
+.pill-title {
+ color: $jinger-bread;
+ background-color: transparentize($imperial, 0.9);
+ border-radius: 65px;
+ height: 113px;
+ line-height: 113px;
+ margin-top: 20px;
+ border: 10px solid transparent;
+
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+
+ h1 {
+ margin: 0;
+ }
+
+ &.alt {
+ position: relative;
+ background-color: transparent;
+ border-color: transparentize($imperial, 0.9);
+
+ .icon {
+ width: 35px;
+ height: 35px;
+ background-repeat: no-repeat;
+ position: absolute;
+ left: 13px;
+ background-color: $jinger-bread;
+
+ top: 50%;
+ transform: translate(0, -50%);
+ display: none;
+
+ @include on-desktop {
+ left: 33px;
+ width: 50px;
+ height: 50px;
+ display: block;
+ }
+ }
+
+ @include big-button-icon(speaking);
+ @include big-button-icon(venue);
+ @include big-button-icon(registration);
+ @include big-button-icon(sponsor);
+ @include big-button-icon(volunteering);
+ @include big-button-icon(about);
+ }
+
+ &.alt-2 {
+ // yychen-2020-06-29: Ugly... but... another style
+ position: relative;
+ background-color: transparent;
+
+ .icon {
+ width: 35px;
+ height: 35px;
+ background-repeat: no-repeat;
+ position: relative;
+ background-color: $jinger-bread;
+
+ display: none;
+
+ @include on-desktop {
+ top: 17px;
+ left: -10px;
+ width: 50px;
+ height: 50px;
+ display: inline-block;
+ }
+ }
+
+ @include big-button-icon(speaking);
+ @include big-button-icon(venue);
+ @include big-button-icon(registration);
+ @include big-button-icon(sponsor);
+ @include big-button-icon(volunteering);
+ @include big-button-icon(about);
+ }
+}
+
+// customize privacy_policy and guidelines page ol
+ol.custom_ol,
+ul.custom_ul {
+ margin-top: 20px;
+
+ > * {
+ line-height: 35px;
+ }
+}
+
+// customize privacy_policy and guidelines page h5 edited_info
+.edited_info {
+ text-align: right;
+ color: darkgray;
+}
+
+.multi {
+ height: 100%;
+ display: flex;
+ align-content: center;
+ justify-content: center;
+ flex-direction: column;
+
+ > div {
+ line-height: 1.2;
+ .icon {
+ position: absolute;
+ left: 0;
+ }
+ }
+}
+
+// Page-specific styling.
+@import "pages/about";
+@import "pages/keynotes";
+@import "pages/talks";
+@import "pages/ticket-info";
+@import "pages/tutorials";
+@import "pages/venue";
+@import "pages/schedule";
+@import "pages/staff";
+@import "pages/portal";
+@import "pages/sponsorship-prospectus";
+@import "pages/live";
+@import "pages/job-listings";
+@import "pages/discord";
diff --git a/src/static/pycontw-2024/styles/pages/_about.scss b/src/static/pycontw-2024/styles/pages/_about.scss
new file mode 100644
index 000000000..ee6f14b80
--- /dev/null
+++ b/src/static/pycontw-2024/styles/pages/_about.scss
@@ -0,0 +1,50 @@
+.about-page .year-ribbon {
+ flex: 1 0 auto; // Fix for sticky footer
+ display: flex;
+ align-content: center;
+ align-items: center;
+ justify-content: center;
+ flex-wrap: wrap;
+ height: 125px;
+ margin: 0 0 30px;
+ padding: 0 2rem;
+
+ @mixin arrow($arrow) {
+ color: $jinger-bread;
+ content: $arrow;
+ font-size: 0.8rem;
+ line-height: 1rem;
+ position: relative;
+ top: 2px;
+ }
+
+ &::before {
+ @include arrow("◀");
+ padding-right: 1rem;
+ }
+
+ &::after {
+ @include arrow("▶");
+ padding-left: 1rem;
+ }
+
+ li {
+ @include menu-items();
+ @include h3(0);
+ margin: 0;
+ line-height: 2rem;
+
+ &:not(:first-of-type) {
+ margin-left: 0.7rem;
+ }
+ &:not(:last-of-type)::after {
+ content: '.';
+ margin-left: 0.7rem;
+ }
+ color: $black;
+ a {
+ font-family: "Quicksand";
+ color: $jinger-bread;
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/pages/_discord.scss b/src/static/pycontw-2024/styles/pages/_discord.scss
new file mode 100644
index 000000000..2e7922367
--- /dev/null
+++ b/src/static/pycontw-2024/styles/pages/_discord.scss
@@ -0,0 +1,58 @@
+.discord-page {
+ .entry {
+ .toturial {
+ margin: 20px 0;
+ .small{
+ padding: 0;
+ font-size: small;
+ }
+
+ p {
+ margin: 14px 0;
+ }
+ }
+
+ .roles-list {
+ margin: 12px 0;
+ }
+
+ .channels-list {
+ margin: 24px 0;
+
+ h4 {
+ text-align:left;
+ margin: 12px 0;
+ }
+
+ h6 {
+ text-align:left;
+ font-size: 12px;
+ margin: 8px 0;
+ }
+ }
+
+ h3 {
+ margin-bottom: 6px;
+ }
+
+
+
+
+
+ li {
+ text-align:left;
+ }
+
+ .sec {
+ margin-bottom: 18px;
+ }
+
+ img {
+ max-width: 100%;
+ height: auto;
+ }
+ }
+}
+
+@import "../../css/vendors/semantic.min.css";
+@import "../../css/vendors/transition.min.css";
diff --git a/src/static/pycontw-2024/styles/pages/_events.scss b/src/static/pycontw-2024/styles/pages/_events.scss
new file mode 100644
index 000000000..33fbad935
--- /dev/null
+++ b/src/static/pycontw-2024/styles/pages/_events.scss
@@ -0,0 +1,463 @@
+@import 'pycontw-2020/styles/palette.scss';
+
+$icon-width: 26px;
+$icon-height: 26px;
+
+@mixin icon($name, $margin-top: 0, $x: left, $width: $icon-width) {
+ width: $width;
+ height: $width;
+ margin-top: $margin-top; // Visual compensation.
+ background: url('../../assets/icon-#{$name}.svg') top $x no-repeat;
+}
+
+@mixin time() {
+ font-family: $header-font-family;
+ font-size: 18px;
+ color: $jinger-bread;
+}
+
+@mixin room($content) {
+ &::before {
+ display: inline;
+ content: $content;
+ white-space: pre;
+ }
+}
+
+@mixin roomDisplayStyle() {
+ min-width: 2ch;
+ font-family: $text-font-family;
+ color: #ffffff;
+ text-align: center;
+ background: $brown;
+ border-radius: 5px;
+}
+
+@mixin rooms() {
+ .room-2-all {
+ @include room('All');
+ }
+
+ .room-3-r012 {
+ @include room('R1, R2, R3');
+ }
+
+ .room-4-r0 {
+ @include room('R1');
+ }
+
+ .room-5-r1 {
+ @include room('R2');
+ }
+
+ .room-6-r2 {
+ @include room('R3');
+ }
+
+ .room-1-r3 {
+ @include room('Multifunction room\A多功能廳');
+ }
+
+ .room-7-r4 {
+ @include room('Goodideas Studio\A好想工作室');
+ }
+}
+
+@mixin eventItem() {
+ display: flex;
+ font-family: $text-font-family;
+ border-radius: 5px;
+
+ a {
+ text-decoration: none;
+ }
+
+ .context-container {
+ position: sticky;
+ top: 70px;
+ padding: 12px;
+
+ .context {
+ .title {
+ margin-bottom: 8px;
+ font-size: 18px;
+ font-weight: 700;
+ }
+
+ .remote-block {
+ margin-top: -8px;
+ margin-bottom: 8px;
+
+ .remote-label {
+ font-size: 0.8rem;
+ color: white;
+ background-color: $jinger-bread;
+
+ padding: 0.8px 3.5px;
+ border-radius: 3px;
+ position: relative;
+ }
+ }
+
+ .speaker {
+ margin-bottom: 8px;
+
+ .name {
+ margin-bottom: 8px;
+ font-weight: 600;
+ font-size: 14px;
+ text-decoration: underline;
+ }
+ }
+ }
+
+ .room {
+ display: flex;
+ margin-bottom: 8px;
+ flex-wrap: wrap;
+
+ & > .room-tag {
+ @include roomDisplayStyle();
+
+ padding: 4px;
+ }
+ }
+
+ .description {
+ margin-bottom: 8px;
+ font-style: italic;
+ }
+ }
+
+ & > .custom-event {
+ display: flex;
+ width: 100%;
+ height: 100%;
+ flex-direction: column;
+ color: $dark-gray;
+ text-align: center;
+ background: rgba($dark-gray, 0.1);
+ border-radius: 5px;
+ cursor: default;
+
+ .context {
+ display: flex;
+ justify-content: center;
+
+ :not(.title) {
+ flex: 1;
+ }
+
+ .title {
+ flex: 3
+ }
+ }
+
+ .time {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+ }
+
+ & > .keynote-event {
+ display: flex;
+ width: 100%;
+ height: 100%;
+ flex-direction: column;
+ text-align: center;
+ background: rgba(255, 255, 255, 0.7);
+ border-radius: inherit;
+
+ .time {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+ }
+
+ & > .talk-event {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ height: 100%;
+ background: rgba(255, 255, 255, 0.7);
+ border-radius: inherit;
+
+ .title {
+ display: -webkit-box;
+ overflow: hidden;
+ line-height: 1.2em;
+ text-overflow: ellipsis;
+ box-sizing: border-box;
+ -webkit-line-clamp: 3;
+ }
+
+ .tags {
+ display: flex;
+ }
+ }
+
+ .language-enen {
+ @include icon('language-enen', 0, center, 2 * $icon-width);
+ }
+
+ .language-zhen {
+ @include icon('language-zhen', 0, center, 2 * $icon-width);
+ }
+
+ .language-zhzh {
+ @include icon('language-zhzh', 0, center, 2 * $icon-width);
+ }
+
+ .python-level-novice {
+ @include icon('level-1', 2px);
+ }
+
+ .python-level-intermediate {
+ @include icon('level-2', 2px);
+ }
+
+ .python-level-experienced {
+ @include icon('level-3', 2px);
+ }
+
+ .no-recording {
+ @include icon('no-recording', 1px);
+ }
+
+ @include rooms();
+}
+
+@mixin toggleTimetableOrTimeList() {
+ @media (min-width: 901px) {
+ .py-schedule-timetable {
+ display: initial;
+
+ .room-tag {
+ display: none;
+ }
+ }
+
+ .py-schedule-time-list {
+ display: none;
+ }
+ }
+
+ @media (max-width: 900px) {
+ .py-schedule-timetable {
+ display: none;
+ }
+
+ .py-schedule-time-list {
+ display: initial;
+
+ .room-tag::before {
+ white-space: initial;
+ }
+ }
+
+ .py-schedule-tabs__tab {
+ padding: 24px;
+ }
+ }
+}
+
+main {
+ max-width: unset;
+ margin: unset;
+ padding: 24px;
+
+ .py-schedule {
+ &-tabs {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ &__tab {
+ margin: 0 24px 24px;
+ padding: 24px 72px;
+ font-family: $header-font-family;
+ font-size: 20px;
+ border-radius: 8px;
+ cursor: default;
+
+ &:hover:not(.--active) {
+ color: red;
+ cursor: pointer;
+ }
+
+ &.--active {
+ color: $jinger-bread;
+ background: $salmon;
+ }
+ }
+ }
+
+ &-timetable {
+ &-header {
+ position: sticky;
+ top: 0;
+ z-index: 1000;
+ display: flex;
+ background: transparentize($brick, 0.3);
+
+ &-column {
+ @include roomDisplayStyle();
+
+ margin: 8px 8px 8px 0;
+ padding: 12px 0;
+ font-size: 18px;
+
+ &:last-child {
+ margin-right: 0;
+ }
+
+ &.--timeline {
+ flex: 1;
+ background: transparent;
+ }
+
+ &.--room {
+ flex: 2;
+ }
+ }
+
+ @include rooms();
+
+ &:not(.--active) {
+ display: none;
+ }
+ }
+
+ &-body {
+ display: grid;
+ grid-template-columns:
+ [times] 1fr
+ [room-4-r0-start] 2fr
+ [room-4-r0-end room-5-r1-start] 2fr
+ [room-5-r1-end room-6-r2-start] 2fr
+ [room-6-r2-end room-8-r3-start] 2fr
+ [room-8-r3-end room-7-r4-start] 2fr
+ [room-7-r4-end];
+ grid-column-gap: 8px;
+ grid-row-gap: 8px;
+
+ &-item {
+ @include eventItem();
+ }
+
+ .room-3-r012 {
+ grid-column: room-4-r0-start / room-6-r2-end;
+ }
+
+ .room-4-r0 {
+ grid-column: room-4-r0-start / room-4-r0-end;
+ }
+
+ .room-5-r1 {
+ grid-column: room-5-r1-start / room-5-r1-end;
+ }
+
+ .room-6-r2 {
+ grid-column: room-6-r2-start / room-6-r2-end;
+ }
+
+ .room-7-r4 {
+ grid-column: room-7-r4-start / room-7-r4-end;
+ }
+
+ .room-1-r3 {
+ grid-column: room-8-r3-start / room-8-r3-end;
+ }
+
+ .room-2-all {
+ grid-column: room-4-r0-start / room-8-r3-end;
+ }
+
+ .timeline {
+ grid-column: times;
+ justify-self: center;
+ @include time();
+
+ &.--hour {
+ font-size: 20px;
+ font-weight: 500;
+ }
+
+ &.--half-an-hour {
+ font-size: 18px;
+ }
+ }
+
+ &:not(.--active) {
+ display: none;
+ }
+ }
+ }
+
+ &-time-list {
+ &-section {
+ &-header {
+ position: sticky;
+ position: -webkit-sticky;
+ top: 0;
+ z-index: 10;
+ padding: 16px 0;
+ background: $brick;
+
+ & > .time {
+ @include time();
+
+ font-size: 22px;
+ }
+ }
+
+ &-items {
+ display: flex;
+ flex-direction: column;
+ margin: 12px 0;
+
+ &-item {
+ @include eventItem();
+ margin-bottom: 12px;
+ }
+
+ .room-2-all {
+ order: 1;
+ }
+
+ .room-3-r012 {
+ order: 2;
+ }
+
+ .room-4-r0 {
+ order: 3;
+ }
+
+ .room-5-r1 {
+ order: 4;
+ }
+
+ .room-6-r2 {
+ order: 5;
+ }
+
+ .room-1-r3 {
+ order: 6;
+ }
+
+ .room-7-r4 {
+ order: 7;
+ }
+ }
+ }
+
+ &:not(.--active) {
+ display: none;
+ }
+ }
+ }
+
+ @include toggleTimetableOrTimeList();
+}
diff --git a/src/static/pycontw-2024/styles/pages/_job-listings.scss b/src/static/pycontw-2024/styles/pages/_job-listings.scss
new file mode 100644
index 000000000..fa11008f1
--- /dev/null
+++ b/src/static/pycontw-2024/styles/pages/_job-listings.scss
@@ -0,0 +1,13 @@
+.job-listings-page {
+ .media {
+ > header {
+ > figure {
+ img {
+ width: 100%;
+ height: unset;
+ border-radius: unset;
+ }
+ }
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/pages/_keynotes.scss b/src/static/pycontw-2024/styles/pages/_keynotes.scss
new file mode 100644
index 000000000..42a240a99
--- /dev/null
+++ b/src/static/pycontw-2024/styles/pages/_keynotes.scss
@@ -0,0 +1,55 @@
+/*
+.keynotes-page {
+ .breadcrumbs {
+ height: 40px;
+ margin-top:0px;
+ margin-bottom: 0px;
+ border-bottom: 1px solid #dbdbdb;
+ font-size: 16px;
+ color: black;
+ ol {
+ display: block;
+ list-style: none;
+ padding-left: 0;
+ li {
+ display: inline;
+ list-style: none;
+ + li:before {
+ content: "> ";
+ padding: 0 5px;
+ }
+ }
+ a {
+ color: black;
+ &:hover {
+ color: $elf-green;
+ }
+ }
+ }
+ }
+ .social {
+ padding-top: 0.5rem;
+
+ a:hover {
+ color: darken($link-dark, 20%);
+ }
+ .fa {
+ display: inline-block;
+ margin-right: 0.75rem;
+ font-size: 125%;
+ }
+ }
+ .media {
+ margin-bottom: 120px;
+ &:last-child {
+ margin-bottom: inherit;
+ }
+ figcaption {
+ color: $jazz;
+ }
+ .title {
+ color: $jinger-bread;
+ }
+ }
+}
+*/
diff --git a/src/static/pycontw-2024/styles/pages/_live.scss b/src/static/pycontw-2024/styles/pages/_live.scss
new file mode 100644
index 000000000..6695f3dcc
--- /dev/null
+++ b/src/static/pycontw-2024/styles/pages/_live.scss
@@ -0,0 +1,32 @@
+.live-page {
+ .entry {
+ p {
+ margin-top: 0;
+ }
+ }
+
+ main {
+ width: calc(100% - 80px);
+
+ @include on-desktop() {
+ min-width: 720px;
+ }
+ }
+
+ .video-container {
+ position: relative;
+ width: 100%;
+ height: 0;
+ padding-bottom: 56.25%;
+ margin-top: 0;
+
+ & > iframe {
+
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 100%;
+ height: 100%;
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/pages/_portal.scss b/src/static/pycontw-2024/styles/pages/_portal.scss
new file mode 100644
index 000000000..c811b0de9
--- /dev/null
+++ b/src/static/pycontw-2024/styles/pages/_portal.scss
@@ -0,0 +1,48 @@
+.portal-page {
+ $buy-button-max-width: 240px;
+ text-align: center;
+
+ .portal-cards {
+ display: grid;
+ grid-template-rows: 20% 20% 20% 20%;
+ @include on-desktop(){
+ grid-template-rows: 33% 33%;
+ grid-template-columns: 50% 50%;
+ }
+
+ justify-items: center;
+ align-items: center;
+ margin: 0;
+ .card {
+ display: flex;
+ width: 100%;
+ height: 120px;
+ margin: 10px;
+ justify-content: center;
+ align-items: center;
+ border-radius: 12px;
+ border: solid 2px #23a16d;
+ background-image: url(/static/pycontw-2019/assets/button-hover-bg.svg);
+
+ @include on-desktop(){
+ width: 80%;
+ }
+
+ a {
+ display: flex;
+ width: 100%;
+ height: 100%;
+ align-items: center;
+ justify-content: center;
+ color: $egyptian-blue;
+ font-size: 28px;
+ font-weight: normal;
+ letter-spacing: -0.08px;
+ }
+ &:hover {
+ border: solid 2px $portica;
+ }
+ }
+ }
+
+}
diff --git a/src/static/pycontw-2024/styles/pages/_schedule.scss b/src/static/pycontw-2024/styles/pages/_schedule.scss
new file mode 100644
index 000000000..96379039b
--- /dev/null
+++ b/src/static/pycontw-2024/styles/pages/_schedule.scss
@@ -0,0 +1,342 @@
+.schedule-page {
+ form .button-round {
+ @include button(276deg, $dark-peach, $maize);
+ width: 160px;
+ margin: 24px 0;
+ text-align: center;
+ cursor: pointer;
+ }
+
+ // Icon
+ $icon-width: 26px;
+ $icon-height: 26px;
+
+ @mixin icon($name, $margin-top: 0, $x: left, $width: $icon-width) {
+ &::before {
+ width: $width;
+ margin-top: $margin-top; // Visual compensation.
+ background: url('../assets/icon-#{$name}.svg') top $x no-repeat;
+ }
+ }
+
+ @mixin icon-info() {
+ ul {
+ @include list-reset();
+ text-indent: 0;
+ li {
+
+ display: flex;
+ align-content: baseline;
+ align-items: flex-start;
+
+ > * {
+ flex: 1;
+ min-height: 24px;
+ margin-bottom: 12px;
+ }
+
+ &:before {
+ content: ' ';
+ height: $icon-height;
+ margin-right: 1rem;
+ }
+
+ &.speech-en {
+ @include icon('language-enen', -1px);
+ }
+ &.speech-zh {
+ @include icon('language-zhzh', -1px);
+ }
+ &.slides-en {
+ @include icon('language-enen', 0, right);
+ }
+ &.slides-zh {
+ @include icon('language-zhzh', 0, right);
+ }
+ &.language-enen {
+ @include icon('language-enen', 0, center, 2 * $icon-width);
+ }
+ &.language-zhen {
+ @include icon('language-zhen', 0, center, 2 * $icon-width);
+ }
+ &.language-zhzh {
+ @include icon('language-zhzh', 0, center, 2 * $icon-width);
+ }
+ &.python-level-novice {
+ @include icon('level-1');
+ }
+ &.python-level-intermediate {
+ @include icon('level-2');
+ }
+ &.python-level-experienced {
+ @include icon('level-3');
+ }
+ &.no-recording {
+ @include icon('no-recording', 1px);
+ }
+ &.room-R0 {
+ @include icon('room-R0', 1px, center);
+ }
+ &.room-R1 {
+ @include icon('room-R1', 1px, center);
+ }
+ &.room-R2 {
+ @include icon('room-R2', 1px, center);
+ }
+ &.room-R3 {
+ @include icon('room-R3', 1px, center);
+ }
+ &.grass {
+ @include icon('grass-group', 0, right);
+ &:before {
+ background-size: contain;
+ @include on-desktop() {
+ height: $icon-height * 1.5;
+ width: $icon-width * 1.5;
+ }
+ }
+ }
+ &.snake {
+ @include icon('snake', 0, right);
+ &:before {
+ background-size: contain;
+ @include on-desktop() {
+ height: $icon-height * 1.5;
+ width: $icon-width * 1.5;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ .schedule-legend {
+
+ background: $pale-grey;
+ word-wrap: break-word;
+ padding: 32px 24px;
+ border-radius: 2px;
+
+ @include on-desktop() {
+ padding: 32px;
+ columns: 2;
+ }
+ @include icon-info();
+ }
+
+ .time-table {
+ width: calc(100% + 50px);
+ margin: -16px;
+ background: transparent;
+ text-align: center;
+
+ // Fonts.
+ @include text(16px);
+ tbody, tr, th, td, ul {
+ // display: block;
+ @include text(16px);
+ font-weight: normal;
+ }
+
+ $border-color: $pale-grey;
+ // Round corners.
+ th, td, .time-stack-ribbon[class~='2-all'] + .event-info {
+ border-radius: 0;
+ }
+ .time-stack-ribbon + .event-info {
+ border-radius: 0;
+ }
+ .time-stack-ribbon {
+ border-radius: 0;
+ }
+
+ // Not actually a table!
+ display: block;
+ thead, tfoot {
+ display: none;
+ }
+ tbody, tr, th, td, ul {
+ display: block;
+ }
+
+ th, td, tr{
+ display: flex;
+ align-items: stretch;
+ justify-content: left;
+ margin: 0;
+ padding: 0;
+ }
+
+ tr {
+ align-items: flex-start;
+
+ &.slot {
+ min-height: 100px;
+
+ border-style: solid;
+ border-width: 0px;
+ border-left-width: 3px;
+ border-color: transparent;
+ border-radius: 4px;
+ background: $ghost-gray;
+
+ &.custom {
+ background-color: $light-grayish-yellow;
+ border: 0px;
+ }
+
+ &.first-slot {
+ border-top-color: $gold-yellow;
+ border-top-width: 1px;
+ margin-top: 10px;
+ }
+ &:hover {
+ border-left-color: $gold-yellow;
+ }
+
+ @each $name, $color in ("R123": $gold-yellow, "R0": $gold-yellow, "R1": $egyptian-blue, "R2": $forest-green, "R3": $dark-orange) {
+ &.slot-room-#{$name} {
+ &.first-slot {
+ border-top-color: $gold-yellow;
+ }
+ &:hover {
+ border-left-color: $color;
+ background: $white;
+ }
+ }
+ }
+ }
+ }
+
+
+ td {
+ $slot-padding-top: 20px;
+
+ &.event {
+ flex: 3;
+
+ .event-info {
+ display: flex;
+ flex: 1;
+ text-align: left;
+ flex-direction: column;
+ padding-top: $slot-padding-top;
+ font-weight: 400;
+
+ a:hover {
+ text-decoration: none;
+ }
+
+ .talk-info {
+ flex: 3;
+ p {
+ &.talk-speakers {
+ color: $light-gray;
+ }
+ }
+ }
+
+ .talk-tags {
+ @include list-reset();
+ display: flex;
+ justify-content: left;
+ margin: 0.375rem;
+ text-indent: 0;
+ flex: 1;
+
+ > li::before {
+ content: ' ';
+ margin-right: 5px;
+ }
+ @include on-desktop() {
+ justify-content: center;
+ }
+ }
+
+ @include on-desktop() {
+ flex-direction: row;
+ }
+ }
+
+ &.event-not-first {
+ border-top: dashed 1px $light-gray;
+ }
+
+ &.talk, &.tutorial {
+ @include list-reset();
+ @include icon-info();
+ }
+ &.keynote {
+ .event-info {
+ flex-direction: column;
+ }
+ }
+ &.custom {
+ align-self: center;
+ width: 100%;
+ .event-info {
+ @include list-reset();
+ @include icon-info();
+ padding-top: 0;
+ justify-content: center;
+ ul {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ li {
+ margin: 0px 5px 0px 0px;
+ font-weight: 500;
+ &:before {
+ margin-right: 0;
+ }
+ &.info {
+ text-align: center;
+ &:before {
+ content: none;
+ }
+ }
+ @include on-desktop {
+ margin: 0px 10px 0px 0px;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ &.time-table-time {
+ flex: 1;
+ flex-direction: column;
+ @include list-reset();
+ @include icon-info();
+ padding-top: $slot-padding-top;
+ padding-left: 20px;
+ &.custom {
+ display: none;
+ }
+ ul {
+ margin: 0;
+ li {
+ &.time {
+ text-align: left;
+ font-size: 16px;
+ &:before {
+ content: none;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ .room-info {
+ @include icon-info();
+ ul {
+ margin: 0;
+ display: flex;
+ justify-content: center;
+ text-indent: $icon-width;
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/pages/_sponsorship-prospectus.scss b/src/static/pycontw-2024/styles/pages/_sponsorship-prospectus.scss
new file mode 100644
index 000000000..a56a5d60d
--- /dev/null
+++ b/src/static/pycontw-2024/styles/pages/_sponsorship-prospectus.scss
@@ -0,0 +1,41 @@
+//
+// Basic Bootstrap table
+//
+
+.table-sponsorship-prospectus {
+ width: 130%;
+ word-wrap: break-word;
+ position: relative;
+ border-spacing: 0;
+ border-collapse: collapse;
+
+ th, td {
+ text-indent: 0;
+ text-align: left;
+
+ line-height: 1.2;
+ padding-top: 10px;
+ vertical-align: top;
+
+ border-top: 1px solid #999;
+ padding: 10px 5px;
+ }
+
+ th {
+ font-weight: 500;
+ }
+
+ tbody {
+ tr:first-child {
+ td, th {
+ border-top: 2px solid #999;
+ }
+ }
+ }
+
+ thead {
+ th {
+ border-top: none;
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/pages/_staff.scss b/src/static/pycontw-2024/styles/pages/_staff.scss
new file mode 100644
index 000000000..b24291040
--- /dev/null
+++ b/src/static/pycontw-2024/styles/pages/_staff.scss
@@ -0,0 +1,9 @@
+.staff-list {
+ @include list-reset();
+ margin: auto auto 64px auto;
+ text-align: center;
+
+ li {
+ text-indent: 0;
+ }
+}
diff --git a/src/static/pycontw-2024/styles/pages/_talks.scss b/src/static/pycontw-2024/styles/pages/_talks.scss
new file mode 100644
index 000000000..cfcc3562a
--- /dev/null
+++ b/src/static/pycontw-2024/styles/pages/_talks.scss
@@ -0,0 +1,222 @@
+.talk-list {
+ .talk-title {
+ color: #262727;
+ font-weight: 400;
+ }
+
+ p {
+ text-align: left;
+ letter-spacing: 0;
+ color: $imperial;
+ font-weight: 500;
+ }
+
+}
+
+.talk-label {
+ font-size: 0.8rem;
+ color: white;
+ background-color: $jinger-bread;
+
+ // color: $jinger-bread;
+ // background-color: $salmon;
+
+ padding: 1px 4px;
+ border-radius: 3px;
+ position: relative;
+ top: -2px;
+
+ a {
+ color: #EEE;
+
+ &:hover {
+ color: white;
+ text-decoration: none;
+ }
+ }
+}
+
+.remote-label {
+ font-size: 1.1rem;
+ color: white;
+ background-color: $jinger-bread;
+
+ padding: 1px 4px;
+ border-radius: 5px;
+ position: relative;
+}
+
+section.note {
+ border-top: 1px solid transparentize($dark-gray, 0.9);
+ margin-top: 70px;
+ padding-top: 70px;
+
+ font-family: $text-font-family;
+
+ .talk-label {
+ font-size: 1rem;
+ }
+}
+
+// Styling for Markdown-rendered fields
+.talk-detail, .tutorial-detail {
+ .editor-preview {
+ * {
+ max-width: 100%;
+ }
+ h1, h2, h3 {
+ @include h3();
+ }
+ h4 {
+ @include h4();
+ }
+ h5 {
+ @include h5();
+ }
+ h6 {
+ @include h6();
+ }
+ h1, h2, h3, h4, h5, h6 {
+ + hr {
+ margin-top: -8px;
+ }
+ }
+ hr {
+ height: 1px;
+ margin: 0;
+ }
+ a { // https://css-tricks.com/handling-long-unexpected-content-css/
+ overflow-wrap: break-word;
+ word-wrap: break-word;
+ word-break: break-word;
+ }
+ li > ol {
+ text-indent: 0rem;
+ }
+ }
+
+ .content {
+ p, ul, li {
+ text-align: left;
+ letter-spacing: 0;
+ font-weight: normal;
+ }
+
+ padding: 32px 16px;
+ background: transparentize($imperial, 0.9);
+ word-wrap: break-word;
+
+ @include on-desktop() {
+ padding: 32px;
+ }
+
+ .social {
+ padding-top: 0.5rem;
+
+ a:hover {
+ color: darken($link-dark, 20%);
+ }
+
+ .fa {
+ display: inline-block;
+ margin-right: 0.75rem;
+ font-size: 125%;
+ }
+ }
+ }
+
+ .info {
+ $icon-width: 60px;
+ $spacing: 0.75rem;
+ padding-left: 0;
+ padding-top:10px;
+ padding-bottom: 10px;
+ border-radius: 2px;
+ ul {
+ @include list-reset();
+ // @include on-desktop() {
+ // columns: 2;
+ // -webkit-columns: 2;
+ // -moz-columns: 2;
+ // }
+ display: flex;
+ margin-left:0px;
+ flex-direction: column;
+ flex-wrap: wrap;
+ align-items: flex-start;
+ justify-content: flex-end;
+ @include on-desktop(){
+ max-height: 180px;
+ margin-left: -4px;
+ }
+ text-align: left;
+ letter-spacing: 0;
+ li {
+ flex-grow: 1;
+ flex-basis: 30px;
+ margin-top: 10px;
+ margin-bottom:10px;
+ display: flex;
+ align-content: flex-start;
+ align-items: flex-start;
+ .info--content{
+ max-width: 180px;
+ font-size: 16px;
+ font-weight: 300;
+ line-height: 1.75;
+ text-indent: 0;
+ margin-left: 0;
+
+ }
+ dfn {
+ min-height: 24px;
+ min-width: 60px;
+ margin-right: 1.5rem;
+ margin-left: 1.5rem;
+ font-size: 0;
+ @mixin icon($name, $margin-top: 0) {
+ background: url('../assets/icon-#{$name}.svg') top right no-repeat;
+ margin-top: $margin-top; // Visual compensation.
+ }
+
+
+ &.location {
+ @include icon('location');
+ }
+ &.slot {
+ @include icon('clock');
+ }
+ &.category {
+ @include icon('tag', -2px);
+ }
+ &.language {
+ &.enen {
+ @include icon('language-enen');
+ }
+ &.zhen {
+ @include icon('language-zhen');
+ }
+ &.zhzh {
+ @include icon('language-zhzh');
+ }
+ }
+ &.python-level {
+ &.novice {
+ @include icon('level-1');
+ }
+ &.intermediate {
+ @include icon('level-2');
+ }
+ &.experienced {
+ @include icon('level-3');
+ }
+ }
+ &.recording-no {
+ @include icon('no-recording');
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/static/pycontw-2024/styles/pages/_ticket-info.scss b/src/static/pycontw-2024/styles/pages/_ticket-info.scss
new file mode 100644
index 000000000..c9c09abf0
--- /dev/null
+++ b/src/static/pycontw-2024/styles/pages/_ticket-info.scss
@@ -0,0 +1,203 @@
+.ticket-info-page {
+ .box-row{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ font-family: $text-font-family;
+ @include on-desktop{
+ flex-direction: row;
+ justify-content: space-between;
+ }
+
+ $ticket_box_height: 280px;
+ $ticket_box_width: $ticket_box_height * 0.75;
+ $ticket_info_height: 360px;
+ $ticket_box_title_height: 40px;
+ $price_box_height: $ticket_box_height - $ticket_box_title_height;
+
+ .ticket-info {
+ height: $ticket_info_height;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin-bottom: 20px;
+
+ @include on-desktop() {
+ margin-bottom: 0;
+ }
+
+ .ticket-box{
+ height: $ticket_box_height;
+ width: $ticket_box_width;
+ border-radius: 10px;
+ border: solid 2px #6A3F3B;
+ margin-bottom: 10px;
+
+ @include on-desktop() {
+ margin-bottom: 20px;
+ }
+
+
+
+ .ticket-box-title{
+ height: $ticket_box_title_height;
+ font-size: 2rem;
+ font-weight: normal;
+ line-height: normal;
+ letter-spacing: -0.03px;
+ color: #333333;
+ margin: 30px auto 20px auto;
+ text-align: center;
+ }
+ .price-box {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ width:100%;
+ height: $price_box_height;
+
+ .price-title {
+ width: 100%;
+ margin: 4px 1px;
+ padding: 4px 1px;
+ text-align: center;
+ font-weight: 300;
+ font-size: 1.25rem;
+ line-height: normal;
+ letter-spacing: normal;
+
+ .price {
+ color: #6A3F3B;
+ font-weight: 300;
+ font-size: 1.25rem;
+ text-align: center;
+ margin: 0;
+ }
+ }
+ }
+ }
+ .buy {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background: center;
+ width: 100%;
+ height: 50px;
+ text-align: center;
+ border: solid 2px #6A3F3B;
+ color: #FBD9CA;
+ text-decoration: none;
+
+ font-size: 1.5rem;
+ font-weight: 300;
+ line-height: normal;
+ letter-spacing: normal;
+ background-color: #6A3F3B;
+ border-radius: 10px;
+ &:hover{
+ color: #6A3F3B;
+ border: solid 2px #6A3F3B;
+ background-color: #FBD9CA;
+ }
+ }
+ }
+
+ .ticket-info-imperial {
+ height: $ticket_info_height;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin-bottom: 20px;
+
+ @include on-desktop() {
+ margin-bottom: 0;
+ }
+
+ .ticket-box-imperial{
+ height: $ticket_box_height;
+ width: $ticket_box_width;
+ border-radius: 10px;
+ border: solid 2px #E23728;
+ margin-bottom: 10px;
+
+ @include on-desktop() {
+ margin-bottom: 20px;
+ }
+
+ .ticket-box-title-imperial{
+ height: $ticket_box_title_height;
+ font-size: 2rem;
+ font-weight: normal;
+ line-height: normal;
+ letter-spacing: -0.03px;
+ color: #E23728;
+ margin: 30px auto 20px auto;
+ text-align: center;
+ }
+ .price-box-imperial {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ width:100%;
+ height: $price_box_height;
+
+ .price-title-imperial {
+ width: 100%;
+ margin: 4px 1px;
+ padding: 4px 1px;
+ text-align: center;
+ font-weight: 300;
+ font-size: 1.25rem;
+ line-height: normal;
+ letter-spacing: normal;
+
+ .price-imperial {
+ color: #E23728;
+ font-weight: 300;
+ font-size: 1.25rem;
+ text-align: center;
+ margin: 0;
+ }
+ }
+ }
+ }
+ .buy-imperial {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background: center;
+ width: 100%;
+ height: 50px;
+ text-align: center;
+ border: solid 2px #E23728;
+ color: #FBD9CA;
+ text-decoration: none;
+ font-size: 1.5rem;
+ font-weight: 300;
+ line-height: normal;
+ letter-spacing: normal;
+ background-color: #E23728;
+ border-radius: 10px;
+ &:hover{
+ color: #E23728;
+ border: solid 2px #E23728;
+ background-color: #FBD9CA;
+ }
+ }
+ }
+}
+
+ .desc-box{
+ background-color: #FBD9CA;
+ padding: 20px 5px;
+ .entry{
+ padding-left: 20px;
+ margin-bottom: 40px;
+ h4 {
+ color: #E23728;
+ text-align: left;
+ margin-bottom: 10px;
+ }
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/pages/_tutorials.scss b/src/static/pycontw-2024/styles/pages/_tutorials.scss
new file mode 100644
index 000000000..4448b3db3
--- /dev/null
+++ b/src/static/pycontw-2024/styles/pages/_tutorials.scss
@@ -0,0 +1,25 @@
+.exchange-page {
+
+ $buy-button-max-width: 240px;
+
+ dt {
+ font-weight: 400;
+ }
+
+ .buy {
+ text-align: center;
+
+ a {
+ @include button(276deg, $dark-peach, $maize);
+
+ display: inline-block;
+ width: 100%;
+ margin: 8px auto 16px auto;
+ text-align: center;
+
+ @include on-desktop() {
+ max-width: $buy-button-max-width;
+ }
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/pages/_venue.scss b/src/static/pycontw-2024/styles/pages/_venue.scss
new file mode 100644
index 000000000..bc201aa8d
--- /dev/null
+++ b/src/static/pycontw-2024/styles/pages/_venue.scss
@@ -0,0 +1,146 @@
+.venue-page {
+ $map-height-mobile: 320px;
+ $map-height-desktop: 496px;
+
+ .map-section {
+ height: $map-height-mobile;
+ @include full-width();
+ max-height: 50vh; // Make sure the user has some room to flick.
+
+ @include on-desktop() {
+ height: $map-height-desktop;
+ max-height: none;
+ width: 100vw;
+ }
+ }
+
+ .map {
+ width: 100%;
+ height: 100%;
+ z-index: 1;
+ border-style: solid;
+ border-color: $salmon;
+ border-width: 2px 0px 2px 0px;
+ }
+
+ .map-info {
+ display: none;
+
+ &:after {
+ background: url("../assets/button-hover-bg.svg");
+ content: "";
+ height: 17%;
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ left: 0;
+ }
+
+ @include on-desktop() {
+ $total-width: 32vw;
+ $padding-left: 4vw;
+ $padding-right: 3vw;
+
+ display: block;
+ position: absolute;
+ height: $map-height-desktop;
+ width: $total-width - $padding-left - $padding-right;
+ z-index: 2;
+ background-color: rgba(255, 255, 255, 0.95);
+ padding: 0 $padding-right 0 $padding-left;
+ margin-top: 2px;
+
+ @include breakpoint(1280px) {
+ $total-width: 28vw;
+ $padding-left: 4vw;
+ $padding-right: 3vw;
+
+ height: $map-height-desktop;
+ width: $total-width - $padding-left - $padding-right;
+ padding: 0 $padding-right 0 $padding-left;
+ }
+
+ h2 {
+ font-size: 1.4rem;
+ line-height: 1;
+ text-align: left;
+
+ > span {
+ display: inline-block;
+ margin-top: 1.2rem;
+
+ &:first-child {
+ margin-top: 0;
+ }
+ }
+ }
+
+ .name-block {
+ h2 {
+ margin-bottom: 12px;
+ }
+
+ .hint {
+ color: #333;
+ font-weight: 300;
+ font-size: 0.9rem;
+ }
+ }
+
+ p {
+ font-size: 1rem;
+ text-align: left;
+ }
+ }
+
+ font-size: 0.6rem;
+
+ h2 {
+ margin-top: 40px;
+ }
+
+ @include breakpoint(90px) {
+ h2 {
+ margin-top: 60px;
+ }
+
+ font-size: 1rem;
+ }
+
+ @include breakpoint(1900px) {
+ h2 {
+ margin-top: 72px;
+ }
+
+ font-size: 1rem;
+ }
+ }
+
+ .tutorial-block {
+ padding-top: 50px;
+
+ h1 {
+ margin: 0;
+ }
+
+ .location-block {
+ h2 {
+ margin-top: 50px;
+ color: #333;
+ font-size: 1.6rem;
+ margin-bottom: 10px;
+ }
+
+ p {
+ text-align: center;
+ }
+ }
+ }
+
+ .parking-info {
+ img {
+ max-width: 100%;
+ height: auto;
+ }
+ }
+}
diff --git a/src/static/pycontw-2024/styles/site.scss b/src/static/pycontw-2024/styles/site.scss
new file mode 100644
index 000000000..ea5428164
--- /dev/null
+++ b/src/static/pycontw-2024/styles/site.scss
@@ -0,0 +1,16 @@
+@import 'palette';
+@import 'normalize';
+@import 'breakpoints';
+@import 'utils';
+
+@import 'layout';
+
+@import 'box';
+@import 'button';
+@import 'media';
+@import 'nav';
+@import 'menu'; // This depends on nav.
+@import 'popup';
+@import 'tabbing';
+@import 'tag';
+@import 'slido';
diff --git a/src/templates/default/_includes/nav/nav_base.html b/src/templates/default/_includes/nav/nav_base.html
index 6a2eb00f4..62b73cfe6 100644
--- a/src/templates/default/_includes/nav/nav_base.html
+++ b/src/templates/default/_includes/nav/nav_base.html
@@ -7,11 +7,11 @@
-
-
-
PyCon TW 2023
+
PyCon TW 2024
diff --git a/src/templates/pycontw-2024/404.html b/src/templates/pycontw-2024/404.html
new file mode 100644
index 000000000..87bf76cbf
--- /dev/null
+++ b/src/templates/pycontw-2024/404.html
@@ -0,0 +1,37 @@
+{% load i18n static %}
+
+
+
+
+
+
+
+
+
+
+{% trans 'Page Not Found' %} | PyCon Taiwan 2018
+
+
+
+
+
+
+
+{% include '_includes/error-styles.html' %}
+
+
+
+
+
+
+
+
+
{% blocktrans %}Ooops! It’s a 404 problem.{% endblocktrans %}
+
{% trans 'We cannot find what you’re looking for.' %}
+
+
+
+
+
+
+
diff --git a/src/templates/pycontw-2024/500.html b/src/templates/pycontw-2024/500.html
new file mode 100644
index 000000000..d48a297b7
--- /dev/null
+++ b/src/templates/pycontw-2024/500.html
@@ -0,0 +1,37 @@
+{% load i18n static %}
+
+
+
+
+
+
+
+
+
+
+{% trans 'Server Error' %} | PyCon Taiwan 2018
+
+
+
+
+
+
+
+{% include '_includes/error-styles.html' %}
+
+
+
+
+
+
+
+
+
{% blocktrans %}Ooops! It’s a 500 problem.{% endblocktrans %}
+
{% trans 'We screwed up. It’s not your fault.' %}
+
+
+
+
+
+
+
diff --git a/src/templates/pycontw-2024/_includes/error-styles.html b/src/templates/pycontw-2024/_includes/error-styles.html
new file mode 100644
index 000000000..3bca4b1e1
--- /dev/null
+++ b/src/templates/pycontw-2024/_includes/error-styles.html
@@ -0,0 +1,47 @@
+
+
+
+
diff --git a/src/templates/pycontw-2024/_includes/ext/discord.html b/src/templates/pycontw-2024/_includes/ext/discord.html
new file mode 100644
index 000000000..87e9553e3
--- /dev/null
+++ b/src/templates/pycontw-2024/_includes/ext/discord.html
@@ -0,0 +1,158 @@
+{% load static i18n compress %}
+
+
+
+
+
{% trans 'discord-tutorials' %}
+
{% trans "If you have not installed Discord or joined Python Taiwan Discord server, follow Setting up Discord and setup your Discord first." %}
+
+
+
{% trans '1. Register yourself' %}
+
{% trans 'Users can find a #registration-desk channel under PYCON TW 2021 category. There is a PyCon TW RegBot in this channel to help you register to your roles.' %}
+ {% if token %}
+
{% trans 'Enter' %} !register {{ token }}
{% trans 'in this channel to register' %}
+ {% else %}
+
{% trans 'Enter !register [TOKEN]
in this channel to register' %}
+
{% trans '(If you want to get your own Token, please click the link in the letter or use Opass.)' %}
+ {% endif %}
+
{% trans 'Enter !help
if you need command help from RegBot.' %}
+
{% trans 'If you register successfully, you can see several new channels appear in the left.' %}
+
{% trans 'If you keep failing to register, you can directly raise your question in #registration-desk channel and mention 2021-staff 。' %}
+
+
+
+
{% trans '2. Take a look at official announcements' %}
+ {% trans "All official announcements channel names contain the word 'announcements' ." %}
+
{% trans 'You can check for important announcements first after you are in.' %}
+
+
+
+
{% trans '3. Join session channel' %}
+
{% trans "All session channel names contain the word 'track' ." %}
+
{% trans 'You can enter keynote channel when it is time for keynote, or track channel according to which track you are in.' %}
+
+
+
+
{% trans 'Roles list' %}
+
{% trans 'Users can be assigned several different roles, each role would have their own permission to enter some private channel.' %}
+
+
{% trans '2021-session-chair' %}
+
{% trans 'Target: PyCon TW 2021 session chairs and assistant chairs' %}
+
+
+
{% trans '2021-staff' %}
+
{% trans 'Target: PyCon TW 2021 staff' %}
+
+
+
{% trans '2021-speaker' %}
+
{% trans 'Target: PyCon TW 2021 speakers' %}
+
+
+
{% trans '2021-remote' %}
+
{% trans 'Target: PyCon TW 2021 remote session staff and remote speakers.' %}
+
+
+
{% trans '2021-attendee' %}
+
{% trans 'Target: PyCon TW 2021 attendees' %}
+
+
+
+
{% trans 'Channels list' %}
+
{% trans 'There are two type of channels in Discord, which is Text Channel and Voice Channel. Below we use:' %}
+
{% trans '#CHANNEL_NAME to represent a text channel' %}
+
{% trans '🔊CHANNEL_NAME to represent a voice channel.' %}
+
+
{% trans 'Registration channel' %}
+
{% trans '#registration-desk' %}
+
{% trans 'Roles:@everyone
' %}
+
{% trans 'When you just enter Python Taiwan Discord server, use this channel to provide your registration information, so that robot can promote you to the roles you are in.' %}
+
+
+
{% trans 'Session channel' %}
+
{% trans '#keynote-track' %}
+
{% trans 'Roles:2021-staff
, 2021-speaker
, 2021-attendee
' %}
+
{% trans 'Keynote discussion channel' %}
+
{% trans '#r1-track' %}
+
{% trans 'Roles:2021-staff
, 2021-speaker
, 2021-attendee
' %}
+
{% trans 'R1 track discussion channel' %}
+
{% trans '#r2-track' %}
+
{% trans 'Roles:2021-staff
, 2021-speaker
, 2021-attendee
' %}
+
{% trans 'R2 track discussion channel' %}
+
{% trans '#r3-track' %}
+
{% trans 'Roles:2021-staff
, 2021-speaker
, 2021-attendee
' %}
+
{% trans 'R3 track (remote track) discussion channel' %}
+
+
+
{% trans 'Announcements channel' %}
+
{% trans '#announcements' %}
+
{% trans 'Roles:2021-staff
, 2021-speaker
, 2021-attendee
' %}
+
{% trans 'Official announcement channel, any official announcements will be posted here.' %}
+
{% trans '#speakers-announcements' %}
+
{% trans 'Roles:2021-staff
, 2021-speaker
' %}
+
{% trans 'A special announcement channel for speakers, speaker can also have discussion with each other in this channel.' %}
+
{% trans '#staff-announcements' %}
+
{% trans 'Roles:2021-staff
' %}
+
{% trans 'A special announcement channel for staff, staff can also contact to others in this channel.' %}
+
+
+
{% trans 'Information desk channel' %}
+
{% trans '#information-desk' %}
+
{% trans 'Roles:2021-staff
, 2021-speaker
, 2021-attendee
' %}
+
{% trans 'Official online information desk, speakers or attendees can give questions or suggestions in this channel.' %}
+
{% trans '#speakers' %}
+
{% trans 'Roles:2021-staff
, 2021-speaker
' %}
+
{% trans 'Speakers only information desk, speakers can give sessions or speakers related questions here for answers or further instruction.' %}
+
{% trans '#session-chairs' %}
+
{% trans 'Roles:2021-session-chair
' %}
+
{% trans 'A channel for session chairs and assistant chairs to give any related questions here for answers or further instruction.' %}
+
+
+
{% trans 'Special channel' %}
+
{% trans '🔊remote-guide' %}
+
{% trans 'Roles: 2021-remote
' %}
+
{% trans 'A special channel for remote partners to contact with each other during sessions, mainly for session chairs to give a cue to remote speakers.' %}
+
+
+
{% trans 'Appendices' %}
+
{% trans 'Setting up Discord' %}
+
{% trans "1.Download the Discord client for your platform and install it. If you already have this, please make sure it is the latest available version." %}
+
+
{% trans "2.Register an account on Discord if you don’t have one. Open the Discord client you just installed. Click the 'Register' link below and complete your registration. (You may be asked to verify your account with the verification mail that Discord sends you)" %}
+
+
+
{% trans "3.Join the Python Taiwan Discord server. Python Taiwan Discord server invite link: https://discord.gg/94hgCQv In your Discord client App, click the button with plus sign, and then select 'Join a server'." %}
+
+
+
{% trans "In this dialog, copy the invite link above and paste it to the inputbox, then click 'Join'." %}
+
+
+
+
+
+{% compress js %}
+
+
+
+
+
+{% endcompress %}
diff --git a/src/templates/pycontw-2024/_includes/ext/live.html b/src/templates/pycontw-2024/_includes/ext/live.html
new file mode 100644
index 000000000..bd45cf379
--- /dev/null
+++ b/src/templates/pycontw-2024/_includes/ext/live.html
@@ -0,0 +1,39 @@
+{% load i18n %}
+{% if attendee.verified %}
+{% for room, live in rooms.items %}
+
+
{{ room }}
+ {% if live %}
+
+ VIDEO
+
+ {% else %}
+
+ {% trans 'This broadcast is not ready yet.' %}
+
+ {% endif %}
+
+{% endfor %}
+
+{% elif attendee %}
+
+
+{% trans 'The broadcasts are not ready yet, please try again later.' %}
+
+
+{% else %}
+
+
+{% trans 'The token within the link is invalid. Please contact staff for further help.' %}
+
+
+{% endif %}
+
+
diff --git a/src/templates/pycontw-2024/_includes/footer.html b/src/templates/pycontw-2024/_includes/footer.html
new file mode 100644
index 000000000..119d1e13c
--- /dev/null
+++ b/src/templates/pycontw-2024/_includes/footer.html
@@ -0,0 +1,19 @@
+{% load i18n %}
+
+{% url 'page' path='about/code-of-conduct' as coc_url %}
+{% url 'page' path='about/community' as community_url %}
+{% url 'page' path='about/privacy_policy' as privacy_policy_url %}
+{% url 'page' path='about/staff' as staff_url %}
+
+
+
+
+ 2021 PyCon Taiwan
+
diff --git a/src/templates/pycontw-2024/_includes/hero.html b/src/templates/pycontw-2024/_includes/hero.html
new file mode 100644
index 000000000..ae303aaf2
--- /dev/null
+++ b/src/templates/pycontw-2024/_includes/hero.html
@@ -0,0 +1,18 @@
+{% load i18n static %}
+
+
+
+ Welcome to PyCon TW21
+
+
+
+
diff --git a/src/templates/pycontw-2024/_includes/menu.html b/src/templates/pycontw-2024/_includes/menu.html
new file mode 100644
index 000000000..a55756f5c
--- /dev/null
+++ b/src/templates/pycontw-2024/_includes/menu.html
@@ -0,0 +1,151 @@
+{% load i18n %}
+{% load pycontw_tools %}
+
+{% url 'page' path='about/pycontw' as about_pycontw_url %}
+{% url 'page' path='about/code-of-conduct' as about_coc_url %}
+{% url 'page' path='about/community' as about_community_url %}
+{% url 'page' path='about/staff' as about_staff_url %}
+
+{% url 'page' path='sponsor/sponsor' as sponsor_url %}
+
+{% url 'page' path='speaking/cfp' as speaking_cfp_url %}
+{% url 'page' path='speaking/talk' as speaking_talk_url %}
+{% url 'page' path='speaking/tutorial' as speaking_tutorial_url %}
+{% url 'page' path='speaking/recording' as speaking_recording_url %}
+
+{% url 'events_schedule' as events_schedule_url %}
+{% url 'page' path='conference/keynotes' as events_keynote_url %}
+{% url 'events_talk_list' as events_talk_list_url %}
+{% url 'events_tutorial_list' as events_tutorial_list_url %}
+{% url 'community_track' as community_track_url %}
+
+{% url 'page' path='events/overview' as events_overview_url %}
+{% url 'page' path='events/warmup-session' as warmup_session %}
+{% url 'page' path='events/sprints' as events_sprint_url %}
+{% url 'page' path='events/job-listings' as events_job_listings_url %}
+{% url 'page' path='events/open-spaces' as events_openspaces_url %}
+{% url 'page' path='events/pyday' as events_pyday_url %}
+
+{% url 'page' path='registration/financial-aid' as reg_financial_aid_url %}
+{% url 'page' path='registration/ticket-info' as reg_ticket_info_url %}
+{% url 'page' path='registration/registration' as reg_registration_url %}
+{% url 'page' path='venue' as venue_url %}
+{% url 'page' path='venue/accommodation' as venue_accommodation_url %}
+{% url 'page' path='portal' as portal_url %}
+{% url 'page' path='covid-19/guidelines' as guidelines_url %}
+
+
+
diff --git a/src/templates/pycontw-2024/_includes/portal.html b/src/templates/pycontw-2024/_includes/portal.html
new file mode 100644
index 000000000..e6e381c61
--- /dev/null
+++ b/src/templates/pycontw-2024/_includes/portal.html
@@ -0,0 +1,21 @@
+{% load i18n %}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/templates/pycontw-2024/_includes/pycontw_year_ribbon.html b/src/templates/pycontw-2024/_includes/pycontw_year_ribbon.html
new file mode 100644
index 000000000..599dfbb30
--- /dev/null
+++ b/src/templates/pycontw-2024/_includes/pycontw_year_ribbon.html
@@ -0,0 +1,10 @@
+
\ No newline at end of file
diff --git a/src/templates/pycontw-2024/_includes/social.html b/src/templates/pycontw-2024/_includes/social.html
new file mode 100644
index 000000000..2f1f1fc55
--- /dev/null
+++ b/src/templates/pycontw-2024/_includes/social.html
@@ -0,0 +1,8 @@
+{% load i18n %}
+
+
diff --git a/src/templates/pycontw-2024/_includes/sponsors.html b/src/templates/pycontw-2024/_includes/sponsors.html
new file mode 100644
index 000000000..a571169e0
--- /dev/null
+++ b/src/templates/pycontw-2024/_includes/sponsors.html
@@ -0,0 +1,71 @@
+{% load i18n static %}
+
+
+
+ {% trans 'Sponsor Partners' %}
+
+
+
+ {% for name, section in sponsor_sections %}
+
+ {% for sponsor in section %}
+
+ {% endfor %}
+
+
+ {% endfor %}
+
+
diff --git a/src/templates/pycontw-2024/_includes/staff.html b/src/templates/pycontw-2024/_includes/staff.html
new file mode 100644
index 000000000..dd43ce280
--- /dev/null
+++ b/src/templates/pycontw-2024/_includes/staff.html
@@ -0,0 +1,226 @@
+{#{% load i18n %}#}
+{##}
+{#{% trans 'Chairperson' context 'staff' %} #}
+{##}
+{##}
+{#{% trans 'Registration' context 'staff' %} #}
+{##}
+{# Yucheng #}
+{# Marr #}
+{# twtrubiks #}
+{# Malo Yang #}
+{# tumi #}
+{##}
+{# #}
+{##}
+{#{% trans 'Development' context 'staff' %} #}
+{##}
+{# Tom Chen #}
+{# tai #}
+{# Wei-Hsiang (Matt) Wang #}
+{# Rex #}
+{# 阿嘉 #}
+{# Alice #}
+{# Macs #}
+{# Maliao Guo #}
+{# Annie Bu #}
+{# Pearlie #}
+{# GTB #}
+{# Jeremy Sung #}
+{# Leon Fu #}
+{# Josix #}
+{# SHY #}
+{# Flynn #}
+{##}
+{# #}
+{#{% trans 'OPass Development' context 'staff' %} #}
+{##}
+{# Denny Huang #}
+{# 腹黒い茶 #}
+{##}
+{# #}
+{##}
+{#{% trans 'Public Relations' context 'staff' %} #}
+{##}
+{# Ko-Hsin Tsai #}
+{# 米方 #}
+{# Hane #}
+{# Zonghan #}
+{# Alvin Lin #}
+{##}
+{# #}
+{##}
+{#{% trans 'Design' context 'staff' %} #}
+{##}
+{# Ben 游本元 #}
+{# 王禹翔 #}
+{# Carol Cho #}
+{# Elaine 迎琪 #}
+{# Andy Chuang #}
+{##}
+{# #}
+{##}
+{#{% trans 'Photography' context 'staff' %} #}
+{##}
+{# Andy #}
+{# Deimos #}
+{# 小草 #}
+{# 大鳥 #}
+{# 家維 #}
+{# 阿緯 #}
+{# 毓鎂 #}
+{##}
+{# #}
+{##}
+{#{% trans 'Program' context 'staff' %} #}
+{##}
+{# Wei Lee #}
+{# TP #}
+{# Frank #}
+{# Jason #}
+{# Adrian #}
+{# Kun Yu #}
+{# PoChun #}
+{# pinglin #}
+{# Peihsaun #}
+{# Wun Hua #}
+{# JunWei Song #}
+{# 小知 #}
+{# Cicilia Lee #}
+{# Pearlie Lin #}
+{# Annie Bu #}
+{# Ming-Hung Hung #}
+{# Jordan #}
+{# Gina #}
+{# KK #}
+{# Sonia Wu #}
+{# petertc #}
+{# Yider #}
+{# Gina Wang #}
+{# Kyle #}
+{##}
+{# #}
+{##}
+{#{% trans 'Sponsorship' context 'staff' %} #}
+{##}
+{# 祐豪五六 #}
+{# 小知 #}
+{# Robert Lin #}
+{# 太一 #}
+{# Diana #}
+{# 小 David #}
+{# Mike #}
+{# 品淳 #}
+{# Cynthia Lu #}
+{# Tina #}
+{# Ken #}
+{# Andy #}
+{# 坤賢 #}
+{# Bill #}
+{# Stanley #}
+{##}
+{# #}
+{##}
+{#{% trans 'Financial' context 'staff' %} #}
+{##}
+{# Rock #}
+{# Timchen #}
+{# Lelia Lin #}
+{##}
+{# #}
+{##}
+{#{% trans 'Venue' context 'staff' %} #}
+{##}
+{# David Lu #}
+{# Andy Chang #}
+{# 阿嘉 #}
+{# Macs Lin #}
+{# Ray Chen #}
+{# Wei-Hua Lee #}
+{# Yider Hsu #}
+{# 地瓜(VeryCold) #}
+{# Benson Chen #}
+{# Winfred Huang #}
+{# 林彥儒 #}
+{# Divik #}
+{# Howard Hsu #}
+{# Cody Chen #}
+{# Tim Hsu #}
+{# Wayne Yu #}
+{# HexRabbit #}
+{# Rex Huang #}
+{# Chieh-Cheng Weng #}
+{# Jui-Hsiang Chen #}
+{# Sonia #}
+{# 阿偉 #}
+{# 郭奕 #}
+{# 林真瑜 #}
+{# Gina Lin #}
+{# 陳家瑩 #}
+{# 二二 #}
+{# 高致霆 #}
+{# Syiu #}
+{# Jacob #}
+{# 陳家霖 #}
+{##}
+{# #}
+{##}
+{##}
+{#{% trans 'Recruitment' context 'staff' %} #}
+{##}
+{# tai271828 #}
+{# catcatcatcat #}
+{# Rex Wu #}
+{# Wei Lee #}
+{##}
+{# #}
+{##}
+{##}
+{#{% trans 'Review Committee' context 'staff' %} #}
+{##}
+{# Kir Chou #}
+{# Cicilia Chia-ying Lee #}
+{# 廖偉涵 Adrian Liaw #}
+{# 劉純睿(阿吉) #}
+{# 李昱勳 #}
+{# Ping Chu Hung #}
+{# Liang-Bo Wang #}
+{# Jason #}
+{# Chi-Hsuan Huang #}
+{# Cheng-Lung Sung (宋政隆) #}
+{# Shuen-Huei Guan #}
+{# Jack Pan #}
+{# 曾君宇 #}
+{# 郭學聰 (Hsueh-Tsung Kuo) #}
+{# Zong-han, Xie #}
+{# Jian-Ming Huang #}
+{# Kilik Kuo #}
+{# Kuo-tung Kao #}
+{# 席恩 #}
+{# Malo #}
+{# 古宣佑 Hsuanyu #}
+{# Spin Lai #}
+{# petertc #}
+{# 王文傑 #}
+{# Kelly Chang #}
+{# Sammy Fung #}
+{# sosorry #}
+{# Shuhsi Lin #}
+{# JunWei Song #}
+{# 何泰祥 Taihsiang Ho (tai271828) #}
+{# Ing Wei Tang #}
+{# Thinker #}
+{# 柯維然 #}
+{# Tzu-ping Chung #}
+{# Wei Lin #}
+{# 李唯 (Wei Lee) #}
+{# Stanley Huang #}
+{# KunYu Chen #}
+{# Frank #}
+{# Keith Yang #}
+{# Yen #}
+{# Jimmy Lai #}
+{##}
+{# #}
diff --git a/src/templates/pycontw-2024/_includes/top_nav.html b/src/templates/pycontw-2024/_includes/top_nav.html
new file mode 100644
index 000000000..824118974
--- /dev/null
+++ b/src/templates/pycontw-2024/_includes/top_nav.html
@@ -0,0 +1,41 @@
+{% load i18n %}
+{% load i18n_plus %}
+
+
+
+
+
+
+
+
+
+
+
+ {% include '_includes/social.html' with type='desktop' %}
+
+
+
+
+
+
diff --git a/src/templates/pycontw-2024/base.html b/src/templates/pycontw-2024/base.html
new file mode 100644
index 000000000..34cfdb3df
--- /dev/null
+++ b/src/templates/pycontw-2024/base.html
@@ -0,0 +1,78 @@
+{% load i18n static %}
+{% load compress %}
+
+
+
+
+
+
+
+
+
+
+
+{% block titletag %}
+{% block title %}{% endblock title %} | PyCon Taiwan 2021
+{% endblock titletag %}
+{% block meta_seo %}{% endblock meta_seo %}
+
+
+
+
+
+
+
+{% block meta_og %}
+
+
+{% endblock meta_og %}
+
+
+
+
+
+{% compress css %}
+
+{% block styles %}{% endblock styles %}
+{% endcompress %}
+
+{% block extra_css %}{% endblock extra_css %}
+
+{# Google Tag Manager. #}
+{% if GTM_TRACK_ID %}
+
+{% endif %}
+
+
+
+
+
+{# Google Tag Manager noscript fallback. #}
+{% if GTM_TRACK_ID %}
+
+{% endif %}
+
+{% block nav %}
+{% include '_includes/top_nav.html' %}
+{% endblock nav %}
+
+{% block content_full %}{% endblock content_full %}
+
+{% block footer %}
+{% include '_includes/footer.html' %}
+{% endblock footer %}
+
+{% compress js %}
+{% block scripts %}
+
+{% endblock scripts %}
+{% endcompress %}
+{% block extra_js %}{% endblock extra_js %}
+
+
+
+
diff --git a/src/templates/pycontw-2024/ccip/discord.html b/src/templates/pycontw-2024/ccip/discord.html
new file mode 100644
index 000000000..3e93a697a
--- /dev/null
+++ b/src/templates/pycontw-2024/ccip/discord.html
@@ -0,0 +1,26 @@
+{% extends 'base.html' %}
+{% load static i18n %}
+
+{% block body_class %}{{ block.super }} discord-page{% endblock body_class %}
+
+{% block styles %}
+{{ block.super }}
+
+{% endblock %}
+
+{% block extra_css %}
+
+{% endblock extra_css %}
+
+{% block title %}{% trans 'Discord Guideline' %}{% endblock %}
+
+{% block nav %}{% endblock nav %}
+
+{% block content_full %}
+
+{% include '_includes/ext/discord.html' %}
+
+{% endblock content_full %}
+
+{% block footer %}
+{% endblock footer %}
diff --git a/src/templates/pycontw-2024/ccip/live.html b/src/templates/pycontw-2024/ccip/live.html
new file mode 100644
index 000000000..6ee09c139
--- /dev/null
+++ b/src/templates/pycontw-2024/ccip/live.html
@@ -0,0 +1,26 @@
+{% extends 'base.html' %}
+{% load static %}
+
+{% block body_class %}{{ block.super }} live-page{% endblock body_class %}
+
+{% block styles %}
+{{ block.super }}
+
+{% endblock %}
+
+{% block extra_css %}
+
+{% endblock extra_css %}
+
+{% block title %}Live Broadcast - PyCon Taiwan 2020{% endblock %}
+
+{% block nav %}{% endblock nav %}
+
+{% block content_full %}
+
+{% include '_includes/ext/live.html' %}
+
+{% endblock content_full %}
+
+{% block footer %}
+{% endblock footer %}
diff --git a/src/templates/pycontw-2024/ccip/sponsors.html b/src/templates/pycontw-2024/ccip/sponsors.html
new file mode 100644
index 000000000..d8a346da3
--- /dev/null
+++ b/src/templates/pycontw-2024/ccip/sponsors.html
@@ -0,0 +1,27 @@
+{% extends 'base.html' %}
+
+{% load i18n static %}
+
+{% block styles %}
+
+{% endblock %}
+
+{% block extra_css %}
+
+{% endblock extra_css %}
+
+{% block titletag %}
+PyCon Taiwan 2020
+{% endblock titletag %}
+
+{% block nav %}{% endblock nav %}
+
+{% block content_full %}
+{% language 'en-us' %}
+{% include '_includes/sponsors.html' %}
+{% endlanguage %}
+{% endblock content_full %}
+
+{% block footer %}
+
+{% endblock footer %}
diff --git a/src/templates/pycontw-2024/ccip/staff.html b/src/templates/pycontw-2024/ccip/staff.html
new file mode 100644
index 000000000..50a020408
--- /dev/null
+++ b/src/templates/pycontw-2024/ccip/staff.html
@@ -0,0 +1,27 @@
+{% extends 'base.html' %}
+{% load static %}
+
+{% block styles %}
+{{ block.super }}
+
+{% endblock %}
+
+{% block extra_css %}
+
+{% endblock extra_css %}
+
+{% block titletag %}
+PyCon Taiwan 2020
+{% endblock titletag %}
+
+{% block nav %}{% endblock nav %}
+
+{% block content_full %}
+{% include '_includes/staff.html' %}
+{% endblock content_full %}
+
+{% block footer %}
+
+{% endblock footer %}
+
+
diff --git a/src/templates/pycontw-2024/contents/_base.html b/src/templates/pycontw-2024/contents/_base.html
new file mode 100644
index 000000000..3e7f293eb
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/_base.html
@@ -0,0 +1,20 @@
+{% extends 'base.html' %}
+
+{% load static %}
+
+{% block styles %}
+
+{% endblock %}
+
+
+{% block content_full %}
+
+
+
+{% block content %}{% endblock content %}
+
+{% endblock content_full %}
diff --git a/src/templates/pycontw-2024/contents/_default/conference/keynotes.html b/src/templates/pycontw-2024/contents/_default/conference/keynotes.html
new file mode 100644
index 000000000..2d33f093f
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/_default/conference/keynotes.html
@@ -0,0 +1,85 @@
+{% extends 'contents/_base.html' %}
+
+{% load i18n static %}
+{% load events %}
+
+{% block title %}{% trans 'Keynotes' %}{% endblock title %}
+
+{% block body_class %}keynotes-page{% endblock body_class %}
+
+
+{% block content %}
+
+
+
+
+ {% trans 'Keynotes' %}
+
+
+{% get_keynote_events as keynote_events %}
+
+{% for event in keynote_events %}
+
+{% with data=event.get_static_data_for_locale %}
+
+
+
+
+
+ {{ data.speaker.name }}
+
+ {{ data.session.title }}
+
+
+
+
+ {% trans 'Biography' %}
+
+
+ {% trans 'Speech' %}
+
+ {% if data.slido %}
+
+ {% trans 'Slido' %}
+
+ {% endif %}
+
+
+
+ {% trans 'Biography' %}
+ {{ data.speaker.bio|linebreaks }}
+
+ {% for key, url in data.social.items %}
+ {% if url %}
+
+ {% endif %}
+ {% endfor %}
+
+
+
+ {% trans "To be announced" as placeholder_description %}
+ {% trans 'Speech' %}
+ {{ data.session.description|default:placeholder_description|linebreaks }}
+
+ {% if data.slido %}
+
+
+
+ {% endif %}
+
+
+
+
+{% endwith %}
+
+{% endfor %}
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/_default/events/job-listings.html b/src/templates/pycontw-2024/contents/_default/events/job-listings.html
new file mode 100644
index 000000000..ba9a250f9
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/_default/events/job-listings.html
@@ -0,0 +1,76 @@
+{% extends 'contents/_base.html' %}
+
+{% load i18n static %}
+{% load sponsors %}
+{% load events %}
+
+{% block titletag %}
+【2020年Python工作職缺】Python知名企業職缺一覽表
+{% endblock titletag %}
+{% block meta_seo %}
+
+
+
+
+
+{% endblock meta_seo %}
+{% block meta_og %}
+
+
+
+
+
+
+{% endblock meta_og%}
+
+
+{% block body_class %}job-listings-page{% endblock body_class %}
+
+{% block content %}
+
+
+
+ {% trans 'Job Listings' %}
+
+
+
+{% get_open_roles_of_sponsors as open_roles_of_sponsors %}
+{% get_open_roles as open_roles %}
+
+{% for sponsor in open_roles_of_sponsors %}
+
+
+
+ {% if sponsor.logo.url %}
+
+ {% endif %}
+ {{ sponsor.name }}
+
+
+
+
+
+ {% trans 'Open Roles' %}
+
+
+
+
+ {% trans 'Open Roles' %}
+ {% for open_role in open_roles %}
+ {% if open_role.sponsor.name == sponsor.name %}
+
+ {% if open_role.url %}
+ {{ open_role.name }} {{ open_role.description|linebreaks }}
+ {% else %}
+ {{ open_role.name }} {{ open_role.description|linebreaks }}
+ {% endif %}
+
+ {% endif %}
+ {% endfor %}
+
+
+
+
+{% endfor %}
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/_default/portal.html b/src/templates/pycontw-2024/contents/_default/portal.html
new file mode 100644
index 000000000..a363fd7e8
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/_default/portal.html
@@ -0,0 +1,19 @@
+{% extends 'contents/_base.html' %}
+
+{% load i18n %}
+{% load static %}
+
+{% block title %}{% trans 'Portal' %}{% endblock title %}
+
+{% block body_class %}portal-page{% endblock body_class %}
+
+{% block content %}
+
+{% trans 'Portal' %}
+
+
+ {% include '_includes/portal.html' %}
+
+
+{% endblock content %}
+
diff --git a/src/templates/pycontw-2024/contents/_pycontw.html b/src/templates/pycontw-2024/contents/_pycontw.html
new file mode 100644
index 000000000..4e7744709
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/_pycontw.html
@@ -0,0 +1,20 @@
+{% extends 'contents/_base.html' %}
+
+{% block body_class %}{{ block.super }} about-page{% endblock body_class %}
+
+{% block content_full %}
+
+{{ block.super }}
+
+
+
+{% endblock content_full %}
diff --git a/src/templates/pycontw-2024/contents/_staff.html b/src/templates/pycontw-2024/contents/_staff.html
new file mode 100644
index 000000000..c2df021f3
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/_staff.html
@@ -0,0 +1,15 @@
+{% extends 'contents/_base.html' %}
+
+{% load i18n %}
+
+{% block title %}{% trans 'Staff' %}{% endblock title %}
+
+{% block content %}
+
+
+
+{% include '_includes/staff.html' %}
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/_venue.html b/src/templates/pycontw-2024/contents/_venue.html
new file mode 100644
index 000000000..93a6873da
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/_venue.html
@@ -0,0 +1,33 @@
+{% extends 'contents/_base.html' %}
+
+{% load static %}
+{% load compress %}
+
+{% block extra_css %}
+{{ block.super }}
+{# Use the CDN because I can't get the local images load correctly. #}
+
+{% endblock extra_css %}
+
+{% block body_class %}{{ block.super }} venue-page{% endblock body_class %}
+
+{% block content %}
+
+
+ {% block map_info %}{% endblock map_info %}
+
+
+
+
+{% endblock content %}
+
+{% block extra_js %}
+{{ block.super }}
+{% compress js %}
+
+{% endcompress %}
+{% endblock extra_js %}
diff --git a/src/templates/pycontw-2024/contents/en/about/code-of-conduct.html b/src/templates/pycontw-2024/contents/en/about/code-of-conduct.html
new file mode 100644
index 000000000..d8e6806d2
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/about/code-of-conduct.html
@@ -0,0 +1,88 @@
+{% extends 'contents/_base.html' %}
+
+{% block title %}Code of Conduct{% endblock title %}
+
+{% block content %}
+
+
+
+PyCon Taiwan aims to provide a joyous, pleasant and vibrant environment for our participants. This convention applies to all the words and deeds of participants in the relevant entities and digital fields of PyCon Taiwan. It is hoped that everyone will work together to make PyCon Taiwan full of mutual respect and trust.
+
+
+Principles
+
+PyCon Taiwan is dedicated to providing a harassment-free conference experience for everyone. We do not tolerate harassment toward conference participants in any form.
+
+
+ Do not harass others.
+ Appreciate each other.
+ Show consideration to others.
+
+
+Remember that harassment and jokes that are sexist, racist, or exclusionary are not tolerated at PyCon Taiwan. PyCon Taiwan take appropriate actions to redirect behavior violating the Code of Conduct.
+
+Do not harass others
+PyCon Taiwan will not tolerate any form of harassment and discrimination. Each attendee should be equally respected regardless of nationality, race, language, gender, sexual orientation, age, disability, physical appearance, faith, profession, seniority, political view, or intellect.
+
+Appreciate each other
+Each attendee is expected to act professionally when attending Pycon Taiwan. Users of Python are diverse in their professional roles, technical backgrounds, and application areas. They contribute to the technology in many different ways, some amazingly unimaginable. Opinions or actions that undervalue other members of the community are inappropriate and will not be tolerated.
+
+Show consideration to others
+Sexual contents in any form are inappropriate in any conference venue, including but not limited to talks, open spaces, or social media. Words and actions originated from stereotypes are discouraged. Cell phones should be set to silent or a mode that does not annoy others in the conference rooms.
+
+
+Violation and Reporting
+
+Conference organizers will take appropriate actions on behaviors violating the Code of Conduct. Violators may be required to leave the conference without a refund at the sole discretion of the organizers. This Code of Conduct is applicable to both physical and online events approved by the organizers of PyCon Taiwan.
+
+Attendee Procedure For Reporting Code of Conduct Incidents
+If you believe someone is in danger, including from themselves, the most important thing is to find help.
+If you feel your safety is in jeopardy, please immediately contact law enforcement in Taiwan (dialing 110 in Taiwan). Ask an organizing staff if you do not have a cell phone.
+If you believe the Code of Conduct has been violated, please report the incident to a staff member right away. If you are unsure whether it is a violation, or whether the space where it has happened is covered by this Code of Conduct, we encourage you to still report it.
+In the event where there is conflict of interest, you may directly contact any of the lead incident responders:
+
+
+ Committee of Incident Response, PyCon Taiwan
+
+
+
+Report Data
+If you make a report via email or phone, please include:
+
+ Your contact information (so we can get in touch with you if we need to follow up).
+ Date and time of the incident.
+ Location of the incident.
+ Whether the incident is ongoing.
+ Description of the incident.
+ Identifying information of the reported person: name, physical appearance, height, clothing, voice accent, identifying badge information such as company name, ribbons, or badge number.
+ Additional circumstances surrounding the incident.
+ Other people involved in, or witnesses to the incident, and their contact information or description.
+
+
+Confidentiality
+All reports are confidential. When we discuss incidents with people who are reported, we will anonymize details as much as we can to protect the reporter’s privacy.
+However, the reported person may be able to guess who made the report in certain situations, even with details anonymized. If you have concerns about retaliation or your personal safety, please note those in your report. We still encourage you to report, so that we can support you while keeping our conference attendees safe. In some cases, we can compile several anonymized reports into a pattern of behavior, and take action based on these reports.
+In cetain cases, we may determine that a public statement needs to be made. In such cases, the identities of all victims and reporters will remain confidential unless the individuals involved instruct us otherwise.
+
+Report Handling Procedure
+When you make a report to an incident responder, they will gather information about the incident according to the Procedure For Incident Response.
+After an incident responder takes the report, they will immediately consult with the PyCon Taiwan staff, unless there is a conflict of interest (involved directly with one of the PyCon Taiwan staff), in which case any non-interested parties will be contacted.
+If the incident is ongoing and needs to be immediately addressed, any lead incident responder may take appropriate action to ensure the safety of everyone involved. If the situation requires it, this may take the form of a referral to an appropriate non-PyCon agency, including the law enforcement in Taiwan.
+If the incident is less urgent, the report will be discussed by the event staff, who will meet to determine an appropriate response.
+
+Notes
+This procedure has been adapted from the PyCon Procedure for Incident Handling .
+
+
+License (CC BY-SA 3.0 TW)
+This document is licensed under an Attribution-ShareAlike 3.0 Taiwan license.
+
+
+The Code of Conduct of PyCon TW 2023 is effective from Mar 1st, 2023. PyCon Taiwan reserve the right to modify this announcement at any time and will announce any updates when available.
+Thank you.
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/about/community.html b/src/templates/pycontw-2024/contents/en/about/community.html
new file mode 100644
index 000000000..0f7789481
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/about/community.html
@@ -0,0 +1,59 @@
+{% extends 'contents/_base.html' %}
+
+{% block title %}Python Community in Taiwan{% endblock title %}
+
+
+{% block content %}
+
+
+
+
+
+PyHUG, founded by yyc and Albert Huang in 2011, is the first Python user community in Taiwan. The meetup was first located at Operations Center for Industry Collaboration, NTHU, and was later moved to Information Technology Service Center, NCTU. Speakers were invited on a monthly basis. The majority of participants were university students, along with engineers from Hsinchu Science Park, linguists, and even Hsinchu police officers. Therefore, topics were mostly about scientific application in Python, which affected the focus of first PyCon TW. In recent years, the meetup, held in a coffee shop with around 20 attendees on every Wednesday, turns to be “eating, chatting, talking about Python and everything”. Currently the community is organized by Dainese. They are looking for new face to join.
+
+
+
+
+After COSCUP 2012, Keith, Tim and some enthusiasts launched Taipei.py. The number of members rapidly grew up to 50 after the first few meetups. The events are hosted monthly at CLBC. The topics are mainly related to web programming and web application. Recently there are more sharing of big data topics. Since most of the organizers are in web-related industry, Andy also hosts other activities, such as Python Web Meetup and Django study group, besides the monthly meetups.
+
+
+
+
+In 2013, Joe founded Tainan.py when he moved from Taipei to Tainan due to the change of company location. Since jserv also became the faculty in Department of Computer Science and Information Engineering, NCKU, Joe decided to launch “Tainan.py × MOSUT” events with MOSUT, another community located in Tainan. In order to promote local Tainan food, local dishes, like fried chicken and almond soup, are provided during the break in Tainan.py. Monthly meetup takes place in the weekend afternoon, so attendees are welcome to try more Tainan food after the meetup if the local dishes during the break is just not enough :)
+
+
+
+PyLadies is a group of women developers who love the Python programming language. We are an international mentorship group with a focus on helping more women become active participants and leaders in the Python open-source community. We host monthly meetups with different topics such as beginners meetups, project of python presentation and tutorial. Open to all who identify as women. Feel free to join us!
+
+See report: PyLadies 社群注入台灣女性技術社群新動能
+
+
+
+
+Before Kaohsiung.py was founded, Python enthusiasts, like TooMore and CD, sometimes shared Python-related topics in the KSDG meetups. Founder of Kaohsiung.py is Victor Gau. He joined Tainan.py regularly until one day he had an accident with a speeding motorcycle on the way from Tainan to Kaohsiung. The accident induced him to launch a Python community in Kaohsiung. Therefore, Kaohsiung Python User Group was founded in 2014. In addition to casual meetups, which invites specialist from other cities, there is a regular gathering in Wenzao Ursuline University of Languages on one Monday night every month. They welcome anyone who passes by Kaohsiung to join the events.
+
+
+
+
+Taichung.py was started in 2014 by Prof. Yuan-Liang Tang and several enthusiasts. The events were held at restaurants or coffee shops until later Microprogram Co. supported the event venue. Now the events are held monthly in Saturday afternoon, which is best suited for a walk to have some snacks in Fengjia Night Market after the event.
+
+
+
+
+The history of Hualien.py can be dated back to 2013, Prof. Tzer-Jen Wei felt the lack of open source and technology communities in the east part of Taiwan. He started to invite Python speakers from other cities. Having speakers like c3h2, clkao and Mosky, Hualien.py began the first event in 2014. Events have been located in Hualien Railway Cultural Park, National Dong Hwa University, Hualien Cultural Creative Industries Park and so on. By the supports from all over the Taiwan, the community in Hualien thrives. Now there are more and more local speakers in the meetups. In addition to speeches, there are casual gathering and special focus workshop. Next time when having a trip in Taiwan east coast, drop by Hualien.py.
+
+
+
+
+Django Girls Taipei was founded by Michelle Leu in 2014. Currently there are casual tutorials and workshops to help girls build their own Django website. Also there are events held with the Python Web Meetup for novice. Highly recommend to girls with basic understanding of Django to learn more.
+
+Facebook Group
+
+
+Led by the Vice President of Nan Kai University of Technology, Prof. Cheng-Min Lin, “Nantou.py” has regularly held a monthly meeting at 768 Art Space, a public welfare platform, to share the latest information and newest experiences with all the Python lovers in central Taiwan. Although Nantou County was once called the technology desert, our members have contributed their efforts to bring along industry connection as well as a selfless and boundless location or all the Python learners.
+
+Facebook 社團
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/about/privacy_policy.html b/src/templates/pycontw-2024/contents/en/about/privacy_policy.html
new file mode 100644
index 000000000..8a2189b39
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/about/privacy_policy.html
@@ -0,0 +1,127 @@
+{% extends 'contents/_base.html' %}
+{% load static %}
+{% block title %}Privacy Policy of PyCon Taiwan{% endblock title %}
+
+{% block content %}
+
+
+ Privacy Policy of PyCon Taiwan
+
+(CC BY-SA 3.0 TW) Last Updated:2020-08-04
+Policy of Personal Information Protection
+
+
+ First, we would like to thank you for joining us in PyCon Taiwan (hereafter referred to as “PyCon TW”).
+ We are going to ask for your permission to collect and to use your personal information
+ recorded in the registration form. We value your privacy and we would follow the terms and
+ conditions as set out below while collecting and using your personal information.
+
+
+The Purpose of Usage of Your Personal Information
+
+
+ For the purposes of organizing the event and providing better services, we are going to collect your personal
+ information on the registration page all according to the Personal Information Protection Act by The specific purpose
+ and the classification of personal information of the Personal Information Protection Act 130. Meeting
+ Management.
+
+The purposes will be including but not limited to:
+
+
+ To confirm the identity by your recognition form
+ To provide you a badge of PyCon TW
+ All other purposes that help us to give better services at the meeting
+
+
+The Way We Collect and the Scope that We Use Your Personal Information
+
+
+ While registering for PyCon TW, we will obtain information about you by asking you to fill in the form on the
+ registration page. The information that we gathered will only be used to provide services to you.
+
+
+How Do We Use Your Personal Information
+
+ We would preserve the personal information that you provided until you request us to cease using it or PyCon TW
+ ceases operation. We will NEVER sell, exchange, lease or otherwise expose your personal information to third
+ party organizations or individuals, with the exception that:
+
+
+
+ We have your prior permission
+ We have received subpoenas or other legal due process that requires us to provide the information.
+
+
+What Personal Informations are Included
+
+
+ The personal informations that we are asking for includes but not limited to: full name and nickname, gender, email
+ address, mobile number, occupation, belonging organization (company), contact address, ... etc. This is done according
+ to The specific purpose and the classification of personal information of the Personal Information Protection Act by
+ its Code 001 Type for identifying individuals.
+
+
+Your Rights of Personal Information
+
+
+ You could exercise your rights (which would be mentioned below) of the personal information by writing to us (either
+ by paper or by electronic means)
+
+
+
+ Any inquiries or requests for viewing the personal information
+ Any requests to make duplications of the personal information
+ Any requests to add supplements or correct the personal information
+ Any requests to discontinue the collection, processing or using of personal information
+ Any requests to delete the personal information unless you do not agree the process of registration and legal
+ regulation
+
+
+
+ We would keep it and change your request all according to Taiwan’s legal obligations.
+ If you would like to have your personal information modified or updated, you could do it on the registration page or
+ email us.
+
+Cancelling Your Participating and Deleting Your Personal Information
+
+
+ You may request us to cease the use of your personal information by notifying us through mail and we shall refrain from using your personal information from then
+ onwards. You are free to provide as much or as little information as you like. However, in the case that the provided
+ information is erroneous, insufficient, or that you request us to cease the usage of your data, then for the proper
+ operation of the event, we may reject your registration and participation.
+
+
+Questions for Privacy Protection Policy
+
+ If you have any questions regarding the gathering and usage of your personal information, please feel free to contact
+ us at organizers@pycon.tw .
+
+
+Privacy: Collecting Personal Information during COVID-19 Outbreak
+
+ The purpose of collecting personal information in accordance with the Personal Data Protection Law and epidemic
+ prevention and control requirements is to best respond and ensure health security for all attendees in COVID-19
+ outbreak. It is necessary to collect, manage, and use relevant personal information. Please read below for
+ details.
+
+
+ PyCon TW 2020 collects personal data of attendees for the purpose of contact tracing during the outbreak of COVID-19.
+ All collected information will be deleted after 28 days. attendees’ access in each venue will be recorded for epidemic
+ control measures. We will inform everyone that if any suspected COVID-19 and provide such information for CECC for the
+ purpose of preventing spread of COVID-19 and tracing contacts.
+
+
+License (CC BY-SA 3.0 TW)
+This document is licensed under a Attribution-ShareAlike
+ 3.0 Taiwan license.
+
+
+The Privacy Policy of PyCon TW will be effective July 1th, 2020.
+
+ However, due to the rapidly changing social and legal environment and the continual advancement in technology, we
+ reserve the right to modify this privacy policy at any time, and will announce any update when available.
+
+Thank you.
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/about/pycontw.html b/src/templates/pycontw-2024/contents/en/about/pycontw.html
new file mode 100644
index 000000000..73073d941
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/about/pycontw.html
@@ -0,0 +1,41 @@
+{% extends 'contents/_pycontw.html' %}
+{% load static %}
+
+{% block title %}History of PyCon Taiwan{% endblock title %}
+
+
+{% block content %}
+
+
+ History of PyCon Taiwan
+
+
+
+thinker organized PyCTW, the predecessor of PyCon Taiwan, in both 2008 and 2011 . They are one-day events gathering Pythonistas in Taiwan together.
+
+The first PyCon Taiwan was founded in 2012, by yyc and volunteers from communities. The topics mainly focused on scientific computation as well as introduction to Python-based tools. The organizers decided to follow the Everybody Pays policy originated from PyCon US: Everyone, including the staffs and speakers of PyCon Taiwan, is required to pay for the ticket. The principle, which we honor to this day, distinguishes PyCon Taiwan from other conferences in Taiwan. The chairperson, yyc, cheerfully recorded this milestone in his blog .
+
+In 2013, the re-elected chairperson, yyc, decided to expand the scale of PyCon Taiwan, and tried several new events. A paid Python tutorial was hosted in collaboration with caterpillar before the conference. It was highly successful. We also held the Birds of a Feather (BoF) event for the first time, featuring with a night market style activity, in which participants enjoyed the buffet with live music performance, and walk among booths hosted by various communities. These new events became a signature for PyCon Taiwan. yyc again summarized some thoughts about the conference in his blog.
+
+We turned to host PyCon APAC/Taiwan , as PyCon for the APAC area, in both 2014 and 2015, lead by chairpersons Tim Hsu and Keith Yang. We were lucky to invite Jessica McKellar, director of Python Software Foundation, and many prestigious contributors in the community as our keynote speakers. During the BoF, we launched a problem-solving competition in collaboration with CheckIO , as an entertaining activity. We also arranged programs like Show Time and Job Event in order to promote sponsors. Tutorials covering several topics were held, ranging from Python introduction to web crawling, data mining, signal processing, and even interaction with Raspberry Pi.
+
+PyDay, an activity for new programmers hosted jointly by PyCon Taiwan and top universities in Taiwan, was also held at the first time in 2015. Keynote speakers from PyCon Taiwan came to the PyDay event, and share their experience throughout sessions.
+
+We passed the APAC flag to South Korea in 2016, and put our focus back to the native Taiwanese community. But PyCon Taiwan, now under the slogan “Implement the Future, Together!”, was strong as ever, and received a overwhelming amount of proposals and participants. We were lucky to invite jserv and Audrey Tang, both famous Taiwanese community leaders and established hackers, as well as foreign speakers including Paul Hildebrandt, senior engineer at Disney Animation Studio, Steve Dower, software developer at Microsoft, and Amber Brown, manager of the Twisted project. Paul brought us an enlightening speech about how Python is applied to animation production in Disney, which the audience greatly enjoyed. Along with the first local keynote speakers at PyCon Taiwan, we also made new attempts including a FinTech session, interactive games combining sensor technology and a vending machine, and experience-sharing talks about teaching programming to young adults. The photo albums have our most tresurous memories.
+
+2017 is our most futuristic PyCon Taiwan ever. All of our keynote speakers, including globally renowed machine-learning expert Hsuan-Tien Lin, are not only recognized in their repective fields, but also community leaders, trend-setters, and visionaries for the next generation. In line with the community-focused theme, we also held an unconference session for the first time, looking forward to spurring discussion in the community, to great success. The late-night party is also expanded to include contributions from community members with great talent. Adrian Liaw’s piano performance was such a treat.
+
+The largely same team were brought back to host PyCon Taiwan in 2018. Continuing the established theme, the image is set to “acceletation”, both in the technical sense and community-wise.
+
+We retrospected the role of PyCon Taiwan as a community platform in Taiwan in 2019. We have continued improving our agenda and events by introducing wonderful thoughts and experience from the other Python Conferences in the world to PyCon Taiwan. We also enhanced the exchange of experience between local-to-local and local-to-international Python communities, and kept adopting innovative plans.
+
+Following the expectation and work of 2019, we host PyCon Taiwan in Tainan. This is the first time we host PyCon Taiwan in southern Taiwan. We hope we could bring local communities more and different experience.
+
+As a platform for Python communities, PyCon Taiwan invites all Python users, developers, and promoters in Taiwan to join our events.
+
+
+
+
+
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/about/staff.html b/src/templates/pycontw-2024/contents/en/about/staff.html
new file mode 100644
index 000000000..a7714264c
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/about/staff.html
@@ -0,0 +1 @@
+{% extends 'contents/_staff.html' %}
diff --git a/src/templates/pycontw-2024/contents/en/covid-19/guidelines.html b/src/templates/pycontw-2024/contents/en/covid-19/guidelines.html
new file mode 100644
index 000000000..80baeaf18
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/covid-19/guidelines.html
@@ -0,0 +1,132 @@
+{% extends 'contents/_base.html' %}
+{% load static %}
+{% block title %}PyCon Taiwan COVID-19 Guidelines{% endblock title %}
+
+{% block content %}
+
+{% url 'page' path='about/privacy_policy' as privacy_policy %}
+
+
+ PyCon Taiwan COVID-19 Guidelines
+
+(CC BY-SA 3.0 TW) Last Updated:2020-08-03
+
+
+ In response to the 2019 novel coronavirus (COVID-19) outbreak, the PyCon TW host team (We) announced PyCon Taiwan
+ COVID-19 Guidelines that are based on the COVID-19 prevention guidelines from Taiwan Central Epidemic Command
+ Center (CECC). During the COVID-19 outbreak, these guidelines must be followed so as to prevent epidemic transmission
+ and protect oneself and others. The guidelines will adopt any changes required by CECC without further notifications.
+ Please pay attention to our website in particular to relevant modification. The final guideline will be announced on
+ August 20th, 2020.
+
+
+
+Epidemic Prevention Guidelines
+
+
+
+ Every PyCon TW attendee has to fill out the PyCon
+ TW 2020 Personal Health Declaration Form online , a personal QR code will be generated after you complete the
+ form. Your QR code is your entry to PyCon TW 2020, it is not retrievable after it is lost. If you lose your QR code,
+ you will need to fill out the Health Declaration Form again to obtain a new one.
+
+
+ PyCon TW 2020 Health Declaration Form will be available online for previewing on August 20 and be ready
+ for use on August 30.
+
+
+ If you are unable to fill out the form online, PyCon TW will provide the form in paper, please fill it out and
+ give it to staff at the venue.
+
+
+
+
+ According to Taiwan Central Epidemic Command Center (CECC) COVID-19 Prevention Guidance, To avoid close
+ contact,
+ all people should keep a distance from others of at least 1.5 meters in the indoor environment and 1 meter in
+ outdoor. When these social distancing are not able to be maintained, all people are urged to wear face masks.
+ Therefore, all PyCon TW 2020 attendees are required to wear face masks all the time when in
+ the indoor environments.
+
+
+ PyCon TW will be a real-name registration. All attendees need to show the QR code (the proven completion of Health
+ Declaration) to receive a badge. We will check badges at each venue for the entry, please complete the
+ registration process and collect your badge at the registration desk before entering each venue. All attendees’
+ temperature will be taken prior to the entry.
+
+
+ Capacity limits are set for each venue for your safety and comfort. There are staff on site to control the total
+ number of people in each venue, please follow the instructions from staff on site. Do not enter a venue that is
+ full.
+
+
+ If you feel ill or have high risk of infection (home isolation, home quarantine, self monitoring). Please stay
+ home, do not go to the PyCon TW venue.
+
+
+
+Self-preparation for Preventing COVID-19
+
+
+
+ To complete PyCon TW 2020 Personal Health Declaration Form online before joining PyCon TW 2020 activities.
+
+
+ To wear a face mask before entering indoor places. It is recommended that you have one or two spare face masks
+ with you.
+
+ To wash hands frequently, using hand sanitizer and keeping social distancing are also helpful.
+ To sanitize seats and tables your own when moving to different venues.
+
+
+PyCon TW Preparedness for preventing COVID-19
+
+
+
+ PyCon TW helps cleaning and disinfecting venues before and after each conference day. We prepare bleach solutions
+ to sanitize all venues and facilities within, including: floors of each venue and hallways, door and window handles,
+ light and other facilities switches, tables, seats, washstand, and stair handrail.
+
+
+ Infrared Ear/Forehead Thermometers are available at the conference desk for anyone that feels like measuring
+ temperatures.
+
+ Alcohol sanitizers are available for use at the conference desk.
+
+
+Privacy Policy of PyCon Taiwan
+
+
+
+ PyCon TW 2020 collects personal data of attendees for the purpose of contact tracing during the outbreak of
+ COVID-19. All collected information will be deleted after 28 days. attendees’ access in each venue will be recorded
+ for epidemic control measures. We will inform everyone that if any suspected COVID-19 and provide such information
+ for CECC for the purpose of preventing spread of COVID-19 and tracing contacts. For more details please
+ visit:Privacy Policy
+ of PyCon Taiwan.
+
+
+
+Government Documents
+
+
+
+License (CC BY-SA 3.0 TW)
+
+ This document is licensed under a Attribution-ShareAlike
+ 3.0 Taiwan license.
+
+
+
+The Privacy Policy of PyCon TW will be effective July 1th, 2020.
+
+ However, due to the rapidly changing social and legal environment and the continual advancement in technology, we
+ reserve the right to modify this privacy policy at any time, and will announce any update when available.
+
+Thank you.
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/events/open-spaces.html b/src/templates/pycontw-2024/contents/en/events/open-spaces.html
new file mode 100644
index 000000000..05ab25675
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/events/open-spaces.html
@@ -0,0 +1,61 @@
+{% extends 'contents/_base.html' %}
+
+{% block title %}Open Spaces{% endblock %}
+
+{% block content %}
+
+
+
+Open Spaces are self-organizing meetup events which happen simultaneously with the main conference. Open Spaces are organized during the period of PyCon by attendees, which provides a way for you to define, organize, plain out the meetup as you preferred. Enjoy the Open Space while making new friends, chat about any topic you’d like at the same time.
+
+For those who have participated in previous PyCon Taiwan, Open Spaces may sound familiar to you. Yes! it’s basically the good old BoF (Birds of a Feather) , but with a name that is more comprehensive to new conference attendees.
+
+How do I participate in an Open Space?
+
+It’s pretty easy: Just show up :)
+
+Instead of Academia Sinica, this year’s PyCon will be hosted at International Conference Hall in National Cheng Kung University. Therefore, the Open Space has its dedicated space. Just find a subject that interests you, greet with the host, and enjoy!
+
+
+Where and when are the Open Spaces?
+
+Location: The Multifunction Room located at the first floor of the conference.
+
+Time: Between the morning keynote ended and afternoon keynote started of day 1 (11:10 ~ 16:30) and from the morning keynote ended till noon of day 2 (10:10 ~ 12:10).
+
+
+What Open Spaces are there?
+
+We don’t know either! It’s up to you and fellow attendees 😉
+
+Just like the attendees, Open Spaces are very versatile. There are no limits to the subject of the Open Space! An Open Space can be a mani/pedi party, a feminist hacking space, an AcroYoga space, or even a board games room. It can also be a discussion about any of the technical subjects, from computer security to your favorite Python project to professional occupation such as SRE.
+
+How do I host an Open Space?
+
+Just get a whiteboard from the information desk, fill in the subject, time and your name and you’re all set!
+
+For those who want to get the event started immediately, simply find a desk and place the whiteboard in front of it. Otherwise, you can leave the whiteboard at the information desk and get it back when your event starts.
+
+Ideas for Open Spaces
+
+Here are a few ideas for potential Open Space topics and activities:
+
+
+ Hacker space (maker projects) that use Python (e.g. in Raspberry Pis, IOT, home automation, robots / drones / blimps autopiloted with Python)
+ Hacking / networking / devops
+ Data visualization / science
+ Natural language processing and generation (e.g. chatbots)
+ Quantified self
+ Diversity initiatives, for example a feminist hackerspace
+ A space for organizers of conferences, workshops, diversity initiatives (Django Girls, PyLadies, etc.)
+ Framework-specific Open Spaces, e.g. Django or Flask
+ How to contribute to open source, a help / mentoring group for beginners
+ Git
+ Support: how to avoid burnout
+ Recruitment workshops
+
+
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/events/overview.html b/src/templates/pycontw-2024/contents/en/events/overview.html
new file mode 100644
index 000000000..f97e758b8
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/events/overview.html
@@ -0,0 +1,121 @@
+{% extends 'contents/_base.html' %}
+
+{% load i18n %}
+
+{% block title %}Events Overview{% endblock title %}
+{% block content %}
+
+{% url 'page' path='conference/keynotes' as events_keynote_url %}
+{% url 'events_talk_list' as events_talk_list_url %}
+{% url 'events_tutorial_list' as events_tutorial_url %}
+{% url 'page' path='events/open-spaces' as events_openspaces_url %}
+{% url 'community_track' as community_track_url %}
+{% url 'page' path='events/sprints' as events_sprint_url %}
+
+
+
+
+Keynotes
+
+PyCon Taiwan invites three speakers to give keynote speeches during the two-day conference. Each keynote speaker is
+ considered one of the most important figures in their respective fields. They share their professional experience and
+ the image of their domain’s future.
+
+More information about keynotes can be found on the {% trans 'Keynotes' %} page.
+
+
+Talks
+
+The two conference days are packed with talks about Python by speakers from Taiwan and around the world. The talks
+ will be either 30- or 15-minute long. Three tracks of talks will be delivered simultaneously, all with different
+ topics and difficulties. We suggest you to make a schedule beforehand, and choose what you want ot listen based on
+ your interests. Many people take notes on the program schedule before the meeting so they don’t run to wrong places.
+
+
+More information about talk can be found on the {% trans 'Talks' %}
+ page.
+
+
+Tutorials
+
+Tutorial are events held as part of the main conference, but attendees need to register separately in order to join.
+ They are 1.5 hours events held to help participants better understand talks during the conference, or get their hands
+ on more Python applications.
+
+More information about tutorials can be found on the {% trans 'Tutorials' %} page.
+
+
+Lightning Talks
+
+Lightning talks are held at the end of each conference day. It’s known for its fast-paced nature that allows only 5
+ minutes for each talk, including setup. If you would like to give a lightning talk, please write down your name and
+ the subject on a piece of paper, and put it into the jar near the registration desk. We will announce in each noon the
+ list of talks for the day.
+
+
+Open Spaces
+
+Open Spaces are held both in parallel with the main conference, and during a dedicated slot at the three day of the
+ conference. The schedule is created just-in-time by the attendees. If you would like to host an Open Space event,
+ please use an Open Space card found in your goodies bag, fill it and pin it on the Open Space board.
+
+More information about Open Spaces can be found on the {% trans 'Open Spaces' %} page.
+
+
+Job Fair
+
+Job Fair is a career expo for Python developers. During the Job Fair session, our sponsors will take turns introduce
+ themselves on the stage and promote their job openings. For attendees that are looking for a career, this is a great
+ opportunity for you to interact with the sponsors or submit your rèsumè!
+
+
+Community Track
+
+The community track is a new event in PyCon TW. We choose the talks with specific topics and package them into the
+ same session. We'll leave the conference rooms and go to characteristic cafes, exhibition spaces, and even monuments
+ so that the attendees and speakers can interact with each other more comfortably and closely.
+
+In short, the "community track" is to build strong connections between attendees, speakers, sponsors, and
+ communities!
+
+The community track will take place in the afternoon of day 2 (9/6), with a duration of 3 hours, including 90-minute
+ talks arranged by PyCon Taiwan.
+
+More information about Community Track can be found on the {% trans 'Community Track' %} page.
+
+
+Sprints
+
+Sprints are held out of the main conference. A sprint event gathers open source project owners, contributors, and
+ people who wants to contribute but trying to find a place to start. During a sprint, project hosts bring their
+ unresolved issues or new features under development and share with everyone. You can join a project of your choice, or
+ bring your own project here!
+
+For those who already knows fundamentals of Python and wants to participate open source projects, but doesn't know
+ where to start, sprints are great opportunities to get yourself involved! As for project hosts, this is a great chance
+ for you to find people with similar interests, having face-to-face interactions with contributors, and getting new
+ contributors to your project's development! Be prepared to get your hands dirty!
+
+More information about Sprints can be found on the {% trans 'Sprints' %} page.
+
+Registration: KKTIX
+
+Projects: HackMD
+
+PyNight
+
+PyNight is an extension to the BoF event we held in previous years. This year's event is expanded to provide a more
+ diverse occasion for the community. It consists of both “music” and “communication” parts. During the music event, the
+ protagonist is a group of versatile friends from the community, bringing their carefully prepared music. In the
+ community event, you are the protagonist! No matter what your thoughts, you can find like-minded friends here; the
+ subject without any restrictions, as long as you are interested, everything is welcome.
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/events/pyhug.html b/src/templates/pycontw-2024/contents/en/events/pyhug.html
new file mode 100644
index 000000000..fe8ac23ab
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/events/pyhug.html
@@ -0,0 +1,78 @@
+
+{% extends 'contents/_base.html' %}
+
+{% load static %}
+
+{% block title %}PyCon TW x PyHUG Co-hosting Online/Offline Meet-up Streaming{% endblock title %}
+
+{% block meta_description %}PyCon Taiwan are co-hosting the mixed online/offline event together with PyHUG this time!{% endblock meta_description %}
+
+
+{% block content %}
+
+
+ PyCon TW x taipei.py Co-hosting Online/Offline Meet-up Streaming
+
+
+Here comes the third warm-up event. We are co-hosting the mixed online/offline event together with PyHUG this time!
+
+
+
+ Event Time
+ Wednesday, 29 July 2020
+ 7:30 pm to 8:30 pm GMT+8
+
+
+ Event Info
+ Youtube Streaming(
+
+ streaming link
+
+ )
+
+
+ Physical Meet-up
+ Micro Beer
+
+
+ Host
+ Dainese
+
+
+
+
+Welcome to PyHUG! We are a group of Python programmers near the Hsinchu, Taiwan. We regularly hold seminar and coding meetings. You are very welcomed to join us!
+
+Agenda
+
+
+
+ Time
+ Event
+
+
+
+
+ 19:00 - 19:25
+ Welcome
+
+
+ 19:25 - 19:30
+ Speaker introduction
+
+
+ 19:30 - 20:00
+ 用 Loki 做個能究責的 NLU 模型 - 以金融場景應用為例
+
+
+ 20:00 - 20:20
+ Q & A
+
+
+ 20:20 - 21:00
+ Free sharing
+
+
+
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/events/sprints.html b/src/templates/pycontw-2024/contents/en/events/sprints.html
new file mode 100644
index 000000000..acfd592b1
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/events/sprints.html
@@ -0,0 +1,34 @@
+{% extends 'contents/_base.html' %}
+
+{% block title %}Sprints{% endblock title %}
+
+{% block body_class %}{{ block.super }} exchange-page{% endblock body_class %}
+
+
+{% block content %}
+
+
+
+Sprints are held out of the main conference. A sprint event gathers open source project owners, contributors, and people who want to contribute but trying to find a place to start. During a sprint, project hosts bring their unresolved issues or new features under development and share with everyone. You can join a project of your choice, or bring your own project here!
+
+For those who already know fundamentals of Python and want to participate open source projects, but doesn't know where to start, sprints are great opportunities to get yourself involved! As for project hosts, this is a great chance for you to find people with similar interests, having face-to-face interactions with contributors, and getting new contributors to your project's development! Be prepared to get your hands dirty!
+
+This year’s PyCon TW Sprints will be held in physical and online at the same time, so you can keep contributing to open source projects.
+
+Physical Sprints
+
+The physical sprints meetup will be held on 8/30 Sunday in Tainan Goodideas Studio. You can interact with the project hosts in close, learn about the project, and contribute your code to the open-source project with everyone together. In this meetup, the venue will also provide snacks so that you can have something delicious while contributing to your code!
+
+Please RSVP on our KKTIX
+
+Online Sprints
+
+The online sprints are through contacting the project hosts you are interested in. The project hosts will add you to a group and interact with you online. If you are still not satisfied with the physical sprints, you can still join the online sprints to keep communicating with project hosts. In this way, contributing to open source is not limited to time and place, but a long-term community promotion.
+
+Sprint Host Registration
+
+If you’re interested in being a project host at the sprint, please add your project at HackMD
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/events/tainan-dot-py-mosut.html b/src/templates/pycontw-2024/contents/en/events/tainan-dot-py-mosut.html
new file mode 100644
index 000000000..fe4b619c1
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/events/tainan-dot-py-mosut.html
@@ -0,0 +1,66 @@
+
+{% extends 'contents/_base.html' %}
+
+{% load static %}
+
+{% block title %}Tainan.py x MOSUT Co-hosting Online/Offline Meet-up Streaming{% endblock title %}
+
+{% block meta_description %}An online/offline meet-up streaming event co-hosted by Tainan.py x MOSUT{% endblock meta_description %}
+
+
+{% block content %}
+
+
+ Tainan.py x MOSUT Co-hosting Online/Offline Meet-up Streaming
+
+
+Our last warm up session takes place a week before PyCon Taiwan 2020, right at where the tutorials will be hosted during the actual event.
+
+
+
+ Event Time
+ Saturday, August 29, 2020
+ 2:00 PM to 5:00 PM GMT+8
+
+
+ Event Info
+ Youtube Streaming(
+
+ streaming link
+
+ )
+
+
+ Physical Meet-up
+ Goodideas Studio Section 2, Beimen Road · East District
+
+
+
+
+We welcome those who in southern Taiwan to join us to share, have fun, meet people and see the beauty in Python with us.
+
+Agenda
+
+
+
+ Time
+ Event
+
+
+
+
+ -
+ Eric - Building an end-to-end natural language processing framework
+
+
+ -
+ Wei Lee - commitizen-tools: What can we gain from crafting a git message convention?
+
+
+ -
+ Free sharing
+
+
+
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/events/taipei-dot-py.html b/src/templates/pycontw-2024/contents/en/events/taipei-dot-py.html
new file mode 100644
index 000000000..1cf40302c
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/events/taipei-dot-py.html
@@ -0,0 +1,78 @@
+
+{% extends 'contents/_base.html' %}
+
+{% load static %}
+
+{% block title %}PyCon TW x taipei.py 聯合線上直播{% endblock title %}
+
+{% block meta_description %}PyCon Taiwan 合併 taipei.py 實體聚會所進行的線上與線下聯播活動!!{% endblock meta_description %}
+
+
+{% block content %}
+
+
+ PyCon TW x taipei.py Co-hosting Online/Offline Meet-up Streaming
+
+
+Following the previous Python NPF x nantou.py event, we are co-hosting the mixed online/offline event together with taipei.py this time!
+
+
+
+ Event Time
+ Thursday, 18 June 2020
+ 7:00 pm to 9:00 pm GMT+8
+
+
+ Event Info
+ Youtube Streaming(
+
+ streaming link
+
+ )
+
+
+ Physical Meet-up
+ iCHEF Office Lobby
+
+
+ Session Chairs
+ Keith, Tim
+
+
+
+
+We hold seminar meetings regularly in Taipei and invite you to enjoy the fun, insights, and perspectives in this Python community
+
+Agenda
+
+
+
+ Time
+ Event
+
+
+
+
+ 19:00 - 19:10
+ Warm-up and taipei.py introduction
+
+
+ 19:20 - 19:50
+ Wei Lee - commitizen-tools: What can we gain from crafting a git message convention?
+
+
+ 19:50 - 20:20
+ Keith Yang - Django Cookiecutter: their everyday Django project template
+
+
+ 20:20 - 20:50
+ Tim Hsu - What's New in Python 3.9
+
+
+ 20:50 - 21:00
+ Wrap up
+
+
+
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/events/warmup-session.html b/src/templates/pycontw-2024/contents/en/events/warmup-session.html
new file mode 100644
index 000000000..0628d1662
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/events/warmup-session.html
@@ -0,0 +1,37 @@
+{% extends 'contents/_base.html' %}q
+
+{% block title %}Warm-up session{% endblock title %}
+
+{% block meta_description %}Overview on how to submit a financial aid application to PyCon Taiwan, and allow us to help you attend the conference.{% endblock meta_description %}
+
+
+{% block content %}
+{% url 'page' path='events/passion-fruit' as passion_fruit_url %}
+{% url 'page' path='events/taipei-dot-py' as taipei_dot_py %}
+{% url 'page' path='events/pyhug' as pyhug %}
+{% url 'page' path='events/tainan-dot-py-mosut' as tainan_dot_py_mosut %}
+
+
+
+
+
+
+Python NPF is the first event collaborated with nantou.py to host a mixed online/offline event. We expect we could get familiar with this type of mixed meetup event so we could enjoy our pythonic time during COVID-19 era.
+
+
+
+Following the previous Python NPF x nantou.py event, we are co-hosting the mixed online/offline event together
+ with taipei.py this time!
+
+
+
+Here comes the third warm-up event. We are co-hosting the mixed online/offline event together
+ with PyHUG this time!
+
+
+
+Here comes the last warm-up event before PyCon TW 2020. Tainan.py and MOSUT are co-hosting the mixed online/offline event together!
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/registration/financial-aid.html b/src/templates/pycontw-2024/contents/en/registration/financial-aid.html
new file mode 100644
index 000000000..6771eca04
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/registration/financial-aid.html
@@ -0,0 +1,72 @@
+{% extends 'contents/_base.html' %}
+
+{% block title %}Financial Aid{% endblock title %}
+
+{% block meta_description %}Overview on how to submit a financial aid application to PyCon Taiwan, and allow us to help you attend the conference.{% endblock meta_description %}
+
+
+{% block content %}
+
+
+
+The Program
+
+Everybody Contributes is one of PyCon’s core principles. All attendees, including speakers and volunteers, have to pay for registering. While following this convention, PyCon Taiwan also has a financial aid program to help friends in the community, financially or otherwise, so more people are able join us in the big event.
+
+All who look for help attending the conference are welcomed to apply. The organizers will review all applications and allocate resources based on both the conference budget and the applicants’ conditions.
+
+While we hope to support everyone to participate in the community, the budget is unfortunately limited, and so is the financial aid program. In cases of insufficient resources, we wish to support those who are most in need and to maximize community gain available from the applicant’s participation. As such, we may be forced to turn down your application to prioritize others.
+
+Application How-Tos
+
+The procedure of the application is what follows:
+
+
+
+
+ The applicant (you) enters a valid email address for contact in the
+
+ form
+
+ .
+
+
+ Leave a brief description about yourself, and provide at least your full name.
+ The conference staff (we) will contact you to verify the information and try to learn more about you.
+ The Financial Aid Program closes on 21 June 15 July (15:30 UTC).
+ We will inform you of the results before the end of the conference registration. You will receive instructions about how to claim your aid. Please make sure to bring papers and/or proofs as appropriate to the conference for the claim process.
+
+
+Information for Financial Aid
+
+ Eligibility: The financial aid program is open to all contributors, attendees, students, and speakers and aims to provide assistance to those who otherwise might not be able to attend the conference.
+ Allowance: In general, the support limit is up to NTD 20,000. If you need more financial aid, you are encouraged to provide more detailed information while completing the form.
+ Visa: If you need to apply for a Visitor VISA, feel free to contact us at organizers@pycon.tw
+ Reimbursement: The native residents would get the funds via wire transfer, and for the foreigners, you can get the cash funds at the conference counter.
+ The Financial Aid includes conference fee, travel and accommodation expenses. (The travel and accommodation will be partly reimbursed at the actual expense, based on the results of the review.)
+
+
+Some Tips on Application
+
+
+ Describe your interests, what you did in the Python community, and what you plan to do in the future
+ Describe why you would require additional help to attend. For example, higher transportation cost than average attendees is needed, that cause financial difficulty.
+ Describe what makes your situation unique. Say, you might represent a particular group that is not well-represented.
+ Describe how other attendees would benefit from your presence. Say, you’ll share your experience, or can help raise awareness of an issue in the community, etc.
+
+
+
+
+We understand that we all have different financial situations, and contribution is difficult to quantify. As we have a limited budget, we cannot guarantee to fund all applicants. But please do let us know if you need support, and we will do our best.
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/registration/ticket-info.html b/src/templates/pycontw-2024/contents/en/registration/ticket-info.html
new file mode 100644
index 000000000..2ffa576d9
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/registration/ticket-info.html
@@ -0,0 +1,150 @@
+{% extends 'contents/_base.html' %}
+
+{% block title %}Conference Tickets{% endblock title %}
+
+{% block meta_description %}Tickets are on sale for PyCon Taiwan 2020. Get yours now before it’s too
+late!{% endblock meta_description %}
+
+{% block body_class %}{{ block.super }} ticket-info-page{% endblock body_class %}
+
+{% block content %}
+
+{% url 'page' path='registration/financial-aid' as reg_financial_aid_url %}
+
+
+
+
+
+
+
Individual
+
+
+
EarlyBird / Discount
+
2,600 NTD
+
+
+
+
+
Buy
+
+
+
+
+
+
+
Reserved
+
+
+
+
Contributor
+
1,500 NTD
+
+
+
+
Buy
+
+
+
+
+
+
Individual:
+
Tickets are limited. Be sure to get your ticket before they are sold
+ out. We will send
+ out electronic invoices by email after the conference. If you need reimbursement from your company, you might
+ want a corporate ticket to meet our local tax regulation.
+
+
+
Corporate:
+
Provide company name and Unified Business Number, or N/A if
+ reimbursement is not required. We will send out electronic invoices by email after the
+ conference.
+
+
+
Reserved:
+
Please enter your invitation code on checkout.
+
+
+
+
+
+ Tickets provide access to the main conference from September 5 to September 6. Please refer to their own
+ pages for tutorial.
+
+
+ Early bird ticket sales end on July 20, or upon sold out. All ticket sales end on August 21.
+
+
+ All price settled in New Taiwan Dollars (NTD). Reference rate: NTD 31.31 = USD 1.00.
+
+
+ Company Unified Business Number will be present on receipts for those who require reimbursement. Contact
+ organizers[at]pycon.tw for English receipt requests, or any questions regarding ticket sales.
+
+
+
+
+Notices
+
+Everybody Contributes
+
+PyCon Taiwan is a paid conference. Everybody, including staffs and speakers, contributes or pays for attending (see
+ PyCon:
+ Everybody Pays ).
+
+Ways to Pay for Tickets
+
+You can pay through credit card, PayPal, or ATM transfer.
+
+Refund
+
+You may ask for refund earlier than ten days before the conference, by contacting us, or directly via KKTIX.
+
+Financial Aids
+
+You can contact us for a financial aid if you feel any difficulty affording a ticket and/or other expanses attending
+ the conference. Please apply before your purchase. More info about applications can be found here .
+
+Dietary Requirements
+
+We provide lunch during the conference. Please let us know if you have any specific dietary habit.
+
+Valid Contact Required
+
+Please provide valid means of contact (phone number and email) on purchase, so that we will be able to inform you of
+ any important notices.
+
+Ticketing Consultancy
+
+Please email to organizers[at]pycon.tw if you have any questions regarding ticket information. We will reply
+ as soon as possible.
+
+Other Events
+
+Events like Tutorials or Sprints might need a separate registration. Be sure to check out the related details on the
+ event's page.
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/speaking/cfp.html b/src/templates/pycontw-2024/contents/en/speaking/cfp.html
new file mode 100644
index 000000000..15a3f2aaa
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/speaking/cfp.html
@@ -0,0 +1,111 @@
+{% extends 'contents/_base.html' %}
+{% load static %}
+
+{% block title %}Call for Proposals {% endblock title %}
+
+{% block meta_description %}The Call for Proposals is now open. PyCon Taiwan 2021 is accepting talks and tutorials!{% endblock meta_description %}
+
+{% block content %}
+{% url 'page' path='speaking/recording' as speaking_recording_url %}
+{% url 'page' path='speaking/talk' as speaking_talk_url %}
+{% url 'page' path='speaking/tutorial' as speaking_tutorial_url %}
+{% url 'page' path='event/open-space' as event_open-space_url %}
+{% url 'page' path='about/code-of-conduct' as about_coc_url %}
+{% url 'signup' as signup_url %}
+{% url 'user_dashboard' as dashboard_url %}
+
+
+
+The Call for Proposals is now open. PyCon 2021 Taiwan is accepting talks and tutorials!
+
+
+Important Dates
+
+
+ Talks & Tutorial CfP begins: 21 Feb
+ Talks & Tutorial CfP ends: 18 Apr 23:59:59 AoE
+ Announcement of acceptance: In the middle of June (tentative)
+
+
+All talks will be recorded, edited then uploaded to pyvideo.org by the PyCon Taiwan committee, unless the speaker requests otherwise. See more info about the recording release .
+
+All speakers are required to buy their own conference tickets (Everyone Contributes Policy )
+
+
+How to Submit Your Proposal
+
+You need to sign up for a new account on tw.pycon.org. With an activated account, you can fill up the speaker profile and create new proposals through the My PyCon page.
+
+We encourage you to submit the proposal as early as possible. You are welcomed to submit multiple proposals.
+
+Due to the effects of COVID-19, you can choose to give your talk or tutorial remotely. If we make sure the offline speaking will take place as scheduled, you can still decide whether to come to the meeting venue in person.
+
+Guidelines for Proposal Submission
+
+Talks
+
+We accept a broad range of Python-related proposals from academic research to commercial projects, case studies, or soft topics such as running a community, making good communication, mental health, etc. So basically, if you are reading this, just submit your proposal!
+
+We encourage speakers to talk about your own Python package or application, your experience of learning Python or hosting a Python community, etc. Talks on advanced topics are highly welcomed as well. For your inspiration, our committee has suggested that they’d love to see talks on the following topics: FinTech, Community, A.I, Data Analytics, IoT, Machine Learning, Testing , etc.
+
+When considering different topics, you may be interested in reviewing selected speeches over the past few years at PyCon Taiwan.
+
+
+
+Talks will be lasting either 30 minutes or 15 minutes , depends on you, you'll measure and decide how much time you need. Note that the length of a talk includes setup and Q&A session .
+
+Talks can be given in either English, Mandarin or Taiwanese Hokkien.
+
+If it's your first time to propose a talk at PyCon Taiwan or a conference in general, please have a look at How to Propose a Talk? to learn more about conventions, and it might help you organize your thoughts on your proposal.
+
+This year, we will invite part of the unselected talks to share at the local communities. PyCon Taiwan will partially compensate for your transportation cost.
+
+Tutorials
+
+Similar to talks, we don’t pose limitations on tutorial topics.
+ This year, tutorials are free and the length has been changed to 1 hour and 30 minutes.
+ It will be at the same time as the conference.
+ Venue is tentatively set as Goodideas-Studio .
+ The guideline for tutorial submission is based on the guideline for talks,
+ so make sure you have read How to Propose a Talk?
+ On top of that, We have some special requirements for tutorial submission,
+ please refer to How to Propose a Tutorial?
+ for more information.
+
+Proposals Review Process
+
+After the Call for Proposal ends, and before the announcement of acceptance, the PyCon TW 2020 Proposals Review Committee is going to review the proposals and give scores and provide useful feedback. The process consists of three phases:
+
+ Stage 1 Review: Reviewers are going to score and give feedback. This will last for about 2 ~ 3 weeks
+ Modification Step: According to reviewers’ comments, you can modify your proposal through the dashboard. This step lasts for about 1 to 2 weeks
+ Stage 2 Review: Reviewers are going to re-score and re-give feedback to the modified proposals
+
+
+Modification Step
+
+ Between the stage-1 and stage-2 review, you can see the feedback from the reviewer.
+ You may modify your proposal according to reviewers’ comments or feedback. If you want to make your change obvious to the reviewers, you can point out the ID of the comment, and mention about what you’ve modified according to the comment in the "Supplementary" section, e.g. "#4: Updated the time management for xxx phase"
+
+
+If you have any questions, please contact us at program@pycon.tw .
+
+Inappropriate words or images
+
+Please note that PyCon Taiwan is a conference where the audience comes from different cultural backgrounds. Some jokes may be rude to others. If you want to add some humorous images or words to your speech, please double check if there is any possibility of offense, and refer to our Code of Conduct .
+
+
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/speaking/recording.html b/src/templates/pycontw-2024/contents/en/speaking/recording.html
new file mode 100644
index 000000000..404c2f723
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/speaking/recording.html
@@ -0,0 +1,14 @@
+{% extends 'contents/_base.html' %}
+
+{% block title %}Recording Release{% endblock title %}
+
+{% block content %}
+
+
+
+Since one of the PyCon motivations is to help Python education and advocate the use of Python, by default all talks are recorded . If the speaker agrees to give permission to PyCon Taiwan, we will record, edit, and release the audio and video of the speaker's presentation to online video sites such as YouTube and pyvideo.org . The recording might be also live streamed if it is technically feasible.
+
+If you don’t want your talk being recorded, make sure you leave the recording option unchecked during the proposal submission.
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/speaking/talk.html b/src/templates/pycontw-2024/contents/en/speaking/talk.html
new file mode 100644
index 000000000..d9e352d4f
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/speaking/talk.html
@@ -0,0 +1,129 @@
+{% extends 'contents/_base.html' %}
+
+{% block title %}How to Propose a Talk{% endblock %}
+
+{% block content %}
+{% url 'page' path='speaking/cfp' as speaking_cfp_url %}
+{% url 'user_dashboard' as dashboard_url %}
+
+
+ How to Propose a Talk?
+
+
+For general proposal calling information, see Call for Proposals .
+
+First of all, thank you for contributing to PyCon Taiwan! The following will help you submit a successful proposal. In the following, we are going to provide you the tips to make your proposal strong and informative and get the best chance of acceptance.
+
+ What’s your topic?
+ Who is your target audience?
+ What will the audience gain after your talk?
+ How will you organize your time slot?
+
+
+You will be asked to fill the following fields in your proposal:
+
+ Title
+ Category
+ Duration
+ Language
+ Abstract
+ Python Level
+ Objectives
+ Detailed Description (optional)
+ Outline (optional)
+ Supplementary (optional)
+ Recording Policy
+ Slide Link (optional)
+
+
+Hmmm, that is a lot. Well, if you skip all optional fields, it would only take you about 500 characters. But we encourage you to fill most of the fields to help reviewers understand your proposal.
+
+Some of the fields are for reviewers only, so don’t worry about spoilers:
+
+ Objectives
+ Outline
+ Supplementary
+
+
+If you are a very experienced speaker, you can directly enter the My PyCon page to propose!
+
+Next, we will give more detailed advice on each aspect.
+
+
+Topics and General Advice
+
+To pick a topic that suits PyCon Taiwan, you can first find out what accepted talks are about from the previous PyCons:
+
+
+Good Ideas
+
+
+
+ The abstract or detail description should include but not limited to:
+
+ Who is the intended audience?
+ What should they know before the talk?
+ Is there any special domain knowledge required?
+ What will they get after my talk?
+
+
+
+ The abstract and the content are as close as possible to the title.
+ Content must be original. Should let the audience and reviewer understand which part is original content in your proposal.
+ Enumerate each of your talk section in outline with estimated time length.
+ If your topic is not that familiar to normal Pythonistas, make sure you provide sufficient information through links of blog posts, wiki, source codes, or materials that help the understanding of your content.
+
+
+
+Bad Ideas
+
+
+
+ Avoid infomercials.
+
+ Try not to merely sell your products or introduce how to use them in your talk. However, we do welcome talks about how your company solves the problem or your open source project that can benefit the general attendees.
+
+
+
+ Don’t assume everyone in the review committee knows you. Please always submit a full proposal.
+ Avoiding plagiarism. We welcome all forms of sharing, but it should be clear which sections are original and which are the citation of previous work.
+
+
+
+How to Choose the Python Level
+
+It is very important for you to choose an appropriate Python level.
+
+Your talk won’t be simply accepted because it is either super hard or deadly simple. The acceptance correlates with the specified Python level and your targeted audience.
+
+If your talk is for Python first-timers and it is about your Python learning experience and how you solve some tricky issues you face. This is a proper proposal. If your talk is about inspecting the Python memory usage and coordinating two GC systems together with reusing pointers, and you specify your talk as being novice or intermediate, it is not a good idea.
+
+For the extreme conditions (like topics above), it will be easy to decide. But topics lie somewhere in between are not. Therefore, there are more descriptions below to help you find the proper level.
+
+Novice
+
+People who have little to none Python knowledge. One can expect them to have basic knowledge about Python syntax and control flow (e.g. if-else, for loops; functions), but the audience does not understand every module in stdlib, nor the concepts of tricky variables visible scope and OOP (and MRO inheritance).
+
+Sharing your experience learning Python, leading a community perfectly fits in this level. Generally, a talk about non-builtin Python packages, say pandas and Django, is not a novice talk. Unless people can actually learn all the content you give right after your talk.
+
+Intermediate
+
+The possible applications are more diverse than novice talks. Intermediate talks are for those who just learned how Python works and wish to know more about how it can be used in different tasks. The talk topic can be about setting up web frameworks, talking to databases, monitoring web traffic, auto trading in the stock market and so on.
+
+From previous submissions over the past few years, around half of the talks should fall into this category. Note that we may contact you to adjust your talk to be novice or experienced based on your proposal.
+
+Experienced
+
+People coming to experienced talks should have a good proficiency in Python (or programming).
+
+The main difference between intermediate and experienced talks is that experienced talks assume more domain knowledge about the talk topic. For example, talks about optimization and tool’s internals should be at this level.
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/speaking/tutorial.html b/src/templates/pycontw-2024/contents/en/speaking/tutorial.html
new file mode 100644
index 000000000..1e08b74fb
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/speaking/tutorial.html
@@ -0,0 +1,48 @@
+{% extends 'contents/_base.html' %}
+
+{% block title %}How to Propose a Tutorial{% endblock title %}
+
+{% block content %}
+{% url 'page' path='speaking/cfp' as speaking_cfp_url %}
+{% url 'page' path='speaking/talk' as speaking_talk_url %}
+
+
+ How to Propose a Tutorial?
+
+
+For general proposal calling information, see Call for Proposals .
+
+First of all, thank you for considering giving a tutorial in PyCon Taiwan 2020.
+
+Generally speaking, Good tutorials possess most of the traits good talks have. The most discernible differences of a tutorial from a talk are the hands-on nature and the longer duration . By longer duration, generally more content is required and it should remain interesting and keep the attendees awake and hyped even after hours of lecture and exercises. By containing hands-on exercises, the experience of teaching coding to people is necessary. You might also need teaching assistants who you should be able to comfortably communicate during the tutorial, usually at least two teaching assistants for a general class size of 20 people is needed.
+
+Both differences require many times of practice and experience. Therefore, a tutorial speaker usually satisfies at least one of the following prerequisites:
+
+ A previous tutorial speaker in any programming conferences or communities
+ More than one time of speaking experience in open source communities, preferably the local Python communities
+ Teaching assistant in previous tutorials
+
+
+We might ask you to give the tutorial to the community before the conference if you lack the experience.
+
+Tutorial Duration
+
+The length of the tutorial is 1 hour and 30 minutes.
+
+In our previous experiences, tutorials with a length of 6 hours are exhausted for both instructors and students, students usually find it difficult to consistently follow in the second half of the tutorial. Full-day tutorials require a relatively experienced instructor, thus the length of the tutorial is 1 hour and 30 minutes this year. We strongly recommend you to clearly define prerequisites and goals , which helps building the best learning experience.
+
+Tutorial Dates and Location
+
+Tutorials are held in parallel with the main conference, therefore, the classroom would be outside of the venue. Venue is tentatively set as Goodideas-Studio .
+
+
+Charging Policy
+
+No additional charge.
+
+How to become a tutorial speaker?
+
+The easiest and the best answer: Go speak and involved in the local Python communities!
+If you have any questions or suggestions, please don't hesitate to contact us .
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/sponsor/prospectus.html b/src/templates/pycontw-2024/contents/en/sponsor/prospectus.html
new file mode 100644
index 000000000..41afcdf32
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/sponsor/prospectus.html
@@ -0,0 +1,339 @@
+{% extends 'contents/_base.html' %}
+
+{% load i18n %}
+
+{% block title %}Sponsor{% endblock title %}
+{% block body_class %}scroll-x{% endblock %}
+{% block content %}
+
+{% url 'page' path='sponsor/community-tracks' as community_track_url %}
+
+
+ Sponsorship Prospectus
+
+
+
+
+ Contact:
+
+ sponsorship@pycon.tw
+ to Sponsorship Team of PyCon Taiwan 2020
+
+
+
+ PyCon Taiwan 2020 Chair, Chun-Yu Tseng
+
+ PyCon Taiwan 2020 Program Chair, Wei Lee
+
+ PyCon Taiwan 2020 Sponsorship Director, You-Hao Chang
+
+
+
+ PyCon Taiwan is the largest annual gathering for the community using and developing the open-source Python programming language in Taiwan.
+ "PyCon Taiwan" is a trademark authorized according to "PSF PyCon Trademark Usage Policy", and is organized by the Taiwan Python community and Open Culture Foundation (OCF, GUI 38552170) for growing the local community.
+
+ PyCon Taiwan continues to connect with new community members locally, nationally, and globally.
+ Your sponsorship keeps PyCon Taiwan affordable and accessible to the widest potential audience. Having your support, we are able to provide financial aid to needed attendences.
+
+ We have several sponsor packages including but not limited to the list below:
+
+
+
+ We are eager to hear from you! Only you know your business and what your are looking for the best. We do provide cutomized sponsor packages and are more than willing to take your suggestions into build suitable packages.
+
+
+Estimated attendance: 400+ (The first PyCon Taiwan in southern Taiwan!)
+
+
+Quick stats from 2019:
+
+ 675 attendees
+ Of those 675 attendees, 20% were from 9+ different countries out of Taiwan.
+ Most attendees are soft engineers. Others are: developers, potential job seekers, data scientist, students, managers, researchers, consultants, CEOs and CTOs etc.
+ Around 30% attendees have been using Python for more than 5 years.
+
+
+
+Conference Schedule (Taiwan timezone (UTC+8) if not specified)
+
+ Call for Proposal: March 1st, 2020
+ Deadline of Call for Proposal: April 26th, 2020 (23:59:59 AoE )
+ Schedule Announcement: middle of June, 2020 (TBD)
+ Job Fair: September 5th, 2020 (TBD)
+ Main Conference: September 5-6th, 2020
+
+
+Sponsor Packages
+
+
+Notes
+
+
+ Job Fair Introduction, restricted to 5 minutes per organization.
+
+
+ PyCon TW 2020 will not produce a digital brochure, all information will be posted on our website and app.
+
+
+ PyCon TW 2020 do not provide tote bag and physical brochure to our participants. However, sponsors have the liberty to design, print and provide copies of their own handbook.
+
+
+ PyCon TW 2020 community track is currently divided into 5 sectors. The PyCon TW organization holds the final right to decide the location of each sponsor. Diamond and Platinum sponsors have the highest priority for venue selection (already included in the sponsorship plan). Gold sponsors have the option to select subscriptions (right after Diamond and Platinum). The total amount is limited, so the first-come-first-served is adopted. Priorities can pre-subscribe and choose venue .
+
+
+ The sponsoring talk in the community track is limited to 30 minutes, and 1 talk per community track.
+
+
+ Regarding the purchase restrictions on technical speeches, one sponsor can only have one of them basically. But if a sponsor has special needs, then the official will discuss and decide on it. Besides, If a sponsor above the gold level claims a community track, the selection order will take priority over the single purchase of technical speeches.
+
+
+ Diamond Sponsorship includes title rights, the company logo will be displayed with PyCon TW 2020. However, PyCon TW 2020 reserves the right to further evaluate such action.
+
+
+ Diamond Sponsorship includes the title right of the main meeting room, set sponsor can name the meeting room. Nevertheless, PyCon TW 2020 reserves the right to evaluate such action.
+
+
+ Transportation sponsorship includes the title right for PyCon TW 2020 shuttle bus. However, PyCon TW 2020 reserves the right to evaluate such action.
+
+
+ To further promote diversity of PyCon TW 2020, company (group/sponsoring) tickets will not exceeded 1/3 of the total pass sold. Thus, such group passes are sold in a first come first served manner, please order ASAP.
+
+
+ To ensure the quality of your speech, those who long to speak at the PyCon TW 2020 conference must be aware of Call for Proposal (CFP) deadlines.
+
+
+ In response to the impact of the COVID-19 epidemic, the sponsorship plan will be slightly modified and will be released in mid-June with the final meeting details.
+
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/en/sponsor/sponsor.html b/src/templates/pycontw-2024/contents/en/sponsor/sponsor.html
new file mode 100644
index 000000000..b06389232
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/sponsor/sponsor.html
@@ -0,0 +1,33 @@
+{% extends 'contents/_base.html' %}
+
+{% load i18n %}
+
+{% block title %}Sponsor{% endblock title %}
+{% block content %}
+{% url 'page' path='sponsor/prospectus' as prospectus_url %}
+
+
+
+PyCon Taiwan is driven both by our hardcore community members and, YOU, our awesome sponsor partners!
+
+Your generous support is the engine for us to move forward. Ever since PyCon Taiwan was first held in 2012, the conference has expend its visibility, accessibility, and varieties with a goal to continuously provide a platform for developers, new contributors, organizations, and companies to share knowledge and ideas and to strengthen Python communities in Taiwan.
+
+PyCon Taiwan calls for your sponsorship in order to create more possibilities for all this to happen. Our sponsorship packages make sure your benefits:
+
+
+ Visibility on Python Community
+ Recruit in the conference
+ Promote your brand
+ Connect with strong talent network
+
+
+Our sponsorship partners are what makes PyCon Taiwan possible! We work closely with our partners in order to optimize what PyCon Taiwan can offer. Look for your participation!
+
+See our full prospectus for Sponsorship Package
+Talk us about sponsorship
+
+{% endblock content %}
+
diff --git a/src/templates/pycontw-2024/contents/en/venue.html b/src/templates/pycontw-2024/contents/en/venue.html
new file mode 100644
index 000000000..d0e1fe0e5
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/en/venue.html
@@ -0,0 +1,173 @@
+{% extends 'contents/_venue.html' %}
+
+{% block title %}Venue{% endblock title %}
+
+{% block map_info %}
+
+{% load static %}
+
+
+ International conference room
+ National Cheng Kung University
+
+No. 1, Daxue Rd., East Dist., Tainan City 701, Taiwan
+
+
+ Goodideas Studio
+
+
+ Tutorial Place
+
+
+Rm. L2A, No. 16, Sec. 2, Beimen Rd., East Dist., Tainan City 701, Taiwan
+
+{% endblock map_info %}
+
+{% block content %}
+
+
+
+
+{{ block.super }}
+
+Transportation
+
+From Taiwan Taoyuan International Airport (TPE)
+
+1. MRT: Airport Terminal Station (A12 or A13) to Taoyuan HSR Station (A18)
+
+
+
+2. Taiwan High Speed Rail: Taoyuan to Tainan
+
+
+
+3. Train: Shalun Station (4272) to Tainan Sation (4220)
+
+
+
+4. Tainan Sation to National Cheng Kung University
+
+
+ Please exit by Rear Exit. And then Go along Daxue Road. When you see the school gate, please turn left. After
+ entering the school gate, please turn left at the next intersection. And you can find an International conference
+ room. It takes around 7 minutes to walk.
+ Google Maps
+
+
+From Kaohsiung International Airport (KHH)
+
+1. MRT: Siaogang Station (R3) to Kaohsiung Main Station (R11)
+
+
+
+2. Train: Kaohsiung Sation (4400) to Tainan Sation(4220)
+
+
+
+3. Tainan Sation to National Cheng Kung University
+
+
+ Please exit by Rear Exit. And then Go along Daxue Road. When you see the school gate, please turn left. After
+ entering the school gate, please turn left at the next intersection. And you can find an International conference
+ room. It takes around 7 minutes to walk.
+ Google Maps
+
+
+
+
Nearby parking information
+
+
+
+
+
+
+
Tutorial Place
+
+
+
Goodideas Studio
+
Rm. L2A, No. 16, Sec. 2, Beimen Rd., East Dist., Tainan City 701, Taiwan
+
+
+
Transportation
+
+
From National Cheng Kung University
+
+
+ Please exit by school gat. And then go along Daxue Road to Tainan Station. Exit the station by Front Exit. After
+ exiting Front Exit, turn right and go along Beimen Road. And you can find Goodideas Studio. It takes around 12
+ minutes to walk.
+ Google Maps
+
+
+
+{% endblock content %}
+
+{% block extra_js %}
+
+{{ block.super }}
+{% endblock %}
diff --git a/src/templates/pycontw-2024/contents/zh/about/code-of-conduct.html b/src/templates/pycontw-2024/contents/zh/about/code-of-conduct.html
new file mode 100644
index 000000000..9d98d6ab8
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/about/code-of-conduct.html
@@ -0,0 +1,88 @@
+{% extends 'contents/_base.html' %}
+
+{% block title %}行為準則{% endblock title %}
+
+{% block content %}
+
+
+
+PyCon Taiwan 為了提供歡樂、愉快、生氣蓬勃的環境,特訂定此行為準則。本準則適用於參與者在 PyCon Taiwan 相關實體與數位場域中的一切言行,期望所有人一起遵守,讓 PyCon Taiwan 充滿互敬與互信。
+
+
+三大準則
+
+PyCon Taiwan 致力於為所有人提供無騷擾的會議體驗(包含數位場域),我們不容許以任何形式騷擾任何參與者。請各位務必遵守以下三大原則:
+
+
+ 禁止騷擾言行。
+ 彼此欣賞。
+ 體貼他人。
+
+
+請記住,PyCon Taiwan 不容許任何的騷擾和性別歧視、種族主義或排他性笑話。PyCon Taiwan 籌備團隊(以下簡稱「籌備團隊」)有權調整任何違反此準則的行為。
+
+禁止騷擾言行
+大會不容忍任何的騷擾或歧視。無分國籍、種族、語言、性別、性取向、年齡、身心狀況、信仰、職業、資歷、政治傾向、智力等,每一位參與者都應該獲得同樣的尊重。
+
+彼此欣賞
+每位參與者都應該抱持專業的態度與行為。Python 的使用者來自不同的專業分工、技術背景與應用領域。我們以非常多樣的方式使用並貢獻 Python 技術。任何貶低社群中其它成員的言行都是不適當的。
+
+體貼他人
+請勿在大會的任何場合做出任何形式的性暗示。這些場合包含但不限於演講、開放空間、社群媒體。請避免源自刻板印象的言行。會議中請把手機調為靜音,或是其它不會影響他人的模式。
+
+
+違反與通報
+
+籌備團隊有權調整任何違反此準則的行為。僅需根據籌備團隊的裁決,違反本行為準則者可能必須離開會場(包含數位場域)並不得要求退費。本行為準則適用於實體場地與數位場域,並經由籌備團隊認可執行。
+
+通報行為準則事件之程序
+如果您認為某人處於危險之中(包含他們自己造成的危險),請立即提供或替他尋求幫助。
+如果您確實感到自己的安全受到威脅,請立即撥打 110(臺灣警察單位)以聯繫臺灣執法單位。如果您沒有行動電話,只需詢問 PyCon Taiwan 工作人員(以下簡稱「大會工作人員」)即可。
+如果您認為有人違反本行為準則,我們鼓勵您通報。如果您不確定該事件是否違規,或是所發生場域是否在本行為準則的範疇內,我們仍然鼓勵您通報。
+如果發生利益衝突,您可以直接聯繫任一通報應變者:
+
+
+ PyCon Taiwan 事件通報應變委員會
+
+
+
+通報內容
+如果您透過電子郵件進行通報,請盡量包含以下內容:
+
+ 您的聯繫方式(以便我們在需要跟進時與您取得聯繫)。
+ 事件發生的日期和時間。
+ 事件發生地點。
+ 事件是否正在發生。
+ 事件描述。
+ 被舉報人的識別資訊:姓名、外貌、身高、服裝、口音、識別徽章資訊,如公司名稱、名牌或識別證。
+ 事件發生的情境與相關情況。
+ 其他參與或目擊事件的人及其聯繫方式或描述。
+
+
+保密
+所有通報內容都將保密。 當我們與被舉報人討論通報事件時,我們將盡可能匿名化通報之事件細節以保護舉報者之隱私。
+然而,有些事件是發生在一對一的互動中,即便我們匿名化通報之事件細節,被檢舉者仍可能猜到是誰舉報他們。如果您擔心遭遇報復或人身安全,請在通報內容中註明。儘管如此,我們仍鼓勵您通報,以便我們在確保與會者安全的同時為您提供協助。在某些情況下,我們會將多個匿名通報轉譯成一種行為模式,並針對該行為採取行動。
+在某些情況下,我們可能會需要發表公開聲明。除非收到來自所有的受害者和通報者的指示,否則所有的受害者和通報者的身份都將被保密。
+
+通報處理流程
+當您通報違反準則的事件後,通報應變者將根據 通報行為準則事件之程序 蒐集相關的事件資訊。
+通報應變者收到通報後,他們將立即與大會工作人員協商討論如何處理,然而若通報事件與大會工作人員存在利益衝突(直接與大會工作人員有關),通報應變者則會與其他非利益相關方協商討論。
+如果事件正在發生且需要立即處理,任何通報應變者都可以採取適當的行動,以確保所有相關人員的安全。視情況需要可轉交由 PyCon Taiwan 以外的合適單位(包含臺灣執法單位)處理。
+如果事件不具急迫性,大會工作人員將開會討論通報之事件以確定應變方式。
+
+備註
+以上通報流程改寫自 PyCon 通報行為準則事件處理流程 。
+
+
+授權 (CC BY-SA 3.0 TW)
+此文件採用 姓名標示-相同方式分享 3.0 台灣 授權條款。
+
+
+PyCon TW 2023 行為準則從 2023 年 03 月 01 日起開始生效,PyCon Taiwan 保留最終解釋與調整權,如有需要我們將隨時修改此份準則,並將儘速更新與公告予您。
+感謝。
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/about/community.html b/src/templates/pycontw-2024/contents/zh/about/community.html
new file mode 100644
index 000000000..fa7327412
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/about/community.html
@@ -0,0 +1,62 @@
+{% extends 'contents/_base.html' %}
+
+{% block title %}台灣的在地 Python 社群{% endblock title %}
+
+
+{% block content %}
+
+
+
+
+
+台灣第一個 Python 社群,2011 年由 yyc 和 Albert Huang 共同成立。初期的聚會地點在清大創新育成中心,後來搬到交大的計算機中心,每月定期邀請講者來分享。參加成員以大學生為主,也有竹科工程師、語言學家、新竹市警官。也因此多數講題偏重Python 在科學上的應用,這也影響了第一屆 PyCon Taiwan 的議題走向。近幾年開始,每週三在咖啡館聚會,漸漸變成「吃吃喝喝聊 Python 及雜七雜八」的形式。目前由 Dainese 擔任負責人,聚會人數在 20 人左右,最近成員平均年齡有老化的趨勢?需要地方的新血加入。
+
+
+
+
+2012 年的 COSCUP 後,Keith、Tim 與其快樂夥伴們創立了 Taipei.py。每個月固定在 CLBC 聚會,前幾次聚會過後,成員迅速增加到 50 人以上。聚會分享主題以網路相關技術為主,近期也越來越多大數據相關的分享。由於創辦者們多數在網路相關行業,因此除了每月例會,也會舉辦讀書會等活動。
+
+
+
+
+2013 年,公司從台北搬到台南的 Joe,順勢成立了 Tainan.py。適逢 jserv 移駕成大資工,Joe 為了壯大聲勢,決定與同在台南的 MOSUT 社群合辦聚會,成為「Tainan.py × MOSUT」。Tainan.py 的中場休息時間,會推廣台南在地美食,讓與會者品嘗鹽酥雞、杏仁湯等,讓衣服尺寸變大的食物。一個月聚會一次,時間在週末下午,是一種吃不夠還可以再續攤吃台南美食的概念。
+
+
+
+
+PyLadies 是一個專屬於女生的 Python 愛好者聚會,專供喜歡 Python 的女生、想學 Python 的女生、想瞭解 Python 的女生,彼此交流、交換心得,聊天認識朋友的地方。我們是一個國際性的 Python 交流組織 ,主要任務是希望透過分享、教育與Workshop等活動的方式幫助更多女生可以在 Python 社群中成為主動的參與者與領導者。我們將會於每個月舉辦不同主題的活動,例如:初學者的入門、使用 Python 的應用與經驗分享,相關教學等主題。只要你是女孩並對 Python 有興趣,歡迎你來參加喔!
+
+專訪:PyLadies 社群注入台灣女性技術社群新動能
+
+
+
+
+在 Kaohsiung.py 之前,高雄的同好如 TooMore、CD 等,不定期會安排 Python 的餐敘,在 KSDG 偶爾會有 Python 的主題分享。Victor Gau 是 Kaohsiung.py 的發起人,在 Kaohsiung.py 成立之前,Victor定期的會去參加 Joe 安排的 Tainan.py 的活動,直到有一次從台南回高雄時,與超速的機車發生擦撞,後續繁瑣的事故處理程序,讓 Victor 萌生在高雄成立社群減少交通奔波的念頭。2014 年,Victor 在高雄發起了 Kaohsiung Python UserGroup,除了不定期的在禮拜六下午安排外縣市的專家到高雄來分享新技術,每個月也會挑一個星期一晚上,在文藻外語大學聚會。竭誠歡迎大家路過高雄時,來參加 Kaohsiung.py 的聚會。
+
+Facebook 社團
+
+
+
+唐元亮老師與熱心友人們,也在 2014 年發起了 Taichung.py。初期流浪在各餐廳與咖啡館,後期由微程式科技提供場地空間,告別流浪的生活。每月聚會一次,時間在星期六下午,剛好可以在聚會結束後,到附近的逢甲夜市散步、覓食。
+
+
+
+
+花蓮.py 的創設要回溯到 2013 年,魏澤人老師有感於東部較缺乏開源及技術社群,開始邀約台灣各地的 Python 講者。在 c3h2、clkao、Mosky 等人爽快答應下,花蓮.py 在 2014 年順利展開。活動場地分別在花蓮的鐵道文化園區二館、東華大學理工一館,及花蓮文創園區湛盧狂草黎明公益店等地。之後多虧了各地許多朋友幫忙,前來分享各式技術,讓社群慢慢健康成長,現在花蓮本地的講者也越來越多了。目前聚會的形式,除了演講分享外,也常有自由聚會及特定主題的workshop。如果大家有規劃台灣東部小旅行,歡迎路過花蓮.py。
+
+
+
+
+2014 年,也是 Michelle 成立 Django Girls Taipei 的一年。藉由不定期舉辦教學活動,帶領女孩們一步步製作自己的網站。也和 Python Web Meetup 一起合辦新手村活動,給對 Django 有一點點了解,又想要瞭解更多的女孩們參加。
+
+Facebook 社團
+
+
+
+2019年底,由南開科技大學副校長林正敏教授,號召、帶領並群聚著中台灣喜愛Python的人們。起初聚會地點在草屯768藝術空間,藉由768的公益性平台固定於每月舉行分享會,來自各行各業的大夥,無私地向大家分享自身經驗。在南投,人稱科技沙漠的地區,有著這一群人,為python貢獻己力,帶動產業連結,並為有意學習的大家,帶來一場無私、無限的學習地。
+
+Facebook 社團
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/about/privacy_policy.html b/src/templates/pycontw-2024/contents/zh/about/privacy_policy.html
new file mode 100644
index 000000000..ea1fa37a1
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/about/privacy_policy.html
@@ -0,0 +1,71 @@
+{% extends 'contents/_base.html' %}
+{% load static %}
+{% block title %}PyCon Taiwan 個人資料保護聲明{% endblock title %}
+
+{% block content %}
+
+
+
+ PyCon Taiwan 個人資料保護聲明
+
+
+(CC BY-SA 3.0 TW) 最後更新時間:2020-08-04
+
+個人資料保護政策
+
+感謝您參與臺灣 Python 年會 (以下簡稱「PyCon TW」)。「PyCon TW 主辦團隊」(以下簡稱「我們」)
+ 將依個人資料保護法之規定來使用、保管您於報名時所提供的個人資料,並維護您的隱私權。同時,我們在此對於您個人資料之使用蒐集將依下列聲明為利用、管理。
+
+個人資料之使用目的
+
+我們為求本活動順利進行及提供您相關之服務,蒐集並於使用目的範圍內利用您所提供之個人資料,其法定特定目的為一三〇會議管理 。使用目的包含但不限於:
+
+
+ 確認報名者與前來報到者之身分同一性
+ 提供您的名牌
+ 其他有助於活動順利進行之相關目的
+
+
+個人資料蒐集方式、利用範圍
+
+當您報名參與 PyCon TW 時,我們基於服務將會請您填寫服務所需之相關資料,而取得您的基本資料;我們僅將您的該些資料使用在您所需的個別服務上。
+
+個人資料使用方式
+
+我們將持續保存使用您提供的個人資料直至您提出停止使用或 PyCon TW 停止營運之日為止。我們絕對不會 任意出售、交換、出租或以其他變相之方式,將您的個人資料揭露與其他團體或個人。惟有下列情形,我們會向第三者提供您的個人資料。
+
+
+ 經過您的事前同意或授權允許時。
+ 司法單位或其他主管機關經合法正式的程序要求時。
+
+
+個人資料分類及項目
+
+我們因所提供服務及分析本活動之需要,可能需請您提供的個人基本資料,包括且不限於姓名、暱稱、性別、電子郵件、行動電話、職業別、現職單位(公司)、聯絡地址等資料,其法定蒐集個人資料類別為C〇〇一 辨識個人者。
+
+個人資料變更修改方式
+
+您得就您留於 PyCon TW
+ 報名網站之個人資料依法向我們以書面或電子文件請求行使:查詢或請求閱覽、製給複製本、補充或更正、請求停止蒐集、處理或利用、請求刪除等權利。惟上述權利,若因與會者不符合申請程序或法律規定,或我們依法負有保存義務,或法律另有規定之情況者,則不在此限;我們亦得就您的請求收取行政處理費用。如果您的個人資料有變更,您可自行於
+ PyCon TW 之報名網站中進行更正或來信給我們以修正您的個人資料。
+
+選擇退出方式
+
+如果您不願意將您的資料提供予我們繼續使用,您可以來信 給我們告知,我們將停止使用您的資料。您得自由選擇提供個人資料之程度,惟若提供之資料不足或有誤,或請求刪除,為求本活動順利進行之必要,我們有權利拒絕您的報名及參與。
+
+隱私保護諮詢
+如果您對於我們的隱私權保護政策或是有個人資料蒐集、利用、更新等問題,請來信organizers@pycon.tw 。
+
+針對 2019 年新型冠狀病毒 (COVID-19) 防疫工作之個人資料收集聲明
+蒐集您的個人資料目的及法令依據,係為確保會眾健康安全及「嚴重特殊傳染性肺炎」防疫安全管理所必須,我們將依個人資料保護法,以公共衛生或傳染病防治及場所進出安全管理等目的,故有必要蒐集、處理或利用相關個人資料,請您詳閱。
+PyCon TW 配合防疫期間所蒐集的資料,將在資料蒐集日起 28 天後刪除。參與者進出各館與各廳紀錄將作為疫情管控使用,若會後有任何疑似感染情況,PyCon TW
+ 將主動通知可能被影響的群眾,且得提供我國衛生主管機關依傳染病防治法等規定進行疫情調查及聯繫使用。
+
+授權 License (CC BY-SA 3.0 TW)
+此文件採用 姓名標示-相同方式分享 3.0 台灣 授權條款。
+
+
+本個人資料保護聲明從 2020 年 07 月 01 日起開始生效,惟為因應社會環境及法令的變遷與科技的進步,為保護客戶個人資料安全及隱私,我們將隨時修改這份公告聲明,並將儘速更新與公告予您。
+感謝。
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/about/pycontw.html b/src/templates/pycontw-2024/contents/zh/about/pycontw.html
new file mode 100644
index 000000000..dc2012122
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/about/pycontw.html
@@ -0,0 +1,41 @@
+{% extends 'contents/_pycontw.html' %}
+{% load static %}
+
+{% block title %}歷史{% endblock title %}
+
+{% block content %}
+
+
+
+
+PyCon Taiwan 是一個由台灣在地 Python 社群所組織與發起的 Python 年會,我們致力於讓台灣國內外的 Python 愛好者享受一個高品質的交流平台。本年會除了有從 Python 的語言特性到各方面應用案例實例的精彩演講之外,我們也很重視與會者之間的交流與促成開發者與廠商之間的合作可能,提供創業者交流討論的園地,達到提昇社群技能和豐富產業發展的目的。
+
+在 PyCon Taiwan 之前,社群夥伴 thinker 在 2008 與 2011 籌劃了 PyCTW 讓台灣的 Python 愛好者可以透過這個一日活動聚集在一起。
+
+2012 年是 PyCon Taiwan 元年,首任主席 yyc 催生了這個活動,第一屆的年會主要議題以科學運算為主。同時,從第一屆年會開始,我們就選擇遵從 PyCon US 的 Everybody Pays 原則,這也成為 PyCon Taiwan 有別於台灣地區其他年會的一項特色。隔年,年會擴大舉辦,結果報名十分踴躍,甚至還試辦了付費教學活動。大會主席 yyc 也在自己的 blog 中記下 2012 與 2013 的心得。
+
+2014 年與 2015 年,台灣 Python 社群承辦了亞太區的 Python 年會,讓台灣的 Python 社群與國際 Python 社群的交流達到了高峰。主要議程涵蓋豐富而且廣泛。基調演講除了邀請到 Python Software Foundation 的董事 Jessica McKellar 之外,還有如 PyCuda,Mezzanine,IPython 等專案的重要開發者。我們還與 CheckIO 合作,試辦了解題競賽,相當多人參加現場十分熱鬧。為了顧及議程品質與贊助商曝光,特別規劃了贊助商 show time,以及 job fair 活動。
+
+2015 的 APAC 年會還舉辦了另外付費的 PyDay,由 PyCon Taiwan 和頂尖大學一起舉辦的新手村活動。會議中邀請的主題講者,在主議程之後特別加碼,來帶領大家進行全天的 Python 盛宴。
+
+2016 亞太年會交棒給韓國首爾,我們回歸台灣地區的社群活動,但 PyCon Taiwan 在「Implement the Future, Together!」號召下的動能並沒有下滑,報名人數與投稿數量依然爆滿。我們邀請到台灣社群的兩位領導者 Jserv 與唐鳳、微軟的開發專家 Steve Dower、迪士尼的資深工程師 Paul Hildebrandt 與 Twisted 專案管理員 Amber Brown。不論邀請在地黑客擔任基調講者 、安排 FinTech 議程、結合感應設備與智慧販賣機的互動遊戲、青少年程式教學的經驗分享等等,都是對我們而言嶄新的嘗試。這些點滴也由許多照片 記錄了下來。
+
+2017 將 PyCon Taiwan 的「未來」主題發揮到淋漓盡致。我們邀請了各領域的基調講者,包含全球知名的機器學習專家林軒田老師。這些講者們不但是各自領域的知名人物,同時也是社群領導者,更對次世代技術的前瞻性具有獨自洞見。社群的主題也沒有被落下;本年度首次設計的「非正式會議」議程成功活絡了會眾們的討論,晚間的夜市活動衍生出的派對也讓多才多藝的會眾們有了發揮機會。
+
+在 2018 年度,我們帶回了大多數的會議班底,希望能奠基於近年的發展,而更上一層樓。根據這個希望,我們將該年的主題定義為技術上和人文含意上的「加速」。
+
+2019 我們反思與檢討了 PyCon Taiwan 做為台灣在地社群交流年度平台的角色;在議程與活動的安排上,持續引入其他國家 Python Conference 的長處,並且試著活絡在地各 Python 社群間以及台灣與國際間的交流,持續實驗新的內容與各種革新措施。
+
+延續 2019 的能量,在 2020 我們首次嘗試將 PyCon Taiwan 搬到濁水溪以南的台南,以期能夠替更多台灣在地社群,注入新的活水與帶來更多彼此交流後不一樣的火花。
+
+台灣 Python 年會自許為一個交流平台,我們誠摯邀請每一個台灣 Python 使用者、開發者、推廣者一起多加利用與參與。
+
+
+
+
+
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/about/staff.html b/src/templates/pycontw-2024/contents/zh/about/staff.html
new file mode 100644
index 000000000..a7714264c
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/about/staff.html
@@ -0,0 +1 @@
+{% extends 'contents/_staff.html' %}
diff --git a/src/templates/pycontw-2024/contents/zh/covid-19/guidelines.html b/src/templates/pycontw-2024/contents/zh/covid-19/guidelines.html
new file mode 100644
index 000000000..02591b1f8
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/covid-19/guidelines.html
@@ -0,0 +1,103 @@
+{% extends 'contents/_base.html' %}
+{% load static %}
+{% block title %}PyCon Taiwan COVID-19 防疫守則{% endblock title %}
+
+{% block content %}
+{% url 'page' path='about/privacy_policy' as privacy_policy %}
+
+
+ PyCon Taiwan COVID-19 防疫守則
+
+(CC BY-SA 3.0 TW) 最後更新時間:2020-08-03
+
+
+ 因應 2019 年新型冠狀病毒 (COVID-19) 疫情,「PyCon TW 主辦團隊」(以下簡稱「我們」) 參照我國中央流行疫情指揮中心的防疫措施,發布臺灣 Python 年會 (以下簡稱「PyCon TW」)
+ 實體活動防疫守則。請您與我們一同遵守,保護自己與他人的健康。此防疫守則將視疫情發展與我國中央疫情疫情指揮中心指示有所變動,所有更動將不另通知,請在會前持續回來關心。最終版預計在 2020 年 08 月 20 日發布。
+
+
+
+防疫要點
+
+
+
+ 每一位與會者須線上填寫「PyCon TW 2020 個人健康聲明書 」
+ (以下簡稱「個人健康申明書」),填寫完畢個人健康聲明書可獲得專屬入場的 QR Code 與即能參與 PyCon TW 實體活動,該 QR Code 請務必妥善保管,因資料僅供儲存用,
+ 遺失將無法取回,僅能再度填寫個人健康聲明書領取新的 QR Code。
+
+
+ PyCon TW 2020 個人健康聲明書預計於 2020 年 08 月20 日開放檢視 ,並於 2020 年 08 月 30 日開放填寫 。
+
+
+ 若當日無法使用電子設備進行填寫者,PyCon TW 將提供紙本個人健康聲明書,請填妥後交由現場工作人員。
+
+
+ 若對於個人健康申明書有疑慮者,歡迎向我們提出建議。
+
+
+
+
+ 配合我國中央流行疫情指揮中心的防疫措施:「保持社交距離(室內 1.5 公尺、室外 1 公尺),無法維持社交距離時,應配戴口罩」 ,
+ 與會者進入大會會議廳,請全程配戴口罩。
+
+
+ PyCon TW 會場進出採實名制,與會者須憑 QR Code 於報到處報到換取識別證,有識別證之參與者方可進入會場,工作人員將在各議程廳入口、社群議程軌場地入口、好想工作室入口檢查與會者識別證,請務必先完成報到領取識別證後再行入場。所有與會者在入場前都要量測體溫。
+
+
+ 各議程廳採人數總量管制,演講廳將有工作人員管控演講廳內部人數,請依照工作人員指示,若演講廳已達人數上限請勿進入。
+
+
+ 若有身體不適或具感染風險 (居家隔離、居家檢疫、自主健康管理) 等情形者,請在家裡好好休息,請勿前往 PyCon TW 會場。
+
+
+
+參與者防疫準備
+
+
+
+ 務必填寫「PyCon TW 2020 個人健康聲明書」 (中英文版填寫一份即可)。
+
+
+ 配戴口罩:進入會議廳必須全程配戴口罩,可以隨身多備 1~2 枚口罩。
+
+ 勤洗手,可搭配酒精消毒手部與座位。
+ 議程移動時,請與會者自行消毒桌椅。
+
+
+PyCon TW 防疫準備
+
+
+
+ PyCon TW 活動前一天與第一天會議結束時,我們將以漂白水做全區域消毒,消毒範圍包含:室內與走廊地板、門把、窗戶把手、電器開關、桌椅、洗手臺、樓梯扶手。
+
+
+ 大會報到處與服務台將備有額溫槍/耳溫槍,若有身體不適者,可前往量測。
+
+ 大會報到處與服務台備有消毒用酒精,如有需要,可自行取用。
+
+
+個人資料保護聲明
+
+
+
+ PyCon TW 配合防疫期間所蒐集的資料,將在活動日起 28 天後刪除。參與者進出各館與各廳紀錄將作為疫情管控使用,若會後有任何疑似感染情況,PyCon TW
+ 將主動通知可能被影響的群眾,且得提供我國衛生主管機關依傳染病防治法等規定進行疫情調查及聯繫使用。詳細聲明請參照:PyCon Taiwan
+ 個人資料保護聲明。
+
+
+
+政府機關公文
+
+
+授權 License (CC BY-SA 3.0 TW)
+此文件採用 姓名標示-相同方式分享 3.0 台灣 授權條款。
+
+
+本個人資料保護聲明從 2020 年 07 月 01 日起開始生效,惟為因應社會環境及法令的變遷與科技的進步,為保護客戶個人資料安全及隱私,我們將隨時修改這份公告聲明,並將儘速更新與公告予您。
+感謝。
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/events/open-spaces.html b/src/templates/pycontw-2024/contents/zh/events/open-spaces.html
new file mode 100644
index 000000000..ed0222690
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/events/open-spaces.html
@@ -0,0 +1,62 @@
+{% extends 'contents/_base.html' %}
+
+{% block title %}開放空間{% endblock %}
+
+{% block content %}
+
+
+
+開放空間(Open Spaces)是自助式、聚會形式的活動,與大會議程同時進行。開放空間有別於大會大部分的會議內容,議程規劃是由大會與會者「當場」計畫的。開放空間讓你能用任何你喜歡的方式定義、組織、規劃你自己的小聚。也歡迎你揪其他好夥伴一起來參與、分享、聊天、交朋友!
+對於曾經參加過過往 PyCon Taiwan 或是其他研討會的會眾,開放空間的概念也許讓你覺得似曾相識。沒有錯,開放空間基本上很類似 BoF ,不過「開放空間 / Open Spaces」對於第一次參加的會眾來說更容易理解。
+
+
+如何參與一個開放空間?
+
+很簡單:人到場就好了 :)
+
+不同於往年舉辦在中研院,本次 PyCon TW 首次移師台南成功大學國際會議廳,而開放空間也很幸運地擁有了自己的場地。你只需要找到有興趣的主題,友善的與主持人打個招呼,就可以坐下與大家一起參與了。
+
+開放空間在哪裡?在什麼時候?
+
+地點:大會 1F 的多功能廳
+
+時間:第一天早上 Keynote 結束後到下午 Keynote 開始前(11:10 ~ 16:30)
+ 第二天早上 Keynote 結束後到午餐前(10:10 ~ 12:10)
+
+總計有超過四個多小時的時間可以讓會眾們盡情享受開放空間中盈滿熱情的交流和討論。
+
+有哪些開放空間?
+
+這由你與其他會眾決定,我們也不知道會有什麼 😉
+
+開放空間有各種與會者想討論的主題。由於與會者非常多元化,開放空間也同樣非常多元化。開放空間的主題並沒有限制,可以是關於美甲、女權主義、瑜珈、甚至是桌遊。也可以是討論各種常見的技術議題,從資訊安全到你最喜歡的 Python 專案,到一些特定職位的討論,比如說 SRE。
+
+如何舉辦一個開放空間?
+
+只要到大會服務台索取白板,填上您想要討論的主題、時間、以及您的名字。
+
+如果是馬上就要分享,可以直接挑個桌子坐下,將白板放在桌上讓大家知道這裡的主題就可以了;而如果是晚一點才會開始的話,則可以先將白板寄放在服務台,等到準備開始了再回來拿。
+
+開放空間的好主意
+
+以下有幾個可以辦成開放空間的點子,提供您參考:
+
+
+ 用 Python 的 Maker 專案(例如樹莓派、IoT、居家自動化、機器人、四軸飛行器)
+ Hacking / Networking / DevOps
+ 資料視覺化、科學
+ 自然語言處理(例如聊天機器人)
+ 自我量化
+ 女性主義
+ 主辦人們的聚會:研討會、工作坊、在地社群的主辦人們
+ 網頁框架,例如 Django 或 Flask
+ 如何做開源貢獻:給初心者的協助、指導
+ Git
+ 如何避免職業倦怠
+ 求職相關討論
+
+
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/events/overview.html b/src/templates/pycontw-2024/contents/zh/events/overview.html
new file mode 100644
index 000000000..961e3699e
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/events/overview.html
@@ -0,0 +1,97 @@
+{% extends 'contents/_base.html' %}
+
+{% load i18n %}
+
+{% block title %}活動總覽{% endblock title %}
+{% block content %}
+
+{% url 'page' path='conference/keynotes' as events_keynote_url %}
+{% url 'events_talk_list' as events_talk_list_url %}
+{% url 'events_tutorial_list' as events_tutorial_url %}
+{% url 'page' path='events/open-spaces' as events_openspaces_url %}
+{% url 'community_track' as community_track_url %}
+{% url 'page' path='events/sprints' as events_sprint_url %}
+
+
+
+基調演講(Keynote)
+
+為期兩天的議程中,將有三位講者於不同場次進行基調演講(Keynote)。基調演講講者都是在全球而言各領域非常頂尖的人士;他們將帶來對自己的領域、專案的經驗分享,或者對於未來數年發展的方向與想像。
+
+更多關於基調演講 的內容請參考 {% trans 'Keynotes' %} 頁面。
+
+
+演講(Talk)
+
+演講為會期兩天最主要的活動,屆時將會有來自台灣各地與全球的講者分享他們在 Python 相關的發現。Talk 有 30 分鐘與 15
+ 分鐘兩種長度,每天都將有三軌議程同步進行,配合各個演講的難易度與類型,選擇自己有興趣的主題聆聽。許多人都會事先筆記想聽的議程,才不會跑錯地點。
+
+更多關於演講 的內容請參考 {% trans 'Talks' %} 頁面。
+
+
+專業課程(Tutorial)
+
+專業課程(Tutorial)是 PyCon Taiwan 的一部份,但需要另外報名,以獲得參加資格。活動提供 1.5 小時課程,課程內容採取公開遴選方式徵求提案。
+
+更多關於專業課程 的內容請參考 {% trans 'Tutorials' %} 頁面。
+
+
+閃電秀(Lightning Talks)
+
+閃電秀在會議每天下午結束之前舉辦,是每個演講包含設置投影片僅限五分鐘的刺激活動。如果要報名閃電秀,請在註冊櫃檯的「閃電秀」罐中投入你的講題與姓名,我們會在每天中午抽出當日的中選名單。
+
+
+開放空間(Open Spaces)
+
+開放空間(Open
+ Spaces)是自助式、聚會形式的活動。該活動將會舉辦在一樓多功能廳,與大會議程平行進行。開放空間有別於大會大部分的會議內容,議程規劃是由大會與會者「當場」計畫的。開放空間讓你能用任何你喜歡的方式定義、組織、規劃你自己的小聚。
+
+對於曾經參加過過往 PyCon Taiwan 或是其他研討會的會眾,開放空間的概念也許讓你覺得似曾相識。沒有錯,開放空間基本上很類似 BoF ,不過「開放空間 / Open Spaces」對於第一次參加的會眾來說是個更好猜測的詞語。
+
+更多關於 Open Spaces 的內容請參考 {% trans 'Open Spaces' %} 頁面。
+
+
+Job Fair
+
+這是一個專門為 Python 工程師而設的就業博覽會。Job Fair
+ 雖不會安排任何議程,但開放廠商在台上自我介紹,會眾可以趁此時與現場的廠商交流、投屨歷,廠商也會藉此時宣傳自己徵才的需求。對於想找工作的會眾,我們鼓勵在這時段多與廠商互相交流,也許美好的機會就此出現。
+
+
+社群軌(Community Track)
+
+社區軌是 PyCon TW 的一項新活動。我們選定數個熱門的主題,並且將同主題的精采演講打包成 N
+ 場連續放送的形式,讓會眾能聽得過癮。我們捨棄了儘管專業但是死板的會議室,在有特色的咖啡廳、展演空間、甚至是古蹟內來舉辦上述各種主題的演講,讓會眾能更加舒適地且近距離地與他人互動。
+
+簡言之,「社群軌」就是希望可以為所有人:會眾、講者、贊助商、社群建立更強的連結!
+
+活動將在第二天(9 月 6 日)下午進行,時間為 180 個分鐘,包含 90 分鐘的大會安排演講。 更多關於 Community Track 的內容請參考 {% trans 'Community Track' %} 頁面。
+
+
+衝刺開發(Sprints)
+
+
+ 衝刺開發(Sprints)安排在大會的兩天之外。衝刺開發是一個聚集開源專案負責人、貢獻者、想貢獻但不知道從何開始的人的活動。在活動中,將會有專案領導人帶著他們專案待解決的問題、待開發的功能來現場分享與解說。你可以選擇加入自己喜歡的專案,或是帶著自己的專案和大家分享!
+
+
+對已經有一定 Python
+ 基礎的人,想參與開源專案但不知如何加入,或者害羞怕自己不了解該專案環境的人,參加衝刺開發是個大展身手的好時機;而對於專案領導人來說,這是一個找到志同道合的朋友、面對面和貢獻者交流、帶領更多新人加入開發的好機會!
+
+更多關於 Sprints 的內容請參考 {% trans 'Sprints' %} 頁面。
+
+Sprints 報名頁面: KKTIX
+Sprints 專案頁面: HackMD
+
+
+PyNight
+
+PyNight 是往年 BoF 活動的延伸,在第一天(9 月 5 日)議程結束之後,試著為 Python
+ 社群提供一個更多元的娛樂與社交場合。活動包含「音樂」與「交流」兩個主軸:在音樂會中,主角是一群多才多藝的社群朋友,為大家帶來他們精心準備的音樂演出。在社群交流活動中,主角就是你!不論你有什麼想法,都可以在這裡尋找志同道合的朋友;主題沒有任何限制,只要你有興趣,一切都歡迎。
+
+
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/events/pyhug.html b/src/templates/pycontw-2024/contents/zh/events/pyhug.html
new file mode 100644
index 000000000..a66720192
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/events/pyhug.html
@@ -0,0 +1,78 @@
+
+{% extends 'contents/_base.html' %}
+
+{% load static %}
+
+{% block title %}PyCon TW x PyHUG 聯合線上直播{% endblock title %}
+
+{% block meta_description %}PyCon Taiwan 與地方社群 PyHUG 實體聚會進行線上與線下聯播活動!{% endblock meta_description %}
+
+
+{% block content %}
+
+
+ PyCon TW x PyHUG 聯合線上直播
+
+
+暖身活動來到第三場,PyCon Taiwan 與地方社群 PyHUG 實體聚會進行線上與線下聯播活動。
+
+
+
+
+歡迎來到 PyHUG。我們是一群活動於新竹周邊的 Python 程式員。我們會定期舉辦技術討論與程式設計的聚會。非常歡迎你加入我們!
+
+活動議程
+
+
+
+ 時間
+ 執行項目
+
+
+
+
+ 19:00 - 19:25
+ 入座
+
+
+ 19:25 - 19:30
+ 講員介紹
+
+
+ 19:30 - 20:00
+ 分享: 用 Loki 做個能究責的 NLU 模型 - 以金融場景應用為例
+
+
+ 20:00 - 20:20
+ Q&A
+
+
+ 20:20 - 21:00
+ 會後自由分享
+
+
+
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/events/sprints.html b/src/templates/pycontw-2024/contents/zh/events/sprints.html
new file mode 100644
index 000000000..cef524e21
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/events/sprints.html
@@ -0,0 +1,34 @@
+{% extends 'contents/_base.html' %}
+
+{% block title %}衝刺開發{% endblock title %}
+
+{% block body_class %}{{ block.super }} exchange-page{% endblock body_class %}
+
+
+{% block content %}
+
+
+
+衝刺開發 (Sprints) 安排在大會的兩天之外。衝刺開發是一個聚集開源專案負責人、貢獻者、想貢獻但不知道從何開始的人的活動。在活動中,將會有專案領導人帶著他們專案待解決的問題、待開發的功能來現場分享與解說。你可以選擇加入自己喜歡的專案,或是帶著自己的專案和大家分享!
+
+對已經有一定 Python 基礎的人,想參與開源專案但不知如何加入,或者害羞怕自己不了解該專案環境的人,參加衝刺開發是個大展身手的好時機;而對於專案領導人來說,這是一個找到志同道合的朋友、面對面和貢獻者交流、帶領更多新人加入開發的好機會!
+
+今年的 PyCon TW Sprints 將會以實體和線上同步進行,讓你可以持續參與貢獻開源專案。
+
+實體 Sprints
+
+實體 Sprints 聚會將在 8/30 星期日,在台南好想工作室舉辦。你可以近距離與專案領導人互動,瞭解專案,並在聚會中與大家一同為開源專案貢獻你的程式碼,在聚會中,會場也有提供小點心,讓你可以一邊享受美食一邊敲打你的程式!
+
+報名方式請至 KKTIX 報名
+
+線上 Sprints
+
+線上 Sprints 聚會則是透過與你有興趣的專案領導人聯絡,專案領導人會將你加入共同的聊天室群組,並與你在線上進行互動,如果你覺得在實體聚會還意猶未盡,仍然可以透過線上的 Sprints 與專案領導人持續交流。如此一來,貢獻開源便不受限於時間與地點,而是一個長期的社群經營。
+
+Sprint 主持人報名
+
+如果你有興趣當專案主持人,歡迎透過 HackMD 新增你的專案
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/events/tainan-dot-py-mosut.html b/src/templates/pycontw-2024/contents/zh/events/tainan-dot-py-mosut.html
new file mode 100644
index 000000000..3cd5a41a3
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/events/tainan-dot-py-mosut.html
@@ -0,0 +1,66 @@
+
+{% extends 'contents/_base.html' %}
+
+{% load static %}
+
+{% block title %}Tainan.py x MOSUT 聯合線上直播{% endblock title %}
+
+{% block meta_description %}Tainan.py 合併 MOSUT 實體聚會所進行的線上與線下聯播活動!!{% endblock meta_description %}
+
+
+{% block content %}
+
+
+ Tainan.py x MOSUT 聯合線上直播
+
+
+我們最後一場聚會將在 PyCon Taiwan 2020 開始前的一個禮拜在專業課程與衝刺開發場地舉行。
+
+
+
+ 活動時間
+ Saturday, August 29, 2020
+ 2:00 PM to 5:00 PM GMT+8
+
+
+ 活動形式
+ Youtube 線上直播(
+
+ 影片連結
+
+ )
+
+
+ 線下聚會
+ 好想工作室 台南市東區北門路二段 16 號
+
+
+
+
+讓各位期待已久的 Python 台南使用者群組終於成立了!此聚會簡稱為 Tainan.py ,將以一個月一次的頻率舉辦。歡迎南部地區的 Python 愛好者或對 Python 此一優雅之程式語言有興趣的朋友,一同來共襄盛舉,分享你的所見所得。期待各位在討論、把玩各項 Python 技術的同時,也能認識許多新朋友,共同領略 Python 之美。
+
+活動議程
+
+
+
+ 時間
+ 執行項目
+
+
+
+
+ -
+ 講者分享1 : Eric - 打造一套end2end的自然語言處理框架
+
+
+ -
+ 講者分享2 : Wei Lee - commitizen-tools: What can we gain from crafting a git message convention?
+
+
+ -
+ 自由投稿
+
+
+
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/events/taipei-dot-py.html b/src/templates/pycontw-2024/contents/zh/events/taipei-dot-py.html
new file mode 100644
index 000000000..1a7bf40d2
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/events/taipei-dot-py.html
@@ -0,0 +1,78 @@
+
+{% extends 'contents/_base.html' %}
+
+{% load static %}
+
+{% block title %}PyCon TW x taipei.py 聯合線上直播{% endblock title %}
+
+{% block meta_description %}PyCon Taiwan 合併 taipei.py 實體聚會所進行的線上與線下聯播活動!!{% endblock meta_description %}
+
+
+{% block content %}
+
+
+ PyCon TW x taipei.py 聯合線上直播
+
+
+接續 Python NPF x 南投.py 活動的經驗,PyCon Taiwan 這次合併 taipei.py 實體聚會進行線上與線下聯播活動。
+
+
+
+
+Taipei.py 又稱台北 Python 使用者群組,每個月會舉辦 Seminar(討論會)讓大台北的 Python 愛好者或對 Python 有興趣的人,能藉由難得的機會一起分享、研究、把玩、認識它五花八門的應用與技術,以及 Python 之美。
+
+活動議程
+
+
+
+ 時間
+ 執行項目
+
+
+
+
+ 19:00 - 19:10
+ 活動開始、歡迎暖場與社群介紹
+
+
+ 19:20 - 19:50
+ 講者分享1 : Wei Lee - commitizen-tools: What can we gain from crafting a git message convention?
+
+
+ 19:50 - 20:20
+ 講者分享2 : Keith Yang - Django Cookiecutter: their everyday Django project template
+
+
+ 20:20 - 20:50
+ 講者分享3 : Tim Hsu - What's New in Python 3.9
+
+
+ 20:50 - 21:00
+ 活動結尾
+
+
+
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/events/warmup-session.html b/src/templates/pycontw-2024/contents/zh/events/warmup-session.html
new file mode 100644
index 000000000..e4b662325
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/events/warmup-session.html
@@ -0,0 +1,35 @@
+{% extends 'contents/_base.html' %}q
+
+{% block title %}Warm-up session{% endblock title %}
+
+{% block meta_description %}Overview on how to submit a financial aid application to PyCon Taiwan, and allow us to help you attend the conference.{% endblock meta_description %}
+
+
+{% block content %}
+{% url 'page' path='events/passion-fruit' as passion_fruit_url %}
+{% url 'page' path='events/taipei-dot-py' as taipei_dot_py %}
+{% url 'page' path='events/pyhug' as pyhug %}
+{% url 'page' path='events/tainan-dot-py-mosut' as tainan_dot_py_mosut %}
+
+
+
+
+
+
+Python NPF百香果是今年一個由PyCon Taiwan所籌備的小型線上會議,在疫情肆虐全球的情況下,我們希望藉由這樣的線上活動來拉近彼此間的距離,並利用此本次活動向大家揭露南投.py的神秘面紗!
+
+
+
+接續 Python NPF x 南投.py 活動的經驗,PyCon Taiwan 這次合併 taipei.py 實體聚會進行線上與線下聯播活動。
+
+
+
+暖身活動來到第三場,PyCon Taiwan 與地方社群 PyHUG 實體聚會進行線上與線下聯播活動。
+
+
+
+PyCon TW 2020 暖身活動的最後一場,Tainan.py 與 MOSUT 將共同舉辦實體聚會、進行線上與線下聯播活動。
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/registration/financial-aid.html b/src/templates/pycontw-2024/contents/zh/registration/financial-aid.html
new file mode 100644
index 000000000..e6e6d7be6
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/registration/financial-aid.html
@@ -0,0 +1,70 @@
+{% extends 'contents/_base.html' %}
+
+{% block title %}財務補助{% endblock title %}
+
+{% block meta_description %}如何申請 PyCon Taiwan 財務補助,讓我們協助你參與會議。{% endblock meta_description %}
+
+
+{% block content %}
+
+
+
+方案介紹
+
+Everybody Contributes 是 PyCon 的核心價值,亦即除特邀來賓外,所有的會議參與者,包括講者與志工,皆需自己付費,方能參加會議。在維持 Everybody Contributes 此一核心價值的同時,我們也規劃了財務補助方案,希望協助對會議有興趣,但由於成本而難以參加的朋友們,能夠參與這次會議。我們採取審核制,請有需求的朋友主動與我們聯絡,我們收到所有申請後,會根據預算、申請者狀況等因素,決定是否給予補助,以及其資源多寡。
+
+我們並不想對受理對象有太多硬性限制。只要有任何困難,而在熱愛 Python 之餘也願意為 Python 社群付出些什麼,就算符合申請標準。由於會議經費有限,因此能夠補助的數量不多;這種情況下我們希望受理的對象大致為「最需要被幫助的人」或「對與會者幫助最大的人」。舉例而言,若拿家庭收入欠佳的學生與已有穩定工作的工程師相比,我們會優先協助學生。更進一步,以申請者身分而言,對 Python 社群有所貢獻者,或這次會議的講者,會是我們優先協助的目標。在資源不足的狀況下,我們可能會迫使拒絕您的申請,以幫助更有需要的人。
+
+申請流程
+
+申請財務補助的方式如下:
+
+
+
+
+ 填寫
+
+ 表單
+
+
+ 留下聯絡方式(email)。
+
+ 根據表單欄位填寫,內容應包含身分(真實姓名),處境與需求的說明。
+ 我們會有專人與您聯絡、核對資料及了解您的狀況。
+ 受理時間為即日起至 6 月 21 日 7 月 15 日 23:30 (台北時間) 截止。
+ 售票期間我們會主動告知您是否能獲得補助。若申請通過,請您仔細閱讀退費的注意事項,像交通補助會需要單據證明,請保留單據並在會場交付工作人員。
+
+
+財務補助資訊:
+
+ 申請人資格:只要你有需要都可以申請,我們盡力協助讓更多人能藉由補助參與會議。
+ 補助上限:原則上最高 NTD 20,000,如果需要更多的話,在填寫時需提供更詳細資訊。
+ 如果需要申請台灣入境簽證,可寄信至organizers@pycon.tw
+ 領取方式:原則上本國人以匯款方式進行,外國人在會場櫃檯以現金方式領取。
+ 可補助項目:門票、交通費、住宿費 (交通費與住宿費採實報實銷,補助金額依審核結果決定)
+
+
+申請小技巧
+
+
+ 描述你的興趣、在 Python 社群從事過的事情、未來期望達成的目標等。
+ 描述為何需要額外協助,例如相對其他會眾需要較高成本,需要很大的旅行開銷等等。
+ 描述你與大多數會眾的特殊處境。可能你住在偏遠地區、或者屬於某個社群內較少見的族群。
+ 描述你能為其他會眾帶來什麼影響,例如你計畫分享自己的經驗,或者可以為某些特殊議題發聲等等。
+
+
+
+
+我們知道每個人的經濟狀況皆有不同,對 Python 社群的貢獻也都難以比較。財務補助的資源有限,無法保證能幫到所有人,但我們還是想對有困難的朋友們說:「需要幫忙就說一聲吧!我們盡力!」
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/registration/ticket-info.html b/src/templates/pycontw-2024/contents/zh/registration/ticket-info.html
new file mode 100644
index 000000000..f31ce8da8
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/registration/ticket-info.html
@@ -0,0 +1,141 @@
+{% extends 'contents/_base.html' %}
+
+{% block title %}會議售票{% endblock title %}
+
+{% block meta_description %}PyCon Taiwan 2020 熱烈售票中。趕快來搶票以免向隅!{% endblock meta_description %}
+
+{% block body_class %}{{ block.super }} ticket-info-page{% endblock body_class %}
+
+{% block content %}
+
+{% url 'page' path='registration/financial-aid' as reg_financial_aid_url %}
+
+
+
+
+
+
+
+
+
+
+
保留
+
+
+
+
貢獻者/工作人員票
+
1,500 NTD
+
+
+
+
購票
+
+
+
+
+
+
個人票:
+
限時限量,請及早購買。電子發票於會後統一以 email 寄送。無法使用統一編號。
+
+
+
企業票:
+
有統編需求,請填寫公司抬頭與統一編號。無統編需求,請於抬頭與統編填寫 N/A。電子發票於會後統一以 email 寄送。
+
+
+
保留票:
+
我們誠摯邀請您以貴賓身份參與本會議。請於報名時輸入邀請碼。
+
+
+
+
+
+ 上列票種用於報名 9 月 5 日至 6 日的議程活動。
+
+
+ 早鳥票售完即止,或是最晚在 7 月 20 日結束。所有票種販售於 8 月 21 日結束。
+
+
+ 若無特別標註,皆以台幣計價;參考匯率 USD 1.00 = NTD 31.31。
+
+
+ 所有票種預設將於會後統一寄發電子發票。
+
+
+ 企業票的電子發票標示買方統編,可用於公司報帳;個人留存之用的電子發票,預設只顯示賣方統編。如需開立英文收據,或有票務相關問題,請來信 organizers[at]pycon.tw 洽詢。
+
+
+
+
+注意事項
+
+Everybody Contributes
+
+PyCon Taiwan 是需付費的活動。所有參加者,包括籌備人員和講者,均需透過貢獻 PyCon Taiwan 社群或是付費而來參加。見公平付費 。
+
+
+付款方式
+
+我們提供三種付款方式:信用卡、PayPal、ATM 轉帳。
+
+退費規則
+
+部份票種 (例如個人票) 可由 KKTIX 逕行辦理退票,您可於會議開始十天前聯絡我們。
+
+財務補助(Financial Aids)
+
+若您資金上有困難,歡迎申請大會 Financial Aid 計劃。若您計畫申請購票補助,請於購票之前先行申請 ,再依獲得的憑證購買補助用票券。更多的申請程序請至專頁 說明。
+
+飲食需求
+
+會議當天提供午餐。請在註冊問卷裡註明您的飲食偏好
+
+正確的聯絡資訊
+
+報名時請留下正確的聯絡方式(手機號碼與 email),以便大會通知。
+
+票務諮詢管道
+
+如有任何問題,請寄信至 organizers[at]pycon.tw 洽詢,我們將盡快給予回應。
+
+其他活動
+
+本頁所售票券僅供大會使用,課程或衝刺開發等相關活動需要另外的報名動作。請於頁面上方選單選擇相關活動頁面進行報名。
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/speaking/cfp.html b/src/templates/pycontw-2024/contents/zh/speaking/cfp.html
new file mode 100644
index 000000000..18e267aad
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/speaking/cfp.html
@@ -0,0 +1,103 @@
+{% extends 'contents/_base.html' %}
+{% load static %}
+
+{% block title %}稿件徵求{% endblock title %}
+
+{% block meta_description %}PyCon Taiwan 2021 正式開始徵稿,接受包括議程(Talk)與課程(Tutorial)的稿件喔!{% endblock meta_description %}
+
+{% block content %}
+{% url 'page' path='speaking/recording' as speaking_recording_url %}
+{% url 'page' path='speaking/talk' as speaking_talk_url %}
+{% url 'page' path='speaking/tutorial' as speaking_tutorial_url %}
+{% url 'page' path='event/open-space' as event_open-space_url %}
+{% url 'page' path='about/code-of-conduct' as about_coc_url %}
+{% url 'signup' as signup_url %}
+{% url 'user_dashboard' as dashboard_url %}
+
+
+
+ 投稿募集
+ Call for Proposals
+
+
+
+
+PyCon Taiwan 2021 正式開始徵稿,接受包括議程(talk)與課程(tutorial)的稿件!
+
+
+重要日期
+
+
+ 議程、課程 開放徵稿:2 月 21 日
+ 議程、課程 投稿截止:4 月 18 日(23:59:59 AoE )
+ 公告完整議程: 6 月 中旬(暫定)
+
+
+演講(talk)預設將會被錄影、編輯。之後 PyCon Taiwan 會把錄影編輯後上傳至 pyvideo.org ,除非講者特別要求。參考錄影釋出 。
+
+每一位講者皆需購買會議門票(Everyone Contributes Policy )
+
+
+如何提交您的稿件
+
+您需要先在 tw.pycon.org 註冊 一個新的帳號。在啟用您的帳號之後,就可以填寫講者資訊,並從 My PyCon 頁面中建立新的投搞。
+
+我們強烈建議您儘早送出您的投稿。
+
+因應 COVID-19 疫情,今年演講與專業課程開放您自行選擇是否採取遠端進行,即使後續疫情穩定,實體會議確定舉辦,您也可以依照自身狀況選擇是否親自前來。
+
+稿件提交指南
+
+演講(Talk)
+
+我們接受泛 Python 相關的各類投稿,包括學術報告、商用專案或者案例研究等,或是社群經營、溝通、心理健康、失敗經驗等軟議題。正在閱讀本文件的您,想必也應該是要來投稿的!
+
+若您在金融科技(FinTech)、機器學習(machine learning)、物聯網(IoT)、硬體(sensors, RaspberryPi, Gadgets)等相關領域上有著成就與發現,我們誠摯歡迎您的投稿。如果講師有任何在 Python 應用、使用 Python 解決問題與如何主持您的社群圈的經驗,也都邀請您投稿到 PyCon Taiwan。當然我們也非常歡迎適合進階者內容的投稿,例如探討 Python 內部運作等。 另外如果您的演講是關於特定的 Python package,請確保他已被廣泛使用,或者您可以考慮將重點放在相關的最佳實踐上,這類主題會有更多的受眾。
+
+在考慮不同的主題時,您可能會有興趣回顧過去幾年在 PyCon Taiwan 被選上的演講
+
+
+
+您可以投稿 長度為 30 分鐘 或是 15 分鐘 的演講,根據您自己評估所需的時間而決定。需要注意的是,議程的時間長度將會包含開場與 Q&A 的時間。
+
+議程可以使用的語言為:英文、中文、台語 。
+
+若您是第一次投稿 PyCon Taiwan,請您參考如何投稿演講? 一文,以了解更多相關規範以及協助您組織投稿的想法。
+
+此外,我們會邀請部分未錄取 PyCon Taiwan 的講者到在地社群進行分享,PyCon Taiwan 將提供部分交通補助。
+
+專業課程(Tutorial)
+
+同演講,我們對專業課程的主題並不做任何限制。專業課程為一個半小時的活動,不額外收費,將與 PyCon Taiwan 同時進行,場地會在會場外,暫定於 好想工作室 舉行。投稿課程的方針基於演講,所以請先閱讀如何投稿演講? 除了該文中的事項外,我們對課程投稿本身有額外的規範,請參見如何投稿專業課程? 一文。
+
+審稿流程
+
+在投稿截止與公告完整議程之間是審稿的時段,每篇演講和專業課程的稿件將會由 PyCon Taiwan 的審稿委員會進行評分與評論。審稿分成三個階段:
+
+ 第一階段審稿:審稿者會依據投稿內容給予評分與評論。此階段大約為期二到三週,在此階段我們不會看到您的名子。
+ 修稿階段:根據第一階段審稿者的評論與建議,您可以修改稿件。 此階段大約為期一到二週
+ 第二階段審稿:審稿者會依據修改後的內容重新評分與評論,此階段大約為期二週
+
+
+修稿階段
+在第一與第二階段審稿之間的修稿階段,您可以依據審稿者給予的評論,修改您的稿件。若您想強調您根據某個評論進行了某個更改,您可以在「補充說明」 欄位中指名評論的編號以及說明您所做的修改,例如:「#4: 修改了 xxx 段落的時間分配」 。或是如果您對於某個評論持反對意見,也可以依照同樣的方式向審稿者回覆。
+
+如果您有任何疑問,請發送電子郵件至 program@pycon.tw
+
+不適當的言語或圖像
+
+請注意,PyCon Taiwan 是一次會議,聽眾來自不同文化背景,某些團體認為有趣的笑話對於其他團體來說可能是無禮的。 如果您想在演講過程加入一些幽默的圖像或用詞,請再三檢視是否會有冒犯的可能,並請參考我們的行為準則 。
+
+
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/speaking/recording.html b/src/templates/pycontw-2024/contents/zh/speaking/recording.html
new file mode 100644
index 000000000..53e35f41d
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/speaking/recording.html
@@ -0,0 +1,14 @@
+{% extends 'contents/_base.html' %}
+
+{% block title %}錄影釋出{% endblock title %}
+
+{% block content %}
+
+
+
+PyCon 致力於協助 Python 教育及提倡 Python 的使用,演講預設會由 PyCon Taiwan 委員會錄影、剪輯並上傳至線上影音網站(如:Youtube)以及 pyvideo.org 。在技術可行的情況下,我們也可能實況轉播議程的錄影。
+
+如果您不希望自己的演講被錄影,請在投稿時取消勾選錄影的選項。
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/speaking/talk.html b/src/templates/pycontw-2024/contents/zh/speaking/talk.html
new file mode 100644
index 000000000..8b0051dc2
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/speaking/talk.html
@@ -0,0 +1,130 @@
+{% extends 'contents/_base.html' %}
+
+{% block title %}如何投稿議程{% endblock %}
+
+{% block content %}
+{% url 'page' path='speaking/cfp' as speaking_cfp_url %}
+{% url 'user_dashboard' as dashboard_url %}
+
+
+
+有關投稿的整體流程說明,請參考投稿募集 頁面。
+
+首先,感謝您投稿 PyCon Taiwan!下面的內容將會幫助您成功地送出一份投稿。我們將會提供一些訣竅使得您的投稿資訊更加完整豐富且具吸引力,並有更高的機率通過審稿。從大方向來說,在投稿之前將從下面幾個方面與問題展開您的思路:
+
+ 投稿的主題是?
+ 誰是您的目標觀眾群?
+ 聽眾群在演講後能得到什麼收穫?
+ 如何在時間限制內組識這演講?
+
+
+思考完這些問題後,就可以準備投稿了!投稿表單有以下欄位:
+
+ 題目
+ 分類
+ 時間長度
+ 語言
+ 摘要
+ Python 難易度
+ 演講目標
+ 詳細講題說明(選填)
+ 大綱(選填)
+ 補充資訊(選填)
+ 議程錄影
+ 投影片連結(選填)
+
+
+看起來有很多欄位需要填寫吧。嗯⋯⋯不過如果您跳過所有選填的欄位的話,那麼整個投稿就只需要約 500 字就能完成。儘管如此,我們依舊鼓勵您儘可能填寫與完成所有的欄位,這能協助審核人員了解您投稿的內容與想法。
+
+這些欄位中,有些只開放讓審查人員和議程組看得到,不會公開,因此不用在意會有破梗的問題。這些不公開的欄位有:
+
+
+這樣已經簡介了投稿的內容。如果您是很有經驗的講者,可以直接進入 My PyCon 投稿囉!
+
+如果這是您第一次投稿或不太了解在 PyCon 演講的方式,請繼續閱讀。接下來,我們將針對投稿不同面向提供更多的建議。
+
+
+主題與一般建議
+
+在判斷題目適不適合 PyCon Taiwan 時,可以先看看過去幾屆有哪些被接受的講題:
+
+
+投稿好主意
+
+
+
+ 摘要、詳細講題說明中應能回答以下幾點問題(但不受限於):
+
+ 誰是你的目標聽眾?
+ 演講之前是否需要什麼背景知識?
+ 又或者是否需要事先了解某些特定領域的專業知識(domain knowledge)?
+ 聽眾在演講之後將會得到哪些收穫?
+
+
+
+
+ 雖然不盡然所有的講題都要採取破題法的方式,但建議題目與摘要需具備關聯性,在摘要時儘可能能夠清楚呼應到您的講題。
+ 內容應該具備原創性並能夠清楚的讓審查員與會眾瞭解您的原創內容屬於哪一部分。
+ 請在大綱中詳細列出此議程的各段綱要與預估所需要的時間。
+ 如果您的主題,對於 Python 使用者而言並不常見,請確保您能將相關介紹內容透過連結、部落格、維基、程式碼或者其他有於瞭解內容的資料中提供足夠的資訊。這能幫助審查者以及會眾了解您的演講。
+
+
+
+投稿不推薦的主意
+
+
+
+
+如何設定投稿的 Python 難易度?
+
+選擇一個合適的 Python 難易度是非常重要的 。
+
+您的投稿不會因為過於艱深或者極為簡單而被接受。投稿的接受與否會取決於您所設定的 Python 難易度與目標聽眾是否相關而決定。
+
+如果您的演講目標是給第一次接觸 Python 的初學者,而且內容是關於使用 Python 的經驗跟分享如何解決你所面對的問題,這將是個合適的投稿。但如果您的演講是剖析 Python 記憶體的使用與垃圾回收機制中指標的重用管理,最後結合兩個 GC 系統並且互傳指標,而你所選擇的難易度為入門或中階,這就不會是個好主意。此時就直接設定為進階,然後隨心所欲地分享吧!
+
+上述的舉例分別是兩個極端的狀況,要判斷難易度十分容易。但如果分享的主題是介於兩端之間,有時就不這麼好決定。因此,我們底下提供了更多說明去幫助您找到合適的分類。
+
+入門
+
+目標群眾僅有鮮少或沒有任何 Python 相關的知識。你可以預期他們懂 Python 基本語法、程式控制流程(例如:if-else,迴圈,函式等)的基本知識。但不建議假設他們有任何基本函式庫中的模組的知識、變數可視範圍的知識,或者物件導向程式設計與物件繼承的知識一些比較進階概念(如:變數可見範圍、物件的 MRO 繼承關係等)。
+
+這個難易度適合分享您學習 Python 的經驗、如何經營社群。一般而言,非基本函式庫中的所有模組都不屬於初級難度,除非會眾能在演講中就能完全學會使用,否則關於 Python 第三方套件的使用(如:pandas、Django)不能被歸類為入門的演講。
+
+中階
+
+相比於入門難度,中階演講的應用會更為多元。中階演講適合對了解 Python 如何運作與使用 Python 並想知道更多 Python 實際應用的聽眾。演講範疇包括建置網站(與框架)、資料庫溝通互動、監控網路流量、股票市場中的程式交易、科學計算等等。
+
+根據往年投稿經驗,過去幾年的投稿中約有半數的演講都是屬於這個難度。另外也請注意,審稿過程中,也有可能根據您投稿內容給於您建議調整難度到入門或進階。
+
+進階
+
+會參與的會眾都已經對 Python 與程式開發非常熟悉。
+
+進階相較於中階的演講,最主要的差別為進階的演講會需要更多或更專精的背景知識(domain knowledge)來了解該主題。例如:效能的優化、工具的內部實作可能會在此難易度。
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/speaking/tutorial.html b/src/templates/pycontw-2024/contents/zh/speaking/tutorial.html
new file mode 100644
index 000000000..61523f282
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/speaking/tutorial.html
@@ -0,0 +1,49 @@
+{% extends 'contents/_base.html' %}
+
+{% block title %}如何投稿專業課程{% endblock title %}
+
+{% block content %}
+{% url 'page' path='speaking/cfp' as speaking_cfp_url %}
+{% url 'page' path='speaking/talk' as speaking_talk_url %}
+
+
+
+有關投稿的整體流程說明,請參考投稿募集 一頁。
+
+首先,謝謝您考慮投稿專業課程至 PyCon Taiwan 2020。
+
+一般來說,好的課程滿足一場好演講的諸多特性。不過專業課程較演講 最大的差異在課程有手把手的指導 ,以及較長的時間 。因為有更長的時間,專業課程需要準備更多的內容,並且讓聽眾即便在數個小時的講課與操作之後還能覺得有趣且清醒;由於有手把手的指導,一個 20 名學員的課程通常要有兩位(以上)的助教來協助,過程中必須能與助教保持良好的溝通。
+
+上述兩個差異使得準備一個專業課程遠比準備演講需要更多練習和經驗。因此,投稿課程的講師最好需要滿足以下至少一個前提:
+
+ 曾經為程式會議或社群的課程講師。
+ 在開源社群中,擁有一次以上的演講經驗,並以 Python 在地社群為優。
+ 曾經是過去課程的助教。
+
+
+如果您比較缺乏上述的經驗,我們可能會請您先在社群試教。
+
+專業課程的長度
+
+專業課程的長度為一個半小時
+
+在過往的經驗中,6 小時的課程對於講師以及學員而言都非常的累,學員容易因為疲勞而無法持續跟上進度,且難以吸收所學。全天的課程需要相當的教學經驗,為此今年改為 1.5 小時的課程。 我們強烈建議清楚定義先備知識 以及課程目標 ,以達到最佳的教學效果。
+
+專業課程的時間與場地
+
+專業課程與會期同時,將和 PyCon Taiwan 大會平行舉行,教室暫定於好想工作室 。
+
+
+專業課程售票政策
+
+本次會議專業課程不額外收費。
+
+如何成為專業課程的講師?
+
+最簡單也是最好的答案:多多參與各地 Python 的社群並多給演講吧!
+如果有任何疑問或需要協助的地方,歡迎聯繫我們 。
+
+{% endblock content %}
+
diff --git a/src/templates/pycontw-2024/contents/zh/sponsor/prospectus.html b/src/templates/pycontw-2024/contents/zh/sponsor/prospectus.html
new file mode 100644
index 000000000..15e0e50ba
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/sponsor/prospectus.html
@@ -0,0 +1,336 @@
+{% extends 'contents/_base.html' %}
+
+{% load i18n %}
+
+{% block title %}Sponsor{% endblock title %}
+{% block body_class %}scroll-x{% endblock %}
+{% block content %}
+
+{% url 'page' path='sponsor/community-tracks' as community_track_url %}
+
+
+
+
+
+ 聯絡方式:電子信箱
+
+ sponsorship@pycon.tw
+ 致「台灣 Python 年會贊助組」收
+
+
+
+ 台灣 Python 年會 2020 大會主席 曾君宇
+
+ 台灣 Python 年會 2020 議程主席 李唯
+
+ 台灣 Python 年會 2020 贊助總監 張祐豪
+
+
+
+ 台灣 Python 年會,是每年在台灣舉辦、並且聚集了最多的在地的使用、開發 Python 的社群技術研討會。
+ 台灣 Python 年會是在 Python Software Foundation 授權下,由 Python 社群與財團法人開放文化基金會(統一編號 38552170)合作,自發性地為了 Python 社群自身所舉辦的年度技術研討會。
+
+ 台灣 Python 年會歷年來持續促進台灣的 Python 社群彼此之間,與台灣與國際上的 Python 社群彼此之間,有更多、更好、更緊密的交流,以期促進 Python 語言的成長與茁壯。
+ 您的贊助會使得台灣 Python 年會能夠持續運作,並且盡可能觸及更多的會眾前往交流。我們不只舉辦年會,也透過財務補助的方式,鼓勵更多人前往參與台灣 Python 年會。
+
+ 我們期待您的來訊洽詢,請隨時透過上方的聯繫方式與我們聯繫、洽談最適合您的贊助方式,以達到您想要在 Python 社群曝光、徵才或是單純回饋 Python 社群的初衷與期待。
+
+
+
+本次年會估計出席人數: 400+ (首次於濁水溪以南舉辦年會)
+
+
+2019 快速綜覽:
+
+ 出席人數:675
+ 675 位會眾當中,其中有 20% 來自非台灣的、九個以上的不同的國家。
+ 會眾身份以軟體工程師居多,其他樣貌尚有開發者、尋找工作者、資料科學家、學生、管理人員、學術研究者、顧問、 CEOs 、 CTOs 等。
+ 整體會眾有 30% 使用 Python 超過五年。
+
+
+
+大會重要時間點
+
+ 議程、課程 開放徵稿:3 月 1 日
+ 議程、課程 投稿截止:4 月 26 日(23:59:59 AoE )
+ 公告完整議程: 6 月 中旬(暫定)
+ Job Fair: 9 月 5 日(暫定)
+ 研討會日:9 月 5 日, 9 月 6 日
+
+
+各級贊助方案
+
+
+備註
+
+
+ 徵才介紹 (Job Fair), 每組 5 分鐘為限
+
+
+ PyCon TW 2020 無電子版大會手冊,所有內容整合至網站以及 APP
+
+
+ PyCon TW 2020 無迎賓袋以及實體文宣,贊助商可自行自作發放。
+
+
+ PyCon TW 2020 社群軌共有 5 個場地,PyCon TW 2020 主辦方擁有社群軌場地最終決定權,鑽石級以及白金級贊助商擁有最優先場地選擇權 (已包含在贊助方案中),金級贊助商則擁有選擇認購權 (次於鑽石級以及白金級),數量有限故採先搶先贏制度,優先者可預先認購以及選擇場地 。若金級以上方案皆額滿且仍有社群軌空間尚未被認領,則開放至特別贊助方案。
+
+
+ 贊助商方案中已包含之社群軌技術演講,或是加購之社群軌技術演講,以 30 分鐘為上限,且每個社群軌上限為 1 組。
+
+
+ 關於技術演講的購買限制,基本上一個贊助商限制買一個,若廠商有特殊需求,則由主辦方討論與決定。此外,若有金級以上贊助商認領社群軌,則選擇順序會優先於單購買技術演講者。
+
+
+ 鑽石級贊助方案包含之冠名贊助權,表示贊助者的標誌會與 PyCon TW 2020 同時出現,但 PyCon TW 2020 主辦方保留解釋權利。
+
+
+ 鑽石級贊助方案包含之主場地會議室冠名權,表示贊助者可命名該會議室,但 PyCon TW 2020 主辦方保留審核權利。
+
+
+ 特別贊助方案中的交通車認養方案包含之交通車冠名權,表示贊助者可命名該交通車,但 PyCon TW 2020 主辦方保留審核權利。
+
+
+ 為求會眾多樣性,企業團購優惠票總量不會超過總報名會眾的三分之一。如有意購買此票種,請即早訂購,以免向隅。
+
+
+ 目前僅接受社群軌時段的技術演講。
+
+
+ 因應 COVID-19
+ 疫情影響,贊助方案內容會有些許細部更動,會在六月中旬連同最終會議細節一起發佈。
+
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/sponsor/sponsor.html b/src/templates/pycontw-2024/contents/zh/sponsor/sponsor.html
new file mode 100644
index 000000000..2aa425b1d
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/sponsor/sponsor.html
@@ -0,0 +1,27 @@
+{% extends 'contents/_base.html' %}
+
+{% load i18n %}
+
+{% block title %}Sponsor{% endblock title %}
+{% block content %}
+{% url 'page' path='sponsor/prospectus' as prospectus_url %}
+
+
+
+「您」的支持是推進 PyCon Taiwan 的強大動力!
+PyCon Taiwan 在此召集「您」的加入,透過贊助以具體行動支持 python 社群的成長!
+透過參與 PyCon Taiwan ,我們也提供贊助廠商以下的服務:
+
+
+ 近距離接觸專業人士
+ 標地明確與順暢的徵才場合
+ 提升品牌曝光率
+ 為企業建立人才網絡
+
+
+歡迎參考 2020 PyCon Taiwan 贊助書 ,以了解 2020 PyCon Taiwan 贊助方案,或是聯絡我們 ,讓我們了解貴單位的需求!
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/contents/zh/venue.html b/src/templates/pycontw-2024/contents/zh/venue.html
new file mode 100644
index 000000000..b21aea901
--- /dev/null
+++ b/src/templates/pycontw-2024/contents/zh/venue.html
@@ -0,0 +1,166 @@
+{% extends 'contents/_venue.html' %}
+
+{% block title %}會場{% endblock title %}
+
+{% block map_info %}
+
+{% load static %}
+
+
+ 國立成功大學
+ 國際會議廳
+
+701 台南市東區大學路 1 號
+
+
+ 好想工作室
+
+
+ 專業課程與衝刺開發場地
+
+
+701 台南市東區北門路二段 16 號 L2A
+
+
+{% endblock map_info %}
+
+{% block content %}
+
+
+
+
+{{ block.super }}
+
+交通方式
+
+桃園機場(TPE)出發
+
+1. 捷運機場航廈站(A12 or A13)到高鐵桃園站(A18)
+
+
+
+2. 桃園高鐵站到台南高鐵站
+
+
+
+3. 台鐵沙崙站(4272)到台南火車站(4220)
+
+
+
+4. 台南火車站到成功大學
+
+
+ 由台南火車站後站出來,沿著大學路走,看見成功大學校門時左轉,進校門後第一個路口左轉,即可看見國際會議廳。走路大約 7 分鐘,約 550 公尺。
+ Google Maps 路線
+
+
+小港機場(KHH)出發
+
+1. 捷運小港站(R3)到高雄車站(R11)
+
+
+
+2. 台鐵高雄火車站(4400)到台南火車站(4220)
+
+
+ 時刻表
+ 票價:NT$ 68 ~ 106
+
+
+3. 台南火車站到成功大學
+
+
+ 由台南火車站後站出來,沿著大學路走,看見成功大學校門時左轉,進校門後第一個路口左轉,即可看見國際會議廳。走路大約 7 分鐘,約 550 公尺。
+ Google Maps 路線
+
+
+
+
周邊停車規劃圖
+
+
+
+
+
專業課程與衝刺開發場地
+
+
+
好想工作室
+
701 台南市東區北門路二段 16 號 L2A
+
+
+
交通方式
+
+
國立成功大學出發
+
+
+ 由成功大學校門離開,沿著大學路走回台南火車站,由台南火車站後站前往前站,出站後右轉沿著北門路二段直走,便會看到好想工作室。走路大約 12 分鐘,約 1 公里
+ Google Maps 路線
+
+
+
+{% endblock content %}
+
+{% block extra_js %}
+
+{{ block.super }}
+{% endblock %}
diff --git a/src/templates/pycontw-2024/events/_includes/community-track-traffic.html b/src/templates/pycontw-2024/events/_includes/community-track-traffic.html
new file mode 100644
index 000000000..618ac7bac
--- /dev/null
+++ b/src/templates/pycontw-2024/events/_includes/community-track-traffic.html
@@ -0,0 +1,49 @@
+{% load i18n static %}
+‼請注意,9/06下午的社群議程場地會由成大移動到各社群議程場地哦
+ 為了大家的方便,今年大會安排了交通接駁車方便大家移動到各場地
+ 從外縣市來到台南的朋友們可以不必擔心了~
+
+
+
+
+
+ {% trans 'Time' %}
+ {% trans 'Shuttle bus route' %}
+
+
+
+
+ 12:20
+
+ [Car 1] {% trans 'Cheng Kung University' %} -> {% trans 'Tainan Cultural and Creative Park' %}
+ [Car 2] {% trans 'Cheng Kung University' %} -> {% trans 'Tsang Fong Art Space' %}
+ [Car 3] {% trans 'Cheng Kung University' %} -> {% trans 'Angry Burger' %}
+ [Car 4] {% trans 'Cheng Kung University' %} -> {% trans 'Brunch of San Dao Men Siang Jian' %}
+
+
+
+
+ 12:40
+
+
+ [Car 1, 3] {% trans 'Cheng Kung University' %} -> {% trans 'Tainan Cultural and Creative Park' %}
+ [Car 2] {% trans 'Cheng Kung University' %} -> {% trans 'Tsang Fong Art Space' %}
+ [Car 4] {% trans 'Cheng Kung University' %} -> {% trans 'Brunch of San Dao Men Siang Jian' %} -> {% trans 'Tainan Cultural and Creative Park' %} -> {% trans 'Tsang Fong Art Space' %} -> {% trans 'Angry Burger' %}
+
+
+
+ 13:00
+
+
+ [Car 2] {% trans 'Cheng Kung University' %} -> {% trans 'Brunch of San Dao Men Siang Jian' %} -> {% trans 'Tainan Cultural and Creative Park' %} -> {% trans 'Tsang Fong Art Space' %} -> {% trans 'Angry Burger' %}
+
+
+
+ 13:30
+
+ [Car 3] {% trans 'Cheng Kung University' %} -> {% trans 'Brunch of San Dao Men Siang Jian' %} -> {% trans 'Tainan Cultural and Creative Park' %} -> {% trans 'Tsang Fong Art Space' %} -> {% trans 'Angry Burger' %}
+
+
+
+
+
diff --git a/src/templates/pycontw-2024/events/_includes/schedule_custom_event.html b/src/templates/pycontw-2024/events/_includes/schedule_custom_event.html
new file mode 100644
index 000000000..beefd0999
--- /dev/null
+++ b/src/templates/pycontw-2024/events/_includes/schedule_custom_event.html
@@ -0,0 +1,24 @@
+{% load events %}
+
+
diff --git a/src/templates/pycontw-2024/events/_includes/schedule_keynote_event.html b/src/templates/pycontw-2024/events/_includes/schedule_keynote_event.html
new file mode 100644
index 000000000..5036a5cd8
--- /dev/null
+++ b/src/templates/pycontw-2024/events/_includes/schedule_keynote_event.html
@@ -0,0 +1,25 @@
+{% load events %}
+
+{% with data=event.get_static_data_for_locale %}
+
+
+
+
+
Keynote: {{ data.session.title }}
+ {% if is_remote %}
+
+
+ Remote
+
+
+ {% endif %}
+
by {{ data.speaker.name }}
+
+
+ {{ event.begin_time.value|date:'H:i' }} ~ {{ event.end_time.value|date:'H:i' }}
+
+
+
+{% endwith %}
diff --git a/src/templates/pycontw-2024/events/_includes/schedule_talk_event.html b/src/templates/pycontw-2024/events/_includes/schedule_talk_event.html
new file mode 100644
index 000000000..da8c044cb
--- /dev/null
+++ b/src/templates/pycontw-2024/events/_includes/schedule_talk_event.html
@@ -0,0 +1,36 @@
+{% load i18n i18n_plus %}
+{% load events %}
+
+
+
+
+
+
+ {{ info.title }}
+
+ {% if is_remote %}
+
+
+ Remote
+
+
+ {% endif %}
+
by {{ speakers }}
+
+
+
+ {{ event.begin_time.value|date:'H:i' }} ~ {{ event.end_time.value|date:'H:i' }}
+
+
+
diff --git a/src/templates/pycontw-2024/events/schedule.html b/src/templates/pycontw-2024/events/schedule.html
new file mode 100644
index 000000000..f1cb579e1
--- /dev/null
+++ b/src/templates/pycontw-2024/events/schedule.html
@@ -0,0 +1,48 @@
+{% extends 'contents/_base.html' %}
+
+{% load i18n static %}
+
+
+{% block title %}{% trans 'Schedule' %}{% endblock title %}
+
+
+{% block styles %}
+ {{ block.super }}
+
+
+{% endblock %}
+
+
+{% block body_class %} schedule-page{% endblock body_class %}
+
+
+{% block content %}
+
+ {% block pagetitle %}{% trans 'Schedule' %}{% endblock pagetitle %}
+
+ {% block schedule %}
+
+ {{ schedule_html|safe }}
+
+ {% endblock schedule %}
+
+
+
+ {% block controls %}{% endblock controls %}
+
+{% endblock content %}
+
+
+{% block scripts %}
+ {{ block.super }}
+
+{% endblock scripts %}
diff --git a/src/templates/pycontw-2024/events/schedule_create.html b/src/templates/pycontw-2024/events/schedule_create.html
new file mode 100644
index 000000000..ab8ccd70a
--- /dev/null
+++ b/src/templates/pycontw-2024/events/schedule_create.html
@@ -0,0 +1,113 @@
+{% extends 'events/schedule.html' %}
+
+{% load i18n static %}
+{% load events %}
+
+
+{% block title %}{% trans 'Export New Schedule' %}{% endblock title %}
+
+
+{% block styles %}
+ {{ block.super }}
+
+{% endblock %}
+
+
+{% block pagetitle %}{% trans 'Export New Schedule' %}{% endblock pagetitle %}
+
+
+{% block schedule %}
+
+
+
+ Day 1 (9/5)
+
+
+ Day 2 (9/6)
+
+
+
+
+ {% for schedule_date, schedule_info in schedule_days.items %}
+
+ {% for begin, slots in schedule_info.slots_mobile.items %}
+
+
+
+ {% for event in slots %}
+
+ {{ event|event_display }}
+
+ {% endfor %}
+
+
+ {% endfor %}
+
+ {% endfor %}
+
+{% endblock schedule %}
+
+
+{% block controls %}
+
+
+ {% blocktrans trimmed %}
+ Schedule table generation requires JavaScript. Please. (´・_・`)
+ {% endblocktrans %}
+
+
+
+
+{% endblock controls %}
diff --git a/src/templates/pycontw-2024/events/sponsored_event_detail.html b/src/templates/pycontw-2024/events/sponsored_event_detail.html
new file mode 100644
index 000000000..86131234c
--- /dev/null
+++ b/src/templates/pycontw-2024/events/sponsored_event_detail.html
@@ -0,0 +1,2 @@
+{% extends 'events/talk_detail.html' %}
+{# Exists for possible future implementation. #}
diff --git a/src/templates/pycontw-2024/events/talk_detail.html b/src/templates/pycontw-2024/events/talk_detail.html
new file mode 100644
index 000000000..aafe4cb99
--- /dev/null
+++ b/src/templates/pycontw-2024/events/talk_detail.html
@@ -0,0 +1,139 @@
+{% extends 'contents/_base.html' %}
+
+{% load i18n static %}
+{% load events %}
+
+{% block title %}{{ object.title }}{% endblock %}
+
+{% block body_class %}{{ block.super }} talk-detail{% endblock body_class %}
+
+{% block content %}
+
+
+
+ {{ object.title }}
+ {% if event.is_remote %}
+
+ Remote
+
+ {% endif %}
+
+
+
+
+
+ {% if community_track_event %}
+ {% with event=community_track_event %}
+
+
+ {{ event.venue }}
+
+
+
+ {% blocktrans with date_display=event|event_date_display begin_time_display=event.begin_time.value|date:'H:i' end_time_display=event.end_time.value|date:'H:i' %}{{ date_display }}, {{ begin_time_display }}‑{{ end_time_display }}{% endblocktrans %}
+
+ {% endwith %}
+ {% elif event %}
+
+
+ {{ event.get_location_display|default:event.location }}
+
+
+
+ {% blocktrans with date_display=event|event_date_display begin_time_display=event.begin_time.value|date:'H:i' end_time_display=event.end_time.value|date:'H:i' %}{{ date_display }}, {{ begin_time_display }}‑{{ end_time_display }}{% endblocktrans %}
+
+ {% endif %}
+
+ {% trans 'Category: ' %}
+ {{ object.get_category_display }}
+
+
+ {% trans 'Language: ' %}
+ {{ object.get_language_display }}
+
+
+ {% trans 'Python Level: ' %}
+ {{ object.get_python_level_display }}
+
+ {% if not object.recording_policy %}
+
+
+ {% trans 'No Recording' %}
+
+ {% endif %}
+
+
+
+
+{% trans 'Abstract' %}
+
+ {{ object.abstract|linebreaks }}
+
+
+
+{% if object.detailed_description %}
+{% trans 'Description' %}
+
+ {{ object.detailed_description }}
+
+{% endif %}
+
+{% if object.slide_link %}
+{% trans 'Slides' %}
+
+{% endif %}
+
+
+
+ {% if object.speaker_count > 1 %}
+ {% trans 'Speakers' context 'speaker info in talk detail' %}
+ {% else %}
+ {% trans 'Speaker' context 'speaker info in talk detail' %}
+ {% endif %}
+
+
+{% for info in object.speakers %}
+{% with user=info.user %}
+
+
+
+
+
+ {{ user.speaker_name }}
+
+
+
+ {{ user.bio|linebreaks }}
+ {% if user.github_id or user.twitter_id or user.facebook_profile_url %}
+
+ {% if user.github_id %}
+
+ {% endif %}
+ {% if user.twitter_id %}
+
+ {% endif %}
+ {% if user.facebook_profile_url %}
+
+ {% endif %}
+
+ {% endif %}
+
+
+
+{% endwith %}
+{% endfor %}
+
+{% if object.slido_embed_link %}
+
+{% endif %}
+
+{% endblock content %}
+
+
+{% block extra_js %}
+{{ block.super }}
+
+
+{% endblock extra_js %}
diff --git a/src/templates/pycontw-2024/events/talk_list.html b/src/templates/pycontw-2024/events/talk_list.html
new file mode 100644
index 000000000..ea36e9ab7
--- /dev/null
+++ b/src/templates/pycontw-2024/events/talk_list.html
@@ -0,0 +1,82 @@
+{% extends 'contents/_base.html' %}
+
+{% load i18n proposals %}
+
+
+{% block title %}{% trans 'Talks' %}{% endblock %}
+
+{% block content %}
+
+{% url 'community-track' as community_track_url %}
+
+
+
+
+ {% blocktrans trimmed %}The two conference days are packed with talks about Python by speakers from Taiwan and around the world. The talks will be either 15- or 30-minute long. Three tracks of talks will be delivered simultaneously, all with different topics and difficulties. We suggest you to plan beforehand, and choose what you want to listen based on your interests. Many people take notes on the program schedule before the meeting so they don't end up in the wrong place.{% endblocktrans %}
+ {% blocktrans trimmed %}Program schedule is subject to change. Please check this page frequently to get the latest version.{% endblocktrans %}
+
+
+{% trans 'Categories' %}
+
+{% for category, talk_list in talk_category_list_pairs %}
+{{ category }}
+{% endfor %}
+
+{% for category, talk_list in talk_category_list_pairs %}
+
+
+
+ {{ category }}
+
+
+
+
+
+
+{% endfor %}
+
+{% if sponsored_events %}
+
+ {% trans 'Invited Events' %}
+
+
+{% endif %}
+
+
+
+ {% trans 'Community Track' %}
+
+ {% blocktrans %}The community track is a new event in PyCon TW. We choose the talks with specific topics and package them into the same session. We'll leave the conference rooms and go to characteristic cafes, exhibition spaces, and even monuments so that the attendees and speakers can interact with each other more comfortably and closely.{% endblocktrans %}
+
+
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/events/tutorial_detail.html b/src/templates/pycontw-2024/events/tutorial_detail.html
new file mode 100644
index 000000000..b5bb15600
--- /dev/null
+++ b/src/templates/pycontw-2024/events/tutorial_detail.html
@@ -0,0 +1,125 @@
+{% extends 'contents/_base.html' %}
+
+{% load i18n static %}
+{% load events %}
+
+{% block title %}{{ object.title }}{% endblock %}
+
+{% block body_class %}{{ block.super }} tutorial-detail{% endblock body_class %}
+
+{% block content %}
+
+
+ {% trans 'Tutorial: ' %}{{ object.title }}
+ {% if event.is_remote %}
+
+ Remote
+
+ {% endif %}
+
+
+
+
+ {% if event %}
+
+ {% trans 'Location: ' %}
+ {{ event.get_location_display|default:event.location }}
+
+
+ {% trans 'Slot: ' %}
+ {% blocktrans with date_display=event|event_date_display begin_time_display=event.begin_time.value|date:'H:i' end_time_display=event.end_time.value|date:'H:i' %}{{ date_display }}, {{ begin_time_display }}‑{{ end_time_display }}{% endblocktrans %}
+
+ {% endif %}
+
+ {% trans 'Category: ' %}
+ {{ object.get_category_display }}
+
+
+ {% trans 'Language: ' %}
+ {{ object.get_language_display }}
+
+
+ {% trans 'Python Level: ' %}
+ {{ object.get_python_level_display }}
+
+ {# Tutorials are never recorded. #}
+
+
+ {% trans 'No Recording' %}
+
+
+
+
+
+{% trans 'Abstract' %}
+
+ {{ object.abstract|linebreaks }}
+
+
+
+{% if object.detailed_description %}
+{% trans 'Description' %}
+
+ {{ object.detailed_description }}
+
+{% endif %}
+
+{% if object.slide_link %}
+{% trans 'Slides' %}
+
+{% endif %}
+
+
+
+ {% if object.speaker_count > 1 %}
+ {% trans 'Lecturers' context 'speaker info in tutorial detail' %}
+ {% else %}
+ {% trans 'Lecturer' context 'speaker info in tutorial detail' %}
+ {% endif %}
+
+
+{% for info in object.speakers %}
+{% with user=info.user %}
+
+
+
+
+
+ {{ user.speaker_name }}
+
+
+
+ {{ user.bio|linebreaks }}
+ {% if user.github_id or user.twitter_id or user.facebook_profile_url %}
+
+ {% if user.github_id %}
+
+ {% endif %}
+ {% if user.twitter_id %}
+
+ {% endif %}
+ {% if user.facebook_profile_url %}
+
+ {% endif %}
+
+ {% endif %}
+
+
+
+{% endwith %}
+{% endfor %}
+
+{% if object.slido_embed_link %}
+
+{% endif %}
+
+{% endblock content %}
+
+
+{% block extra_js %}
+{{ block.super }}
+
+
+{% endblock extra_js %}
diff --git a/src/templates/pycontw-2024/events/tutorial_list.html b/src/templates/pycontw-2024/events/tutorial_list.html
new file mode 100644
index 000000000..8e821e393
--- /dev/null
+++ b/src/templates/pycontw-2024/events/tutorial_list.html
@@ -0,0 +1,43 @@
+{% extends 'contents/_base.html' %}
+
+{% load i18n proposals %}
+
+
+{% block title %}{% trans 'Tutorials' %}{% endblock %}
+
+{% block content %}
+
+
+ {% trans 'Tutorials' %}
+
+
+
+ {% blocktrans trimmed %}Tutorial are events held as part of the main conference, but attendees need to register separately in order to join. They are 90-minute events held to help participants better understand talks during the conference, or get their hands on more Python applications.{% endblocktrans %}
+ {% blocktrans trimmed %}Program schedule is subject to change. Please check this page frequently to get the latest version.{% endblocktrans %}
+
+
+
+{% for object in object_list %}
+
+{% with event=object proposal=object.proposal %}
+
+
+ {{ proposal.title }}
+
+
+
+
+{% endwith %}
+
+{% endfor %}
+
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/ext/discord.html b/src/templates/pycontw-2024/ext/discord.html
new file mode 100644
index 000000000..f20e7f5e6
--- /dev/null
+++ b/src/templates/pycontw-2024/ext/discord.html
@@ -0,0 +1,14 @@
+{% extends 'contents/_base.html' %}
+
+{% load i18n compress static %}
+
+{% block title %}{% trans 'Discord Guideline' %}{% endblock %}
+
+{% block body_class %}{{ block.super }} discord-page{% endblock body_class %}
+
+{% block content %}
+
+ {% trans 'PyCon TW Discord Guideline' %}
+
+{% include '_includes/ext/discord.html' %}
+{% endblock content %}
diff --git a/src/templates/pycontw-2024/ext/live.html b/src/templates/pycontw-2024/ext/live.html
new file mode 100644
index 000000000..85217902b
--- /dev/null
+++ b/src/templates/pycontw-2024/ext/live.html
@@ -0,0 +1,24 @@
+{% extends 'contents/_base.html' %}
+
+{% load i18n compress static %}
+
+{% block title %}{% trans 'Live broadcast' %}{% endblock %}
+
+{% block body_class %}{{ block.super }} live-page{% endblock body_class %}
+
+{% block content %}
+
+
+ {% trans 'Live broadcast' %}
+
+
+{% include '_includes/ext/live.html' %}
+
+{% endblock content %}
+
+
+{% block extra_js %}
+{% compress js %}
+
+{% endcompress %}
+{% endblock %}
diff --git a/src/templates/pycontw-2024/index.html b/src/templates/pycontw-2024/index.html
new file mode 100644
index 000000000..f8bc05283
--- /dev/null
+++ b/src/templates/pycontw-2024/index.html
@@ -0,0 +1,102 @@
+{% extends 'base.html' %}
+
+{% load i18n static %}
+
+{% block styles %}
+
+{% endblock %}
+
+{% block extra_css %}
+
+{% endblock extra_css %}
+
+{% block titletag %}
+{% trans 'PyCon Taiwan 2021' %}
+{% endblock titletag %}
+
+
+{% block content_full %}
+
+{% url 'page' path='speaking/cfp' as speaking_cfp_url %}
+
+{% include '_includes/hero.html' %}
+
+
+
+{##}
+{# #}
+{# {% trans 'Portal' %} #}
+{# #}
+{# {% include '_includes/portal.html' %}#}
+{#
#}
+{# #}
+{# #}
+
+
+{% comment %} {% include '_includes/sponsors.html' %} {% endcomment %}
+
+
+
+
+ {% trans 'What is PyCon' %}
+ {% blocktrans trimmed %}
+ The original PyCon was formed in North America in 2003, and now there are many other conferences being run in
+ the PyCon spirit around the world.
+ {% endblocktrans %}
+
+
+
+ {% trans 'What is PyCon Taiwan' %}
+ {% blocktrans trimmed %}
+ PyCon Taiwan is an annual convention in Taiwan for the discussion and promotion of the Python programming
+ language. It is held by enthusiasts and focuses on Python technology and its versatile applications. We welcome
+ people who are interested in Python to join PyCon Taiwan to share knowledge, exchange ideas, make connections
+ and to help us grow our network.
+ {% endblocktrans %}
+
+
+
+
+
+{% endblock content_full %}