code:
ul.tabs.group
	li
		a(href='#tab-1') #{__('General')}
	li
		a(href='#tab-2') #{__('Security')}
	li
		a(href='#tab-3') #{__('Limits')}
	li
		a(href='#tab-4') #{__('Captcha')}
	li
		a(href='#tab-5') #{__('Antispam')}
	li
		a(href='#tab-6') #{__('Style')}
	li
		a(href='#tab-7') #{__('Webring')}
	li
		a(href='#tab-8') #{__('Web3')}
	li
		a(href='#tab-9') #{__('Files & Thumbnails')}
	li
		a(href='#tab-10') #{__('Frontend Script Defaults')}
	li
		a(href='#tab-11') #{__('Board Defaults')}
.box-wrap
	.tab.tab-1
		.col
			.row
				.label #{__('Global Announcement')}
				textarea(name='global_announcement') #{settings.globalAnnouncement.raw}
			.row
				.label #{__('Country Code Header')}
				input(type='text' name='country_code_header' value=settings.countryCodeHeader)
			.row
				.label #{__('IP Header')}
				input(type='text' name='ip_header' value=settings.ipHeader)
			.row
				.label #{__('Meta Site Name')}
				input(type='text' name='meta_site_name' value=settings.meta.siteName)
			.row
				.label #{__('Meta URL')}
				input(type='text' name='meta_url' value=settings.meta.url)
			.row
				.label #{__('Language')}
				select(name='language')
					each language in languages
						option(value=language selected=settings.language === language) #{__(language)} (#{language})
			.row
				.label #{__('Disable Anonymizer File Posting')}
				label.postform-style.ph-5
					input(type='checkbox', name='disable_anonymizer_file_posting', value='true' checked=settings.disableAnonymizerFilePosting)
			.row
				.label #{__('Stats Count Anonymizers')}
				label.postform-style.ph-5
					input(type='checkbox', name='stats_count_anonymizers', value='true' checked=settings.statsCountAnonymizers)
			.row
				.label #{__('Prune Files Immediately')}
				label.postform-style.ph-5
					input(type='checkbox', name='prune_immediately', value='true' checked=settings.pruneImmediately)
			.row
				.label #{__('Fuzzy Hash Images')}
				label.postform-style.ph-5
					input(type='checkbox', name='hash_images' value='true' checked=settings.hashImages)
			.row
				.label #{__('Template Cache')}
				label.postform-style.ph-5
					input(type='checkbox', name='cache_templates' value='true' checked=settings.cacheTemplates)
			.row
				.label #{__('Template Generation Lock Time')}
				input(type='number' name='lock_wait' value=settings.lockWait)
			.row
				.label #{__('Hot Threads Limit')}
				input(type='number' name='hot_threads_limit' value=settings.hotThreadsLimit)
			.row
				.label #{__('Hot Threads Reply Threshold')}
				input(type='number' name='hot_threads_threshold' value=settings.hotThreadsThreshold)
			.row
				.label #{__('Hot Threads Max Age')}
				input(type='text' name='hot_threads_max_age' placeholder=__('e.g. 1mo') value=settings.hotThreadsMaxAge)
			.row
				.label #{__('Overboard Index Thread Limit')}
				input(type='number' name='overboard_limit' value=settings.overboardLimit)
			.row
				.label #{__('Overboard Catalog Thread Limit')}
				input(type='number' name='overboard_catalog_limit' value=settings.overboardCatalogLimit)
			.row
				.label #{__('Overboard Reverse Image Search')}
				label.postform-style.ph-5
					input(type='checkbox', name='overboard_reverse_links' value='true' checked=settings.overboardReverseLinks)
			.row
				.label #{__('Allow Custom Overboard')}
				label.postform-style.ph-5
					input(type='checkbox', name='allow_custom_overboard' value='true' checked=settings.allowCustomOverboard)
			.row
				.label
					| #{__('External Archive Links URL')}
					|
					small
						| (
						a(href='/faq.html#archive-reverse-url-format') ?
						| )
				input(type='text', name='archive_links', value=settings.archiveLinksURL)
			.row
				.label
					| #{__('Reverse Image Search Links URL')}
					|
					small
						| (
						a(href='/faq.html#archive-reverse-url-format') ?
						| )
				input(type='text', name='reverse_links', value=settings.reverseImageLinksURL)
			.row
				.label #{__('Prune Modlogs Days')}
				input(type='number', name='prune_modlogs' value=settings.pruneModlogs)

	.tab.tab-2
		.col
			.row
				.label #{__('Referer Check')}
				label.postform-style.ph-5
					input(type='checkbox', name='referrer_check', value='true' checked=settings.refererCheck)
			.row
				.label #{__('Allowed Hosts')}
				textarea(name='allowed_hosts' placeholder=__('Newline separated')) #{settings.allowedHosts.join('\n')}
			.row
				.label #{__('Secure Cookies')}
				label.postform-style.ph-5
					input(type='checkbox', name='secure_cookies', value='true' checked=settings.secureCookies)
			.row
				.label #{__("Don't store raw IPs")}
				label.postform-style.ph-5
					input(type='checkbox', name='dont_store_raw_ips', value='true' checked=settings.dontStoreRawIps)
			.row
				.label #{__('Prune IPs Days')}
				input(type='number', name='prune_ips' value=settings.pruneIps)
			.row
				.label #{__('Use Socks Proxy')}
				label.postform-style.ph-5
					input(type='checkbox', name='proxy_enabled', value='true' checked=settings.proxy.enabled)
			.row
				.label #{__('Proxy Address')}
				input(type='text' name='proxy_address' placeholder='socks5h://127.0.0.1:9050' value=settings.proxy.address)
			.row
				.label #{__('Force Account 2FA')}
				label.postform-style.ph-5
					input(type='checkbox' name='force_account_twofactor' value='true' checked=settings.forceAccountTwofactor)
			.row
				.label
					| #{__('Force Action 2FA')}
					|
					small
						| (
						a(href='/faq.html#twofactor-enforcement') ?
						| )
				label.postform-style.ph-5
					input(type='checkbox' name='force_action_twofactor' value='true' checked=settings.forceActionTwofactor)

	.tab.tab-3
		.col
			.row
				.label #{__('Default Ban Duration')}
				input(type='text', name='default_ban_duration',  placeholder=__('e.g. 1w'), value=settings.defaultBanDuration)
			.row
				.label #{__('Quote Limit')}
				input(type='number', name='quote_limit', value=settings.quoteLimit)
			.row
				.label #{__('Preview Replies')}
				input(type='number', name='preview_replies', value=settings.previewReplies)
			.row
				.label #{__('Sticky Preview Replies')}
				input(type='number', name='sticky_preview_replies', value=settings.stickyPreviewReplies)
			.row
				.label #{__('Early 404 Fraction')}
				input(type='number', name='early_404_fraction', value=settings.early404Fraction)
			.row
				.label #{__('Early 404 Replies')}
				input(type='number', name='early_404_replies', value=settings.early404Replies)
			.row
				.label #{__('Max Homepage News Entries')}
				input(type='number', name='max_recent_news', value=settings.maxRecentNews)
			.row
				.label #{__('Inactive Account Time')}
				input(type='text', name='inactive_account_time',  placeholder=__('e.g. 1w'), value=settings.inactiveAccountTime)
			.row
				.label #{__('Inactive Account Action')}
				select(name='inactive_account_action')
					option(value='0', selected=settings.inactiveAccountAction === 0) #{__('Do nothing')}
					option(value='1', selected=settings.inactiveAccountAction === 1) #{__('Forfeit staff positions')}
					option(value='2', selected=settings.inactiveAccountAction === 2) #{__('Delete Account')}
			.row
				.label #{__('Abandoned Board Action')}
				select(name='abandoned_board_action')
					option(value='0', selected=settings.abandonedBoardAction === 0) #{__('Do nothing')}
					option(value='1', selected=settings.abandonedBoardAction === 1) #{__('Lock board')}
					option(value='2', selected=settings.abandonedBoardAction === 2) #{__('Lock+Unlist board')}
					option(value='3', selected=settings.abandonedBoardAction === 3) #{__('Delete board')}
			.row
				h4.mv-5 #{__('Global Limits')}
			.row
				.label #{__('Reply Limit Min')}
				input(type='number' name='global_limits_reply_limit_min' value=settings.globalLimits.replyLimit.min)
			.row
				.label #{__('Reply Limit Max')}
				input(type='number' name='global_limits_reply_limit_max' value=settings.globalLimits.replyLimit.max)
			.row
				.label #{__('Thread Limit Min')}
				input(type='number' name='global_limits_thread_limit_min' value=settings.globalLimits.threadLimit.min)
			.row
				.label #{__('Thread Limit Max')}
				input(type='number' name='global_limits_thread_limit_max' value=settings.globalLimits.threadLimit.max)
			.row
				.label #{__('Bump Limit Min')}
				input(type='number' name='global_limits_bump_limit_min' value=settings.globalLimits.bumpLimit.min)
			.row
				.label #{__('Bump Limit Max')}
				input(type='number' name='global_limits_bump_limit_max' value=settings.globalLimits.bumpLimit.max)
			.row
				.label #{__('Files Per Post Max')}
				input(type='number' name='global_limits_post_files_max' value=settings.globalLimits.postFiles.max)
			.row
				.label #{__('Post File Size Max')}
				input(type='number' name='global_limits_post_files_size_max' value=settings.globalLimits.postFilesSize.max)
			.row
				.label #{__('Custom Pages Max Characters')}
				input(type='number' name='global_limits_custom_pages_max_length' value=settings.globalLimits.customPages.maxLength)
			.row
				.label #{__('Total Custom Pages Per Board')}
				input(type='number' name='global_limits_custom_pages_max' value=settings.globalLimits.customPages.max)
			.row
				.label #{__('Banner Width Max')}
				input(type='number' name='global_limits_banner_files_width' value=settings.globalLimits.bannerFiles.width)
			.row
				.label #{__('Banner Height Max')}
				input(type='number' name='global_limits_banner_files_height' value=settings.globalLimits.bannerFiles.height)
			.row
				.label #{__('Force 3:1 Banner Aspect Ratio')}
				label.postform-style.ph-5
					input(type='checkbox', name='global_limits_banner_files_force_aspect_ratio' value='true' checked=settings.globalLimits.bannerFiles.forceAspectRatio)
			.row
				.label #{__('Banner File Size Max')}
				input(type='number' name='global_limits_banner_files_size_max' value=settings.globalLimits.bannerFilesSize.max)
			.row
				.label #{__('Banners Per Upload Max')}
				input(type='number' name='global_limits_banner_files_max' value=settings.globalLimits.bannerFiles.max)
			.row
				.label #{__('Total Banners Per Board')}
				input(type='number' name='global_limits_banner_files_total' value=settings.globalLimits.bannerFiles.total)
			.row
				.label #{__('Flag File Size Max')}
				input(type='number' name='global_limits_flag_files_size_max' value=settings.globalLimits.flagFilesSize.max)
			.row
				.label #{__('Flags Per Upload Max')}
				input(type='number' name='global_limits_flag_files_max' value=settings.globalLimits.flagFiles.max)
			.row
				.label #{__('Total Flags Per Board')}
				input(type='number' name='global_limits_flag_files_total' value=settings.globalLimits.flagFiles.total)
			.row
				.label #{__('Asset File Size Max')}
				input(type='number' name='global_limits_asset_files_size_max' value=settings.globalLimits.assetFilesSize.max)
			.row
				.label #{__('Assets Per Upload Max')}
				input(type='number' name='global_limits_asset_files_max' value=settings.globalLimits.assetFiles.max)
			.row
				.label #{__('Total Assets Per Board')}
				input(type='number' name='global_limits_asset_files_total' value=settings.globalLimits.assetFiles.total)
			.row
				.label #{__('Max Filters Per Board')}
				input(type='number' name='global_limits_filters_max' value=settings.globalLimits.filters.max)
			.row
				h4.mv-5 #{__('Field Length Limits')}
			.row
				.label #{__('Name')}
				input(type='number', name='global_limits_field_length_name' value=settings.globalLimits.fieldLength.name)
			.row
				.label #{__('Email')}
				input(type='number', name='global_limits_field_length_email' value=settings.globalLimits.fieldLength.email)
			.row
				.label #{__('Subject')}
				input(type='number', name='global_limits_field_length_subject' value=settings.globalLimits.fieldLength.subject)
			.row
				.label #{__('Post Password')}
				input(type='number', name='global_limits_field_length_postpassword' value=settings.globalLimits.fieldLength.postpassword)
			.row
				.label #{__('Message')}
				input(type='number', name='global_limits_field_length_message' value=settings.globalLimits.fieldLength.message)
			.row
				.label #{__('Report Reason')}
				input(type='number', name='global_limits_field_length_report_reason' value=settings.globalLimits.fieldLength.report_reason)
			.row
				.label #{__('Ban Reason')}
				input(type='number', name='global_limits_field_length_ban_reason' value=settings.globalLimits.fieldLength.ban_reason)
			.row
				.label #{__('Log Messages')}
				input(type='number', name='global_limits_field_length_log_message' value=settings.globalLimits.fieldLength.log_message)
			.row
				.label #{__('Board URI')}
				input(type='number', name='global_limits_field_length_uri' value=settings.globalLimits.fieldLength.uri)
			.row
				.label #{__('Board Name')}
				input(type='number', name='global_limits_field_length_boardname' value=settings.globalLimits.fieldLength.boardname)
			.row
				.label #{__('Board Description')}
				input(type='number', name='global_limits_field_length_description' value=settings.globalLimits.fieldLength.description)
			.row
				.label #{__('Multi Input Form Anon')}
				input(type='number', name='global_limits_multi_input_posts_anon' value=settings.globalLimits.multiInputs.posts.anon)
			.row
				.label #{__('Multi Input Form Staff')}
				input(type='number', name='global_limits_multi_input_posts_staff' value=settings.globalLimits.multiInputs.posts.staff)

	.tab.tab-4
		.col
			.row
				.label #{__('Type')}
				select(name='captcha_options_type')
					option(value='text', selected=settings.captchaOptions.type === 'text') #{__('Text')}
					option(value='grid', selected=settings.captchaOptions.type === 'grid') #{__('Grid v1')}
					option(value='grid2', selected=settings.captchaOptions.type === 'grid2') #{__('Grid v2')}
					option(value='google', selected=settings.captchaOptions.type === 'google') #{__('Google')}
					option(value='hcaptcha', selected=settings.captchaOptions.type === 'hcaptcha') #{__('Hcaptcha')}
					option(value='yandex', selected=settings.captchaOptions.type === 'yandex') #{__('Yandex')}
			.row
				.label #{__('Generate Limit')}
				input(type='number' name='captcha_options_generate_limit' value=settings.captchaOptions.generateLimit)
			.row
				.label #{__('Font')}
				select(name='captcha_options_font')
					option(value='default' selected=(settings.captchaOptions.font === 'default')) #{__('Default')}
					each font in fontList
							option(value=font.path selected=(settings.captchaOptions.font === font.path)) #{font.name}
			.row
				h4.mv-5 #{__('Text Captcha Options')}
			.row
				.label #{__('Strikethrough Effect')}
				label.postform-style.ph-5
					input(type='checkbox', name='captcha_options_text_line', value='true' checked=settings.captchaOptions.text.line)
			.row
				.label #{__('Wave Effect Strength')}
				label.postform-style.ph-5
					input(type='range' name='captcha_options_text_wave' min='0' max='10' value=settings.captchaOptions.text.wave)
			.row
				.label #{__('Paint Effect Strength')}
				label.postform-style.ph-5
					input(type='range' name='captcha_options_text_paint' min='0' max='10' value=settings.captchaOptions.text.paint)
			.row
				.label #{__('Noise Effect Strength')}
				label.postform-style.ph-5
					input(type='range' name='captcha_options_text_noise' min='0' max='10' value=settings.captchaOptions.text.noise)
			.row
				h4.mv-5 #{__('Grid Captcha Options')}
			.row
				.label #{__('Image Size')}
				input(type='number' name='captcha_options_grid_image_size' value=settings.captchaOptions.grid.imageSize)
			.row
				.label #{__('Grid Size')}
				input(type='number' name='captcha_options_grid_size' value=settings.captchaOptions.grid.size)
			.row
				.label #{__('Icon Offset')}
				input(type='number' name='captcha_options_grid_icon_y_offset' value=settings.captchaOptions.grid.iconYOffset)
			.row
				.label #{__('True Characters')}
				textarea(name='captcha_options_grid_trues' placeholder=__('Newline separated')) #{settings.captchaOptions.grid.trues.join('\n')}
			.row
				.label #{__('False Characters')}
				textarea(name='captcha_options_grid_falses' placeholder=__('Newline separated')) #{settings.captchaOptions.grid.falses.join('\n')}
			.row
				.label #{__('Question Text')}
				input(type='text' name='captcha_options_grid_question' value=settings.captchaOptions.grid.question)
			.row
				.label #{__('Edge Effect Strength')}
				label.postform-style.ph-5
					input(type='range' name='captcha_options_grid_edge' min='0' max='50' value=settings.captchaOptions.grid.edge)
			.row
				.label #{__('Noise Effect Strength')}
				label.postform-style.ph-5
					input(type='range' name='captcha_options_grid_noise' min='0' max='10' value=settings.captchaOptions.grid.noise)
			.row
				h4.mv-5 #{__('Captcha Distortion')}
			.row
				.label #{__('Minimum Distortions')}
				input(type='number' name='captcha_options_num_distorts_min' value=settings.captchaOptions.numDistorts.min)
			.row
				.label #{__('Maximum Distortions')}
				input(type='number' name='captcha_options_num_distorts_max' value=settings.captchaOptions.numDistorts.max)
			.row
				.label #{__('Distortion Intensity')}
				input(type='number' name='captcha_options_distortion' value=settings.captchaOptions.distortion)

	.tab.tab-5
		.col
			.row
				.label #{__('Block Bypass')}
				label.postform-style.ph-5
					input(type='checkbox', name='block_bypass_enabled', value='true' checked=settings.blockBypass.enabled)
			.row
				.label #{__('Force Anonymizers')}
				label.postform-style.ph-5
					input(type='checkbox', name='block_bypass_force_anonymizers', value='true' checked=settings.blockBypass.forceAnonymizers)
			.row
				.label #{__('Bypass DNSBL')}
				label.postform-style.ph-5
					input(type='checkbox', name='block_bypass_bypass_dnsbl', value='true' checked=settings.blockBypass.bypassDnsbl)
			.row
				.label #{__('Expire After Uses')}
				input(type='number' name='block_bypass_expire_after_uses' value=settings.blockBypass.expireAfterUses)
			.row
				.label #{__('Expire After Time')}
				input(type='text' name='block_bypass_expire_after_time' placeholder=__('e.g. 1d') value=settings.blockBypass.expireAfterTime)
			.row
				h4.mv-5 #{__('Flood Protection')}
			.row
				.label #{__('Same Content Same IP/ID')}
				input(type='number' name='flood_timers_same_content_same_ip' value=settings.floodTimers.sameContentSameIp)
			.row
				.label #{__('Same Content Any IP/ID')}
				input(type='number' name='flood_timers_same_content_any_ip' value=settings.floodTimers.sameContentAnyIp)
			.row
				.label #{__('Any Content Same IP/ID')}
				input(type='number' name='flood_timers_any_content_same_ip' value=settings.floodTimers.anyContentSameIp)
			.row
				h4.mv-5 #{__('DNSBL')}
			.row
				.label #{__('DNSBL Enabled')}
				label.postform-style.ph-5
					input(type='checkbox', name='dnsbl_enabled', value='true' checked=settings.dnsbl.enabled)
			.row
				.label #{__('DNSBL Addresses')}
				textarea(name='dnsbl_blacklists' placeholder=__('Newline separated')) #{settings.dnsbl.blacklists.join('\n')}
			.row
				.label #{__('Cache Time')}
				input(type='text' name='dnsbl_cache_time' placeholder=__('e.g. 1h') value=settings.dnsbl.cacheTime)
			.row
				h4.mv-5 #{__('Ratelimits')}
			.row
				.label #{__('Generate Captcha')}
				input(type='number' name='rate_limit_cost_captcha' value=settings.rateLimitCost.captcha)
			.row
				.label #{__('Change Board Settings')}
				input(type='number' name='rate_limit_cost_board_settings' value=settings.rateLimitCost.boardSettings)
			.row
				.label #{__('Edit Post')}
				input(type='number' name='rate_limit_cost_edit_post' value=settings.rateLimitCost.editPost)

	.tab.tab-6
		.col
			.row
				.label #{__('Allowed Themes')}
				textarea(name='themes' placeholder=__('Newline separated')) #{settings.themes.join('\n')}
			.row
				.label #{__('Allowed Code Themes')}
				textarea(name='code_themes' placeholder=__('Newline separated')) #{settings.codeThemes.join('\n')}
			.row
				.label #{__('Default Theme')}
				select(name='board_defaults_theme')
					each theme in themes
						option(value=theme selected=settings.boardDefaults.theme === theme) #{theme}
			.row
				.label #{__('Default Code Theme')}
				select(name='board_defaults_code_theme')
					each theme in codeThemes
						option(value=theme selected=settings.boardDefaults.codeTheme === theme) #{theme}
			.row
				.label
					| #{__('Code Highlighting Auto-Detect Languages')}
					|
					small
						| (
						a(rel='nofollow' referrerpolicy='same-origin' target='_blank' href='https://github.com/highlightjs/highlight.js/blob/master/SUPPORTED_LANGUAGES.md') #{__('Supported Languages')}
						| )
				textarea(name='highlight_options_language_subset' placeholder=__('Newline separated')) #{settings.highlightOptions.languageSubset.join('\n')}
			.row
				.label #{__('Code Highlight Language Detect Threshold')}
				input(type='number' name='highlight_options_threshold' value=settings.highlightOptions.threshold)
			.row
				.label #{__('Board Custom CSS')}
				label.postform-style.ph-5
					input(type='checkbox', name='global_limits_custom_css_enabled' value='true' checked=settings.globalLimits.customCss.enabled)
			.row
				.label #{__('Custom CSS Filters')}
				textarea(name='global_limits_custom_css_filters' placeholder=__('Newline separated')) #{settings.globalLimits.customCss.filters.join('\n')}
			.row
				.label #{__('Strict Filtering')}
				label.postform-style.ph-5
					input(type='checkbox', name='global_limits_custom_css_strict' value='true' checked=settings.globalLimits.customCss.strict)
			.row
				.label #{__('Custom CSS Max Length')}
				input(type='number' name='global_limits_custom_css_max' value=settings.globalLimits.customCss.max)

	.tab.tab-7
		.col
			.row
				.label #{__('Enable')}
				label.postform-style.ph-5
					input(type='checkbox', name='enable_webring' value='true' checked=settings.enableWebring)
			.row
				.label #{__('Following')}
				textarea(name='webring_following' placeholder=__('Newline separated')) #{settings.following.join('\n')}
			.row
				.label #{__('Logo URLs')}
				textarea(name='webring_logos' placeholder=__('Newline separated')) #{settings.logo.join('\n')}
			.row
				.label #{__('Blacklist')}
				textarea(name='webring_blacklist' placeholder=__('Newline separated')) #{settings.blacklist.join('\n')}

	.tab.tab-8
		.col
			.row
				.label #{__('Enable')}
				label.postform-style.ph-5
					input(type='checkbox', name='enable_web3' value='true' checked=settings.enableWeb3)
			.row
				.label
					| #{__('Ethereum Links URL')}
					|
					small
						| (
						a(href='/faq.html#archive-reverse-url-format') ?
						| )
				input(type='text', name='ethereum_links', value=settings.ethereumLinksURL)
			//- .row
				.label
					| #{__('Ethereum Node')}
					|
					small
						| (
						a(rel='nofollow' referrerpolicy='same-origin' target='_blank' href='https://ethereumnodes.com/') #{__('Nodes')}
						| )
				input(type='text' name='ethereum_node' value=settings.ethereumNode)

	.tab.tab-9
		.col
			.row
				.label #{__('Animated .gif Thumbnails')}
				label.postform-style.ph-5
					input(type='checkbox', name='animated_gif_thumbnails', value='true' checked=settings.animatedGifThumbnails)
			.row
				.label #{__('Audio Thumbnails')}
				label.postform-style.ph-5
					input(type='checkbox', name='audio_thumbnails', value='true' checked=settings.audioThumbnails)
			.row
				.label #{__('Use ffmpeg For .gif Thumbnails')}
				label.postform-style.ph-5
					input(type='checkbox', name='ffmpeg_gif_thumbnails', value='true' checked=settings.ffmpegGifThumbnails)
			.row
				.label #{__('Thumbnail Dimensions')}
				input(type='number', name='thumb_size', value=settings.thumbSize)
			.row
				.label #{__('Video Thumbnail Percentage')}
				input(type='number', name='video_thumb_percentage', value=settings.videoThumbPercentage)
			.row
				.label #{__('Other Mime Types')}
				textarea(name='other_mime_types' placeholder=__('Newline separated')) #{settings.otherMimeTypes.join('\n')}
			.row
				.label #{__('Validate Mime Types')}
				label.postform-style.ph-5
					input(type='checkbox', name='check_real_mime_types', value='true' checked=settings.checkRealMimeTypes)
			.row
				.label #{__('Unknown Types Pass Validation')}
				label.postform-style.ph-5
					input(type='checkbox', name='allow_mime_no_match', value='true' checked=settings.allowMimeNoMatch)
			.row
				.label #{__('Space File Name Replacement')}
				input(type='text', name='space_file_name_replacement', value=settings.spaceFileNameReplacement)
			.row
				.label #{__('URI Decode File Names')}
				label.postform-style.ph-5
					input(type='checkbox', name='uri_decode_file_names', value='true' checked=settings.uriDecodeFileNames)
			.row
				.label #{__('Thumbnail File Extension')}
				input(type='text' name='thumb_extension' value=settings.thumbExtension)
			.row
				.label #{__('Image Max Resolution')}
				input(type='text' name='global_limits_post_files_size_image_resolution' value=settings.globalLimits.postFilesSize.imageResolution)
			.row
				.label #{__('Video Max Resolution')}
				input(type='text' name='global_limits_post_files_size_video_resolution' value=settings.globalLimits.postFilesSize.videoResolution)

	.tab.tab-10
		.col
			.row
				.label #{__('Embeds Enabled')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_embeds_enabled', value='true' checked=settings.frontendScriptDefault.embedsEnabled)
			.row
				.label #{__('Unlimit Media Height')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_height_unlimit', value='true' checked=settings.frontendScriptDefault.heightUnlimit)
			.row
				.label #{__('Hover Expands Media')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_hover_expands_media', value='true' checked=settings.frontendScriptDefault.hoverExpandsMedia)
			.row
				.label #{__('Hover Expands Follow Cursor')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_hover_expands_follow_cursor', value='true' checked=settings.frontendScriptDefault.hoverExpandsFollowCursor)
			.row
				.label #{__('Recursive Post Hiding')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_hide_recursive', value='true' checked=settings.frontendScriptDefault.hideRecursive)
			.row
				.label #{__('Crisp Image Rendering')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_crisp_images', value='true' checked=settings.frontendScriptDefault.crispImages)
			.row
				.label #{__('Hide Thumbnails')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_hide_thumbnails', value='true' checked=settings.frontendScriptDefault.hideThumbnails)
			.row
				.label #{__('Non-Color IDs')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_non_color_ids', value='true' checked=settings.frontendScriptDefault.nonColorIds)
			.row
				.label #{__('Always Reveal Spoiler Markdown')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_always_show_spoilers', value='true' checked=settings.frontendScriptDefault.alwaysShowSpoilers)
			.row
				.label #{__('Hide Post Stubs')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_hide_post_stubs', value='true' checked=settings.frontendScriptDefault.hidePostStubs)
			.row
				.label #{__('Hide Deleted Post Content')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_hide_deleted_post_content', value='true' checked=settings.frontendScriptDefault.hideDeletedPostContent)
			.row
				.label #{__('Smooth Scrolling')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_smooth_scrolling', value='true' checked=settings.frontendScriptDefault.smoothScrolling)
			.row
				.label #{__('Thread Watcher')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_thread_watcher', value='true' checked=settings.frontendScriptDefault.threadWatcher)
			.row
				.label #{__('Default Volume')}
				label.postform-style.ph-5
					input(type='range' name='frontend_script_default_volume' min='0' max='100' value=settings.frontendScriptDefault.defaultVolume)
			.row
				.label #{__('Loop Audio/Video')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_loop', value='true' checked=settings.frontendScriptDefault.loop)
			.row
				.label #{__('Image Loading Bars')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_image_loading_bars', value='true' checked=settings.frontendScriptDefault.imageLoadingBars)
			.row
				.label #{__('Live Posts')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_live', value='true' checked=settings.frontendScriptDefault.live)
			.row
				.label #{__('Scroll To New Posts')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_scroll_to_posts', value='true' checked=settings.frontendScriptDefault.scrollToPosts)
			.row
				.label #{__('Local Time')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_local_time', value='true' checked=settings.frontendScriptDefault.localTime)
			.row
				.label #{__('24 Hour Time')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_hour_24_time', value='true' checked=settings.frontendScriptDefault.hour24Time)
			.row
				.label #{__('Use Relative Time')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_relative_time', value='true' checked=settings.frontendScriptDefault.relativeTime)
			.row
				.label #{__('Notifications')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_notifications', value='true' checked=settings.frontendScriptDefault.notificationsEnabled)
			.row
				.label #{__('Show (You)s')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_show_yous', value='true' checked=settings.frontendScriptDefault.showYous)
			.row
				.label #{__('Only Notify (You)s')}
				label.postform-style.ph-5
					input(type='checkbox', name='frontend_script_default_notifications_yous_only', value='true' checked=settings.frontendScriptDefault.notificationsYousOnly)
			.row
				.label #{__('Tegaki Width')}
				input(type='number', name='frontend_script_default_tegaki_width', value=settings.frontendScriptDefault.tegakiWidth)
			.row
				.label #{__('Tegaki Height')}
				input(type='number', name='frontend_script_default_tegaki_height', value=settings.frontendScriptDefault.tegakiHeight)

	.tab.tab-11
		.col
			.row
				.label #{__('SFW')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_sfw' value='true' checked=settings.boardDefaults.sfw)
			.row
				.label #{__('Unlisted Locally')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_unlisted_local' value='true' checked=settings.boardDefaults.unlistedLocal)
			.row
				.label #{__('Unlisted From Webring')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_unlisted_webring' value='true' checked=settings.boardDefaults.unlistedWebring)
			.row
				.label #{__('Unique Message Enforcement')}
				select(name='board_defaults_message_r9k_mode')
					option(value='0', selected=settings.boardDefaults.messageR9KMode === 0) #{__('Off')}
					option(value='1', selected=settings.boardDefaults.messageR9KMode === 1) #{__('Per Thread')}
					option(value='2', selected=settings.boardDefaults.messageR9KMode === 2) #{__('Board Wide')}
			.row
				.label #{__('Unique File Enforcement')}
				select(name='board_defaults_file_r9k_mode')
					option(value='0', selected=settings.boardDefaults.fileR9KMode === 0) #{__('Off')}
					option(value='1', selected=settings.boardDefaults.fileR9KMode === 1) #{__('Per Thread')}
					option(value='2', selected=settings.boardDefaults.fileR9KMode === 2) #{__('Board Wide')}
			.row
				.label #{__('Lock Mode')}
				select(name='board_defaults_lock_mode')
					option(value='0', selected=settings.boardDefaults.lockMode === 0) #{__('Unlocked')}
					option(value='1', selected=settings.boardDefaults.lockMode === 1) #{__('Lock Thread Creation')}
					option(value='2', selected=settings.boardDefaults.lockMode === 2) #{__('Board Locked')}
			.row
				.label #{__('Captcha Mode')}
				select(name='board_defaults_captcha_mode')
					option(value='0', selected=settings.boardDefaults.captchaMode === 0) #{__('No Captcha')}
					option(value='1', selected=settings.boardDefaults.captchaMode === 1) #{__('Captcha for new thread')}
					option(value='2', selected=settings.boardDefaults.captchaMode === 2) #{__('Captcha for all posts')}
			.row
				.label #{__('PPH Trigger Threshold')}
				input(type='number', name='board_defaults_pph_trigger', value=settings.boardDefaults.pphTrigger)
			.row
				.label #{__('PPH Trigger Action')}
				select(name='board_defaults_pph_trigger_action')
					option(value='0', selected=settings.boardDefaults.pphTriggerAction === 0) #{__('Do nothing')}
					option(value='1', selected=settings.boardDefaults.pphTriggerAction === 1) #{__('Enable captcha for new thread')}
					option(value='2', selected=settings.boardDefaults.pphTriggerAction === 2) #{__('Enable captcha for all posts')}
					option(value='3', selected=settings.boardDefaults.pphTriggerAction === 3) #{__('Lock thread creation')}
					option(value='4', selected=settings.boardDefaults.pphTriggerAction === 4) #{__('Lock board')}
			.row
				.label #{__('TPH Trigger Threshold')}
				input(type='number', name='board_defaults_tph_trigger', value=settings.boardDefaults.tphTrigger)
			.row
				.label #{__('TPH Trigger Action')}
				select(name='board_defaults_tph_trigger_action')
					option(value='0', selected=settings.boardDefaults.tphTriggerAction === 0) #{__('Do nothing')}
					option(value='1', selected=settings.boardDefaults.tphTriggerAction === 1) #{__('Enable captcha for new thread')}
					option(value='2', selected=settings.boardDefaults.tphTriggerAction === 2) #{__('Enable captcha for all posts')}
					option(value='3', selected=settings.boardDefaults.tphTriggerAction === 3) #{__('Lock thread creation')}
					option(value='4', selected=settings.boardDefaults.tphTriggerAction === 4) #{__('Lock board')}
			.row
				.label #{__('Trigger Reset Lock Mode')}
				select(name='board_defaults_lock_reset')
					option(value='0', selected=settings.boardDefaults.lockReset === 0) #{__('No change')}
					option(value='1', selected=settings.boardDefaults.lockReset === 1) #{__('Unlock board')}
					option(value='2', selected=settings.boardDefaults.lockReset === 2) #{__('Lock thread creation')}
			.row
				.label #{__('Trigger Reset Captcha Mode')}
				select(name='board_defaults_captcha_reset')
					option(value='0', selected=settings.boardDefaults.captchaReset === 0) #{__('No change')}
					option(value='1', selected=settings.boardDefaults.captchaReset === 1) #{__('Captcha disabled')}
					option(value='2', selected=settings.boardDefaults.captchaReset === 2) #{__('Captcha for new thread')}
			.row
				.label #{__('Anon Name')}
				input(type='text' name='board_defaults_default_name' value=settings.boardDefaults.defaultName)
			.row
				.label #{__('Language')}
				select(name='board_defaults_language')
					each language in languages
						option(value=language selected=settings.boardDefaults.language === language) #{__(language)} (#{language})
			.row
				.label #{__('Force Anon')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_force_anon', value='true' checked=settings.boardDefaults.forceAnon)
			.row
				.label #{__('Sage Only Email')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_sage_only_email', value='true' checked=settings.boardDefaults.sageOnlyEmail)
			.row
				.label #{__('Early 404')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_early404', value='true' checked=settings.boardDefaults.early404)
			.row
				.label #{__('IDs')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_ids', value='true' checked=settings.boardDefaults.ids)
			.row
				.label #{__('Geo Flags')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_geo_flags', value='true' checked=settings.boardDefaults.geoFlags)
			.row
				.label #{__('Custom Flags')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_custom_flags', value='true' checked=settings.boardDefaults.customFlags)
			.row
				.label #{__('Enable Tegaki')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_enable_tegaki', value='true' checked=settings.boardDefaults.enableTegaki)
			.row
				.label #{__('Enable Web3')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_enable_web3', value='true' checked=settings.boardDefaults.enableWeb3)
			.row
				.label #{__('User Post Deletion')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_user_post_delete', value='true' checked=settings.boardDefaults.userPostDelete)
			.row
				.label #{__('User File Spoilering')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_user_post_spoiler', value='true' checked=settings.boardDefaults.userPostSpoiler)
			.row
				.label #{__('User File Unlinking')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_user_post_unlink', value='true' checked=settings.boardDefaults.userPostUnlink)
			.row
				.label #{__('Thread Limit')}
				input(type='number' name='board_defaults_thread_limit' value=settings.boardDefaults.threadLimit)
			.row
				.label #{__('Reply Limit')}
				input(type='number' name='board_defaults_reply_limit' value=settings.boardDefaults.replyLimit)
			.row
				.label #{__('Bump Limit')}
				input(type='number' name='board_defaults_bump_limit' value=settings.boardDefaults.bumpLimit)
			.row
				.label #{__('Max Files')}
				input(type='number' name='board_defaults_max_files' value=settings.boardDefaults.maxFiles)
			.row
				.label #{__('Force Thread Subject')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_force_thread_subject', value='true' checked=settings.boardDefaults.forceThreadSubject)
			.row
				.label #{__('Force Thread Message')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_force_thread_message', value='true' checked=settings.boardDefaults.forceThreadMessage)
			.row
				.label #{__('Force Thread File')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_force_thread_file', value='true' checked=settings.boardDefaults.forceThreadFile)
			.row
				.label #{__('Force Reply Message')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_force_reply_message', value='true' checked=settings.boardDefaults.forceReplyMessage)
			.row
				.label #{__('Force Reply File')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_force_reply_file', value='true' checked=settings.boardDefaults.forceReplyFile)
			.row
				.label #{__('Disable Reply Subject')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_disable_reply_subject', value='true' checked=settings.boardDefaults.disableReplySubject)
			.row
				.label #{__('Hide Banners')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_hide_banners', value='true' checked=settings.boardDefaults.hideBanners)
			.row
				.label #{__('Min Thread Message Length')}
				input(type='number' name='board_defaults_min_thread_message_length' value=settings.boardDefaults.minThreadMessageLength)
			.row
				.label #{__('Min Reply Message Length')}
				input(type='number' name='board_defaults_min_reply_message_length' value=settings.boardDefaults.minReplyMessageLength)
			.row
				.label #{__('Max Thread Message Length')}
				input(type='number' name='board_defaults_max_thread_message_length' value=settings.boardDefaults.maxThreadMessageLength)
			.row
				.label #{__('Max Reply Message Length')}
				input(type='number' name='board_defaults_max_reply_message_length' value=settings.boardDefaults.maxReplyMessageLength)
			.row
				.label #{__('OP Reply Count Delete Protection')}
				input(type='number' name='board_defaults_delete_protection_count' value=settings.boardDefaults.deleteProtectionCount)
			.row
				.label #{__('OP Thread Age Delete Protection')}
				input(type='text' name='board_defaults_delete_protection_age' placeholder=__('e.g. 1w') value=settings.boardDefaults.deleteProtectionAge)
			.row
				.label #{__('Disable anonymizer file posting')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_disable_anonymizer_file_posting', value='true' checked=settings.boardDefaults.disableAnonymizerFilePosting)
			.row
				.label #{__('Allow Video Files')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_allowed_file_types_video', value='true' checked=settings.boardDefaults.allowedFileTypes.video)
			.row
				.label #{__('Allow Image Files')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_allowed_file_types_image', value='true' checked=settings.boardDefaults.allowedFileTypes.image)
			.row
				.label #{__('Allow Animated Image Files')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_allowed_file_types_animated_image', value='true' checked=settings.boardDefaults.allowedFileTypes.animatedImage)
			.row
				.label #{__('Allow Audio Files')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_allowed_file_types_audio', value='true' checked=settings.boardDefaults.allowedFileTypes.audio)
			.row
				.label #{__('Allow Other Files')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_allowed_file_types_other', value='true' checked=settings.boardDefaults.allowedFileTypes.other)
			.row
				.label #{__('Reverse Image Search Links')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_reverse_image_search_links', value='true' checked=settings.boardDefaults.reverseImageSearchLinks)
			.row
				.label #{__('External Archive Links')}
				label.postform-style.ph-5
					input(type='checkbox', name='board_defaults_archive_links', value='true' checked=settings.boardDefaults.archiveLinks)


