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}`) [>]

repo_name: diegolegion/algochan

license: mit


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 #{isThread ? __('New Reply') : __('New Thread')}
		if board.settings.forceAnon && !modview
			section.row
				.label Sage
				label.postform-style.ph-5
					input(type='checkbox', name='email', value='sage')
				a.close.postform-style(href='#!') ×
			include ./subjectfield.pug
		else
			section.row
				.label #{__('Name')}
				input.mr-1(type='text', name='name', placeholder=board.settings.defaultName maxlength=globalLimits.fieldLength.name)
				a.close.postform-style(href='#!') ×
			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', autocomplete='off' 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)))
	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].parent == null || permissions.get(jsonPermissions[bit].parent);
		- const parentLabel = !parentAllowed ? jsonPermissions[jsonPermissions[bit].parent].label : '';
		label.postform-style.ph-5(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 #{__(jsonPermissions[bit].desc)}
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 !banpage || (ban.appeal == null && ban.allowAppeal === true)
				input.post-check(type='checkbox', name='checkedbans' value=ban._id)
		td
			if ban.global === true
				| #{__('Global')}
			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}/custompage/${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
				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
			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#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)
	a.quote(href=`/${postLink.board || log.board}/${manageLink ? 'manage/' : ''}thread/${postLink.thread || postLink.postId}.html#${postLink.postId}`) >>#{postLink.postId}


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 threadwatcher(minimised)
	.flex-center#threadwatcher(class=(minimised ? 'minimised' : ''))
		.row.noselect#threadwatcher-dragHandle
			span.fw.text-center #{__('Thread Watcher')}
			span.mr-0.close #{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.')}


code:
extends ../layout.pug

block head
	title #{__('Account')}

