Module:Sandbox/SD0001/Chess3

-- Forked from [[Module:Sandbox/Bawolff/Chessboard]]
----------------------------------------------------

local Calculator = require('Module:Sandbox/SD0001/Calculator')
local p = {}

local cfg, nrows, ncols
cfg = {}

-- From Module:Chessboard/Chess
function cfg.dims()
	return 8, 8
end

function cfg.letters()
	return { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' }
end

function cfg.image_board(size)
	return string.format('[[File:Chessboard480.svg|%dx%dpx|link=|class=notpageimage]]', 8 * size, 8 * size)
end

function cfg.image_square(pc, row, col, size)
	local colornames = { l = 'white', d = 'black', u = 'unknown color' }
	local piecenames = {
		p = 'pawn',
		r = 'rook',
		n = 'knight',
		b = 'bishop',
		q = 'queen',
		k = 'king',
		a = 'archbishop',
		c = 'chancellor',
		z = 'champion',
		w = 'wizard',
		t = 'fool',
		M = 'mann',
		h = 'upside-down pawn',
		m = 'upside-down rook',
		B = 'upside-down bishop',
		N = 'upside-down knight',
		f = 'upside-down king',
		g = 'upside-down queen',
		e = 'elephant',
		s = 'boat',
		G = 'giraffe',
		U = 'unicorn',
		Z = 'zebra'
	}
	local symnames = {
		xx = 'black cross',
		ox = 'white cross',
		xo = 'black circle',
		oo = 'white circle',
		ul = 'up-left arrow',
		ua = 'up arrow',
		ur = 'up-right arrow',
		la = 'left arrow',
		ra = 'right arrow',
		dl = 'down-left arrow',
		da = 'down arrow',
		dr = 'down-right arrow',
		lr = 'left-right arrow',
		ud = 'up-down arrow',
		db = 'up-right and down-left arrow',
		dw = 'up-left and down-right arrow',
		x0 = 'zero',
		x1 = 'one',
		x2 = 'two',
		x3 = 'three',
		x4 = 'four',
		x5 = 'five',
		x6 = 'six',
		x7 = 'seven',
		x8 = 'eight',
		x9 = 'nine'
	}
	local colchar = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' }
	local color = mw.ustring.gsub(pc, '^.*(%w)(%w).*$', '%2') or ''
	local piece = mw.ustring.gsub(pc, '^.*(%w)(%w).*$', '%1') or ''
	--local alt = colchar[col] .. row .. ' '
	local alt = ''

	if colornames[color] and piecenames[piece] then
		alt = alt .. colornames[color] .. ' ' .. piecenames[piece]
	else
		alt = alt .. (symnames[piece .. color] or piece .. ' ' .. color)
	end

	return string.format('[[File:Chess %s%st45.svg|%dx%dpx|alt=%s|%s|link=|class=notpageimage|top]]', piece, color, size, size, alt, alt)

end

-- End Module:Chessboard/Chess

-- From Module:Pgn

local BLACK = "black"
local WHITE = "white"

local PAWN = "P"
local ROOK = "R"
local KNIGHT = "N"
local BISHOP = "B"
local QUEEN = "Q"
local KING = "K"

local KINGSIDE = 7
local QUEENSIDE = 12

local DEFAULT_BOARD = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR'

local bit32 = bit32 or require('bit32')

-- in lua 5.3, unpack is not a first class citizen anymore, but - assign table.unpack
local unpack = unpack or table.unpack

local function apply(f, ...)
	res = {}
	targ = { ... }
	for ind = 1, #targ do
		res[ind] = f(targ[ind])
	end
	return unpack(res)
end

local function empty(s)
	return not s or mw.text.trim(s) == ''
end

local function falseIfEmpty(s)
	return not empty(s) and s
end

local function charToFile(ch)
	return falseIfEmpty(ch) and string.byte(ch) - string.byte('a')
end

local function charToRow(ch)
	return falseIfEmpty(ch) and tonumber(ch) - 1
end

local function indexToCoords(index)
	return index % 8, math.floor(index / 8)
end

local function coordsToIndex(file, row)
	return row * 8 + file
end

local function charToPiece(letter)
	local piece = mw.ustring.upper(letter)
	return piece, piece == letter and WHITE or BLACK
end

local function pieceToChar(piece, color)
	return color == WHITE and piece or mw.ustring.lower(piece)
end

local function ambigToIndex(file, row)
	if row == nil then
		return file
	end
	return coordsToIndex(file, row)
end

local function enPasantRow(color)
	return color == WHITE and 5 or 2
end

local function sign(a)
	return a < 0 and -1
		or a > 0 and 1
		or 0
end

local function pieceAt(board, fileOrInd, row)
	-- called with 2 params, fileOrInd is the index, otherwise it's the file.
	local letter = board[ambigToIndex(fileOrInd, row)]
	if not letter then
		return
	end
	return charToPiece(letter)
end

local function findPieces(board, piece, color)
	local result = {}
	local lookFor = pieceToChar(piece, color)
	for index = 0, 63 do
		local letter = board[index]
		if letter == lookFor then
			table.insert(result, index)
		end
	end
	return result
end

local function roadIsClear(board, ind1, ind2)
	if ind1 == ind2 then
		error('call to roadIsClear with identical indices', ind1)
	end
	local file1, row1 = indexToCoords(ind1)
	local file2, row2 = indexToCoords(ind2)
	if (file1 - file2) * (row1 - row2) * (math.abs(row1 - row2) - math.abs(file1 - file2)) ~= 0 then
		error('sent two indices to roadIsClear which are not same row, col, or diagonal: ', ind1, ind2)
	end
	local hdelta = sign(file2 - file1)
	local vdelta = sign(row2 - row1)
	local row, file = row1 + vdelta, file1 + hdelta
	while row ~= row2 or file ~= file2 do
		if pieceAt(board, file, row) then
			return false
		end
		row = row + vdelta
		file = file + hdelta
	end
	return true
end

local function pawnCanMove(board, color, startFile, startRow, file, row, capture)
	local hor, ver = file - startFile, row - startRow
	local absVer = math.abs(ver)
	if capture then
		local ok = hor * hor == 1 and (
			color == WHITE and ver == 1 or
				color == BLACK and ver == -1
		)

		local enpassant = ok and
			row == enPasantRow(color) and
			pieceAt(board, file, row) == nil
		return ok, enpassant
	else
		if hor ~= 0 then
			return false
		end
	end
	if absVer == 2 then
		if not roadIsClear(board, coordsToIndex(startFile, startRow), coordsToIndex(file, row)) then
			return false
		end
		return color == WHITE and startRow == 1 and ver == 2 or
			color == BLACK and startRow == 6 and ver == -2
	end
	return color == WHITE and ver == 1 or color == BLACK and ver == -1
end

local function canMove(board, start, dest, capture, verbose)
	local startFile, startRow = indexToCoords(start)
	local file, row = indexToCoords(dest)
	local piece, color = pieceAt(board, startFile, startRow)
	if piece == PAWN then
		return pawnCanMove(board, color, startFile, startRow, file, row, capture)
	end
	local dx, dy = math.abs(startFile - file), math.abs(startRow - row)
	return piece == KNIGHT and dx * dy == 2
		or piece == KING and bit32.bor(dx, dy) == 1
		or (
		piece == ROOK and dx * dy == 0
			or piece == BISHOP and dx == dy
			or piece == QUEEN and dx * dy * (dx - dy) == 0
	) and roadIsClear(board, start, dest, verbose)
end

local function exposed(board, color)
	-- only test for queen, rook, bishop.
	local king = findPieces(board, KING, color)[1]
	for ind = 1, 63 do
		local letter = board[ind]
		if letter then
			local _, pcolor = charToPiece(letter)
			if pcolor ~= color and canMove(board, ind, king, true) then
				return true
			end
		end
	end
end

local function clone(orig)
	local res = {}
	for k, v in pairs(orig) do
		res[k] = v
	end
	return res
end

local function place(board, piece, color, file, row)
	-- in case of chess960, we have to search
	board[ambigToIndex(file, row)] = pieceToChar(piece, color)
	return board
end

local function clear(board, file, row)
	board[ambigToIndex(file, row)] = nil
	return board
end

local function doCastle(board, color, side)
	local row = color == WHITE and 0 or 7
	local startFile, step = 0, 1
	local kingDestFile, rookDestFile = 2, 3
	local king = findPieces(board, KING, color)[1]
	local rook
	if side == KINGSIDE then
		startFile, step = 7, -1
		kingDestFile, rookDestFile = 6, 5
	end
	for file = startFile, 7 - startFile, step do
		local piece = pieceAt(board, file, row)
		if piece == ROOK then
			rook = coordsToIndex(file, row)
			break
		end
	end
	board = clear(board, king)
	board = clear(board, rook)
	board = place(board, KING, color, kingDestFile, row)
	board = place(board, ROOK, color, rookDestFile, row)
	return board
end

local function doEnPassant(board, pawn, file, row)
	local _, color = pieceAt(board, pawn)
	board = clear(board, pawn)
	board = place(board, PAWN, color, file, row)
	if row == 5 then
		board = clear(board, file, 4)
	end
	if row == 2 then
		board = clear(board, file, 3)
	end
	return board
end

local function generateFen(board)
	local res = ''
	for row = 7, 0, -1 do
		for file = 0, 7 do
			piece = board[coordsToIndex(file, row)]
			res = res .. (piece or '1')
		end
		if row > 0 then
			res = res .. '/'
		end
	end
	return mw.ustring.gsub(res, '1+', function(s)
		return #s
	end)
end

local function findCandidate(board, piece, color, oldFile, oldRow, file, row, capture, notation)
	local enpassant = {}
	local candidates, newCands = findPieces(board, piece, color), {} -- all black pawns or white kings etc.
	if oldFile or oldRow then
		local newCands = {}
		for _, cand in ipairs(candidates) do
			local file, row = indexToCoords(cand)
			if file == oldFile then
				table.insert(newCands, cand)
			end
			if row == oldRow then
				table.insert(newCands, cand)
			end
		end
		candidates, newCands = newCands, {}
	end
	local dest = coordsToIndex(file, row)
	for _, candidate in ipairs(candidates) do
		local can
		can, enpassant[candidate] = canMove(board, candidate, dest, capture)
		if can then
			table.insert(newCands, candidate)
		end
	end

	candidates, newCands = newCands, {}
	if #candidates == 1 then
		return candidates[1], enpassant[candidates[1]]
	end
	if #candidates == 0 then
		error('could not find a piece that can execute ' .. notation)
	end
	-- we have more than one candidate. this means that all but one of them can't really move, b/c it will expose the king
	-- test for it by creating a new board with this candidate removed, and see if the king became exposed
	for _, candidate in ipairs(candidates) do
		local cloneBoard = clone(board) -- first, clone the board
		cloneBoard = clear(cloneBoard, candidate) -- now, remove the piece
		if not exposed(cloneBoard, color) then
			table.insert(newCands, candidate)
		end
	end
	candidates, newCands = newCands, {}
	if #candidates == 1 then
		return candidates[1]
	end
	error(mw.ustring.format('too many (%d, expected 1) pieces can execute %s at board %s', #candidates, notation, generateFen(board)))
end

local function move(board, notation, color)
	local endGame = { ['1-0'] = true, ['0-1'] = true, ['1/2-1/2'] = true, ['*'] = true }

	local cleanNotation = mw.ustring.gsub(notation, '[!?+# ]', '')

	if cleanNotation == 'O-O' then
		return doCastle(board, color, KINGSIDE)
	end
	if cleanNotation == 'O-O-O' then
		return doCastle(board, color, QUEENSIDE)
	end
	if endGame[cleanNotation] then
		return board, true
	end

	local pattern = '([RNBKQ]?)([a-h]?)([1-8]?)(x?)([a-h])([1-8])(=?[RNBKQ]?)'
	local _, _, piece, oldFile, oldRow, isCapture, file, row, promotion = mw.ustring.find(cleanNotation, pattern)
	oldFile, file = apply(charToFile, oldFile, file)
	oldRow, row = apply(charToRow, oldRow, row)
	piece = falseIfEmpty(piece) or PAWN
	promotion = falseIfEmpty(promotion)
	isCapture = falseIfEmpty(isCapture)
	local candidate, enpassant = findCandidate(board, piece, color, oldFile, oldRow, file, row, isCapture, notation) -- findCandidates should panic if # != 1
	if enpassant then
		return doEnPassant(board, candidate, file, row)
	end
	board[coordsToIndex(file, row)] = promotion and pieceToChar(promotion:sub(-1), color) or board[candidate]
	board = clear(board, candidate)
	return board
end

local function create(fen)
	-- converts FEN notation to 64 entry array of positions. copied from enwiki Module:Chessboard (in some distant past i prolly wrote it)
	local res = {}
	local row = 8
	-- Loop over rows, which are delimited by /
	for srow in string.gmatch("/" .. fen, "/%w+") do
		srow = srow:sub(2)
		row = row - 1
		local ind = row * 8
		-- Loop over all letters and numbers in the row
		for piece in srow:gmatch("%w") do
			if piece:match("%d") then
				-- if a digit
				ind = ind + piece
			else
				-- not a digit
				res[ind] = piece
				ind = ind + 1
			end
		end
	end
	return res
end

local function processMeta(grossMeta)
	res = {}
	-- process grossMEta here
	for item in mw.ustring.gmatch(grossMeta or '', '%[([^%]]*)%]') do
		key, val = item:match('([^"]+)"([^"]*)"')
		if key and val then
			res[mw.text.trim(key)] = mw.text.trim(val) -- add mw.text.trim()
		else
			error('strange item detected: ' .. item .. #items) -- error later
		end
	end
	return res
end

local function analyzePgn(pgn)
	local grossMeta = pgn:match('%[(.*)%]') -- first open to to last bracket
	pgn = string.gsub(pgn, '%[(.*)%]', '')
	local steps = mw.text.split(pgn, '%s*%d+%.%s*')
	local moves = {}
	for _, step in ipairs(steps) do
		if mw.ustring.len(mw.text.trim(step)) then
			ssteps = mw.text.split(step, '%s+')
			for _, sstep in ipairs(ssteps) do
				if sstep and not mw.ustring.match(sstep, '^%s*$') then
					table.insert(moves, sstep)
				end
			end
		end
	end
	return processMeta(grossMeta), moves
end

local function pgn2fen(pgn)
	local metadata, notationList = analyzePgn(pgn)
	local fen = metadata.fen or DEFAULT_BOARD
	local board = create(fen)
	local res = { fen }
	local colors = { BLACK, WHITE }
	for step, notation in ipairs(notationList) do
		local color = colors[step % 2 + 1]
		board = move(board, notation, color)
		local fen = generateFen(board)
		table.insert(res, fen)
	end
	return res, metadata
end

-- End Module:Pgn

-- start Module:Chessboard


local function innerboard(definedPieces, pieceInfo, size, rev)
	pattern = cfg.pattern or '%w%w'
	local root = mw.html.create('div')
	root:addClass('chess-pieces notheme')
		:css('position', 'relative')
		:wikitext(cfg.image_board(size))

	for piece in pairs(definedPieces) do
		if piece:match(pattern) then
			local img = cfg.image_square(piece:match(pattern), row, col, size)
			local curPos = pieceInfo[1][piece] or { -1, -1 }
			root:tag('div')
				:css('top', 'calc(var(--calculator-top_piece' .. piece .. ',' .. curPos[1] .. ')*1px)')
				:css('left', 'calc(var(--calculator-left_piece' .. piece .. ',' .. curPos[2] .. ')*1px)')
				:css('z-index', 'min(var(--calculator-top_piece' .. piece .. ',' .. curPos[1] .. '),0)')
				:wikitext(img)
		end
	end

	return tostring(root)
end

local function getPositions(args, size, rev)
	pattern = cfg.pattern or '%w%w'
	local pieceInfo = {}
	local definedPieces = {}

	for moveIndex, move in ipairs(args) do
		pieceInfo[moveIndex] = {}
		local layout = convertFenToArgs(move)
		for trow = 1, nrows do
			local row = rev and trow or (1 + nrows - trow)
			for tcol = 1, ncols do
				local col = rev and (1 + ncols - tcol) or tcol
				local piece = layout[ncols * (nrows - row) + col + 2] or ''
				local pieceName = piece:match(pattern)
				if pieceName then
					-- Maximum number of pieces of the same type and color is 10
					-- (eg. 2 rooks + 8 pawns each promoted to a rook)
					local pieceIdx = 1
					for i = 1, 10 do
						if not pieceInfo[moveIndex][pieceName .. i] then
							pieceIdx = i
							break
						end
					end
					definedPieces[pieceName .. pieceIdx] = true
					pieceInfo[moveIndex][pieceName .. pieceIdx] = { (trow - 1) * size, (tcol - 1) * size }
				end
			end
		end
	end

	return definedPieces, pieceInfo
end

function chessboard(definedPieces, pieceInfo, size, rev, letters, numbers, header, footer, align, clear)
	function letters_row(rev, num_lt, num_rt)
		local letters = cfg.letters()
		local root = mw.html.create('')
		if num_lt then
			root:tag('td')
		end
		for k = 1, ncols do
			root:tag('td')
				:css('height', '18px')
				:css('width', size .. 'px')
				:wikitext(rev and letters[1 + ncols - k] or letters[k])
		end
		if num_rt then
			root:tag('td')
		end
		return tostring(root)
	end

	local letters_top = letters:match('both') or letters:match('top')
	local letters_bottom = letters:match('both') or letters:match('bottom')
	local numbers_left = numbers:match('both') or numbers:match('left')
	local numbers_right = numbers:match('both') or numbers:match('right')
	local width = ncols * size + 2
	if (numbers_left) then
		width = width + 18
	end
	if (numbers_right) then
		width = width + 18
	end

	local root = mw.html.create('div')
				   :addClass('chessboard')
				   :addClass('calculator-container')
				   :addClass('thumb')
				   :addClass('noviewer')
				   :addClass(align)
	if (header and header ~= '') then
		root:tag('div')
			:addClass('center')
			:css('line-height', '130%')
			:css('margin', '0 auto')
			:css('max-width', (width + ncols) .. 'px')
			:wikitext(header)
	end
	local div = root:tag('div')
					:addClass('thumbinner')
					:css('width', width .. 'px')
	local b = div:tag('table')
				 :attr('cellpadding', '0')
				 :attr('cellspacing', '0')
				 :addClass('calculator-field')
				 :attr('data-calculator-type', 'passthru')
				 :attr('data-calculator-formula', 'rotate')

	if (letters_top) then
		b:tag('tr')
		 :wikitext(letters_row(rev, numbers_left, numbers_right))
	end
	local tablerow = b:tag('tr')
	if (numbers_left) then
		tablerow:tag('td')
				:css('width', '18px')
				:css('height', size .. 'px')
				:wikitext(rev and 1 or nrows)
	end
	local td = tablerow:tag('td')
					   :attr('colspan', ncols)
					   :attr('rowspan', nrows)
					   :addClass('pieces')
					   :wikitext(innerboard(definedPieces, pieceInfo, size, rev))

	if (numbers_right) then
		tablerow:tag('td')
				:css('width', '18px')
				:css('height', size .. 'px')
				:wikitext(rev and 1 or nrows)
	end
	if (numbers_left or numbers_right) then
		for trow = 2, nrows do
			local idx = rev and trow or (1 + nrows - trow)
			tablerow = b:tag('tr')
			if (numbers_left) then
				tablerow:tag('td')
						:css('height', size .. 'px')
						:wikitext(idx)
			end
			if (numbers_right) then
				tablerow:tag('td')
						:css('height', size .. 'px')
						:wikitext(idx)
			end
		end
	end
	if (letters_bottom) then
		b:tag('tr')
		 :wikitext(letters_row(rev, numbers_left, numbers_right))
	end

	if footer and mw.text.trim(footer) ~= '' then
		div:tag('div')
		   :addClass('thumbcaption')
		   :wikitext(footer)
	end

	return tostring(root) ..
		mw.getCurrentFrame():extensionTag('templatestyles', '', { src = 'Module:Chessboard/styles.css' })
end

function convertFenToArgs(fen)
	-- converts FEN notation to 64 entry array of positions, offset by 2
	local res = { ' ', ' ' }
	-- Loop over rows, which are delimited by /
	for srow in string.gmatch("/" .. fen, "/%w+") do
		-- Loop over all letters and numbers in the row
		for piece in srow:gmatch("%w") do
			if piece:match("%d") then
				-- if a digit
				for k = 1, piece do
					table.insert(res, ' ')
				end
			else
				-- not a digit
				local color = piece:match('%u') and 'l' or 'd'
				piece = piece:lower()
				table.insert(res, piece .. color)
			end
		end
	end

	return res
end

local function getPieceMoves(definedPieces, pieceInfo)
	local calc = Calculator:new { scoped = false }
	for piece in pairs(definedPieces) do
		local curTop = -1
		local curLeft = -1
		local switchTop = 'switch(move,'
		local switchLeft = 'switch(move,'
		for moveNumber, move in ipairs(pieceInfo) do
			if (move[piece] and move[piece][1] or -1) ~= curTop then
				switchTop = switchTop .. (moveNumber - 1) .. ',' .. curTop .. ','
				curTop = (move[piece] and move[piece][1] or -1)
			end
			if (move[piece] and move[piece][2] or -1) ~= curLeft then
				switchLeft = switchLeft .. (moveNumber - 1) .. ',' .. curLeft .. ','
				curLeft = (move[piece] and move[piece][2] or -1)
			end
		end
		switchTop = switchTop .. curTop .. ')'
		switchLeft = switchLeft .. curLeft .. ')'

		calc:hidden {
			id = 'top_piece' .. piece,
			formula = switchTop
		}
		calc:hidden {
			id = 'left_piece' .. piece,
			formula = switchLeft
		}
	end
	return tostring(calc)
end

function p.board(frame)
	local args = frame.args
	local pargs = frame:getParent().args
	nrows, ncols = cfg.dims()

	local size = args.size or pargs.size or '26'
	local reverse = (args.reverse or pargs.reverse or ''):lower() == "true"
	local letters = (args.letters or pargs.letters or 'both'):lower()
	local numbers = (args.numbers or pargs.numbers or 'both'):lower()
	local header = args[2] or pargs[2] or ''
	local footer = args[nrows * ncols + 3] or pargs[nrows * ncols + 3] or ''
	local align = (args[1] or pargs[1] or 'tright'):lower()
	local clear = args.clear or pargs.clear or (align:match('tright') and 'right') or 'none'

	local pgn = args.pgn or pargs.pgn
	local moves, metadata
	local definedPieces, pieceInfo

	size = mw.ustring.match(size, '[%d]+') or '26' -- remove px from size

	assert(pgn, "pgn argument required")
	moves, metadata = pgn2fen(pgn)
	definedPieces, pieceInfo = getPositions(moves, size, reverse)

	align = args.align or pargs.align or 'tright'
	clear = args.clear or pargs.clear or (align:match('tright') and 'right') or 'none'
	header = args.header or pargs.header or ''
	footer = args.footer or pargs.footer or ''
	if args.animate or pargs.animate then
		align = align .. ' animate'
	end
	local controls = Calculator:new { scoped = false, noJSFallback = '' }
	controls:button { text = '|←', ['for'] = 'move', type = 'default', formula = 1 }
	controls:button { text = '←', ['for'] = 'move', type = 'default', formula = 'max(1, move-1)' }
	controls:button { text = '☯', ['for'] = 'rotate', type = 'default', formula = '(rotate+1)%2' }
	controls:button { text = '→', ['for'] = 'move', type = 'default', formula = 'min('.. #moves..', move+1)' }
	controls:button { text = '→|', ['for'] = 'move', type = 'default', formula = #moves }
	controls:hidden { id = 'move', default = 1 }
	controls:hidden { id = 'rotate', default = 0 }

	header = header .. tostring(controls)
	footer = footer
		.. frame:extensionTag('templatestyles', '', { src = 'Module:Sandbox/SD0001/Chess3/animations.css' })
		.. getPieceMoves(definedPieces, pieceInfo)
	return chessboard(definedPieces, pieceInfo, size, reverse, letters, numbers, header, footer, align, clear)
end

return p

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.