code:
for bit, index in Object.keys(jsonPermissions)
	include ../includes/permissionsform.pug
input(type='submit', value=__('Save'))

repo_name: Marzisoft/jschan

license: mit


code:
meta(charset='utf-8')
meta(name='viewport' content='width=device-width initial-scale=1 viewport-fit=cover')
meta(name='theme-color' content='#282A2E' media='(prefers-color-scheme: dark)')
meta(name='theme-color' content='#DDDDDD' media='(prefers-color-scheme: light)')

//- very basic styles to hide some elements and improve experience for users with noscript
noscript
	style .jsonly { display: none!important; } .user-id { cursor: auto!important; }

//- whether this page is rendered for a board
- const isBoard = board != null;

//- general meta and opengraph meta tags
if isBoard
	if board.settings.description
		meta(name='description' content=board.settings.description)
	if board.settings.tags
		meta(name='keywords' content=board.settings.tags.join(','))
meta(property='og:site_name', value=meta.siteName)
meta(property='og:url', content=meta.url)

//- main stylesheet
link(rel='stylesheet' href=`/css/style.css?v=${commit}&ct=${captchaOptions.type}`)

//- theme stylesheets
- const theme = isBoard ? board.settings.theme : defaultTheme;
link#theme(rel='stylesheet' data-theme=theme href=`/css/themes/${theme}.css`)
- const codeTheme = isBoard ? board.settings.codeTheme : defaultCodeTheme;
link#codetheme(rel='stylesheet' data-theme=codeTheme href=`/css/codethemes/${codeTheme}.css`)
if isBoard && board.settings.customCss
	style#board-customcss #{board.settings.customCss}