block content
	.board-header
		h1.board-title #{__(`Welcome, %s`, user.username)}
	br
	hr(size=1)
	h4.no-m-p #{__('General')}:
	ul
		if !user.twofactor && !user.web3
			li.bold: a(href='/twofactor.html') #{__('Setup 2FA (TOTP)')}
		if permissions.get(Permissions.CREATE_BOARD)
			li: a(href='/create.html') #{__('Create a board')}
		if permissions.get(Permissions.CREATE_ACCOUNT)
			li: a(href='/register.html') #{__('Register an account')}
		li: a(href='/changepassword.html') #{__('Change password')}
		li: a(href='/mypermissions.html') #{__('My permissions')}
		li: a(href='/sessions.html') #{__('Active sessions')}
	form(action='/forms/logout' method='post')
		input(type='submit' value=__('Log out'))

	if permissions.hasAny(Permissions.MANAGE_GLOBAL_GENERAL, Permissions.MANAGE_GLOBAL_BANS, Permissions.MANAGE_GLOBAL_BOARDS, Permissions.MANAGE_GLOBAL_LOGS, Permissions.MANAGE_GLOBAL_ACCOUNTS, Permissions.MANAGE_GLOBAL_NEWS, Permissions.MANAGE_GLOBAL_SETTINGS)
		hr(size=1)
		h4.no-m-p #{__('Global Management')}:
		ul
			li
				if permissions.get(Permissions.MANAGE_GLOBAL_GENERAL)
					a(href=`/globalmanage/recent.html`) #{__('Recent')}
					|
					a(href=`/globalmanage/reports.html`) #{__('Reports')}
						if globalReportCount > 0
							b  (#{globalReportCount})
				if permissions.get(Permissions.MANAGE_GLOBAL_BANS)
					|
					a(href=`/globalmanage/bans.html`) #{__('Bans')}
				if permissions.get(Permissions.MANAGE_GLOBAL_BOARDS)
					|
					a(href=`/globalmanage/boards.html`) #{__('Boards')}
				if permissions.get(Permissions.MANAGE_GLOBAL_LOGS)
					|
					a(href=`/globalmanage/globallogs.html`) #{__('Logs')}
				if permissions.get(Permissions.MANAGE_GLOBAL_ACCOUNTS)
					|
					a(href=`/globalmanage/accounts.html`) #{__('Accounts')}
				if permissions.get(Permissions.MANAGE_GLOBAL_ROLES)
					|
					a(href=`/globalmanage/roles.html`) #{__('Roles')}
				if permissions.get(Permissions.MANAGE_GLOBAL_NEWS)
					|
					a(href=`/globalmanage/news.html`) #{__('News')}
				if permissions.get(Permissions.MANAGE_GLOBAL_SETTINGS)
					|
					a(href=`/globalmanage/filters.html`) #{__('Filters')}
				if permissions.get(Permissions.MANAGE_GLOBAL_SETTINGS)
					|
					a(href=`/globalmanage/settings.html`) #{__('Global Settings')}

	hr(size=1)
	h4.no-m-p #{__('Boards you own')}:
	if user.ownedBoards && user.ownedBoards.length > 0
		ul
			for b in user.ownedBoards
				li
					a(href=`/${b}/index.html`) /#{b}/
					|  -
					a(href=`/${b}/manage/index.html`) #{__('Mod Index')}
					|
					a(href=`/${b}/manage/catalog.html`) #{__('Mod Catalog')}
					|
					a(href=`/${b}/manage/recent.html`) #{__('Recent')}
					|
					a(href=`/${b}/manage/reports.html`) #{__('Reports')}
						if boardReportCountMap[b]
							b  (#{boardReportCountMap[b]})
					|
					a(href=`/${b}/manage/bans.html`) #{__('Bans')}
					|
					a(href=`/${b}/manage/logs.html`) #{__('Logs')}
					|
					a(href=`/${b}/manage/filters.html`) #{__('Filters')}
					|
					a(href=`/${b}/manage/settings.html`) #{__('Settings')}
					|
					a(href=`/${b}/manage/assets.html`) #{__('Assets')}
					|
					a(href=`/${b}/manage/custompages.html`) #{__('Custom Pages')}
					|
					a(href=`/${b}/manage/staff.html`) #{__('Staff')}
	else
		p #{__('Nothing')}

	hr(size=1)
	h4.no-m-p #{__('Boards you are staff on')}:
	if user.staffBoards && user.staffBoards.length > 0
		ul
			for b in user.staffBoards
				li
					if permissions.get(Permissions.MANAGE_BOARD_GENERAL) || boardPermissions[b].get(Permissions.MANAGE_BOARD_GENERAL)
						a(href=`/${b}/index.html`) /#{b}/
						|  -
						a(href=`/${b}/manage/index.html`) #{__('Mod Index')}
						|
						a(href=`/${b}/manage/catalog.html`) #{__('Mod Catalog')}
						|
						a(href=`/${b}/manage/recent.html`) #{__('Recent')}
						|
						a(href=`/${b}/manage/reports.html`) #{__('Reports')}
							if boardReportCountMap[b]
								b  (#{boardReportCountMap[b]})
					if permissions.get(Permissions.MANAGE_BOARD_BANS) || boardPermissions[b].get(Permissions.MANAGE_BOARD_BANS)
						|
						a(href=`/${b}/manage/bans.html`) #{__('Bans')}
					if permissions.get(Permissions.MANAGE_BOARD_LOGS) || boardPermissions[b].get(Permissions.MANAGE_BOARD_LOGS)
						|
						a(href=`/${b}/manage/logs.html`) #{__('Logs')}
					if permissions.get(Permissions.MANAGE_BOARD_SETTINGS) || boardPermissions[b].get(Permissions.MANAGE_BOARD_SETTINGS)
						|
						a(href=`/${b}/manage/settings.html`) #{__('Settings')}
					if permissions.get(Permissions.MANAGE_BOARD_CUSTOMISATION) || boardPermissions[b].get(Permissions.MANAGE_BOARD_CUSTOMISATION)
						|
						a(href=`/${b}/manage/assets.html`) #{__('Assets')}
					if permissions.get(Permissions.MANAGE_BOARD_CUSTOMISATION) || boardPermissions[b].get(Permissions.MANAGE_BOARD_CUSTOMISATION)
						|
						a(href=`/${b}/manage/custompages.html`) #{__('Custom Pages')}
					if permissions.get(Permissions.MANAGE_BOARD_STAFF) || boardPermissions[b].get(Permissions.MANAGE_BOARD_STAFF)
						|
						a(href=`/${b}/manage/staff.html`) #{__('Staff')}
	else
		p #{__('Nothing')}

	if user.staffBoards.length > 0 ||  user.ownedBoards.length > 0
		hr(size=1)
		h4.no-m-p #{__('Resign from a staff position')}:
		.form-wrapper.flexleft.mt-10
			form.form-post(action=`/forms/resign`, enctype='application/x-www-form-urlencoded', method='POST')
				input(type='hidden' name='_csrf' value=csrf)
				.row
					.label #{__('Boards')}
					select(name='board' size='5')
						optgroup(label=__('You own'))
							each board in user.ownedBoards
								option(value=board) #{board}
						optgroup(label=__('You moderate'))
							each board in user.staffBoards
								option(value=board) #{board}
				.row
					.label #{__("I'm sure")}
					label.postform-style.ph-5
						input(type='checkbox', name='confirm', value='true' required)
				input(type='submit', value=__('Resign'))

	hr(size=1)
	h4.no-m-p #{__('Delete your account')}:
	.form-wrapper.flexleft.mt-10
		form.form-post(action=`/forms/deleteaccount`, enctype='application/x-www-form-urlencoded', method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			.row
				.label #{__("I'm sure")}
				label.postform-style.ph-5
					input(type='checkbox', name='confirm', value='true' required)
			input(type='submit', value=__('Delete'))


code:
extends ../layout.pug
include ../mixins/ban.pug

block head
	title #{__('Banned!')}

block content
	h1.board-title #{__('Banned!')}
	h4.board-description #{__('Bans currently in place against your IP')}:
	include ../includes/banform.pug


code:
extends ../layout.pug
include ../mixins/boardheader.pug
include ../mixins/boardnav.pug

block head
	title /#{board._id}/ - #{__('Banners')}

block content
	+boardheader(__('Banners'))
	br
	include ../includes/stickynav.pug
	.pages
		+boardnav('banners', true, false)
	hr(size=1)
	if board.banners.length > 0
		.catalog
			each banner in board.banners
				img.board-banner(src=`/banner/${board._id}/${banner}` loading='lazy')
	else
		p #{__('Board has no custom banners.')}
	include ../includes/stickynav.pug
	hr(size=1)
	.pages
		+boardnav('banners', true, false)


code:
extends ../layout.pug
include ../mixins/post.pug
include ../mixins/boardnav.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug
include ../mixins/announcements.pug

block head
	title /#{board._id}/ - #{board.settings.name} - #{__n('Page %s', page)}

block content
	+boardheader(modview ? __('Mod Index') : null)
	br
	include ../includes/postform.pug
	br
	+announcements()
	include ../includes/stickynav.pug
	if modview
		+managenav('index')
	else
		.pages
			include ../includes/boardpages.pug
			+boardnav(null, false, false)
	form(action=`/forms/board/${board._id}/${modview ? 'mod' : ''}actions` method='POST' enctype='application/x-www-form-urlencoded')
		if modview
			input(type='hidden' name='_csrf' value=csrf)
		hr(size=1)
		if threads.length === 0
			p #{__('No posts.')}
			hr(size=1)
		for thread in threads
			.thread
				+post(thread, true)
				for post in thread.replies
					+post(post, true)
			hr(size=1)
		if modview
			+managenav('index')
		else
			.pages
				include ../includes/boardpages.pug
				+boardnav(null, false, false)
		if modview
			include ../includes/actionfooter_manage.pug
		else
			include ../includes/actionfooter.pug


code:
extends ../layout.pug
include ../mixins/boardtable.pug

block head
	title #{__('Board List')}

block content
	h1.board-title #{__('Board List')}
	.flexcenter.mv-10
		form.form-post(action='/boards.html' method='GET')
			input(type='hidden' value=page)
			.row.wrap.sb
				div(class=`col${enableWebring ? ' mr-5' : ''}`)
					.row
						.label #{__('Search')}
						input(type='text' name='search' value=search placeholder=__('URI or tags'))
					.row
						.label #{__('Sort')}
						select(name='sort')
							option(value='popularity') #{__('Popularity')}
							option(value='activity' selected=query.sort === 'activity') #{__('Latest Activity')}
					.row
						.label #{__('Order')}
						select(name='direction')
							option(value='desc') #{__('Descending')}
							option(value='asc' selected=query.direction === 'asc') #{__('Ascending')}
					if enableWebring
						.row
							.label #{__('Local First')}
							label.postform-style.ph-5
								input(type='checkbox', name='local_first', value='true' checked=localFirst)
				if enableWebring
					.col
						.row
							.label #{__('Sites')}
							select(name='sites' size='5' multiple)
								optgroup(label=__('Shown'))
									each site in shown
										option(value=site selected=true) #{site}
								optgroup(label=__('Not Shown'))
									each site in notShown
										option(value=site) #{site}
			input(type='submit', value=__('Filter'))
	if boards && boards.length > 0
		+boardtable(true, true)
			each board in boards
				- const path = board.webring ? board.path : `/${board._id}/index.html`;
				tr
					td
						span.left
							if board.webring === true
								span.help(title=__('Webring')) 🔗
								|
							if board.settings.sfw === true
								span.help(title=__('SFW')) 💼
								|
						a(href=path) #{board.webring ? board.siteName : ''} /#{board.webring ? board.uri : board._id}/ - #{board.settings.name}
					td #{board.settings.description || '-'}
					td #{board.pph}
					td #{board.ppd != null ? board.ppd : '-'}
					td #{board.ips}
					td #{board.sequence_value-1}
					if board.lastPostTimestamp
						td(style=`background-color: ${board.lastPostTimestamp.color}`) #{board.lastPostTimestamp.text}
					else
						td -
	.pages.text-center.mt-5.mv-0
		include ../includes/pages.pug


code:
extends ../layout.pug

block head
	title #{__('Block Bypass')}

block content
	h1.board-title #{__('Block Bypass')}
	.form-wrapper.flex-center.mv-10
		form.form-post(action=`/forms/blockbypass?language=${encodeURIComponent(pageLanguage)}` method='POST' data-captcha-preload='true')
			.row
				.col
					include ../includes/captcha.pug
			if minimal
				input(type='hidden' name='minimal' value='1')
			input(type='submit', value=__('Submit'))
		if message
			p.title #{message}


code:
doctype html
html
	head
		meta(charset='utf-8')
		link(rel='stylesheet', href='/css/nscaptcha.css')
	body
		img.flexcenter(src='/captcha')
		form(action='/forms/newcaptcha', method='POST')
			input(type='submit' value='↻')


code:
extends ../layout.pug
include ../mixins/catalogtile.pug
include ../mixins/boardnav.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug
include ../mixins/announcements.pug

block head
	title /#{board._id}/ - #{__('Catalog')}

block content
	+boardheader(modview ? __('Mod Catalog') : __('Catalog'))
	br
	include ../includes/postform.pug
	br
	+announcements()
	include ../includes/stickynav.pug
	.wrapbar
		if modview
			+managenav('catalog')
		else
			.pages
				+boardnav('catalog', true, false)
		.pages.jsonly
			input#catalogfilter(type='text' placeholder=__('Filter'))
			select.ml-5.right#catalogsort
				option(value="" disabled selected hidden) #{__('Sort By')}
				option(value="bump") #{__('Bump Order')}
				option(value="date") #{__('Creation Date')}
				option(value="replies") #{__('Reply Count')}
	form(action=`/forms/board/${board._id}/${modview ? 'mod' : ''}actions` method='POST' enctype='application/x-www-form-urlencoded')
		if modview
			input(type='hidden' name='_csrf' value=csrf)
		hr(size=1)
		if threads.length === 0
			p #{__('No posts')}
		else
			.catalog
				for thread, i in threads
					+catalogtile(thread, i+1)
		hr(size=1)
		if modview
			+managenav('catalog')
		else
			.pages
				+boardnav('catalog', true, false)
		if modview
			include ../includes/actionfooter_manage.pug
		else
			include ../includes/actionfooter.pug


code:
extends ../layout.pug

block head
	title #{__('Change Password')}

block content
	h1.board-title #{__('Change Password')}
	.form-wrapper.flex-center.mv-10
		form.form-post(action='/forms/changepassword' method='POST' data-captcha-preload='true')
			.row
				.label #{__('Username')}
				input(type='text', name='username', maxlength='50' required)
			.row
				.label #{__('Existing Password')}
				input(type='password', name='password', maxlength='100' required)
			.row
				.label #{__('New Password')}
				input(type='password', name='newpassword', maxlength='100' required)
			.row
				.label #{__('Confirm New Password')}
				input(type='password', name='newpasswordconfirm', maxlength='100' required)
			.row
				.label #{__('2FA Code')}
				input(type='number' name='twofactor' placeholder=__('if enabled'))
			if captchaOptions.type === 'text'
				include ../includes/captchasidelabel.pug
			else
				include ../includes/captchafieldrow.pug
			input(type='submit', value=__('Change Password'))
		p: a(href='/login.html') #{__('Login')}
		p: a(href='/register.html') #{__('Register')}


code:
extends ../layout.pug

block head
	title #{__('Create Board')}

block content
	h1.board-title #{__('Create Board')}
	.form-wrapper.flex-center.mv-10
		form.form-post(action='/forms/create' method='POST' data-captcha-preload='true')
			.row
				.label #{__('URI e.g. /uri/')}
				input(type='text', name='uri', maxlength=globalLimits.fieldLength.uri pattern='[a-zA-Z0-9]+' required title=__('alphanumeric only'))
			.row
				.label #{__('Name')}
				input(type='text', name='name', maxlength=globalLimits.fieldLength.boardname required)
			.row
				.label #{__('Description')}
				input(type='text', name='description', maxlength=globalLimits.fieldLength.description)
			.row
				.label #{__('Tags')}
				textarea(name='tags' placeholder=__('Newline separated, max 10'))
			if captchaOptions.type === 'text'
				include ../includes/captchasidelabel.pug
			else
				include ../includes/captchafieldrow.pug
			input(type='submit', value=__('Create'))


code:
extends ../layout.pug
include ../mixins/custompage.pug

block head
	title /#{board._id}/ - #{customPage.title}

block content
	.board-header
		a.no-decoration(href=`/${board._id}/index.html`)
			h1.board-title /#{board._id}/ - #{customPage.title}
	include ../includes/stickynav.pug
	+custompage(customPage)


code:
extends ../layout.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Edit Account')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('accounts', true)
	hr(size=1)
	h4.mv-5 Edit account permissions for: "#{accountUsername}"
	- const jsonPermissions = accountPermissions.toJSON();
	.form-wrapper.flexleft
		form(action=`/forms/global/editaccount` method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			input(type='hidden' name='username' value=accountUsername)
			include ../includes/globalpermissionsform.pug
			hr(size=1)
			h4.mv-5 #{__('Or, apply a role')}:
			.row
				.label Role
				select(name='template')
					option(disabled selected) #{__('None')}
					//- limiting which ones atm
					option(value=roles.ANON.base64) #{__('Regular User')}
					option(value=roles.BOARD_STAFF.base64) #{__('Global Board Staff')}
					option(value=roles.BOARD_OWNER.base64) #{__('Global Board Owner')}
					option(value=roles.GLOBAL_STAFF.base64) #{__('Global Staff')}
					option(value=roles.ADMIN.base64) #{__('Admin')}
			input(type='submit', value=__('Apply'))


code:
extends ../layout.pug
include ../mixins/boardheader.pug
include ../mixins/managenav.pug

block head
	title /#{board._id}/ - #{__('Edit Custom Page')}

block content
	+boardheader(__('Edit Custom Page'))
	br
	+managenav('custompages', true)
	hr(size=1)
	include ../includes/stickynav.pug
	.form-wrapper.flex-center.mv-10
		form.form-post(action=`/forms/board/${board._id}/editcustompage` method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			input(type='hidden' name='page_id' value=page._id)
			.row
				.label #{__('.html name')}
				input(type='text' name='page' pattern='[a-zA-Z0-9-_]+' placeholder=__('a-zA-Z0-9-_ only') value=page.page required)
			.table-container.flex-center.mv-5
				table
					tr
						th
							input.edit.left(type='text' name='title' value=page.title required)
							- const pageDate = new Date(page.date);
							time.right.reltime(datetime=pageDate.toISOString()) #{pageDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
					tr
						td

							textarea.edit.fw(name='message' rows='10' placeholder=__('Supports post styling') required) #{page.message.raw}
			input(type='submit', value=__('Save'))


code:
extends ../layout.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug

block head
	title /#{board._id}/ - #{__('Edit Filter')}

block content
	+boardheader(__('Edit Filter'))
	br
	+managenav('filters', true)
	hr(size=1)
	h4.no-m-p
		| #{__('Edit Filter')}
		|  (
		a(href='/faq.html#filters') #{__('Filters FAQ')}
		| ):
	.form-wrapper.flex-center.mv-10
		form.form-post(action=`/forms/board/${board._id}/editfilter` method='POST')
			include ../includes/filtereditform.pug


code:
extends ../layout.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Edit News')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('news', true)
	hr(size=1)
	h4.no-m-p #{__('Edit Newspost')}:
	include ../includes/stickynav.pug
	.form-wrapper.flex-center.mv-10
		form.form-post(action='/forms/global/editnews' method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			input(type='hidden' name='news_id' value=news._id)
			.table-container.flex-center.mv-5
				table
					tr
						th
							input.edit.left(type='text' name='title' value=news.title required)
							- const newsDate = new Date(news.date);
							time.right.reltime(datetime=newsDate.toISOString()) #{newsDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
					tr
						td
							textarea.edit.fw(name='message' rows='10' placeholder=__('Supports post styling') required) #{news.message.raw}
			input(type='submit', value=__('Save'))


code:
extends ../layout.pug

block head
	title #{__('Edit Post')}

block content
	h1.board-title #{__('Edit Post')}
	.form-wrapper.flex-center.mv-10
		form.form-post(action='/forms/editpost' method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			input(type='hidden' name='referer' value=referer)
			input(type='hidden' name='board' value=post.board)
			input(type='hidden' name='postId' value=post.postId)
			.anchor(id=post.postId)
			div(class=`mv-5 post-container ${post.thread || ban === true ? '' : 'op'}` data-board=post.board data-post-id=post.postId data-user-id=post.userId)
				- const postURL = `/${post.board}/thread/${post.thread || post.postId}.html`;
				.post-info
					span.noselect
						label
							if !post.thread
								include ../includes/posticons.pug
							input.edit.post-subject(value=post.subject placeholder=__('Subject') type='text' name='subject' maxlength=globalLimits.fieldLength.subject)
							input.edit.post-name(value=post.email type='text' name='email' placeholder=__('Email') maxlength=globalLimits.fieldLength.email)
							input.edit.post-name(type='text' name='name' placeholder=__('Name') maxlength=globalLimits.fieldLength.name value=post.name+(post.capcode || ''))
						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}
				.post-data
					pre.post-message
						textarea.edit.fw(name='message' rows='15' placeholder=__('Message')) #{post.nomarkup}
					if post.banmessage
						p.ban
							span.message #{__('USER WAS BANNED FOR THIS POST')}
							|
							span.reason(data-reason=post.banmessage) #{post.banmessage}
			label.mt-5
				input.post-check(type='checkbox', name='hide_name' value='1')
				| #{__('Hide Username')}
			label.mv-5
				input(type='text', name='log_message', placeholder=__('Modlog message') autocomplete='off')
			input(type='submit', value=__('Save'))


code:
extends ../layout.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Edit Role')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('roles', true)
	hr(size=1)
	h4.mv-5 #{__('Edit role %s', __(roleNameMap[rolePermissions.base64]))}
	- const jsonPermissions = rolePermissions.toJSON();
	.form-wrapper.flexleft
		form(action=`/forms/global/editrole` method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			input(type='hidden' name='roleid' value=role._id)
			include ../includes/globalpermissionsform.pug


code:
extends ../layout.pug
include ../mixins/boardheader.pug
include ../mixins/managenav.pug

block head
	title /#{board._id}/ - #{__('Edit Staff Permissions')}

block content
	+boardheader(__('Edit Staff Permissions'))
	br
	+managenav('staff', true)
	hr(size=1)
	h4.mv-5 #{__('Edit board permissions for "%s"', staffUsername)}
		|
		if permissions.get(Permissions.MANAGE_GLOBAL_ACCOUNTS)
			|
			a(href=`/globalmanage/editaccount/${staffUsername}.html`) [#{__('Edit Account Permissions')}]
	- const jsonPermissions = staffPermissions.toJSON();
	.form-wrapper.flexleft
		form(action=`/forms/board/${board._id}/editstaff` method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			input(type='hidden' name='username' value=staffUsername)
			include ../includes/staffpermissionsform.pug


code:
extends ../layout.pug

block content
	h1 #{__('Internal Server Error')}


code:
extends ../layout.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Edit Filter')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('filters', true)
	hr(size=1)
	h4.no-m-p
		| #{__('Edit Filter')}
		|  (
		a(href='/faq.html#filters') #{__('Filters FAQ')}
		| ):
	include ../includes/stickynav.pug
	.form-wrapper.flex-center.mv-10
		form.form-post(action='/forms/global/editfilter' method='POST')
			include ../includes/filtereditform.pug


code:
extends ../layout.pug
include ../mixins/globalmanagenav.pug

block head
	title Accounts

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('accounts')
	hr(size=1)
	.form-wrapper.flexleft
		h4.no-m-p Search:
		form.form-post.mv-5(action=`/globalmanage/accounts.html` method='GET')
			input(type='hidden' value=page)
			.row
				.label #{__('Username')}
				input(type='text' name='username' value=username)
			.row
				.label #{__('Board URI')}
				input(type='text' name='uri' value=uri)
			input(type='submit', value=__('Filter'))
		h4.mv-5 #{__('Accounts')}:
		if accounts && accounts.length > 0
			form.form-post.nogrow(action=`/forms/global/deleteaccounts` method='POST' enctype='application/x-www-form-urlencoded')
				input(type='hidden' name='_csrf' value=csrf)
				.table-container.flex-left.text-center
					table.accounttable
						tr
							th
							th #{__('Username')}
							th #{__('Own Boards')}
							th #{__('Staff Boards')}
							th #{__('Last Active')}
							th #{__('Role')}
							th #{__('Permissions')}
						for account in accounts
							tr
								td
									input.postform-style(type='checkbox', name='checkedaccounts' value=account._id)
									|
									if permissions.get(Permissions.MANAGE_GLOBAL_BOARDS)
										.prev-show
											input(type='checkbox', name='delete_owned_boards' value=account._id)
											| Delete all owned boards
								td #{account._id}
								td
									if account.ownedBoards.length > 0
										for b in account.ownedBoards
											a(href=`/${b}/index.html`) /#{b}/
											|
									else
										| -
								td
									if account.staffBoards.length > 0
										for b in account.staffBoards
											a(href=`/${b}/index.html`) /#{b}/
											|
									else
										| -
								td
									if account.lastActiveDate
										time.reltime(datetime=account.lastActiveDate.toISOString()) #{account.lastActiveDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
									else
										| -
								td #{roleNameMap[account.permissions.toString('base64')] || __('Custom')}
								td
									if account._id !== user.username
										a(href=`/globalmanage/editaccount/${account._id}.html`) [#{__('Edit')}]
									else
										a(href=`/mypermissions.html`) [#{__('View')}]
				.pages.mv-5
					include ../includes/pages.pug
				h4.mv-5 #{__('Delete Selected')}:
				input(type='submit', value=__('Delete'))
		else
			p #{__('No results.')}


code:
extends ../layout.pug
include ../mixins/ban.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Bans')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('bans')
	hr(size=1)
	h4.no-m-p #{__('Global Bans & Appeals')}:
	form(action=`/forms/global/editbans` method='POST' enctype='application/x-www-form-urlencoded')
		include ../includes/managebanform.pug


code:
extends ../layout.pug
include ../mixins/ban.pug
include ../mixins/globalmanagenav.pug
include ../mixins/boardtable.pug

block head
	title #{__('Boards')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('boards')
	hr(size=1)
	h4.text-center.no-m-p Filter:
	.flexcenter.mv-10
		form.form-post(action='/globalmanage/boards.html' method='GET')
			input(type='hidden' value=page)
			.row.wrap.sb
				.col.mr-5
					.row
						.label #{__('Search')}
						input(type='text' name='search' value=search placeholder=__('URI or tags'))
					.row
						.label #{__('Sort')}
						select(name='sort')
							option(value='popularity') #{__('Popularity')}
							option(value='activity' selected=query.sort === 'activity') #{__('Latest Activity')}
					.row
						.label #{__('Order')}
						select(name='direction')
							option(value='desc') #{__('Descending')}
							option(value='asc' selected=query.direction === 'asc') #{__('Ascending')}
				.col
					.row
						.label #{__('Unlisted')}
						label.postform-style.ph-5
							input(type='checkbox', name='filter_unlisted', value='1' checked=(query.filter_unlisted != null))
					.row
						.label #{__('SFW')}
						label.postform-style.ph-5
							input(type='checkbox', name='filter_sfw', value='1' checked=(query.filter_sfw != null))
					.row
						.label #{__('Abandoned')}
						label.postform-style.ph-5
							input(type='checkbox', name='filter_abandoned', value='1' checked=(query.filter_abandoned != null))
			input(type='submit', value='Filter')
	if localBoards && localBoards.length > 0
		h4.text-center.mv-10 Board List:
		+boardtable(true, true, permissions.get(Permissions.GLOBAL_MANAGE_ACCOUNTS))
			each board in localBoards
				tr
					td
						span.left
							if board.settings.sfw === true
								span.help(title=__('SFW')) 💼
								|
							if board.settings.unlistedLocal === true
								span.help(title=__('Unlisted')) 👁
								|
							if !board.owner
								span.help(title=__('Abandoned')) 🏚
								|
						a(href=`/${board._id}/manage/index.html`) /#{board._id}/ - #{board.settings.name}
					if permissions.get(Permissions.GLOBAL_MANAGE_ACCOUNTS)
						if board.owner
							td: a(href=`/globalmanage/accounts.html?username=${board.owner}`) #{board.owner}
						else
							td -
					td #{board.settings.description}
					td.nobreak #{board.pph}
					td.nobreak #{board.ppd}
					td.nobreak #{board.ips}
					td.nobreak #{board.sequence_value-1}
					if board.lastPostTimestamp
						td.nobreak(style=`background-color: ${board.lastPostTimestamp.color}`) #{board.lastPostTimestamp.text}
					else
						td -
	.pages.text-center.mt-5.mv-0
		include ../includes/pages.pug


code:
extends ../layout.pug
include ../mixins/filter.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Filters')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('filters')
	hr(size=1)
	h4.no-m-p
		| #{__('Add Filter')}
		|  (
		a(href='/faq.html#filters') #{__('Filters FAQ')}
		| ):
	.form-wrapper.flexleft
		form.form-post(action='/forms/global/addfilter', enctype='application/x-www-form-urlencoded', method='POST')
			include ../includes/filternewform.pug
	if filters.length > 0
		hr(size=1)
		h4.no-m-p #{__('Manage Filters')}:
			.form-wrapper.flexleft
				form.form-post(action='/forms/global/deletefilter', enctype='application/x-www-form-urlencoded', method='POST')
					input(type='hidden' name='_csrf' value=csrf)
					.table-container.mv-5.horscroll
						table
							tr
								th
								th #{__('Filters')}
								th #{__('Strict Filtering')}
								th #{__('Filter Mode')}
								th #{__('Block/Ban Message')}
								th #{__('Filter Auto Ban Duration')}
								th #{__('Filter Bans Appealable')}
								th #{__('Edit')}
							each f in filters
								+filter(f, true)
					input(type='submit', value=__('Delete'))


code:
extends ../layout.pug
include ../mixins/ban.pug
include ../mixins/globalmanagenav.pug
include ../mixins/postlink.pug

block head
	title #{__('Logs')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('logs')
	hr(size=1)
	.form-wrapper.flexleft
		h4.no-m-p Search:
		form.form-post.mv-5(action=`/globalmanage/globallogs.html` method='GET')
			input(type='hidden' value=page)
			.row
				.label #{__('Board URI')}
				input(type='text' name='uri' value=uri)
			.row
				.label #{__('Username')}
				input(type='text' name='username' value=username)
			.row
				.label #{__('IP')}
				input(type='text' name='ip' value=ip)
			input(type='submit', value=__('Filter'))
		h4.no-m-p Global Logs:
		if logs && logs.length > 0
			.table-container.flex-center.mv-10.text-center
				table.fw
						tr
							th #{__('Date')}
							th #{__('Board')}
							th #{__('User')}
							th #{__('IP')}
							th #{__('Actions')}
							th #{__('Posts')}
							th #{__('Log Message')}
						for log in logs
							tr
								- const logDate = new Date(log.date);
								td: time.reltime(datetime=logDate.toISOString()) #{logDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
								td
									a(href=`/${log.board}/index.html`) /#{log.board}/
									|
									a(href=`?uri=${log.board}`) [+]
								td
									if log.user !== __('Unregistered User')
										a(href=`accounts.html?username=${log.user}`) #{log.user}
									else
										| #{log.user}
									|
									a(href=`?username=${log.user}`) [+]
								td
									- const logIp = viewRawIp === true ? log.ip.raw : log.ip.cloak;
									a(href=`recent.html?ip=${encodeURIComponent(logIp)}`) #{logIp}
									|
									a(href=`?ip=${encodeURIComponent(logIp)}`) [+]
								td #{log.actions.map(a => __(a))}
								td
									if log.showLinks
										for postLink in log.postLinks
											+postlink(log, postLink, true)
											|
									else
										| #{log.postLinks.map(l => l.postId)}
								td #{log.message || '-'}
			.pages.mv-5
				include ../includes/pages.pug
		else
			p #{__('No Logs.')}


code:
extends ../layout.pug
include ../mixins/newspost.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('News')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('news')
	hr(size=1)
	h4.no-m-p #{__('Add News')}:
	.form-wrapper.flexleft
		form.form-post(action=`/forms/global/addnews`, enctype='application/x-www-form-urlencoded', method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			.row
				.label #{__('Title')}
				input(type='text' name='title' required)
			.row
				.label #{__('Message')}
				textarea(name='message' rows='10' placeholder=__('Supports post styling') required)
			input(type='submit', value=__('Submit'))
	if news.length > 0
		hr(size=1)
		h4.no-m-p #{__('Manage News')}:
		.form-wrapper.flexleft
			form.form-post(action=`/forms/global/deletenews`, enctype='application/x-www-form-urlencoded', method='POST')
				input(type='hidden' name='_csrf' value=csrf)
				each post in news
					+newspost(post, true)
				if news.length === 1
					.anchor
				input(type='submit', value=__('Delete'))


code:
extends ../layout.pug
include ../mixins/globalmanagenav.pug
include ../mixins/post.pug

block head
	title #{__('Recent Posts')}

block content
	h1.board-title #{__('Global Management')}
	br
	.wrapbar
		+globalmanagenav('recent')
		if page === 1 && !ip
			.jsonly#livetext(data-view-raw-ip=(viewRawIp?'true':'false') data-room=`globalmanage-recent-${viewRawIp === true ? 'raw' : 'hashed'}`)
				.dot#livecolor
				|  #{__('Connecting...')}
				input.postform-style.ml-5.di#updatepostsbutton(type='button' value=__('Update'))
	form(action=`/forms/global/actions` method='POST' enctype='application/x-www-form-urlencoded')
		input(type='hidden' name='_csrf' value=csrf)
		if posts.length === 0
			hr(size=1)
			p #{__('No posts.')}
		else
			hr(size=1)
			if ip
				h4.no-m-p #{__(`Global post history for %s`, ip)}
				hr(size=1)
			for p in posts
				.thread
					+post(p, false, false, true)
				hr(size=1)
			.pages.mv-5
				include ../includes/pages.pug
			include ../includes/actionfooter_globalmanage.pug


code:
extends ../layout.pug
include ../mixins/post.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Reports')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('reports')
	form(action=`/forms/global/actions` method='POST' enctype='application/x-www-form-urlencoded')
		if reports.length === 0
			hr(size=1)
			p #{__('No reports.')}
		else
			input(type='hidden' name='_csrf' value=csrf)
			hr(size=1)
			if ip
				h4.no-m-p #{__('Reports against or by ip %s', ip)}
				hr(size=1)
			for report in reports
				.thread
					+post(report, false, false, true)
				hr(size=1)
			.pages.mv-5
				include ../includes/pages.pug
			include ../includes/actionfooter_globalmanage.pug


code:
extends ../layout.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Roles')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('roles')
	hr(size=1)
	h4.mv-5 #{__('Roles')}:
	.table-container.flex-left.text-center
		table
			tr
				th #{__('Role')}
				th #{__('Permissions')}
			for role in allRoles
				tr
					td #{roleNameMap[role.permissions.toString('base64')]}
					td: a(href=`/globalmanage/editrole/${role._id}.html`) [#{__('Edit')}]


code:
extends ../layout.pug
include ../mixins/globalmanagenav.pug

block head
	title #{__('Settings')}

block content
	h1.board-title #{__('Global Management')}
	br
	+globalmanagenav('settings')
	hr(size=1)
	h4.no-m-p #{__('Settings')}:
	.form-wrapper.flexleft
		form.form-post(action=`/forms/global/settings`, enctype='application/x-www-form-urlencoded', method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			.mv-10
				.sm#tab-1
					.sm#tab-2
						.sm#tab-3
							.sm#tab-4
								.sm#tab-5
									.sm#tab-6
										.sm#tab-7
											.sm#tab-8
												.sm#tab-9
													.sm#tab-10
														.sm#tab-11
															.tabbed-area
																include ../includes/globalmanagesettings.pug
			input.row(type='submit', value=__('Save settings'))
	hr(size=1)
	h4.no-m-p #{__('Delete board')}:
	.form-wrapper.flexleft.mt-10
		form.form-post(action=`/forms/global/deleteboard`, enctype='application/x-www-form-urlencoded', method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			.row
				.label #{__('Board URI')}:
				input(type='text' name='uri' required)
			.row
				.label #{__("I'm sure")}
				label.postform-style.ph-5
					input(type='checkbox', name='confirm', value='true' required)
			input(type='submit', value=__('Submit'))
	hr(size=1)
	h4.no-m-p #{__('Clear All')}:
	.form-wrapper.flexleft.mt-10
		form.form-post(action=`/forms/global/clear`, enctype='application/x-www-form-urlencoded', method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			.row
				.label #{__('Table')}
				select(name='table')
					option(value='sessions') #{__('Login Sessions')}
					option(value='blockbypass') #{__('Block Bypasses')}
			.row
				.label #{__("I'm sure")}
				label.postform-style.ph-5
					input(type='checkbox', name='confirm', value='true' required)
			input(type='submit', value=__('Submit'))


code:
extends ../layout.pug
include ../mixins/boardtable.pug

block head
	title #{meta.siteName}

block content
	h1.board-title #{meta.siteName}
	.table-container.flex-center.mv-10.text-center
		table
			tr
				th.alt #{__('Welcome')}
			tr
				td
					pre.no-m-p
						| The site administrator should edit views/pages/home.pug, then run "pm2 reload all" and "gulp html" to customise this page.
	if recentNews && recentNews.length > 0
		.table-container.flex-center.mv-10
			table.newstable
				tr
					th(colspan=3) #{__('Latest News')}
				each post in recentNews
					tr
						td
							a.left(href=`/news.html#${post._id}`) #{post.title}
						td
							p.no-m-p #{`${post.message.raw.substring(0,50)}${post.message.raw.length > 50 ? '...' : ''}`}
						td
							- const newsDate = new Date(post.date);
							time.right.reltime(datetime=newsDate.toISOString()) #{newsDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
	if hotThreads && hotThreads.length > 0
		.table-container.flex-center.mv-10
			table#hotposts
				tr(colspan=3)
				each post, i in hotThreads
					tr
						td.text-center
							span.help(title=__('Hot Thread (%s)', post.score.toFixed(1))) 🔥
							|  #{post.replyposts}
						td
							- const threadLink = `/${post.board}/thread/${post.postId}.html#${post.postId}`;
							a.quote(href=threadLink)
								if post.subject
									| #{post.subject.substring(0,30)}#{post.subject.length > 30 ? '...' : ''}
									if post.nomarkup
										|  -
								if post.nomarkup
									| #{post.nomarkup.substring(0,40)}#{post.nomarkup.length > 40 ? '...' : ''}
								if !post.nomarkup && !post.subject
									| >>>/#{post.board}/#{post.postId}
						td
							- const postedDate = new Date(post.date);
							time.right.reltime(datetime=postedDate.toISOString()) #{postedDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
	if boards && boards.length > 0
		+boardtable(true, false)
			each board in boards
				tr
					td
						if board.settings.sfw === true
							span.left
								span.help(title=__('SFW')) 💼
								|
						a(href=`/${board._id}/index.html`) /#{board._id}/ - #{board.settings.name}
					td #{board.settings.description}
					td.nobreak #{board.pph}
					td.nobreak #{board.ppd}
					td.nobreak #{board.ips}
					td.nobreak #{board.sequence_value-1}
			if localStats.total-localStats.unlisted > boards.length
				tr
					td(colspan=6)
						a.bold(href='/boards.html') More Boards
		.table-container.flex-center.mv-10.text-center
			table(style='max-width:450px')
				tr
					th #{__('Local Stats')}
				tr
					td
						pre.no-m-p
							| #{__('There are currently %s public boards, %s in total. Sitewide, %s posts have been made in the last day, %s in the last hour, %s in total.', localStats.total-localStats.unlisted, localStats.total, localStats.ppd, localStats.pph, localStats.posts)}
							| #{__('%s files are being served, totaling %s.', fileStats.count, fileStats.totalSizeString)}
		if enableWebring === true && webringStats != null
			.table-container.flex-center.mv-10.text-center
				table(style='max-width:450px')
					tr
						th #{__('Webring Stats')}
					tr
						td
							pre.no-m-p
								| #{__('There are currently %s sites and %s boards in the known webring. Across all webring boards, %s posts have been made in the last hour, %s in total.', webringStats.sites, webringStats.total, webringStats.pph, webringStats.posts)}


code:
extends ../layout.pug

block head
	title #{__('Login')}

block content
	h1.board-title #{__('Login')}
	.form-wrapper.flex-center.mv-10
		form.form-post(action='/forms/login' method='POST')
			input(type='hidden' name='goto' value=goto)
			.row
				.label #{__('Username')}
				input(type='text', name='username', maxlength='50' required)
			.row
				.label #{__('Password')}
				input(type='password', name='password', maxlength='100' required)
			.row
				.label #{__('2FA Code')}
				input(type='number' name='twofactor' placeholder=__('if enabled'))
			input(type='submit', value=__('Login'))
	if enableWeb3 === true
		.jsonly.web3.mv-10
			.text-center OR
			.form-wrapper.flex-center.mv-10
				form.form-post(action='/forms/login' method='POST' data-captcha-preload='true')
					input(type='hidden' name='nonce')
					input(type='hidden' name='address')
					input(type='hidden' name='signature')
					.postform-style.dummy-link.web3-login.ct-r1.ph-5
						img(src='/file/metamask-fox.svg' width=24 height=24)
						| #{__('Login with MetaMask')}
	.text-center.mt-10
		p: a(href='/register.html') #{__('Register')}
		p: a(href='/changepassword.html') #{__('Change Password')}


code:
extends ../layout.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug
include ../mixins/fileform.pug

block head
	title /#{board._id}/ - #{__('Assets')}

block content
	+boardheader(__('Assets'))
	br
	+managenav('assets')
	hr(size=1)
	+fileform('banner', globalLimits.bannerFiles.max, globalLimits.bannerFiles.total,
		`/forms/board/${board._id}/addbanners`, `/forms/board/${board._id}/deletebanners`,
		'checkedbanners', board.banners, board.banners, `/banner/${board._id}`,
		'asset-banner', false, false,
		__('Images randomly chosen and displayed at the top of most pages on the board'))
	hr(size=1)
	+fileform('flag', globalLimits.flagFiles.max, globalLimits.flagFiles.total,
		`/forms/board/${board._id}/addflags`, `/forms/board/${board._id}/deleteflags`,
		'checkedflags', Object.values(board.flags), Object.keys(board.flags),
		`/flag/${board._id}`, 'asset-flag', true, false,
		__('Flags that can be applied to posts if custom flags are enabled in board settings'))
	hr(size=1)
	+fileform('asset', globalLimits.assetFiles.max, globalLimits.assetFiles.total,
		`/forms/board/${board._id}/addassets`, `/forms/board/${board._id}/deleteassets`,
		'checkedassets', board.assets, board.assets,
		`/asset/${board._id}`, 'asset-generic', false, true,
		__('Arbitrary assets that can be used for other purposes e.g. custom CSS'))


code:
extends ../layout.pug
include ../mixins/ban.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug

block head
	title /#{board._id}/ - #{__('Bans & Appeals')}

block content
	+boardheader(__('Bans'))
	br
	+managenav('bans')
	hr(size=1)
	h4.mv-5 #{__('Bans & Appeals')}:
	form(action=`/forms/board/${board._id}/editbans` method='POST' enctype='application/x-www-form-urlencoded')
		include ../includes/managebanform.pug


code:
extends ../layout.pug
include ../mixins/boardheader.pug
include ../mixins/managenav.pug
include ../mixins/custompage.pug

block head
	title /#{board._id}/ - #{__('Custom Pages')}

block content
	+boardheader(__('Custom Pages'))
	br
	+managenav('custompages')
	hr(size=1)
	h4.mv-5 #{__('Add Custom Page')}:
	.form-wrapper.flexleft
		form.form-post(action=`/forms/board/${board._id}/addcustompages`, enctype='application/x-www-form-urlencoded', method='POST')
			input(type='hidden' name='_csrf' value=csrf)
			.row
				.label #{__('.html name')}
				input(type='text' name='page' pattern='[a-zA-Z0-9-_]+' placeholder=__('a-zA-Z0-9-_ only') required)
			.row
				.label #{__('Title')}
				input(type='text' name='title' required)
			.row
				.label #{__('Message')}
				textarea(name='message' rows='10' placeholder=__('Supports post styling') required)
			input(type='submit', value=__('Submit'))
	if customPages.length > 0
		hr(size=1)
		h4.no-m-p #{__('Manage Custom Pages')}:
		.form-wrapper.flexleft
			form.form-post(action=`/forms/board/${board._id}/deletecustompages`, enctype='application/x-www-form-urlencoded', method='POST')
				input(type='hidden' name='_csrf' value=csrf)
				each page in customPages
					+custompage(page, true)
				if customPages.length === 1
					.anchor
				input(type='submit', value=__('Delete'))


code:
extends ../layout.pug
include ../mixins/filter.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug

block head
	title /#{board._id}/ - #{__('Filters')}

block content
	+boardheader(__('Filters'))
	br
	+managenav('filters')
	hr(size=1)
	h4.no-m-p
		| #{__('Add Filter')}
		|  (
		a(href='/faq.html#filters') #{__('Filters FAQ')}
		| ):
	.form-wrapper.flexleft
		form.form-post(action=`/forms/board/${board._id}/addfilter`, enctype='application/x-www-form-urlencoded', method='POST')
			include ../includes/filternewform.pug
	if filters.length > 0
		hr(size=1)
		h4.no-m-p #{__('Manage Filters')}:
		.form-wrapper.flexleft
			form.form-post(action=`/forms/board/${board._id}/deletefilter`, enctype='application/x-www-form-urlencoded', method='POST')
				input(type='hidden' name='_csrf' value=csrf)
				.table-container.mv-5.horscroll
					table
						tr
							th
							th #{__('Filters')}
							th #{__('Strict Filtering')}
							th #{__('Filter Mode')}
							th #{__('Block/Ban Message')}
							th #{__('Filter Auto Ban Duration')}
							th #{__('Filter Bans Appealable')}
							th #{__('Edit')}
						each f in filters
							+filter(f)
				input(type='submit', value=__('Delete'))


code:
extends ../layout.pug
include ../mixins/post.pug
include ../mixins/ban.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug
include ../mixins/postlink.pug

block head
	title /#{board._id}/ - #{__('Logs')}

block content
	+boardheader(__('Logs'))
	br
	+managenav('logs')
	hr(size=1)
	.form-wrapper.flexleft
		h4.no-m-p #{__('Search')}:
		form.form-post.mv-5(action=`/${board._id}/manage/logs.html` method='GET')
			input(type='hidden' value=page)
			.row
				.label #{__('Username')}
				input(type='text' name='username' value=username)
			input(type='submit', value=__('Filter'))
		h4.no-m-p Logs:
		if logs && logs.length > 0
			.table-container.flex-center.mv-10.text-center
				table.fw
						tr
							th #{__('Date')}
							th #{__('User')}
							th #{__('IP')}
							th #{__('Actions')}
							th #{__('Posts')}
							th #{__('Log Message')}
						for log in logs
							tr
								- const logDate = new Date(log.date);
								td: time.reltime(datetime=logDate.toISOString()) #{logDate.toLocaleString(pageLanguage, {hourCycle:'h23'})}
								td
									| #{log.user}
									|
									a(href=`?username=${log.user}`) [+]
								td
									- const logIp = viewRawIp === true ? log.ip.raw : log.ip.cloak;
									| #{logIp}
								td #{log.actions.map(a => __(a))}
								td
									if log.showLinks
										for postLink in log.postLinks
											+postlink(log, postLink, true)
											|
									else
										| #{log.postLinks.map(l => l.postId)}
								td #{log.message || '-'}
			.pages.mv-5
				include ../includes/pages.pug
		else
			p #{__('No logs.')}


code:
extends ../layout.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug
include ../mixins/mypermissions.pug

block head
	title /#{board._id}/ - #{__('My Permissions')}

block content
	+boardheader(__('My Permissions'))
	br
	+managenav('staff')
	hr(size=1)
	h4.mv-5 #{__('Board-specific permissions')}
		|
		if permissions.get(Permissions.MANAGE_BOARD_STAFF) && user.staffBoards.includes(board._id)
			|
			a(href=`/${board._id}/manage/editstaff/${user.username}.html`) [#{__('Edit')}]
	- const jsonPermissions = permissions.toJSON();
	+mypermissions(jsonPermissions, true)


code:
extends ../layout.pug
include ../mixins/post.pug
include ../mixins/ban.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug

block head
	title /#{board._id}/ - #{__('Recent Posts')}

block content
	+boardheader(__('Recent Posts'))
	br
	.wrapbar
		+managenav('recent')
		if page === 1 && !postId && !queryIp
			.jsonly#livetext(data-view-raw-ip=(viewRawIp?'true':'false') data-room=`${board._id}-manage-recent-${viewRawIp === true ? 'raw' : 'hashed'}`)
				.dot#livecolor
				|  #{__('Connecting...')}
				input.postform-style.ml-5.di#updatepostsbutton(type='button' value=__('Update'))
	form(action=`/forms/board/${board._id}/modactions` method='POST' enctype='application/x-www-form-urlencoded')
		input(type='hidden' name='_csrf' value=csrf)
		if posts.length === 0
			hr(size=1)
			p #{__('No posts.')}
		else
			hr(size=1)
			- const ip = viewRawIp === true ? posts[0].ip.raw : posts[0].ip.cloak;
			if postId || (queryIp && queryIp === ip)
				h4.no-m-p #{__('Post history for %s', ip)}
					|
					if permissions.get(Permissions.MANAGE_GLOBAL_GENERAL)
						|
						a(href=`/globalmanage/recent.html?ip=${encodeURIComponent(ip)}`) [#{__('See Global Post History')}]
				hr(size=1)
			for p in posts
				.thread
					+post(p, true, true)
				hr(size=1)
			.pages.mv-5
				include ../includes/pages.pug
			include ../includes/actionfooter_manage.pug


code:
extends ../layout.pug
include ../mixins/post.pug
include ../mixins/ban.pug
include ../mixins/managenav.pug
include ../mixins/boardheader.pug

block head
	title /#{board._id}/ - #{__('Reports')}

block content
	+boardheader(__('Reports'))
	br
	+managenav('reports')
	hr(size=1)
	h4.no-m-p #{__('Reports')}:
	form(action=`/forms/board/${board._id}/modactions` method='POST' enctype='application/x-www-form-urlencoded')
		if reports.length === 0
			p #{__('No reports.')}
		else
			input(type='hidden' name='_csrf' value=csrf)
			for report in reports
				.thread
					+post(report, false, true)
				hr(size=1)
			include ../includes/actionfooter_manage.pug