//- include html_code from gulp-favicon
include ../../gulp/res/icons/html_code.html

//- language pack
- const pageLanguage = isBoard ? board.settings.language : (locale || globalLanguage);
script(src=`/js/lang/${pageLanguage}.js?v=${commit}`)

//- main script
script(src=`/js/all.js?v=${commit}&ct=${captchaOptions.type}`)

//- optional web3 script
if enableWeb3 || isBoard && board.settings.enableWeb3
	script(src=`/js/web3.js?v=${commit}`)

//- additional scripts included only if hcaptcha, recaptcha, or yandex smartcaptcha are used
if captchaOptions.type === 'google'
	script(src='https://www.google.com/recaptcha/api.js' async defer)
if captchaOptions.type === 'hcaptcha'
	script(src='https://hcaptcha.com/1/api.js' async defer)
if captchaOptions.type === 'yandex'
	script(src='https://smartcaptcha.yandexcloud.net/captcha.js' async defer)


code:
if bans.length === 0
	p #{__('No bans.')}
else
	input(type='hidden' name='_csrf' value=csrf)
	include ../includes/bantable.pug
		for ban in bans
			+ban(ban)
	.action-wrapper.mv-10
		.row
			.label #{__('Unban')}
			label.postform-style.ph-5
				input(type='radio' name='option' value='unban' checked='checked')
		.row
			.label #{__('Deny Appeal')}
			label.postform-style.ph-5
				input(type='radio' name='option' value='deny_appeal')
		.row
			.label #{__('Upgrade Ban')}
			label.postform-style.ph-5.mr-1
				input(type='radio' name='option' value='upgrade')
			select(name='upgrade')
				option(value='')
				option(value='1') #{__('Narrow Range')}
				option(value='2') #{__('Wide Range')}
		.row
			.label #{__('Edit Duration')}
			label.postform-style.ph-5.mr-1
				input(type='radio' name='option' value='edit_duration')
			input(type='text' name='ban_duration' placeholder=__('Ban duration e.g. 7d') autocomplete='off')
		.row
			.label #{__('Edit Note')}
			label.postform-style.ph-5.mr-1
				input(type='radio' name='option' value='edit_note')
			input(type='text' name='ban_note')
	input(type='submit' value=__('Submit'))


code:
unless minimal
	nav.navbar
		a.nav-item(href='/index.html') #{__('Home')}
		a(href='/boards.html' class=`nav-item ${enableWebring ? 'short-nav' : ''}`)
			| #{__('Boards')}
			if enableWebring
				.rainbow +Webring
		a.nav-item#overboardlink(href='/overboard.html') #{__('Overboard')}
		a.nav-item(href='/account.html') #{__('Account')}
		if !modview && board
			a.nav-item(href=`/${board._id}/manage/${managePage || 'index.html'}`) #{__('Manage')}
		a.jsonly.nav-item.right#settings(data-label=(__('Settings')))


code:
| #{__('Page')}:
- const qs = queryString ? queryString+'&' : ''
if maxPage === 0
	a.bold(href=`?${qs}page=1`) [1]
else if maxPage > 0
	- for(let i = 1; i <= maxPage; i++)
		if page === i
			a.bold(href=`?${qs}page=${i}`) [#{i}]
		else
			a(href=`?${qs}page=${i}`) [#{i}]
		|
else
	if page > 1
		if page > 2
			a(href=`?${qs}page=1`) [<<]
			|
		a(href=`?${qs}page=${page-1}`) [<]
		|
	a.bold(href=`?${qs}page=${page}`) [#{page}]
	|
	a(href=`?${qs}page=${page+1}`) [>]


code:
if jsonPermissions[bit].title && index > 0
	hr(size=1)
	h4.mv-5 #{__(jsonPermissions[bit].title)}
	if jsonPermissions[bit].subtitle
		p #{__(jsonPermissions[bit].subtitle)}
.row
	- const parentAllowed = jsonPermissions[bit].parents == null || permissions.hasAny(...jsonPermissions[bit].parents);
	- const parentLabel = !parentAllowed ? (jsonPermissions[bit].parents ? jsonPermissions[bit].parents.map(p => jsonPermissions[p].label).join('\n') : '')	: '';
	label.postform-style.ph-5(id=`perm_${bit}` class=(!parentAllowed ? 'notallowed' : null) title=(!parentAllowed ? __(`Requires permission "${parentLabel}"`) : null))
		input(type='checkbox' name=`permission_bit_${bit}` value=bit checked=jsonPermissions[bit].state disabled=(!parentAllowed || jsonPermissions[bit].block))
	.rlabel #{__(jsonPermissions[bit].label)}
	p
		if !parentAllowed && parentLabel
			span.br #{__(`Requires permission "${parentLabel}"`)}
			|  -
		| #{__(jsonPermissions[bit].desc)}


code:
include ../mixins/post.pug
+post(post, false, manage, globalmanage)


code:
if post.country.custom === true
	span(title=post.country.name)
		img.customflag(src=`/flag/${post.board}/${post.country.src}` alt=' ' loading='lazy')
	|
else
	span(class=`flag flag-${post.country.code.toLowerCase()}` title=post.country.name alt=post.country.name)
	|


code:
include ../mixins/filelabel.pug
- const isThread = thread != null;
- const subjectRequired = (!isThread && board.settings.forceThreadSubject);
- const messageRequired = (!isThread && board.settings.forceThreadMessage) || (isThread && board.settings.forceReplyMessage);
- const fileRequired = (!isThread && board.settings.forceThreadFile) || (isThread && board.settings.forceReplyFile);
section.form-wrapper.flex-center
	form.form-post#postform(action=`/forms/board/${board._id}/${modview ? 'mod' : ''}post`, enctype='multipart/form-data', method='POST' data-reset-on-submit='true')
		if modview
			input(type='hidden' name='_csrf' value=csrf)
		input(type='hidden' name='thread' value=isThread ? thread.postId : null)
		section.row.jsonly
			.noselect#postform-dragHandle
				span.fw.text-center #{isThread ? __('New Reply') : __('New Thread')}
				a.mr-0.close(href='#!') [×]
		if board.settings.forceAnon && !modview
			section.row
				.label Sage
				label.postform-style.ph-5
					input(type='checkbox', name='email', value='sage')
			include ./subjectfield.pug
		else
			section.row
				.label #{__('Name')}
				input(type='text', name='name', placeholder=board.settings.defaultName maxlength=globalLimits.fieldLength.name)
			if board.settings.sageOnlyEmail && !modview
				section.row
					.label #{__('Sage')}
					label.postform-style.ph-5
						input(type='checkbox', name='email', value='sage')
			else
				section.row
					.label #{__('Email')}
					input(type='text', name='email', autocomplete='off' maxlength=globalLimits.fieldLength.email)
			include ./subjectfield.pug
		section.row
			.label
				span #{__('Message')}
					if messageRequired
						span.required *
			- const minLength = (isThread ? board.settings.minReplyMessageLength : board.settings.minThreadMessageLength) || 0;
			- const maxLength = Math.min((isThread ? board.settings.maxReplyMessageLength : board.settings.maxThreadMessageLength), globalLimits.fieldLength.message) || globalLimits.fieldLength.message;
			textarea#message(name='message', rows='5', minlength=minLength maxlength=maxLength required=messageRequired)
		if board.settings.maxFiles > 0 && Object.values(board.settings.allowedFileTypes).some(x => x === true)
			- const maxFiles = board.settings.maxFiles;
			section.row
				.label
					span #{__n('Files', maxFiles)}
						if fileRequired
							span.required *
					|
					|
					if maxFiles > 1
						small #{__n('Max %s files', maxFiles)}
					small #{postFilesSize} #{__('total')}
				span.col
					+filelabel('file', maxFiles)
					input#file(type='file', name='file' multiple required=fileRequired )
					.upload-list(data-spoilers=(board.settings.userPostSpoiler ? 'true' : 'false') data-strip-filenames='true')
				if board.settings.userPostSpoiler
					noscript
						label.noselect.postform-style.ph-5.ml-1.fh
							input(type='checkbox', name='spoiler_all', value='true')
							| Spoiler
			if board.settings.enableTegaki && board.settings.allowedFileTypes.image === true
				section.row.jsonly
					.label #{__('Tegaki')}
					input.dummy-link.tegaki-button(type='button', value=__('Draw'))
					if board.settings.allowedFileTypes.other === true
						label.noselect.postform-style.ph-5.ml-1.fh
							input(type='checkbox' name='tegakireplay')
							| #{__('Replayable?')}
		if board.settings.userPostSpoiler || board.settings.userPostDelete || board.settings.userPostUnlink || modview
			section.row
				.label Password
				input(type='password', name='postpassword', placeholder='Password to delete/spoiler/unlink later' maxlength='50' autocomplete='new-password')
		if modview || board.settings.customFlags === true
			- const boardFlags = Object.entries(board.flags)
			if boardFlags.length > 0
				section.row
					.label #{__('Flag')}
					select#customflag(name='customflag')
						option(value='') #{board.settings.geoFlags === true ? __('Geographic Flag') : __('None')}
						each flag in boardFlags
							option(value=flag[0] data-src=`/flag/${board._id}/${flag[1]}`) #{flag[0]}
					img.jsonly#selected-flag
		if enableWeb3 === true && board.settings.enableWeb3 === true
			section.row.jsonly.web3
				.label #{__('Web3')}
				input.dummy-link.web3-sign(type='button' value=__('Sign') disabled=true)
				textarea.ml-1.no-resize(name='signature', rows='1', autocomplete='off' readonly)
		if ((board.settings.captchaMode === 1 && !isThread) || board.settings.captchaMode === 2) && !modview
			if captchaOptions.type === 'text'
				include ./captchasidelabel.pug
			else
				include ./captchaexpand.pug
		input#submitpost(type='submit', value=(isThread ? __('New Reply') : __('New Thread')))
	a.collapse.no-decoration.post-button(href='#postform') [#{isThread ? __('New Reply') : __('New Thread')}]


code:
if post.sticky || post.bumplocked || post.locked || post.cyclic
	span.post-icons
		if post.sticky
			img(src='/file/sticky.png' height='14' width='14' title=`${__('Sticky')} (${post.sticky})`)
			|
		if post.bumplocked
			img(src='/file/bumplock.png' height='14' width='14' title=__('Bumplocked'))
			|
		if post.locked
			img(src='/file/lock.png' height='14' width='14' title=__('Locked'))
			|
		if post.cyclic
			img(src='/file/cyclic.png' height='14' width='14' title=__('Cyclic'))
			|


code:
.form-wrapper.flex-center
	form.form-post(action='/forms/register' method='POST' data-captcha-preload='true')
		.row
			.label #{__('Username')}
			input(type='text', name='username', maxlength='50' pattern='[a-zA-Z0-9]+' required title=__('alphanumeric only'))
		.row
			.label #{__('Password')}
			input(type='password', name='password', maxlength='100' required)
		.row
			.label #{__('Confirm Password')}
			input(type='password', name='passwordconfirm', maxlength='100' required)
		if captchaOptions.type === 'text'
			include ./captchasidelabel.pug
		else
			include ./captchafieldrow.pug
		input(type='submit', value=__('Register'))


code:
for bit, index in Object.keys(jsonPermissions).filter(p => manageBoardBits.includes(parseInt(p)))
	include ../includes/permissionsform.pug
input(type='submit', value=__('Save'))


code:
nav.stickynav
	a.nav-item(href='#bottom') [▼]
	|
	a.nav-item(href='#top') [▲]


code:
if !isThread || !board.settings.disableReplySubject
	section.row
		.label
			span #{__('Subject')}
				if subjectRequired
					span.required *
		input(type='text', name='subject', autocomplete='off' maxlength=globalLimits.fieldLength.subject required=subjectRequired)


code:
include ../mixins/web3signature.pug
+web3signature(signature, address)


code:
doctype html
html
	head
		include includes/head.pug
		block head
	body#top
		include includes/navbar.pug
		main(class=(minimal?'minimal':''))
			.container
				block content
		include includes/footer.pug


code:
mixin announcements(hrTop=true, hrMiddle=true, hrBottom=true)
	- const hasGlobalAnnouncement = globalAnnouncement.markdown;
	- const hasBoardAnnouncement = board && board.settings.announcement.markdown;
	if hrTop && (hasGlobalAnnouncement || hasBoardAnnouncement)
		hr(size=1)
	if hasGlobalAnnouncement
		pre.post-message.no-m-p.text-center !{globalAnnouncement.markdown}
	if hrMiddle && (hasGlobalAnnouncement && hasBoardAnnouncement)
		hr(size=1)
	if board && board.settings.announcement.markdown
		pre.post-message.no-m-p.text-center !{board.settings.announcement.markdown}
	if hrBottom && (hasGlobalAnnouncement || hasBoardAnnouncement)
		hr(size=1)


code:
include ./post.pug

mixin ban(ban, banpage)
	tr
		td
			if (!board || !ban.global) && (!banpage || (ban.appeal == null && ban.allowAppeal === true))
				input.post-check(type='checkbox', name='checkedbans' value=ban._id)
		td
			if ban.global === true
				| #{__('Global')}
				if Array.isArray(ban.board)
					|  (#{ban.board.filter(n => n).join(', ')})
			else
				a(href=`/${ban.board}/`) /#{ban.board}/
		td= ban.reason
		- const ip = viewRawIp === true ? ban.ip.raw : ban.ip.cloak;
		if viewRawIp === true
			td #{ip}
		else
			td #{ip}#{'.*'.repeat(ban.range)}
		td #{__(['IPV4', 'IPV6', 'Bypass', 'Pruned IP'][ban.ip.type])}
		td #{__(['Single', 'Narrow', 'Wide'][ban.range])}
		td #{(!banpage || ban.showUser === true) ? ban.issuer : __('Hidden User')}
		- const banDate = new Date(ban.date);
		td: time.right.reltime(datetime=banDate.toISOString()) #{banDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
		- const expireDate = new Date(ban.expireAt);
		td: time.right.reltime(datetime=expireDate.toISOString()) #{expireDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
		td.banposts
			if ban.posts && ban.posts.length > 0
				| #{__('Hover to view')}
				.thread
					each p in ban.posts
						+post(p, false, false, false, true)
			else
				| #{__('Posts not shown')}
		td
			if ban.seen
				| ✓
			else
				| ⨯
		td
			if ban.allowAppeal && !ban.appeal
				| ✓
			else
				| ⨯
		td
			if ban.appeal
				textarea(rows=1 disabled='true') #{ban.appeal}
			else if ban.allowAppeal
				| #{__('No appeal submitted')}
			else
				| -
		td
			if ban.note
				| #{ban.note}
			else
				| -


code:
mixin banmessage(banmessage)
	p.ban
		span.message #{__('USER WAS BANNED FOR THIS POST')}
		|
		span.reason(data-reason=banmessage) #{banmessage}


code:
mixin boardheader(pagename)
	.board-header
		if board.settings != null && board.settings.hideBanners === false
			img.board-banner(src=`/randombanner?board=${board._id}` loading='lazy')
			br
		if pagename
			h1.board-title #{pagename}(#[a.no-decoration(href=`/${board._id}/index.html`) /#{board._id}/])
		else
			a.no-decoration(href=`/${board._id}/index.html`)
				h1.board-title /#{board._id}/ - #{board.settings.name}
		h4.board-description #{board.settings.description}


code:
mixin boardnav(selected, showIndex, upLevel)
	if showIndex
		|
		a(href=`${upLevel ? '../' : ''}index.html` class=(selected === 'index' ? 'bold' : '')) [#{__('Index')}]
	|
	a(href=`${upLevel ? '../' : ''}catalog.html` class=(selected === 'catalog' ? 'bold' : '')) [#{__('Catalog')}]
	if board.settings != null && board.settings.hideBanners === false
		|
		a(href=`${upLevel ? '../' : ''}banners.html` class=(selected === 'banners' ? 'bold' : '')) [#{__('Banners')}]
	|
	a(href=`${upLevel ? '../' : ''}logs.html` class=(selected === 'logs' ? 'bold' : '')) [#{__('Logs')}]
	if thread != null && board.settings != null && board.settings.archiveLinks === true
		|
		a(href=`${archiveLinksURL.replace('%s', encodeURIComponent(meta.url+'/'+thread.board+'/thread/'+thread.postId+'.html'))}` rel='nofollow' referrerpolicy='same-origin' target='_blank') [#{__('Archive')}]


code:
mixin boardtable(ppd=false, activity=false, owner=false)
	.table-container.flex-center.mv-10.text-center
		table(class=`boardtable${activity ? ' w900' : ''}`)
			tr
				th #{__('Board')}
				if owner
					th #{__('Owner')}
				th #{__('Description')}
				th #{__('PPH')}
				if ppd
					th.nobreak #{__('PPD')}
				th.nobreak #{__('Users')}
				th.nobreak #{__('Posts')}
				if activity
					th.nobreak #{__('Latest Activity')}
			block


code:
mixin captchaexpand()
	include ../includes/captchaexpand.pug


code:
mixin catalogfile(postURL, post, file, small=false)
	- const type = file.mimetype.split('/')[0]
	.post-file-src
		a(href=`${postURL}#${post.postId}`)
			if post.spoiler || file.spoiler
				div.spoilerimg.catalog-thumb(class=(small?'small':''))
			else if file.hasThumb
				img.catalog-thumb(class=(small?'small':'') src=`/file/thumb/${file.hash}${file.thumbextension}` width=file.geometry.thumbwidth height=file.geometry.thumbheight loading='lazy')
			else if file.attachment
				div.attachmentimg.catalog-thumb(class=(small?'small':'') data-mimetype=file.mimetype)
			else if type === 'audio'
				div.audioimg.catalog-thumb(class=(small?'small':''))
			else
				img.catalog-thumb(class=(small?'small':'') src=`/file/${file.filename}` width=file.geometry.width height=file.geometry.height loading='lazy')


code:
include ./catalogfile.pug
mixin catalogtile(post, index, overboard=false)
	- let anchorSubject = post.subject;
	if post.subject
		- const subjectAnchorMatch = post.subject.match(/^\/\w+\//);
		if subjectAnchorMatch
			- anchorSubject = subjectAnchorMatch[0]
	.anchor(id=`${post.board}-${anchorSubject}`)
	.catalog-tile(tabindex=index
		data-board=post.board
		data-post-id=post.postId
		data-user-id=post.userId
		data-name=post.name
		data-tripcode=post.tripcode
		data-subject=post.subject
		data-filter=((post.subject||'')+(post.nomarkup||'')).toLowerCase()
		data-flag=post.country && post.country.code
		data-date=post.date
		data-replies=post.replyposts
		data-bump=post.bumped)
		- const postURL = `/${post.board}/${modview ? 'manage/' : ''}thread/${post.postId}.html`
		.post-info
			if overboard
				div
					| #{__('Thread from')}
					a.no-decoration.post-subject(href=`/${post.board}/`) /#{post.board}/
			else
				input.left.post-check(type='checkbox', name='checkedposts' value=post.postId)
			if modview
				a.left.ml-5.bold(href=`recent.html?postid=${post.postId}`) [+]
			include ../includes/posticons.pug
			if post.country && post.country.code
				if post.country.custom === true
					span(title=post.country.name)
						img.customflag(src=`/flag/${post.board}/${post.country.src}` alt=' ' loading='lazy')
					|
				else
					span(class=`flag flag-${post.country.code.toLowerCase()}` title=post.country.name alt=post.country.name)
					|
			a.no-decoration.post-subject(href=postURL) #{post.subject || `#${post.postId}`}
			|
			select.jsonly.postmenu
				option(value='single') #{__('Hide')}
				if post.subject
					option(value='fsub') #{__('Filter Subject')}
				if post.country && post.country.code
					option(value='fflag') #{__('Filter Flag')}
				if (modview || manage || globalmanage)
					option(value='edit') #{__('Edit')}
				if !overboard
					option(value='moderate') #{__('Moderate')}
				option(value='watch') #{__('Watch')}
				option(value='playlist') #{__('Playlist')}
			br
			span(title=__n('Replies', 2)) R: #{post.replyposts}
			|  /
			span(title=__n('Files', 2)) F: #{post.replyfiles + post.files.length}
			if !overboard
				|  /
				span(title=__('Page')) P: #{Math.ceil(index/10)}
		if post.files.length > 0
			.col
				.row.ct-r1
					- const file = post.files[0]
					+catalogfile(postURL, post, file, false)
				if post.files.length > 1
					.row.ct-r2.wrap
						each file, fileindex in post.files.slice(1)
							+catalogfile(postURL, post, file, true)
		if post.message
			pre.no-m-p.post-message !{post.message}


code:
mixin custompage(page, manage=false)
	.table-container.flex-center.mv-5
		table
			tr
				th
					if manage === true
						input.left.post-check(type='checkbox', name='checkedcustompages' value=page.page)
						a.left(href=`/${board._id}/page/${page.page}.html`) #{page.title}
						a.right.ml-5(href=`/${board._id}/manage/editcustompage/${page._id}.html`) [#{__('Edit')}]
					- const pageDate = new Date(page.date);
					time.right.reltime(datetime=pageDate.toISOString()) #{pageDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
			tr
				td
					if manage === true
						p.no-m-p #{`${page.message.raw.substring(0,50)}...`}
					else
						pre.post-message.no-m-p !{page.message.markdown}
					if page.edited
						small.right.cb.edited
							| #{__('Last edited')}
							- const pageEditDate = new Date(page.edited);
							time.reltime(datetime=pageEditDate.toISOString()) #{pageEditDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}


code:
include ./filelabel.pug

mixin fileform(name, max, total, addPath, deletePath, checkName, fileList, nameList, filePath, imageClass, showName, showLink, formDescription)
	- const capitalName = `${name.charAt(0).toUpperCase()}${name.substring(1)}`;
	h4.no-m-p #{__n(`Add ${capitalName} (Max %s)`, total)}
	p #{formDescription}
	.form-wrapper.flexleft.mt-10
		form.form-post(action=addPath, enctype='multipart/form-data', method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			.row
				.label
					span #{__n(capitalName, max)}
						span.required *
					if max > 1
						|
						|
						small (#{__n('Max %s', max)})
				span.col
					+filelabel(name, max)
					input(id=name type='file', name='file' multiple required)
					.upload-list(data-spoilers='false' data-strip-filenames='false')
			input(type='submit', value=__('Submit'))
	if fileList.length > 0
		h4.mv-5 #{__(`Delete ${capitalName}s`)}:
		.form-wrapper.flexleft.mt-10
			form.form-post(action=deletePath, enctype='application/x-www-form-urlencoded', method='POST')
				input(type='hidden' name='_csrf' value=csrf)
				.catalog
					each file, index in fileList
						label.asset-check
							input(type='checkbox' name=checkName value=nameList[index])
							img(class=imageClass src=`${filePath}/${file}` loading='lazy')
							if showName
								small #{nameList[index]}
							if showLink
								a(href=`${filePath}/${file}`) Link
				input(type='submit', value=__('Delete'))


code:
mixin filelabel(id, max)
	label.jsonly.postform-style.filelabel(for=id)
		| #{__n(`Select/Drop/Paste files`, max)}


code:
mixin filter(f, globalmanage=false)
	.anchor(id=f._id)
	tr
		td
			input.left.post-check(type='checkbox', name='checkedfilters' value=f._id)
		td
			textarea(rows='2' readonly=true) #{f.filters.join('\n')}
		td.text-center
			label
				input(type='checkbox', name='strict_filtering', value='true', checked=f.strictFiltering, disabled='true')
		td
			if f.filterMode === 0
				p.no-m-p.nowrap #{__('Do nothing')}
			else if f.filterMode === 1
				p.no-m-p.nowrap #{__('Block post')}
			else if f.filterMode === 2
				p.no-m-p.nowrap #{__('Ban')}
			else if f.filterMode === 3
				p.no-m-p.nowrap #{__('Replace')}
			else
				p.no-m-p.nowrap ?
		td
			p.no-m-p #{f.filterMessage}
		td
			p.no-m-p(style='text-align:right;') #{f.filterBanDuration}
		td.text-center
			label
				input(type='checkbox', name='filter_ban_appealable', value='true', checked=f.filterBanAppealable, disabled='true')
		td
			p.no-m-p #{f.replaceText}
		td
			if globalmanage
				a.ml-5(href=`/globalmanage/editfilter/${f._id}.html`, style='overflow-wrap: break-word;') [#{__('Edit')}]
			else
				a.ml-5(href=`/${board._id}/manage/editfilter/${f._id}.html`, style='overflow-wrap: break-word;') [#{__('Edit')}]


code:
mixin filters(filterArr)
	- const filterTypeMap = { single: __('Single'), fid: __('ID'), fname: __('Name'), ftrip: __('Tripcode'), fnamer: __('Name'), ftripr: __('Tripcode'), fsub: __('Subject'), fsubr: __('Subject'), fmsg: __('Message'), fmsgr: __('Message'), fflag: __('Flag'), fflagr: __('Flag') }
	if filterArr.length > 0
		each filter in filterArr
			tr
				td #{filterTypeMap[filter.type]}
				td #{filter.val.toString()}
				td: input(disabled type='checkbox' checked=filter.type.endsWith('r'))
				td: a.right.close(data-type=filter.type data-data=filter.val) ×
	else
		td(colspan=4) #{__('No Filters')}


code:
mixin globalmanagenav(selected, upLevel)
	nav.pages
		if permissions.get(Permissions.MANAGE_GLOBAL_GENERAL)
			a(href=`${upLevel ? '../' : ''}recent.html` class=(selected === 'recent' ? 'bold' : '')) [#{__('Recent')}]
			|
			a(href=`${upLevel ? '../' : ''}reports.html` class=(selected === 'reports' ? 'bold' : '')) [#{__('Reports')}]
		if permissions.get(Permissions.MANAGE_GLOBAL_BANS)
			|
			a(href=`${upLevel ? '../' : ''}bans.html` class=(selected === 'bans' ? 'bold' : '')) [#{__('Bans')}]
		if permissions.get(Permissions.MANAGE_GLOBAL_BOARDS)
			|
			a(href=`${upLevel ? '../' : ''}boards.html` class=(selected === 'boards' ? 'bold' : '')) [#{__('Boards')}]
		if permissions.get(Permissions.MANAGE_GLOBAL_LOGS)
			|
			a(href=`${upLevel ? '../' : ''}globallogs.html` class=(selected === 'logs' ? 'bold' : '')) [#{__('Logs')}]
		if permissions.get(Permissions.MANAGE_GLOBAL_ACCOUNTS)
			|
			a(href=`${upLevel ? '../' : ''}accounts.html` class=(selected === 'accounts' ? 'bold' : '')) [#{__('Accounts')}]
		if permissions.get(Permissions.MANAGE_GLOBAL_ROLES)
			|
			a(href=`${upLevel ? '../' : ''}roles.html` class=(selected === 'roles' ? 'bold' : '')) [#{__('Roles')}]
		if permissions.get(Permissions.MANAGE_GLOBAL_NEWS)
			|
			a(href=`${upLevel ? '../' : ''}news.html` class=(selected === 'news' ? 'bold' : '')) [#{__('News')}]
		if permissions.get(Permissions.MANAGE_GLOBAL_SETTINGS)
			|
			a(href=`${upLevel ? '../' : ''}filters.html` class=(selected === 'filters' ? 'bold' : '')) [#{__('Filters')}]
		if permissions.get(Permissions.MANAGE_GLOBAL_SETTINGS)
			|
			a(href=`${upLevel ? '../' : ''}settings.html` class=(selected === 'settings' ? 'bold' : '')) [#{__('Settings')}]


code:
mixin managenav(selected, upLevel)
	nav.pages
		if permissions.get(Permissions.MANAGE_BOARD_GENERAL)
			if selected === 'index'
				include ../includes/boardpages.pug
				|
			else
				a(href=`${upLevel ? '../' : ''}index.html` class=(selected === 'index' ? 'bold' : '')) [#{__('Mod Index')}]
				|
			a(href=`${upLevel ? '../' : ''}catalog.html` class=(selected === 'catalog' ? 'bold' : '')) [#{__('Mod Catalog')}]
			|
			a(href=`${upLevel ? '../' : ''}recent.html` class=(selected === 'recent' ? 'bold' : '')) [#{__('Recent')}]
			|
			a(href=`${upLevel ? '../' : ''}reports.html` class=(selected === 'reports' ? 'bold' : '')) [#{__('Reports')}]
		if permissions.get(Permissions.MANAGE_BOARD_BANS)
			|
			a(href=`${upLevel ? '../' : ''}bans.html` class=(selected === 'bans' ? 'bold' : '')) [#{__('Bans')}]
		if permissions.get(Permissions.MANAGE_BOARD_LOGS)
			|
			a(href=`${upLevel ? '../' : ''}logs.html` class=(selected === 'logs' ? 'bold' : '')) [#{__('Logs')}]
		if permissions.get(Permissions.MANAGE_BOARD_SETTINGS)
			|
			a(href=`${upLevel ? '../' : ''}filters.html` class=(selected === 'filters' ? 'bold' : '')) [#{__('Filters')}]
		if permissions.get(Permissions.MANAGE_BOARD_SETTINGS)
			|
			a(href=`${upLevel ? '../' : ''}settings.html` class=(selected === 'settings' ? 'bold' : '')) [#{__('Settings')}]
		if permissions.get(Permissions.MANAGE_BOARD_CUSTOMISATION)
			|
			a(href=`${upLevel ? '../' : ''}assets.html` class=(selected === 'assets' ? 'bold' : '')) [#{__('Assets')}]
			|
			a(href=`${upLevel ? '../' : ''}custompages.html` class=(selected === 'custompages' ? 'bold' : '')) [#{__('Custom Pages')}]
		if permissions.get(Permissions.MANAGE_BOARD_STAFF)
			|
			a(href=`${upLevel ? '../' : ''}staff.html` class=(selected === 'staff' ? 'bold' : '')) [#{__('Staff')}]


code:
include ../mixins/ban.pug
mixin modal(data)
	.modal-bg(style=data.hidden?'display:none':'')
	.modal(id=(data.settings ? 'settingsmodal' : '') style=data.hidden?'display:none':'')
		.row
			p.bold #{data.title}
			a.close.postform-style#modalclose ×
		if data.bans
			h1.board-title #{__('Banned!')}
			.row#modalbanned
				- const bans = data.bans;
				include ../includes/banform.pug
		if data.message || data.messages || data.error || data.errors
			.row
				ul.nomarks
					if data.message
						li #{data.message}
					if data.error
						li #{data.error}
					if data.messages
						each msg in data.messages
							li #{msg}
					if data.errors
						each error in data.errors
							li #{error}
		if data.frame
			.row.f1
				iframe.bypass#modalframe(src=data.frame frameborder='0' scrolling='no')
		else if data.link
			.row
				a.button.mv-0(href=data.link.href target='_blank') #{data.link.text}
		else if data.redirect && data.title === __('Success')
			.row
				a.button.mv-0(href=data.redirect) #{__('OK')}
		else if data.settings
			.row
				.form-wrapper.flexleft.mt-10
					.row.wrap.sb
						.col.mr-5
							.row
								label.postform-style.ph-5
									input#live-setting(type='checkbox')
								.rlabel #{__('Live posts')}
							.row
								label.postform-style.ph-5
									input#notification-setting(type='checkbox')
								.rlabel #{__('Notifications')}
							.row
								label.postform-style.ph-5
									input#notification-yous-only(type='checkbox')
								.rlabel #{__('Only notify (You)s')}
							.row
								label.postform-style.ph-5
									input#scroll-setting(type='checkbox')
								.rlabel #{__('Scroll to new posts')}
							.row
								label.postform-style.ph-5
									input#localtime-setting(type='checkbox')
								.rlabel #{__('Local time')}
							.row
								label.postform-style.ph-5
									input#24hour-setting(type='checkbox')
								.rlabel #{__('24h time')}
							.row
								label.postform-style.ph-5
									input#relative-setting(type='checkbox')
								.rlabel #{__('Show relative time')}
							.row
								label.postform-style.ph-5
									input#noncolorids-setting(type='checkbox')
								.rlabel #{__('Non-color IDs')}
							.row
								label.postform-style.ph-5
									input#hidepoststubs-setting(type='checkbox')
								.rlabel #{__('Hide post stubs')}
							.row
								label.postform-style.ph-5
									input#hidedeletedpostcontent-setting(type='checkbox')
								.rlabel #{__('Hide deleted post content')}
							.row
								label.postform-style.ph-5
									input#disableboardcss-setting(type='checkbox')
								.rlabel #{__('Disable board custom CSS')}

						.col
							.row
								label.postform-style.ph-5
									input#hidethumbnails-setting(type='checkbox')
								.rlabel #{__('Hide thumbnails')}
							.row
								label.postform-style.ph-5
									input#hiderecursive-setting(type='checkbox')
								.rlabel #{__('Recursive post hide')}
							.row
								label.postform-style.ph-5
									input#loop-setting(type='checkbox')
								.rlabel #{__('Loop audio/video')}
							.row
								label.postform-style.ph-5
									input#heightlimit-setting(type='checkbox')
								.rlabel #{__('Unlimit media height')}
							.row
								label.postform-style.ph-5
									input#hover-expand-setting(type='checkbox')
								.rlabel #{__('Hover expands media')}
							.row
								label.postform-style.ph-5
									input#hover-expand-follow-setting(type='checkbox')
								.rlabel #{__('Hover expands follow cursor')}
							.row
								label.postform-style.ph-5
									input#crispimages-setting(type='checkbox')
								.rlabel #{__('Crisp image rendering')}
							.row
								label.postform-style.ph-5
									input#imageloadingbars-setting(type='checkbox')
								.rlabel #{__('Image loading bars')}
							.row
								label.postform-style.ph-5
									input#alwaysshowspoilers-setting(type='checkbox')
								.rlabel #{__('Always reveal text spoilers')}
							.row
								label.postform-style.ph-5
									input#yous-setting(type='checkbox')
								.rlabel #{__('Show (You)s')}
							.row
								label.postform-style.ph-5
									input#smoothscrolling-setting(type='checkbox')
								.rlabel #{__('Smooth scrolling')}
							.row
								label.postform-style.ph-5
									input#threadwatcher-setting(type='checkbox')
								.rlabel #{__('Thread watcher')}
					.row.wrap.sb.mt-5
						.col.mr-5
							.row
								.label #{__('Video/Audio volume')}
								label.postform-style.ph-5
									input#volume-setting(type='range' min='0' max='100')
							.row
								.label #{__('Default name')}
								input#name-setting(type='text' name='name')
							.row
								.label #{__('Post password')}
								input#postpassword-setting(type='password' name='postpassword' autocomplete='new-password')
							.row
								.label #{__('Theme')}
								select#theme-setting
									option(value='default') default
									each theme in data.settings.themes
										option(value=theme) #{theme}
							.row
								.label #{__('Code theme')}
								select#codetheme-setting
									option(value='default') default
									each theme in data.settings.codeThemes
										option(value=theme) #{theme}

						.col
							.row
								.label #{__('(You)s')}
								input.mr-1#youslist-setting(type='text' readonly)
								input#youslist-clear(type='button' value=__('Clear'))
							.row
								.label #{__('Watchlist')}
								input.mr-1#watchlist-setting(type='text' readonly)
								input#watchlist-clear(type='button' value=__('Clear'))
							.row
								.label #{__('Hidden images')}
								input.mr-1#hiddenimages-setting(type='text' readonly)
								input#hiddenimages-clear(type='button' value=__('Clear'))
							.row
								.label #{__('Cache')}
								input.mr-1#hovercachelist-setting(type='text' readonly)
								input#hovercachelist-clear(type='button' value=__('Clear'))
							.row
								.label #{__('Tegaki Size')}
								input.mr-1.w50#tegakiwidth-setting(type='number')
								.postform-style.ph-5.mr-1 ×
								input.mr-1.w50#tegakiheight-setting(type='number')

					.row.mt-5
						.label #{__('Custom CSS')}
						textarea#customcss-setting(rows=7)

					.row.mt-5
						form.text-center#filter-form
							table.fw
								tbody#advancedfilters
									tr
										th(colspan=4) #{__('Post Filters')}
									tr
										td #{__('Type')}
										td #{__('Value')}
										td #{__('Regex?')}
										td: input.right#filters-clear(type='button' value=__('Clear'))
									tr
										td: select(name='type')
											option(value='fname') #{__('Name')}
											option(value='ftrip') #{__('Tripcode')}
											option(value='fsub') #{__('Subject')}
											option(value='fmsg') #{__('Message')}
											option(value='fflag') #{__('Flag')}
										td
											input#filter-value-input(required type='text' name='value')
										td
											input(type='checkbox' name='regex')
										td: input.right(type='submit' value=__('Add'))
					.row.mt-5
						.label
							| #{__('Import/Export Settings')}
							small.title #{__('Do NOT import untrusted settings data!')}
							small #{__("Export does not include post password or (You)'s")}
						textarea#import-export-setting(type='text')
					.row
						input.mr-1#export-setting(type='button' value=__('Export'))
						input#import-setting(type='button' value=__('Import'))


code:
mixin mypermissions(jsonPermissions, boardOnly=false)
	- const permissionKeys = boardOnly ? Object.keys(jsonPermissions).filter(p => manageBoardBits.includes(parseInt(p))) : Object.keys(jsonPermissions)
	for bit, index in permissionKeys
		if index > 0 && jsonPermissions[bit].title
			hr(size=1)
			h4.mv-5 #{__(jsonPermissions[bit].title)}
			if jsonPermissions[bit].subtitle
				p #{__(jsonPermissions[bit].subtitle)}
		.row
			label.postform-style.ph-5.notallowed
				input(type='checkbox' name=`permission_bit_${bit}` value=bit checked=jsonPermissions[bit].state disabled=true)
			.rlabel #{__(jsonPermissions[bit].label)}
			p #{__(jsonPermissions[bit].desc)}


code:
mixin newspost(post, globalmanage=false)
	.table-container.flex-center.mv-5
		.anchor(id=post._id)
		table
			tr
				th
					if globalmanage === true
						input.left.post-check(type='checkbox', name='checkednews' value=post._id)
					a.left(href=`/news.html#${post._id}`) #{post.title}
					if globalmanage === true
						a.right.ml-5(href=`/globalmanage/editnews/${post._id}.html`) [#{__('Edit')}]
					- const newsDate = new Date(post.date);
					time.right.reltime(datetime=newsDate.toISOString()) #{newsDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
			tr
				td
					if globalmanage === true
						p.no-m-p #{`${post.message.raw.substring(0,50)}...`}
					else
						pre.post-message.no-m-p !{post.message.markdown}

					if post.edited
						small.right.cb.edited
							| #{__('Last edited')}
							- const newsEditDate = new Date(post.edited);
							time.reltime(datetime=newsEditDate.toISOString()) #{newsEditDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}


code:
mixin overboardform(overboardFormAction)
	.flexcenter.mv-10
		details
			summary.collapse #{__('Customise')}
			form.mt-5.form-post#overboardform(action=overboardFormAction method='GET')
				.col
					.row
						.label #{__('Include Default Boards')}
						label.postform-style.ph-5
							input(type='checkbox', name='include_default', value='true' checked=includeDefault)
					.row
						.label #{__('Add Boards')}
						input(type='text' name='add' value=addBoards.join(',') placeholder=__('comma separated'))
					.row
						.label #{__('Remove Boards')}
						input(type='text' name='rem' value=removeBoards.join(',') placeholder=__('comma separated'))
				input(type='submit', value=__('Filter'))


code:
include ./report.pug
include ./banmessage.pug
include ./web3signature.pug
mixin post(post, truncate, manage=false, globalmanage=false, ban=false, overboard=false)
	.anchor(id=post.postId)
	div(class=`post-container ${post.thread || ban === true ? '' : 'op'}`
		data-board=post.board
		data-post-id=post.postId
		data-user-id=post.userId
		data-name=post.name
		data-tripcode=post.tripcode
		data-subject=post.subject
		data-email=post.email
		data-flag=post.country && post.country.code)
		- const postURL = `/${post.board}/${(modview || manage || globalmanage) ? 'manage/' : ''}thread/${post.thread || post.postId}.html`;
		.post-info
			span
				label
					if !overboard
						if globalmanage
							input.post-check(type='checkbox', name='globalcheckedposts' value=post._id)
						else if !ban
							input.post-check(type='checkbox', name='checkedposts' value=post.postId)
						|
					if manage
						- const ip = viewRawIp === true ? post.ip.raw : post.ip.cloak;
						a.bold(href=`${upLevel ? '../' : ''}recent.html?ip=${encodeURIComponent(ip)}`) [#{ip}]
					else if modview
						a.bold(href=`${upLevel ? '../' : ''}recent.html?postid=${post.postId}`) [+]
					else if globalmanage
						a.bold(class='post-board', href=`/${post.board}/manage/index.html`) /#{post.board}/
						|
						- const ip = viewRawIp === true ? post.ip.raw : post.ip.cloak;
						a.bold(href=`?ip=${encodeURIComponent(ip)}`) [#{ip}]
					|
					if !post.thread
						include ../includes/posticons.pug
					if post.subject
						span.post-subject #{post.subject}
						|
					if post.email
						a.post-name(href=`mailto:${post.email}`) #{post.name}
					else
						span.post-name #{post.name}
					|
				if post.country && post.country.code
					include ../includes/postflag.pug
				if post.tripcode
					span.post-tripcode #{post.tripcode}
					|
				if post.capcode
					span.post-capcode #{post.capcode}
					|
				- const postDate = new Date(post.date);
				time.post-date.reltime(datetime=postDate.toISOString()) #{postDate.toLocaleString(pageLanguage, { hourCycle:'h23' })}
				|
				if post.userId
					span.user-id(style=`background-color: #${post.userId}`) #{post.userId}
					|
			span.post-links
				a.noselect.no-decoration(href=`${postURL}#${post.postId}`) #{__('No.')}
				span.post-quoters
					a.no-decoration(href=`${postURL}#postform`) #{post.postId}
				|
				if !post.thread && (truncate || manage || globalmanage)
					|
					span.noselect: a(href=`${postURL}`) [#{__('Open')}]
				select.jsonly.postmenu
					option(value='single') #{__('Hide')}
					if post.userId
						option(value='fid') #{__('Filter ID')}
					if post.name
						option(value='fname') #{__('Filter Name')}
					if post.tripcode
						option(value='ftrip') #{__('Filter Tripcode')}
					if post.subject
						option(value='fsub') #{__('Filter Subject')}
					if post.country && post.country.code
						option(value='fflag') #{__('Filter Flag')}
					if !overboard && !ban
						option(value='moderate') #{__('Moderate')}
					if !ban && (modview || manage || globalmanage)
						option(value='edit') #{__('Edit')}
					if !post.thread
						option(value='watch') #{__('Watch')}
						option(value='playlist') #{__('Playlist')}
		.post-data
			if post.files.length > 0
				.post-files(class=(post.files.length > 1 ? 'fn' : ''))
					each file, fileindex in post.files
						if file.mimetype === 'tegaki/replay' && post.files.some(f => f.originalFilename.slice(0, -3) === file.originalFilename.slice(0,-4))
							- continue; //Skip showing tegaki replay alone if is includes the image
						.post-file
							- const type = file.mimetype.split('/')[0]
							span.post-file-info
								span
									a.filename(href='/file/'+file.filename title='Download '+file.originalFilename download=file.originalFilename) #{post.spoiler || file.spoiler ? __('Spoiler File') : file.originalFilename}
								br
								if globalmanage && file.phash != null
									span #{file.phash}
									br
								if !file.attachment && !(post.spoiler || file.spoiler)
									span.jsonly
										b [
										a.dummy-link.hide-image.noselect(data-src=`/file/${file.hasThumb ? 'thumb/'+file.hash+file.thumbextension : file.filename}`) #{__('Hide')}
										b ]
								span
									|  (#{file.sizeString}
									if file.geometryString
										| , #{file.geometryString}
									if file.durationString
										| , #{file.durationString}
									| )
								if type === 'image'
									if (board && board.settings.reverseImageSearchLinks === true) || (overboard && overboardReverseLinks === true) || manage || globalmanage
										|
										span: a(href=`${reverseImageLinksURL.replace('%s', encodeURIComponent(meta.url+'/file/'+file.filename))}` rel='nofollow' referrerpolicy='same-origin' title=__('Reverse Image Search') target='_blank') #{__('Reverse')}
									if file.originalFilename.endsWith('-tegaki.png')
										- const matchingReplayFile = post.files.find(f => f.originalFilename.slice(0, -4) === file.originalFilename.slice(0,-3));
										if matchingReplayFile !== undefined
											|
											span: a.dummy-link.replay-tegaki.noselect(href=`/file/${matchingReplayFile.filename}` download=matchingReplayFile.originalFilename) #{__('Replay')}
								if file.mimetype === 'tegaki/replay'
									|
									span.jsonly: a.dummy-link.replay-tegaki.noselect(href=`/file/${file.filename}` download=file.originalFilename) #{__('Replay')}
							.post-file-src(data-type=type data-attachment=(file.attachment ? "true" : "false"))
								a(target='_blank' href=`/file/${file.filename}`)
									if post.spoiler || file.spoiler
										div.spoilerimg.file-thumb
									else if file.hasThumb
										img.file-thumb(src=`/file/thumb/${file.hash}${file.thumbextension}` height=file.geometry.thumbheight width=file.geometry.thumbwidth loading='lazy')
									else if file.attachment
										div.attachmentimg.file-thumb(data-mimetype=file.mimetype)
									else if type === 'audio'
										div.audioimg.file-thumb
									else
										img.file-thumb(src=`/file/${file.filename}` height=file.geometry.height width=file.geometry.width loading='lazy')
			- if (post.message && modview) { post.message = post.message.replace(new RegExp(`<a class="quote" href="/${post.board}/`, 'g'), `<a class="quote" href="/${post.board}/manage/`); } //its either this, a subdomain, or nothing.
			- let truncatedMessage = post.message;
			if post.message
				if truncate
					-
						const splitPost = post.message.split('\n');
						const messageLines = splitPost.length;
						if (messageLines > 15) {
							truncatedMessage = splitPost.slice(0, 15).join('\n');
						} else if (post.message.length > 1500) {
							truncatedMessage = post.message.substring(0, 1500).replace(/<([\w]+)?([^>]*)?$/, '');
							const lastAnchorOpen = truncatedMessage.lastIndexOf('<a');
							const lastAnchorClose = truncatedMessage.lastIndexOf('');
							if (lastAnchorOpen >= 0 && (lastAnchorClose === -1 || lastAnchorClose < lastAnchorOpen)) {
								truncatedMessage += '';
							}
						}
					pre.post-message !{truncatedMessage}
				else
					pre.post-message !{post.message}
			if !post.message && post.files.length === 0
				p #{__('No message or files.')}
			if post.signature && post.address
				+web3signature(post.signature, post.address)
			if post.edited
				- const postEditDate = new Date(post.edited.date);
				small.cb.mv-5.ml-5.edited
					- lastEdited = __('Last edited | by %s', (post.edited.username || __('Hidden User'))).split('|'); //How do I interpolate a whole tag properly?
					| #{lastEdited[0]}
					time.reltime(datetime=postEditDate.toISOString()) #{postEditDate.toLocaleString(pageLanguage, { hourCycle:'h23' })}
					| #{lastEdited[1]}
			if post.banmessage
				+banmessage(post.banmessage)
			if truncatedMessage !== post.message
				div.cb.mt-5.ml-5
					| #{__('Message too long.')} #[a.viewfulltext(href=`${postURL}#${post.postId}`) #{__('View the full text')}]
			if post.omittedposts || post.omittedfiles
				div.cb.mt-5.ml-5
					img.jsonly.dummy-link.expand-omitted(height='12' width='12' data-shown=post.replies.length data-board=post.board data-thread=post.postId src='/file/plus.png')
					- const ompo = post.omittedposts;
					- const omfi = post.omittedfiles;
					span
						| #{__(`${ompo > 1 ? '%s' : ompo} repl${ompo > 1 ? 'ies' : 'y'}${omfi > 0 ? ` and ${omfi > 1 ? '%s' : omfi} file${omfi > 1 ? 's' : ''}` : ''} omitted.`, ompo > 1 ? ompo : omfi, omfi)}
					| #[a(href=postURL) #{__('View the full thread')}]
			if post.previewbacklinks != null
				if post.previewbacklinks.length > 0
					div.replies.mt-5.ml-5 #{__n('Replies', 2)}:
						each backlink in post.previewbacklinks
							a.quote(href=`${postURL}#${backlink.postId}`) >>#{backlink.postId}
							|
						if post.previewbacklinks.length < post.backlinks.length
							- const ombls = post.backlinks.length-post.previewbacklinks.length;
							| + #[a(href=`${postURL}#${post.postId}`) #{__('%s earlier', ombls)}]
							|
			else if post.backlinks && post.backlinks.length > 0
				div.replies.mt-5.ml-5 #{__n('Replies', 2)}:
					each backlink in post.backlinks
						a.quote(href=`${postURL}#${backlink.postId}`) >>#{backlink.postId}
						|
	if manage === true
		each r in post.reports
			+report(r, true)
	if globalmanage === true
		each r in post.globalreports
			+report(r)


code:
mixin postlink(log, postLink, manageLink=false)
	if postLink.thread || postLink.postId
		a.quote(href=`/${postLink.board || log.board}/${manageLink ? 'manage/' : ''}thread/${postLink.thread || postLink.postId}.html#${postLink.postId}`) >>#{postLink.postId}
	else
		a.quote(href=`/${postLink.board || log.board}/${manageLink ? 'manage/' : ''}index.html`) >>>/#{postLink.board}/


code:
mixin report(r, manage=false)
	.reports.post-container
		input.post-check(type='checkbox', name='checkedreports' value=r.id)
		|
		- const ip = viewRawIp === true ? r.ip.raw : r.ip.cloak;
		a.bold(href=`${manage ? 'recent.html' : ''}?ip=${encodeURIComponent(ip)}`) [#{ip}]
		|
		- const reportDate = new Date(r.date);
		time.reltime(datetime=reportDate.toISOString()) #{reportDate.toLocaleString(pageLanguage, { hourCycle:'h23' })}
		|  | #{__('Reason')}: #{r.reason}


code:
mixin tegakiwindow(minimised)
	.flex-center.resize#tegakiwindow(class=(minimised ? 'minimised' : ''))
		.row.noselect#tegakiwindow-dragHandle
			span.fw.text-center #{__('Tegaki')}
			span.mr-0.close#minimise #{minimised ? '[+]' : '[−]'}
			span.mr-0.close#maximise [⤢]
			span.mr-0.close#close [×]


code:
mixin threadwatcher(minimised)
	.flex-center#threadwatcher(class=(minimised ? 'minimised' : ''))
		.row.noselect#threadwatcher-dragHandle
			span.fw.text-center #{__('Thread Watcher')}
			span.mr-0.close#minimise #{minimised ? '[+]' : '[−]'}


code:
mixin uploaditem(item)
	div
		.upload-item
			img.upload-thumb(src=item.url)
			p #{item.name}
			a.close ×
		if item.hash
			.row.sb
				if item.spoilers
					label
						input(type='checkbox', name='spoiler', value=item.hash)
						| #{__('Spoiler')}
				if item.stripFilenames
					label
						input(type='checkbox', name='strip_filename', value=item.hash)
						| #{__('Strip Filename')}


code:
mixin watchedthread(thread)
	.row.watched-thread(data-id=`${thread.board}-${thread.postId}` data-unread=(thread.unread||null))
		a.close ×
		- const watchedThreadLink = `/${thread.board}/thread/${thread.postId}.html`;
		a(class=(thread.isCurrentThread ? 'bold' : '') href=watchedThreadLink) /#{thread.board}/ - #{thread.subject || `#${thread.postId}`}
		a.ml-a(href=`${watchedThreadLink}#bottom`) [▼]


code:
mixin web3signature(signature, address)
	div.mv-5.ml-5
		a.web3-address(href=ethereumLinksURL.replace('%s', encodeURIComponent(address)) rel='nofollow' referrerpolicy='same-origin' target='_blank') #{address.substring(0,5)}…#{address.substring(38, 42)}
		details.dummy-link
			summary #{__('Signature')}
			.web3-signature #{signature}


code:
extends ../layout.pug

block content
	h1.board-title #{__('404 Not Found')}


code:
extends ../layout.pug

block content
	h1.board-title #{__('500 Internal Server Error')}
	.col.flex-center.mv-10
		p #{__('The server encountered an error and was unable to fulfill your request.')}


code:
extends ../layout.pug

block content
	h1.board-title #{__('502 Bad Gateway')}
	.col.flex-center.mv-10
		p #{__('The server acting as a gateway or proxy received an invalid response from the upstream server.')}


code:
extends ../layout.pug

block content
	h1.board-title #{__('503 Service Unavailable')}
	.col.flex-center.mv-10
		p #{__('The server is currently unable to handle the request due to a temporary overload or scheduled maintenance.')}


code:
extends ../layout.pug

block content
	h1.board-title #{__('504 Gateway Timeout')}
	.col.flex-center.mv-10
		p #{__('The server acting as a gateway or proxy did not get a response in time from the upstream server.')}