blob: d50ca323fa52e64da0f061c4e7492cc6fc2040b1 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 1.5.8">
<title>Overview</title>
<style>
@import url("backtotop.css");
/* ========================================================================== HTML5 display definitions ========================================================================== */
/** Correct `block` display not defined in IE 8/9. */
@import url(https://fast.fonts.net/cssapi/20974f8a-0939-4574-aef9-681eda2faca8.css);
article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary { display: block; }
/** Correct `inline-block` display not defined in IE 8/9. */
audio, canvas, video { display: inline-block; }
/** Prevent modern browsers from displaying `audio` without controls. Remove excess height in iOS 5 devices. */
audio:not([controls]) { display: none; height: 0; }
/** Address `[hidden]` styling not present in IE 8/9. Hide the `template` element in IE, Safari, and Firefox < 22. */
[hidden], template { display: none; }
script { display: none !important; }
/* ========================================================================== Base ========================================================================== */
/** 1. Set default font family to sans-serif. 2. Prevent iOS text size adjust after orientation change, without disabling user zoom. */
html { /* 1 */ -ms-text-size-adjust: 100%; /* 2 */ -webkit-text-size-adjust: 100%; /* 2 */ background-color: #D5DFEA; }
/** Remove default margin. */
body { margin: 0; background-color: #D5DFEA; font-family:sans-serif; font-weight: 400} /* add margin-right 0 here for mobile*/
/* ========================================================================== Links ========================================================================== */
/** Remove the gray background color from active links in IE 10. */
a { background: transparent; }
/** Address `outline` inconsistency between Chrome and other browsers. */
a:focus { outline: thin dotted; }
/** Improve readability when focused and also mouse hovered in all browsers. */
a:active, a:hover { outline: 0; }
/* ========================================================================== Typography ========================================================================== */
/** Address variable `h1` font-size and margin within `section` and `article` contexts in Firefox 4+, Safari 5, and Chrome. */
h1 { font-size: 2em; margin: 0.67em 0; }
/** Address styling not present in IE 8/9, Safari 5, and Chrome. */
abbr[title] { border-bottom: 1px dotted; }
/** Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. */
b, strong { font-weight: 600; }
/** Address styling not present in Safari 5 and Chrome. */
dfn { font-style: italic; }
/** Address differences between Firefox and other browsers. */
hr { -moz-box-sizing: content-box; box-sizing: content-box; height: 0; }
/** Address styling not present in IE 8/9. */
mark { background: #ff0; color: #000; }
/** Correct font family set oddly in Safari 5 and Chrome. */
code, kbd, pre, samp { font-family: Fira Mono, monospace, serif; font-size: 1em; }
/** Improve readability of pre-formatted text in all browsers. */
pre { white-space: pre-wrap; }
/** Set consistent quote types. */
q { quotes: "\201C" "\201D" "\2018" "\2019"; }
/** Address inconsistent and variable font size in all browsers. */
small { font-size: 80%; }
/** Prevent `sub` and `sup` affecting `line-height` in all browsers. */
sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
sup { top: -0.5em; }
sub { bottom: -0.25em; }
/* ========================================================================== Embedded content ========================================================================== */
/** Remove border when inside `a` element in IE 8/9. */
img { border: 0; }
/** Correct overflow displayed oddly in IE 9. */
svg:not(:root) { overflow: hidden; }
/* ========================================================================== Figures ========================================================================== */
/** Address margin not present in IE 8/9 and Safari 5. */
figure { margin: 0; }
/* ========================================================================== Forms ========================================================================== */
/** Define consistent border, margin, and padding. */
fieldset { border: 1px solid #c0c0c0; margin: 0 2px; padding: 0.35em 0.625em 0.75em; }
/** 1. Correct `color` not being inherited in IE 8/9. 2. Remove padding so people aren't caught out if they zero out fieldsets. */
legend { border: 0; /* 1 */ padding: 0; /* 2 */ }
/** 1. Correct font family not being inherited in all browsers. 2. Correct font size not being inherited in all browsers. 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. */
button, input, select, textarea { font-family: inherit; /* 1 */ font-size: 100%; /* 2 */ margin: 0; /* 3 */ }
/**
#tocbutton {
top: 0;
left: 13rem;
position:fixed;
z-index: 1000;
}
*/
/** Address Firefox 4+ setting `line-height` on `input` using `!important` in the UA stylesheet. */
button, input { line-height: normal; }
/** Address inconsistent `text-transform` inheritance for `button` and `select`. All other form control elements do not inherit `text-transform` values. Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. Correct `select` style inheritance in Firefox 4+ and Opera. */
button, select { text-transform: none; }
/** 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls. 2. Correct inability to style clickable `input` types in iOS. 3. Improve usability and consistency of cursor style between image-type `input` and others. */
button, html input[type="button"], input[type="reset"], input[type="submit"] { -webkit-appearance: button; /* 2 */ cursor: pointer; /* 3 */ }
/** Re-set default cursor for disabled elements. */
button[disabled], html input[disabled] { cursor: default; }
/** 1. Address box sizing set to `content-box` in IE 8/9. 2. Remove excess padding in IE 8/9. */
input[type="checkbox"], input[type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ }
/** 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome (include `-moz` to future-proof). */
input[type="search"] { -webkit-appearance: textfield; /* 1 */ -moz-box-sizing: content-box; -webkit-box-sizing: content-box; /* 2 */ box-sizing: content-box; }
/** Remove inner padding and search cancel button in Safari 5 and Chrome on OS X. */
input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; }
/** Remove inner padding and border in Firefox 4+. */
button::-moz-focus-inner, input::-moz-focus-inner { border: 0; padding: 0; }
/** 1. Remove default vertical scrollbar in IE 8/9. 2. Improve readability and alignment in all browsers. */
textarea { overflow: auto; /* 1 */ vertical-align: top; /* 2 */ }
/* ========================================================================== Tables ========================================================================== */
/** Remove most spacing between table cells. */
table { border-collapse: collapse; border-spacing: 0; }
meta.foundation-mq-small { font-family: "only screen and (min-width: 768px)"; width: 768px; }
meta.foundation-mq-medium { font-family: "only screen and (min-width:1280px)"; width: 1280px; }
meta.foundation-mq-large { font-family: "only screen and (min-width:1440px)"; width: 1440px; }
*, *:before, *:after { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; }
html, body { background-color:#527AA3; }
body { background: white; color: #222222; padding: ; margin: 0; font-family:sans-serif, Helvetica, Arial, sans-serif; font-weight: 400; font-style: normal; position: relative; cursor: auto; padding-left: 2rem; padding-right: 2rem;}
a:hover { cursor: pointer; }
img, object, embed { height: auto; max-width: 90%; }
object, embed { height: 100%; }
img { -ms-interpolation-mode: bicubic; }
#map_canvas img, #map_canvas embed, #map_canvas object, .map_canvas img, .map_canvas embed, .map_canvas object { max-width: none !important; }
.left { float: left !important; }
.right { float: right !important; }
.text-left { text-align: left !important; }
.text-right { text-align: right !important; }
.text-center { text-align: center !important; }
.text-justify { text-align: justify !important; }
.hide { display: none; }
.antialiased, body { -webkit-font-smoothing: antialiased; }
img { display: inline-block; vertical-align: baseline; }
textarea { height: auto; min-height: 50px; }
select { width: 100%; }
object, svg { display: inline-block; vertical-align: middle; }
.center { margin-left: auto; margin-right: auto; }
.spread { width: 100%; margin-right: 2rem; }
p.lead, .paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p { font-size: 1em; line-height: 1.6; }
/* Typography padding etc */
.subheader, .admonitionblock td.content > .title, .audioblock > .title, .exampleblock > .title, .imageblock > .title, .listingblock > .title, .literalblock > .title, .stemblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, table.tableblock > .title, .verseblock > .title, .videoblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title { line-height: 2.4; color: #132445; font-weight: 400; margin-top: 0em; margin-bottom: 0.5em; }
/* Typography resets */
div, dl, dt, dd, ul, ol, li, h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6, pre, form, p, blockquote, th, td { margin: 0; padding: 0; direction: ltr; }
div.openblock.partintro, div.sectionbody.paragraph {font-weight: 500; line-height: 1.4; margin-bottom: 1em; }
div.sect1 {padding-top: 1rem;}
div.paragraph.faq-intro {max-width: 66%;}
/* Default Link Styles */
a { color: #6999d6; text-decoration: none; line-height: inherit; }
a:hover, a:focus { color: #132445; }
a img { border: none; }
/* Grey links with black transition
a { color: #2ba6cb; text-decoration: none; line-height: inherit; color: rgba(0,0,0,.3); transition: .2s; }
a:active, a:hover, a:focus { color: #212121; }
a img { border: none; }
*/
/* Default paragraph styles */
p { font-family:sans-serif; font-weight: 400; font-size: 1.2rem; line-height: 1.4; padding-bottom: 0.5em; }
p aside { font-size: 0.575em; line-height: 1.35; font-style: italic; }
div.p, { width: 100% }
/* Default header styles */
h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { font-family: sans-serif; font-weight: 600; font-style: normal; color: #244d82; text-rendering: optimizeLegibility; margin-bottom: 0em; line-height: 1.2125em; margin-top:; 2rem; }
h1 small, h2 small, h3 small, #toctitle small, .sidebarblock > .content > .title small, h4 small, h5 small, h6 small { font-size: 60%; color: #6999d6; line-height: 0; }
h1 { font-size: 2.125em; max-width:66.66%;}
h2 { font-size: 1.6875em; }
h3, #toctitle, .sidebarblock > .content > .title { font-size: 1.375em; }
h4 { font-size: 1.125em; }
h5 { font-size: 1.125em; }
h6 { font-size: 1em; }
hr { border: solid #dddddd; border-width: 1px 0 0; clear: both; margin: 1.25em 0 1.1875em; height: 0; }
/* Helpful Typography Defaults */
em, i { font-style: italic; line-height: inherit; }
strong, b { font-weight: 600; line-height: inherit; }
small { font-size: 60%; line-height: inherit; }
code { font-family: Fira Mono, Consolas, "Liberation Mono", Courier, monospace; }
/* Lists */
ul, ol, dl { list-style-position: outside; font-family:sans-serif; padding-left: 0rem; list-style-type: none}
ul, ol { margin-left: 0em; }
ul.no-bullet, ol.no-bullet { margin-left: 1.5em; margin-bottom: 0;}
/* Unordered Lists */
ul li ul, ul li ol { margin-left: 1.25em; margin-bottom: 0; font-size: 1em; /* Override nested font-size change */ }
ul.square li ul, ul.circle li ul, ul.disc li ul { list-style: inherit; }
ul.square { list-style-type: square; }
ul.circle { list-style-type: circle; }
ul.disc { list-style-type: none; }
ul.no-bullet { list-style: none; }
/* Ordered Lists */
ol li ul, ol li ol { margin-left: 1.25em; margin-bottom: 0; }
/* Definition Lists */
dl dt { margin-bottom: 0.3125em; font-weight: bold; font-size: 1.2em; font-style: italic}
dl dd { margin-bottom: 1.25em; }
/* Abbreviations */
abbr, acronym { text-transform: uppercase; font-size: 90%; color: #222222; border-bottom: 1px dotted #dddddd; cursor: help; }
abbr { text-transform: none; }
/* Blockquotes */
blockquote { margin: 0 0 1.25em; padding: 0.5625em 1.25em 0 1.1875em; border-left: 1px solid #dddddd; }
blockquote cite { display: block; font-size: inherit; color: color: #132445; }
blockquote cite:before { content: "\2014 \0020"; }
blockquote cite a, blockquote cite a:visited { color: #417dcb; }
blockquote, blockquote p { line-height: 1.6; color: #132445; }
/* Microformats */
.vcard { display: inline-block; margin: 0 0 1.25em 0; border: 1px solid #dddddd; padding: 0.625em 0.75em; }
.vcard li { margin: 0; display: block; }
.vcard .fn { font-weight: bold; font-size: 0.9375em; }
.vevent .summary { font-weight: bold; }
.vevent abbr { cursor: auto; text-decoration: none; font-weight: bold; border: none; padding: 0 0.0625em; }
@media only screen and (min-width: 768px) { h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { line-height: 1.4; margin-top: 1rem; margin-bottom: 0.2rem;}
h1 { font-size: 2.75em; }
h2 { font-size: 2.3125em; }
h3, #toctitle, .sidebarblock > .content > .title { font-size: 1.6875em; }
h4 { font-size: 1.4375em; } }
/* Tables */
table { background: white; margin-bottom: 1.25em; border: solid 1px #dddddd; }
table thead, table tfoot { background: whitesmoke; font-weight: 600; }
table thead tr th, table thead tr td, table tfoot tr th, table tfoot tr td { padding: 0.5em 0.625em 0.625em; font-size: inherit; color: #222222; text-align: left; }
table tr th, table tr td { padding: 0.5625em 0.625em; font-size: inherit; color: #222222; }
table tr.even, table tr.alt, table tr:nth-of-type(even) { background: #f9f9f9; }
table thead tr th, table tfoot tr th, table tbody tr td, table tr td, table tfoot tr td { display: table-cell; line-height: 1.4; }
/* FEATURE TABLE */
table.done, tr.done.alt, table.done tr:nth-of-type(even) {
background: #efe;
padding-top: 0;
padding-bottom: 0;
border: none;
margin-bottom: -1px;
}
table.most, tr.most.alt, table.most tr:nth-of-type(even) {
background: #ffd;
padding-top: 0;
padding-bottom: 0;
border: none;
margin-bottom: -1px;
}
table.tbc, tr.tbc.alt, table.tbc tr:nth-of-type(even) {
background: #fff6de;
padding-top: 0;
padding-bottom: 0;
border: none;
margin-bottom: -1px;
}
table.tbd, tr.tbd.alt, table.tbd tr:nth-of-type(even) {
background: #fee;
padding-top: 0;
padding-bottom: 0;
border: none;
margin-bottom: -1px;
}
table.done thead tr th, table.done tfoot tr th, table.done tfoot tr td, table.done.sect2, table.most thead tr th, table.most tfoot tr th, table.most tfoot tr td, table.most.sect2, table.tbc thead tr th, table.tbc tfoot tr th, table.tbc tfoot tr td, table.tbc.sect2, table.tbd thead tr th, table.tbd tfoot tr th, table.tbd tfoot tr td, table.tbd.sect2 {background: white; font-size: 1.9rem; color: #417dcb; }
/*
green "done" = #efe
yellow "most" = #ffd
orange "tbc" = #fff6de
red "tbd" = #fee
*/
body { tab-size: 4; max-width: 1050px; margin-right: auto; margin-left: auto; position: relative; margin-top: 0rem; margin-bottom: 0rem; padding-top: 0rem; /* Fixes tables, breaks headers */}
h1, h2, h3, #toctitle, .sidebarblock > .content > .title, h4, h5, h6 { line-height: 1.4; margin-top: 0rem;}
.clearfix:before, .clearfix:after, .float-group:before, .float-group:after { content: " "; display: table; }
.clearfix:after, .float-group:after { clear: both; }
*:not(pre) > code { font-size: inherit; font-style: normal !important; letter-spacing: 0; padding: 0; line-height: inherit; }
pre, pre > code { line-height: 1.4; color: black; font-family: monospace, serif; font-weight: normal; }
.keyseq { color: #555555; }
kbd { font-family: Consolas, "Liberation Mono", Courier, monospace; display: inline-block; color: #222222; font-size: 0.65em; line-height: 1.45; background-color: #f7f7f7; border: 1px solid #ccc; -webkit-border-radius: 3px; border-radius: 3px; -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 0.1em white inset; box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 0.1em white inset; margin: 0 0.15em; padding: 0.2em 0.5em; vertical-align: middle; position: relative; top: -0.1em; white-space: nowrap; }
.keyseq kbd:first-child { margin-left: 0; }
.keyseq kbd:last-child { margin-right: 0; }
.menuseq, .menu { color: #090909; }
b.button:before, b.button:after { position: relative; top: -1px; font-weight: normal; }
b.button:before { content: "["; padding: 0 3px 0 2px; }
b.button:after { content: "]"; padding: 0 2px 0 3px; }
#header, #content, #footnotes, #footer { max-width: 1050px; margin-right: auto; margin-left: auto; position: relative; margin-top: 0rem; margin-bottom: 0rem; padding-top: 0rem; padding-right: 0rem;}
#header:before, #header:after, #content:before, #content:after, #footnotes:before, #footnotes:after, #footer:before, #footer:after { content: " "; display: table; }
#header:after, #content:after, #footnotes:after, #footer:after { clear: both; }
#content:before { content: none; }
#content {padding-left: 0.5rem;}
#header > h1:first-child { color: black; font-weight: bold; margin-top: 2.25rem; margin-bottom: 0; }
#header > h1:first-child + #toc { margin-top: 8px; border-top: 1px solid #dddddd; }
#header > h1:only-child, body.toc2 #header > h1:nth-last-child(2) { border-bottom: 1px solid #dddddd; padding-bottom: 8px; }
#header .details { border-bottom: 1px solid #dddddd; line-height: 1.45; padding-top: 0.25em; padding-bottom: 0.25em; padding-left: 0.25em; color: #417dcb; display: -ms-flexbox; display: -webkit-flex; display: flex; -ms-flex-flow: row wrap; -webkit-flex-flow: row wrap; flex-flow: row wrap; }
#header .details span:first-child { margin-left: -0.125em; }
#header .details span.email a { color: #6999d6; }
#header .details br { display: none; }
#header .details br + span:before { content: "\00a0\2013\00a0"; }
#header .details br + span.author:before { content: "\00a0\22c5\00a0"; color: #6999d6; }
#header .details br + span#revremark:before { content: "\00a0|\00a0"; }
#header #revnumber { text-transform: capitalize; }
#header #revnumber:after { content: "\00a0"; }
#content > h1:first-child:not([class]) { color: black; font-weight: bold; border-bottom: 1px solid #dddddd; max-width: 1050px; margin-right: auto; margin-left: auto; position: relative; margin-top: 4rem; margin-bottom: 4rem; padding-top: 0rem; }
/* ========================================================================== Table of Contents ======================================================================= */
#toc { border-bottom: 1px solid #dddddd; padding-bottom: 0.5em; position: relative; left: 0;}
#toc > ul { margin-left: 0.125em; padding-left: 1em; }
#toc ul.sectlevel0 > li > a { font-style: italic; }
#toc ul.sectlevel0 ul.sectlevel1 { margin: 0.5em 0; }
#toc ul { font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; list-style-type: none; }
#toc li { line-height: 1.3334; margin-top: 0.3334em; }
#toc a { text-decoration: none; }
#toc a:active { text-decoration: underline; }
#toc ul li:before {
content: "›";
margin-left: -.75em;
margin-right: .4em;
color: #244d82
}
div.ulist li:before {
content: "›";
position: absolute;
margin-top: .2rem;
font-size: x-large;
margin-left: -.75em;
margin-bottom: -.75em;
margin-right: 0;
line-height: 1rem;
color: #244d82
}
#toctitle { color: #244d82; font-size: 1.2em; padding-left: 1em; }
#faq {
position: relative;
right: 9.3rem;
top: 9rem;
margin-bottom: 20px;
left: 45rem;
z-index:1;padding-left:2rem;border-left:1px solid #d3d3d3
}
@media only screen and (max-width: 945px) {
div#faq { display: none; }
}
#faq h2 {
font-size: 25px;
font-weight: 600;
margin-top: -8rem;
}
div#faq li:before {
content: "›";
position: absolute;
font-size: x-large;
margin-left: -.75em;
margin-bottom: -.75em;
margin-right: 0;
line-height: 1rem;
color: #244d82
}
#features-nav {
position: absolute;
right: 1rem;
top: 2rem;
margin-bottom: 20px;
position:absolute;z-index:1;padding-left:2rem;border-left:1px solid #d3d3d3
}
@media only screen and (max-width: 993px) {
#features-nav { display: none; }
}
#features-nav h2 {
font-size: 25px;
font-weight: 600;
margin-top: -1rem;
}
#features-nav li {
margin-top: .3rem;
}
div#features-nav li:before {
content: "›";
position: absolute;
font-size: x-large;
margin-left: -.75em;
margin-bottom: -.75em;
margin-right: 0;
line-height: 1rem;
color: #244d82
}
@media only screen and (min-width: 1434px) { body.toc2.toc-right #toc.toc2 { border-right-width: 0; border: none; left: 0px; } }
@media only screen and (min-width: 1434px) { #toctitle { padding-top: 1.5rem; font-size: 1.375em; }
body.toc2 { padding-left: 2em; padding-right: 1em; }
#toc.toc2 { margin-top: 0 !important; background-color: #f2f2f2; position: fixed; width: 12em; left: 0; top: 0; border-right: 1px solid #dddddd; border-top-width: 0 !important; border-bottom-width: 0 !important; z-index: 1000; padding: 1.25em 0.25em 0em 0.25em; height: 100%; overflow: auto; }
#toc.toc2 #toctitle { margin-top: 0; margin-bottom: 0.8rem; font-size: 1.2em; padding-left: 1em;}
#toc.toc2 > ul { font-size: 0.9em; margin-bottom: 0; }
#toc.toc2 ul ul { margin-left: 1em; padding-left: .3em; }
#toc.toc2 ul.sectlevel0 ul.sectlevel1 { padding-left: 0; margin-top: 0.5em; margin-bottom: 0.5em; }
body.toc2.toc-right { padding-left: 2em; padding-right: 2em; }
body.toc2.toc-right #toc.toc2 { border-right-width: 0; border-left: 1px solid #dddddd; left: auto; right: -13rem; } }
@media only screen and (min-width: 1535px) {
body.toc2 { padding-left: 2em; padding-right: 2em; }
#toctitle { padding-top: 0rem; font-size: 1.375em; }
#toc.toc2 { width: 13em; }
#toc.toc2 #toctitle { font-size: 1.375em; }
#toc.toc2 > ul { font-size: 0.95em; }
#toc.toc2 ul ul { padding-left: 0; }
body.toc2.toc-right { padding-left: 2em; padding-right: 2em; } }
#content #toc { border-style: solid; border-width: 1px; border-color: #d9d9d9; margin-bottom: 1.25em; padding: 1.25em; background: #f2f2f2; -webkit-border-radius: 0; border-radius: 0; }
#content #toc > :first-child { margin-top: 0; }
#content #toc > :last-child { margin-bottom: 0; }
#footer { width: 1050px;background-color: #132445; padding: 1.25em; padding-bottom: 0rem; margin-right: -2rem; margin-left: -2rem; margin-top: 2rem; color: white}
div.social { line-height: 1.4; color: #FFFFFF;font-size: 1.2rem; font-weight: 400; font-style: bold; background-color: #132445; margin-right: -2rem; margin-left: -2rem; text-align: left; padding-bottom: 4px; padding-left: 25px; }
div.social li a { margin-bottom: 2em; color: #d5dfea;font-size: 1.2rem; font-weight: 800; font-style: bold; list-style: none; list-style-type: none; text-decoration-color: rgb(213, 223, 234); }
/* div.social a:visited { color: #244D82; }*/
div.social a:hover { color: #F7D425; }
div.social :first-child { margin-top: 0; }
div.social h2 { margin-bottom: 20px;font-weight: 600;font-size: 1.3em;margin-top: 4rem;color: #244d82;font-family: sans-serif;}
div.social li:before {content: "› "; color: #244d82;font-size: large;font-weight: 800;}
div.social ul {margin-top: -10px;line-height: 30px;}
div.social li {/* nothing */}
#bottomright {float: right;}
@media only screen and (max-width: 1050px) {
body {width: 100%;}
}
#footer-text { color: #dddddd; line-height: 1.44; }
.sect1 { padding-bottom: 0.625em; }
.sectionbody.paragraph {max-width: 66.666%}
.sectionbody ul {padding-left: 1rem;}
@media only screen and (min-width: 768px) { .sect1 { padding-bottom: 0em; } }
.sect1 + .sect1 { border-top: 0px solid #dddddd; }
#content h1 > a.anchor, h2 > a.anchor, h3 > a.anchor, #toctitle > a.anchor, .sidebarblock > .content > .title > a.anchor, h4 > a.anchor, h5 > a.anchor, h6 > a.anchor { position: absolute; z-index: 1001; width: 1.5ex; margin-left: -1.5ex; display: block; text-decoration: none !important; visibility: hidden; text-align: center; font-weight: 400; max-width: 1050px; }
#content h1 > a.anchor:before, h2 > a.anchor:before, h3 > a.anchor:before, #toctitle > a.anchor:before, .sidebarblock > .content > .title > a.anchor:before, h4 > a.anchor:before, h5 > a.anchor:before, h6 > a.anchor:before { content: "\2771"; font-size: 0.85em; display: block; padding-top: 0.1em; vertical-align: bas }
#content h1:hover > a.anchor, #content h1 > a.anchor:hover, h2:hover > a.anchor, h2 > a.anchor:hover, h3:hover > a.anchor, #toctitle:hover > a.anchor, .sidebarblock > .content > .title:hover > a.anchor, h3 > a.anchor:hover, #toctitle > a.anchor:hover, .sidebarblock > .content > .title > a.anchor:hover, h4:hover > a.anchor, h4 > a.anchor:hover, h5:hover > a.anchor, h5 > a.anchor:hover, h6:hover > a.anchor, h6 > a.anchor:hover { visibility: visible; }
#content h1 > a.link, h2 > a.link, h3 > a.link, #toctitle > a.link, .sidebarblock > .content > .title > a.link, h4 > a.link, h5 > a.link, h6 > a.link { color: #244d82; text-decoration: none; font-family: sans-serif}
#content h1 > a.link:hover, h2 > a.link:hover, h3 > a.link:hover, #toctitle > a.link:hover, .sidebarblock > .content > .title > a.link:hover, h4 > a.link:hover, h5 > a.link:hover, h6 > a.link:hover { color: #1e416e; }
.audioblock, .imageblock, .literalblock, .listingblock, .stemblock, .videoblock { margin-bottom: 1.25em; }
.admonitionblock td.content > .title, .audioblock > .title, .exampleblock > .title, .imageblock > .title, .listingblock > .title, .literalblock > .title, .stemblock > .title, .openblock > .title, .paragraph > .title, .quoteblock > .title, table.tableblock > .title, .verseblock > .title, .videoblock > .title, .dlist > .title, .olist > .title, .ulist > .title, .qlist > .title, .hdlist > .title { text-rendering: optimizeLegibility; text-align: left; }
table.tableblock > caption.title { white-space: nowrap; overflow: visible; max-width: 0; }
.paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p { color: black; max-width: 66%}
table.tableblock #preamble > .sectionbody > .paragraph:first-of-type p { font-size: inherit; }
.admonitionblock > table { border-collapse: separate; border: 0; background: none; max-width: 80%;}
.admonitionblock > table td.icon { text-align: center; width: 80px; }
.admonitionblock > table td.icon img { max-width: none; }
.admonitionblock > table td.icon .title { font-weight: bold; font-family: sans-serif, Georgia, Verdana, "Helvetica", Helvetica, Arial, sans-serif; text-transform: uppercase; }
.admonitionblock > table td.content { padding-left: 1.125em; padding-right: 1.25em; border-left: 1px solid #dddddd; color: #417dcb; }
.admonitionblock > table td.content > :last-child > :last-child { margin-bottom: 0; }
.exampleblock > .content { border-style: solid; border-width: 1px; border-color: #e6e6e6; margin-bottom: 1.25em; padding: 1.25em; background-color: #fffef7; -webkit-border-radius: 0; border-radius: 0; }
.exampleblock > .content > :first-child { margin-top: 0; }
.exampleblock > .content > :last-child { margin-bottom: 0; }
.sidebarblock { position: absolute; border-style: solid; border-width: 1px; border-color: #d9d9d9; margin: -2rem -7.5rem 0rem 63.65rem; padding: .2rem; background: #f2f2f2; -webkit-border-radius: 0; border-radius: 0; text-align: left; width: 5.5rem;}
.sidebarblock > :first-child { margin-top: 0; }
.sidebarblock > :last-child { margin-bottom: 0; }
.sidebarblock > .content > .title { color: #6999d6; margin-top: 0; }
@media only screen and (max-width: 1203px) {
.sidebarblock { position: absolute; right: 12%; }
}
@media only screen and (max-width: 817px) {
.sidebarblock { position: absolute; right: 18%; }
}
@media only screen and (max-width: 562px) {
.sidebarblock { position: absolute; right: 25%; }
}
.exampleblock > .content > :last-child > :last-child, .exampleblock > .content .olist > ol > li:last-child > :last-child, .exampleblock > .content .ulist > ul > li:last-child > :last-child, .exampleblock > .content .qlist > ol > li:last-child > :last-child, .sidebarblock > .content > :last-child > :last-child, .sidebarblock > .content .olist > ol > li:last-child > :last-child, .sidebarblock > .content .ulist > ul > li:last-child > :last-child, .sidebarblock > .content .qlist > ol > li:last-child > :last-child { margin-bottom: 0; }
.literalblock pre, .listingblock pre:not(.highlight), .listingblock pre[class="highlight"], .listingblock pre[class^="highlight "], .listingblock pre.CodeRay, .listingblock pre.prettyprint { background: #eeeeee; }
.sidebarblock .literalblock pre, .sidebarblock .listingblock pre:not(.highlight), .sidebarblock .listingblock pre[class="highlight"], .sidebarblock .listingblock pre[class^="highlight "], .sidebarblock .listingblock pre.CodeRay, .sidebarblock .listingblock pre.prettyprint { background: #f2f1f1; }
.literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { border: 1px solid #cccccc; -webkit-border-radius: 0; border-radius: 0; word-wrap: break-word; padding: 0.8em 0.8em 0.65em 0.8em; font-size: 0.8125em; }
.literalblock pre.nowrap, .literalblock pre[class].nowrap, .listingblock pre.nowrap, .listingblock pre[class].nowrap { overflow-x: auto; white-space: pre; word-wrap: normal; }
@media only screen and (min-width: 768px) { .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { font-size: 0.90625em; } }
@media only screen and (min-width: 1280px) { .literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] { font-size: 1em; } }
.literalblock.output pre { color: #eeeeee; background-color: black; }
.listingblock pre.highlightjs { padding: 0; margin-right: 0em; }
.listingblock pre.highlightjs > code { padding: 0.8em 2rem 0.65em 0.8em; -webkit-border-radius: 0; border-radius: 0; padding-right: 2rem;}
.listingblock > .content { position: relative; }
.listingblock code[data-lang]:before { display: none; content: attr(data-lang); position: absolute; font-size: 0.75em; top: 0.425rem; right: 0.5rem; line-height: 1; text-transform: uppercase; color: #999; padding-right: 2rem; }
.listingblock:hover code[data-lang]:before { display: none; }
.listingblock.terminal pre .command:before { content: attr(data-prompt); padding-right: 0.5em; color: #999; }
.listingblock.terminal pre .command:not([data-prompt]):before { content: "$"; }
table.pyhltable { border-collapse: separate; border: 0; margin-bottom: 0; background: none; }
table.pyhltable td { vertical-align: top; padding-top: 0; padding-bottom: 0; line-height: 1.4; }
table.pyhltable td.code { padding-left: .75em; padding-right: 0; }
pre.pygments .lineno, table.pyhltable td:not(.code) { color: #999; padding-left: 0; padding-right: .5em; border-right: 1px solid #dddddd; }
pre.pygments .lineno { display: inline-block; margin-right: .25em; }
table.pyhltable .linenodiv { background: none !important; padding-right: 0 !important; }
.quoteblock { margin: 0 1em 1.25em 1.5em; display: table; }
.quoteblock > .title { margin-left: -1.5em; margin-bottom: 0.75em; }
.quoteblock blockquote, .quoteblock blockquote p { color: #132445; font-size: 1.15rem; line-height: 1.75; word-spacing: 0.1em; letter-spacing: 0; font-style: italic; text-align: justify; }
.quoteblock blockquote { margin: 0; padding: 1rem; border: 0; }
.quoteblock blockquote:before { content: "\201c"; float: left; font-size: 2.75em; font-weight: bold; line-height: 0.6em; margin-left: -0.6em; color: #6999d6; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); }
.quoteblock blockquote > .paragraph:last-child p { margin-bottom: 0; }
.quoteblock .attribution { margin-top: 1em; margin-right: 0.5ex; text-align: right; }
.quoteblock .quoteblock { margin-left: 0; margin-right: 0; padding: 0.5em 0; border-left: 3px solid #417dcb; }
.quoteblock .quoteblock blockquote { padding: 0 0 0 0.75em; }
.quoteblock .quoteblock blockquote:before { display: none; }
.verseblock { margin: 0 1em 1.25em 1em; }
.verseblock pre { font-family: sans-serif, "Open Sans", "DejaVu Sans", sans; font-size: 1.15rem; color: #6999d6; font-weight: 300; text-rendering: optimizeLegibility; }
.verseblock pre strong { font-weight: 400; }
.verseblock .attribution { margin-top: 1.25rem; margin-left: 0.5ex; text-align: right;}
.quoteblock .attribution, .verseblock .attribution { font-size: inherit; line-height: 1.45; font-style: italic; }
.quoteblock .attribution br, .verseblock .attribution br { display: none; }
.quoteblock .attribution cite, .verseblock .attribution cite { display: block; letter-spacing: -0.025em; color: #417dcb; }
.quoteblock.abstract { margin: 0 0 1.25em 0; display: block; }
.quoteblock.abstract blockquote, .quoteblock.abstract blockquote p { text-align: left; word-spacing: 0; }
.quoteblock.abstract blockquote:before, .quoteblock.abstract blockquote p:first-of-type:before { display: none; }
table.tableblock { max-width: 100%; border-collapse: separate; }
table.tableblock td > .paragraph:last-child p > p:last-child, table.tableblock th > p:last-child, table.tableblock td > p:last-child { margin-bottom: 0; }
table.tableblock, th.tableblock, td.tableblock { border: 0 solid #dddddd; margin-right: 2rem;}
table.grid-all th.tableblock, table.grid-all td.tableblock { border-width: 0 1px 1px 0; padding: 0.5rem;}
table.grid-all tfoot > tr > th.tableblock, table.grid-all tfoot > tr > td.tableblock { border-width: 1px 1px 0 0; }
table.grid-cols th.tableblock, table.grid-cols td.tableblock { border-width: 0 1px 0 0; }
table.grid-all * > tr > .tableblock:last-child, table.grid-cols * > tr > .tableblock:last-child { border-right-width: 0; }
table.grid-rows th.tableblock, table.grid-rows td.tableblock { border-width: 0 0 1px 0; }
table.grid-all tbody > tr:last-child > th.tableblock, table.grid-all tbody > tr:last-child > td.tableblock, table.grid-all thead:last-child > tr > th.tableblock, table.grid-rows tbody > tr:last-child > th.tableblock, table.grid-rows tbody > tr:last-child > td.tableblock, table.grid-rows thead:last-child > tr > th.tableblock { border-bottom-width: 0;}
table.grid-rows tfoot > tr > th.tableblock, table.grid-rows tfoot > tr > td.tableblock { border-width: 1px 0 0 0; }
table.frame-all { border-width: 1px; }
table.frame-sides { border-width: 0 1px; }
table.frame-topbot { border-width: 1px 0; }
th.halign-left, td.halign-left { text-align: left; }
th.halign-right, td.halign-right { text-align: right; }
th.halign-center, td.halign-center { text-align: center; }
th.valign-top, td.valign-top { vertical-align: top; }
th.valign-bottom, td.valign-bottom { vertical-align: bottom; }
th.valign-middle, td.valign-middle { vertical-align: middle; }
table thead th, table tfoot th { font-weight: 600; }
tbody tr th { display: table-cell; line-height: 1.4; background: whitesmoke; }
tbody tr th, tbody tr th p, tfoot tr th, tfoot tr th p { color: #222222; font-weight: 600; }
p.tableblock > code:only-child { background: none; padding: 0; max-width: 100%}
p.tableblock { font-size: 1em; max-width: 100% }
td > div.verse { white-space: pre; }
ol { margin-left: 1.75em; }
ul li ol { margin-left: 1.5em; }
dl dd { margin-left: 1.125em; }
dl dd:last-child, dl dd:last-child > :last-child { margin-bottom: 0; }
ol > li p, ul > li p, ul dd, ol dd, .olist .olist, .ulist .ulist, .ulist .olist, .olist .ulist { margin-bottom: -0.2em; }
ul.unstyled, ol.unnumbered, ul.checklist, ul.none { list-style-type: none; }
ul.unstyled, ol.unnumbered, ul.checklist { margin-left: 0.625em; }
ul.checklist li > p:first-child > .fa-square-o:first-child, ul.checklist li > p:first-child > .fa-check-square-o:first-child { width: 1em; font-size: 0.85em; }
ul.checklist li > p:first-child > input[type="checkbox"]:first-child { width: 1em; position: relative; top: 1px; }
ul.inline { margin: 0 auto 0.625em auto; margin-left: -1.375em; margin-right: 0; padding: 0; list-style: none; overflow: hidden; }
ul.inline > li { list-style: none; float: left; margin-left: 1.375em; display: block; }
ul.inline > li > * { display: block; }
.unstyled dl dt { font-weight: normal; font-style: normal; }
ol.arabic { list-style-type: decimal; }
ol.decimal { list-style-type: decimal-leading-zero; }
ol.loweralpha { list-style-type: lower-alpha; }
ol.upperalpha { list-style-type: upper-alpha; }
ol.lowerroman { list-style-type: lower-roman; }
ol.upperroman { list-style-type: upper-roman; }
ol.lowergreek { list-style-type: lower-greek; }
.hdlist > table, .colist > table { border: 0; background: none; }
.hdlist > table > tbody > tr, .colist > table > tbody > tr { background: none; }
td.hdlist1, td.hdlist2 { vertical-align: baseline; padding: 0 0.625em; }
td.hdlist1 { font-weight: bold; padding-bottom: 1.25em; }
.literalblock + .colist, .listingblock + .colist { margin-top: -0.5em; }
.colist > table tr > td:first-of-type { padding: 0 0.75em; line-height: 1; }
.colist > table tr > td:last-of-type { padding: 0.25em 0; }
.thumb, .th { line-height: 0; display: inline-block; border: solid 4px white; -webkit-box-shadow: 0 0 0 1px #dddddd; box-shadow: 0 0 0 1px #dddddd; }
.imageblock.left, .imageblock[style*="float: left"] { margin: 0.25em 0.625em 1.25em 0; }
.imageblock.right, .imageblock[style*="float: right"] { margin: 0.25em 0 1.25em 0.625em; }
.imageblock > .title { margin-bottom: 0; }
.imageblock.thumb, .imageblock.th { border-width: 6px; }
.imageblock.thumb > .title, .imageblock.th > .title { padding: 0 0.125em; }
.image.left, .image.right { margin-top: 0.25em; margin-bottom: 0.25em; display: inline-block; line-height: 0; }
.image.left { margin-right: 0.625em; }
.image.right { margin-left: 0.625em; }
a.image { text-decoration: none; display: inline-block; }
a.image object { pointer-events: none; }
sup.footnote, sup.footnoteref { font-size: 0.875em; position: static; vertical-align: super; }
sup.footnote a, sup.footnoteref a { text-decoration: none; }
sup.footnote a:active, sup.footnoteref a:active { text-decoration: underline; }
#footnotes { padding-top: 0.75em; padding-bottom: 0.75em; margin-bottom: 0.625em; }
#footnotes hr { width: 20%; min-width: 6.25em; margin: -0.25em 0 0.75em 0; border-width: 1px 0 0 0; }
#footnotes .footnote { padding: 0 0.375em 0 0.225em; line-height: 1.3334; font-size: 0.875em; margin-left: 1.2em; text-indent: -1.05em; margin-bottom: 0.2em; }
#footnotes .footnote a:first-of-type { font-weight: bold; text-decoration: none; }
#footnotes .footnote:last-of-type { margin-bottom: 0; }
#content #footnotes { margin-top: -0.625em; margin-bottom: 0; padding: 0.75em 0; }
.gist .file-data > table { border: 0; background: #fff; width: 100%; margin-bottom: 0; }
.gist .file-data > table td.line-data { width: 99%; }
div.github-block { text-align: right; margin-right: -1rem; }
div.gist {padding-right: 2rem;}
div.unbreakable { page-break-inside: avoid; }
.big { font-size: larger; }
.small { font-size: smaller; }
.underline { text-decoration: underline; }
.overline { text-decoration: overline; }
.line-through { text-decoration: line-through; }
.aqua { color: #00bfbf; }
.aqua-background { background-color: #00fafa; }
.black { color: black; }
.black-background { background-color: black; }
.blue { color: #0000bf; }
.blue-background { background-color: #0000fa; }
.fuchsia { color: #bf00bf; }
.fuchsia-background { background-color: #fa00fa; }
.gray { color: #606060; }
.gray-background { background-color: #7d7d7d; }
.green { color: #006000; }
.green-background { background-color: #007d00; }
.lime { color: #00bf00; }
.lime-background { background-color: #00fa00; }
.maroon { color: #600000; }
.maroon-background { background-color: #7d0000; }
.navy { color: #000060; }
.navy-background { background-color: #00007d; }
.olive { color: #606000; }
.olive-background { background-color: #7d7d00; }
.purple { color: #600060; }
.purple-background { background-color: #7d007d; }
.red { color: #bf0000; }
.red-background { background-color: #fa0000; }
.silver { color: #909090; }
.silver-background { background-color: #bcbcbc; }
.teal { color: #006060; }
.teal-background { background-color: #007d7d; }
.white { color: #bfbfbf; }
.white-background { background-color: #fafafa; }
.yellow { color: #bfbf00; }
.yellow-background { background-color: #fafa00; }
span.icon > .fa { cursor: default; }
.admonitionblock td.icon [class^="fa icon-"] { font-size: 2.5em; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5); cursor: default; }
.admonitionblock td.icon .icon-note:before { content: "\f05a"; color: #207c98; }
.admonitionblock td.icon .icon-tip:before { content: "\f0eb"; text-shadow: 1px 1px 2px rgba(155, 155, 0, 0.8); color: #111; }
.admonitionblock td.icon .icon-warning:before { content: "\f071"; color: #bf6900; }
.admonitionblock td.icon .icon-caution:before { content: "\f06d"; color: #bf3400; }
.admonitionblock td.icon .icon-important:before { content: "\f06a"; color: #bf0000; }
.conum[data-value] { display: inline-block; color: #fff !important; background-color: #222222; -webkit-border-radius: 100px; border-radius: 100px; text-align: center; font-size: 0.75em; width: 1.67em; height: 1.67em; line-height: 1.67em; font-family:sans-serif, "Open Sans", "DejaVu Sans", sans-serif; font-style: normal; font-weight: bold; }
.conum[data-value] * { color: #fff !important; }
.conum[data-value] + b { display: none; }
.conum[data-value]:after { content: attr(data-value); }
pre .conum[data-value] { position: relative; top: -0.125em; }
b.conum * { color: inherit !important; }
.conum:not([data-value]):empty { display: none; }
.literalblock pre, .listingblock pre { background: #eeeeee; }
div#remarks.ulist {
max-width: 70%;
}
div.title:first-of-type {
display: none;
}
/* Mobile */
@media only screen and (max-width: 800px) {
a#bottomright {visibility: hidden;}
.sectionbody.paragraph {max-width: 100%}
.paragraph.lead > p, #preamble > .sectionbody > .paragraph:first-of-type p { max-width: 100% }
}
#div.paragraph.faq-intro {
max-width: 66.66%
}
/* ========================================================================== Mobile Menu ======================================================================= */
#menu {
display: none;
}
div.slicknav_menu {
padding-top: 5px;
padding-right: 15px;
background-color: #132445;
margin-left: -2rem;
margin-right: -2rem;
text-align: right;
display: none;
right: 10px;
font-size: 1rem;
color: white;
padding-bottom: 2rem;
background: url("n4js-logo.png");
background-position: 10px 10px;
background-size: 344.48px 40px;
background-repeat: no-repeat;
background-color: #132445;
}
span.slicknav_menutxt {
margin-right: -20px;
color: white;
}
div.slicknav_menu a.scroll:first-of-type {
color: #F7D425;
font-size: 120%;
font-weight: 600;
}
div.slicknav_menu ul li a {
color: white;
}
div.slicknav_menu ul li a:hover {
color: #F7D425;
}
div.slicknav_menu a:hover {color: #F7D425; }
div.slicknav_menu a:visited {color: white; }
div.slicknav_menu a {color: white;}
a.slicknav_btn {
padding: 1rem;
}
li.slicknav_parent.slicknav_open {
color: white;
}
li.slicknav_parent.slicknav_open {
color: white;
}
@media screen and (max-width: 890px) {
div.slicknav_menu {
display: block;
color: white
}
#mobile-banner {
display: block;
}
}
@media screen and (max-width: 470px) {
div.slicknav_menu ul:first-of-type {
margin-top: 1.5rem;
}
div.slicknav_menu ul li {
color: white;
}
div.slicknav_menu ul li:hover {
color: #F7D425;
}
}
div.slicknav_menu li:last-of-type
{
padding-bottom: 0.7rem;
}
/* ========================================================================== NavMenu ======================================================================= */
.banner {
height: 1rem;
padding-right: 2rem;
max-height: 1rem;
max-width: 50%;
vertical-align: middle;
@media (max-width: 800px) {
flex-basis: 66.666%%;
max-width: 25%;
margin: 1rem;
}
}
div.box p {
text-indent: 0px;
position: absolute;
display: none;
}
#menubar ul { margin: 0; padding: 0; white-space:nowrap; padding-left: 10px; padding-right: 10px; line-height: 2rem;}
#menubar li { margin: 0; padding: 0; }
#menubar a { margin: 0; padding: 0;}
#menubar ul {list-style: none; text-align: right;}
#menubar a {text-decoration: none;}
#menubar li {margin-left: 0;}
#menubar {height: 70px; background-color: #132445; /* box-shadow: 0px 2px 3px rgba(0,0,0,.4); */ position: relative; padding-right: 2rem; margin-left: -2rem; margin-right: -2rem; color: white; font-size: 1.9rem;}
#menubar > ul > li {
display:inline-block;
margin: 0.2rem;
position: relative;
z-index: 10000;
flex-basis: 66.666%%;
font-weight: 700;
}
@media only screen and (max-width: 890px) {
#n4js-mobile-logo {
position: absolute;
top: 0;
left: 0;
width: 178px;
height: 60px;
background-color: transparent;
}
div.box p {
text-indent: -999px;
position: absolute;
}
#menubar > ul > li, #menubar {
visibility: hidden;
display: none;
}
}
@media only screen and (max-width: 500px) {
#menubar {
display: none;
}
#logo {
margin-top: -55px;
}
}
#logo {
height: 40px;
margin-left: 40px;
margin-top: 17px;
position: relative;
overflow: hidden;
}
#menubar > ul > li::after {
content: " · ";
position: relative;
top: 3px;
padding-left: 3px;
font-weight: 400;
}
#menubar > ul > li:last-of-type::after {
content: none;
}
#menubar > ul > li:last-of-type {
padding-right: -1rem;
}
#menubar > ul > li > a {
color: #FFFFFF;
font-size: 1.2rem;
line-height: 50px;
font-weight: 400;
/* padding-top: 2rem; */
webkit-transition: color .15s;
-moz-transition: color .15s;
-o-transition: color .15s;
transition: color .15s;
white-space:nowrap;
-webkit-font-smoothing: auto;
letter-spacing: -.01em;
padding-top: 0.2em;
padding-left: 0rem;
padding-right: 0.1rem;
}
#menubar > ul {
margin-right: 12px;
margin-top: 0px;
}
#menubar > ul > li > a:hover {color: #F7D425; }
body.home li.home, body.tech li.tech {font-weight:bold; }
#menubar > ul > li > ul {
opacity: 0;
visibility: hidden;
padding: 18px 0 20px 0;
background-color: #FFFFFF; /* rgb(15,26,54); top menu color */
text-align: left;
position: absolute;
top: 55px;
left: 50%;
margin-left: -200px;
-webkit-transition: all .3s .1s;
-moz-transition: all .3s .1s;
-o-transition: all .3s .1s;
transition: all .3s .1s;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
-webkit-box-shadow: 0px 1px 3px rgba(0,0,0,.4);
-moz-box-shadow: 0px 1px 3px rgba(0,0,0,.4);
box-shadow: 0px 1px 3px rgba(0,0,0,.4);
}
#menubar > li li {
width:100%;
}
#menubar > ul > li:hover > ul {
opacity: 1;
top: 65px;
visibility: visible;
}
#menubar > ul > li > ul:before{
content: '';
display: block;
border-color: transparent transparent #FFFFFF transparent;
border-style: solid;
border-width: 10px;
position: absolute;
top: -20px;
left: 10%;
margin-left: -10px;
}
#menubar > ul ul > li { position: relative;}
#menubar ul ul a{
color: rgb(50,50,50);
font-family: sans-serif, Verdana, 'Lucida Grande';
font-size: 17px;
background-color: #FFFFFF; /* rgb(15,26,54); top menu color */
padding: 5px 8px 7px 16px;
display: block;
-webkit-transition: background-color .1s;
-moz-transition: background-color .1s;
-o-transition: background-color .1s;
transition: background-color .1s;
}
#menubar ul ul a:hover {background-color: #244D82; color: #F7D425;}
#menubar ul ul ul {
visibility: hidden;
opacity: 0;
position: absolute;
top: -16px;
left: 206px;
padding: 16px 0 20px 0;
background-color: #527AA3;
text-align: left;
width: 160px;
-webkit-transition: all .3s;
-moz-transition: all .3s;
-o-transition: all .3s;
transition: all .3s;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
-webkit-box-shadow: 0px 1px 3px rgba(0,0,0,.4);
-moz-box-shadow: 0px 1px 3px rgba(0,0,0,.4);
box-shadow: 0px 1px 3px rgba(0,0,0,.4);
}
#menubar ul ul > li:hover > ul { opacity: 1; left: 196px; visibility: visible;}
#menubar ul ul a:hover{
background-color: #244D82;
color: #F7D425;
}
.Cell--12-12 {
-webkit-flex-basis: 100%;
-ms-flex-preferred-size: 100%;
flex-basis: 100%;
max-width: 100%
}
.Grid {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-align-items: stretch;
-ms-flex-align: stretch;
align-items: stretch;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-flex: 0 1 auto;
-ms-flex: 0 1 auto;
flex: 0 1 auto;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row
}
.Cell,
.Comparison .Comparison-left,
.Comparison .Comparison-right,
.ExampleExplanation .ExampleExplanation-code,
.ExampleExplanation .ExampleExplanation-text,
.FeatureTabs .FeatureTabs-stage,
.Intro .Intro-Slogan {
padding-left: 1rem;
padding-right: 1rem;
-webkit-flex: 0 0 auto;
-ms-flex: 0 0 auto;
flex: 0 0 auto
}
#_index, #_feature_table {display: none;}
#_documentation {margin-top: -2rem;}
h3 {padding-top: 1rem}
/* ========================================================================== AsciiSpec ======================================================================= */
.requirement {
border: 1px solid #aaaaaa;
padding: 0.5em;
margin-bottom: 1rem;
}
.bibliography .content .paragraph p :first-child::before {
color:#777777;
content: "[" attr(id) "] "; }
.bibliography .content .paragraph {
padding-left: 6em;
text-indent: -6em;
</style>
</head>
<body class="article">
<div id="header">
</div>
<div id="content">
<div class="sect1">
<h2 id="_overview">Overview</h2>
<div class="sectionbody">
<div class="paragraph">
<p><a href="https://reactjs.org/" target="_blank" rel="noopener">React</a> is a popular JavaScript library created by Facebook widely used for developing web user interface. N4JS provides full support for React as well as the JavaScript extension <a href="https://reactjs.org/docs/introducing-jsx.html" target="_blank" rel="noopener">JSX</a> for describing UI elements. Internally, we have been using N4JS in combination with React and JSX for years to develop very large e-commerce web applications.
In this tutorial, we will develop a simple and yet fun (!) chess game with N4JS and React. For the purpose of this tutorial, the chess game only allows two humans to play against each other.</p>
</div>
<div class="paragraph">
<p>Before starting with the implementation, let&#8217;s explicitly state several features we would like to have in our application.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>When the chess application is started, a chess board of 8x8 squares shall be showed containing 16 white pieces and 16 black pieces in their initial positions.</p>
</li>
<li>
<p>A player in turn shall be able to use the mouse to pick one of the pieces that she/he wants to move. A picked piece shall be clearly recognizable. Moreover, to aid players, especially beginners, whenever a piece is picked, all possible valid destination squares shall be visually highlighted as well.</p>
</li>
<li>
<p>In addition to the game board, there shall be a game information area that shows which player is in turn. Moreover, the game information area shall show a complete history of the game protocolling each move made by the players. As a bonus, jumping back to a previous state of the history shall be possible.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The final game will look approximately like this. You may want to challenge your co-worker to a game now!</p>
</div>
<div class="paragraph">
<p>
<iframe src="chess.html" width="100%" height="600"></iframe>
</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_repository">Repository</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The source code of the chess application can be found at <a href="https://github.com/NumberFour/n4js-tutorial-chess" target="_blank" rel="noopener">n4js-tutorial-chess</a>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_run_the_application">Run the application</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In the root folder of the project <code>n4js-tutorial-chess</code>, execute the following command to install all dependencies.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">npm install</code></pre>
</div>
</div>
<div class="paragraph">
<p>In <code>package.json</code>, a <code>start</code> script for starting the Webpack Dev Server serving the application is defined. To start the application, run</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-bash" data-lang="bash">npm start</code></pre>
</div>
</div>
<div class="paragraph">
<p>The chess web app is served at port 8080.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_developer_setup">Developer Setup</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Follow the following steps to import the app into N4JS IDE.</p>
</div>
<div class="paragraph">
<p>Step 1: Download the <a href="https://projects.eclipse.org/projects/technology.n4js/downloads" target="_blank" rel="noopener">latest N4JS IDE</a> for your operating system.</p>
</div>
<div class="paragraph">
<p>Step 2: The project is already an Eclipse with the <code>.project</code> file in the root <code>chess</code>. Hence, you can simply import it into the N4JS IDE workspace via <code>File &#8658; Import &#8658; Existing Projects into Workspace</code>.</p>
</div>
<div class="paragraph">
<p>The IDE may complain that npm dependencies declared in <code>package.json</code> are missing. Use the quickfix <code>run npm/yarn in this project</code> to fix this issue.</p>
</div>
<div class="paragraph">
<p>Step 3: Open the library manager dialog and choose <code>Re-Build node_modules</code>.</p>
</div>
<div class="paragraph">
<p>Step 4: Clean &amp; Build the project. After this step, the project should has no compilation errors anymore.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_n4js_type_definitions_of_react">N4JS type definitions of React</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In order to enable N4JS&#8217;s type checking for React, we need to declare <code>@n4jsd/react</code> as a dev dependency in <code>package.json</code> of the project. <code>@n4jsd/react</code> consists of <code>n4jsd</code> files that contain file definitions for React.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-json" data-lang="json">{
"name": "n4js-tutorial-chess",
"devDependencies": {
"@n4jsd/react": "&lt;=16.6.*",
},
"dependencies": {
"react": "^16.6.0",
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The concept of <code>n4jsd</code> files in N4JS is very similar to TypeScript&#8217;s <code>d.ts</code> definition files in that they both do not contain any implementations and are only used for type checking. In addition to React, the <a href="https://github.com/NumberFour/n4jsd" target="_blank" rel="noopener">n4jd repository</a> has <code>n4jsd</code> projects for many popular JavaScript library such as <code>lodash</code> or <code>express</code> etc.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_file_extension_n4jsx">File extension n4jsx</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The standard file extension of N4JS is <code>.n4js</code>. N4JS files containing React and JSX must have the extension <code>.n4jsx</code>.
Also, every <code>.n4jsx</code> has to have import <code>React</code> explicitly.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_graphical_representation_of_chess_board_and_pieces">Graphical representation of chess board and pieces</h2>
<div class="sectionbody">
<div class="paragraph">
<p>At this point, we probably ask the question: <em>How should we draw the chess board?</em>
We could use <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">Canvas API</a>. To keep the application simple, however, in this tutorial, we draw the chess board with pure CSS using <a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox" target="_blank" rel="noopener">flexbox model</a>. In particular, the chess board can be defined as a flex container with <code>flex-wrap: wrap</code> whereas the squares are flex items.</p>
</div>
<div class="paragraph">
<p><em>How about chess pieces?</em>
Instead of images, we use <a href="https://en.wikipedia.org/wiki/Chess_symbols_in_Unicode" target="_blank" rel="noopener">Chess symbols in Unicode</a> to display chess pieces.
There are many ways to represent pieces in N4JS, the simplest way being to declare a <a href="https://www.eclipse.org/n4js/spec/N4JSSpec.html#_string-based-enums" target="_blank" rel="noopener">String-based enum</a> called <code>Piece</code> to represent pieces. The enum literals are the Unicode chess symbols.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">@StringBased
export public enum Piece {
WHITE_PAWN : '♙',
WHITE_ROOK : '♖',
WHITE_KNIGHT : '♘',
WHITE_BISHOP : '♗',
WHITE_QUEEN : '♕',
WHITE_KING: '♔',
BLACK_PAWN : '♟',
BLACK_ROOK : '♜',
BLACK_KNIGHT : '♞',
BLACK_BISHOP : '♝',
BLACK_QUEEN : '♛',
BLACK_KING: '♚'
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The advantage of String-based enums is that in N4JS code, we can use the enum literals, e.g. Piece.WHITE_PAWN etc., to refer to the pieces in the exact the same way as with normal enums. That means, we receive full validation support from N4JS compiler and IDE as with normal enums. In the transpiled JavaScript code, these enum literals are replaced by the corresponding chess symbols (strings).</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_react_components_tree">React components tree</h2>
<div class="sectionbody">
<div class="paragraph">
<p>As typical with React applications, we need to decide how the UI of our chess game should be structured as a tree of React components. In this example, we have opted for the following structure.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="images/chess-react-components.svg" alt="Chess React components tree">
</div>
</div>
<div class="paragraph">
<p>The root React component is <code>Game</code> that consists of two areas. The left area is the React component <code>Board</code> showing the chess board while the right area shows the game information.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_square_react_component">Square React component</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In the tree of React components in this application, <code>Square</code> is one of the leaf React components. It defines a single square of the chess board that can be clicked by the current user. Its value is either a <code>Piece</code> representing a piece or <code>null</code> if the square is empty. In this example, we define Square as a lightweight functional component since it does not have any state.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">/**
* Square props
*/
export public interface ~SquareProps extends React.ComponentProps {
public isWhite: boolean;
public piece: Piece;
public onClick: {function(): void}
public isPicked: boolean;
public isValidDestination: boolean;
}
/**
* Board square styles
*/
const boardSquareStyles = {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: '100%',
fontSize: '5vw'
}
/**
* Square React component
*/
export public function Square(props: SquareProps): React.Element&lt;?&gt; {
let backgroundColor: string = props.isWhite? '#EADAB9' : '#C2A482';
// Special square highlighting a picked square or valid destination?
if (props.isPicked) {
backgroundColor = 'lime';
} else if (props.isValidDestination) {
backgroundColor = 'yellow';
}
return (
&lt;div style={Object.assign({}, boardSquareStyles, {backgroundColor: backgroundColor})}
onClick={props.onClick}&gt;
{props.piece}
&lt;/div&gt;
);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The functional definition of <code>Square</code>, in fact of any React component, must have a single <code>props</code> parameter of a subtype of <code>React.ComponentProps</code> and return an instance of type <code>React.Element&lt;?&gt;</code>. In this example, <code>SquareProps</code> dictates that when a <code>Square</code> is instantiated, it expects the following <em>mandatory</em> <code>props</code>:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>isWhite</code>: <code>true</code> if the square is a white square and <code>false</code> otherwise.</p>
</li>
<li>
<p><code>piece</code>: the piece on the square, of type <code>Piece</code>. This is necessary because the states of the squares are managed by a parent React component.</p>
</li>
<li>
<p><code>isPicked</code>: <code>true</code> if the square contains a piece that has been picked by the current player with the intention to move it to a new position and <code>false</code> otherwise. This is necessary to change the background of the square to highlight that the square has been picked.</p>
</li>
<li>
<p><code>isValidDestination</code>: <code>true</code> if the square should be highlighted as a valid destination for a picked square and <code>false</code> otherwise.</p>
</li>
<li>
<p><code>onClick</code>: the event handler to be called when the square is clicked. <code>Square</code> component uses this event handler to inform the parent <code>Board</code> component of the clicking event.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>In addition to having explicit types, the props can be declared as mandatory (as in this example) or <em>optional</em> with the help of the question mark. For instance, if we would declare <code>public piece?: string</code>, it would mean that <code>piece</code> would be an optional property when creating <code>Square</code>.</p>
</div>
<div class="paragraph">
<p>Here we start to see the advantages of an N4JS implementation over a pure non-typed JavaScript implementation. First, since the props required by <code>Square</code> are made explicit, the code is more readable. Second, when a <code>Square</code> component is created, the compiler will enforce the types of the props. Third, the N4JS compiler will complain if a mandatory prop is missing. And all these validations happen <em>at compile time</em> during development. In pure JavaScript, we would recognize type mismatch or missing mandatory props problem much later <em>at runtime</em>, possibly during production.</p>
</div>
<div class="paragraph">
<p>The <code>render</code> method of the <code>Square</code> component returns an JSX expression, particularly a <code>&lt;div&gt;</code> whose content is the piece to be displayed. The CSS style is dynamically calculated to set the background color based on the values of the passed props.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_board_react_component">Board React component</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The <code>Board</code> React component represents the chess board. Even though it does not have state, we define it as a class because it contains helper methods. The most important <em>prop</em> needed by this React component is <code>squares</code> that is an 8x8 array of <code>Piece</code> containing an arrangement of pieces on the board. To avoid tiring mental calculation, we use the browser&#8217;s coordinate system, i.e. the top left square has the coordinate <code>(0,0)</code> while the bottom right&#8217;s coordinate is <code>(7,7)</code>. Note that the coordinates of the 8x8 <code>Pieace</code> array is different from that of <a href="https://en.wikipedia.org/wiki/Algebraic_notation_(chess)" target="_blank" rel="noopener">algebraic chess notation</a>.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="images/chess-board-coordinate-system.svg" alt="Chess board coordinate system"></span></p>
</div>
<div class="paragraph">
<p>In addition to 8x8 black/white squares, we should also display the conventional board&#8217;s coordinates because these coordinates are used for displaying the game history.</p>
</div>
<div class="paragraph">
<p><em>How can we create such a board with pure CSS?</em> The probably easiest way is to use <a href="https://css-tricks.com/snippets/css/a-guide-to-flexbox/" target="_blank" rel="noopener">flexbox model</a>.
In particular, the board is defined as a <em>flex container</em> with <code>flex-wrap: wrap</code>.
The squares displaying chess pieces and coordinates in algebraic chess notation are <em>flex items</em>. Together with squares displaying coordinates (called <em>coordinate squares</em> in this implementation), there are 10 x 10 squares inside the <code>Board</code> component in total. As a result, each square occupies 10% width and 10% height of the board&#8217;s width and height. The following diagram graphically depicts this.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="images/chess-board-flexbox.svg" alt="Chess board with flexbox"></span></p>
</div>
<div class="paragraph">
<p>Since we have to deal a lot with coordinates, we define the <code>Coordinate</code> data structure to represent (row,column) coordinates.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">export public class Coordinate {
public row: number;
public col: number;
/**
* Spec constructor
*
public constructor(@Spec spec:~i~this) {}
/**
* Compare two coordinates
*/
public equals(other: Coordinate): boolean {
return (this.row == other.row) &amp;&amp; (this.col == other.col);
}
/**
* Convert the this to board's coordinate
*/
public getBoardCoordinateRepresentation() {
const rowLabel = 8 - this.row;
const colLabel = String.fromCharCode('a'.charCodeAt(0) + this.col);
return `(${rowLabel + ',' + colLabel})`;
}
@Override
public toString(): string {
return `(${this.row},${this.col})`;
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>In the class <code>Coordinate</code> above, we define a <a href="https://www.eclipse.org/n4js/spec/N4JSSpec.html#spec-constructor" target="_blank" rel="noopener">Spec constructor</a>. This Spec constructor allows us to instantiate a Coordinate by supplying all public members in an object literal. For example,</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">let c: Coordinate = new Coordinate({ row: 1, col: 2});</code></pre>
</div>
</div>
<div class="paragraph">
<p>Equally interesting is the method <code>toString</code> which should be very familiar to Java developers. This method defines the string representation of a Coordinate.</p>
</div>
<div class="paragraph">
<p>The data structure <code>BoardProps</code> defining the props of <code>Board</code> component is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">/**
* Board props
*/
export public interface ~BoardProps extends React.ComponentProps {
public squares: Array&lt;Array&lt;Piece&gt;&gt;;
public pickedSquare: Coordinate;
public validDestinations: Array&lt;Coordinate&gt;;
public onClick: {function(Coordinate): void}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>In addition to <code>squares</code>, additional props are:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>pickedSquare</code>: the (row, column) coordinate indicating the currently picked square if exists and <code>null</code> otherwise.</p>
</li>
<li>
<p><code>validDestinations</code>: if <code>pickedSquare</code> exists, this array contains the coordinates of the valid destinations of the piece on the picked square.</p>
</li>
<li>
<p><code>onClick</code>: the event handler to be called when the square at a certain position is clicked. <code>Square</code> component informs <code>Board</code> component which in turn informs a parent component about a clicking event.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The following screenshot graphically depicts a chess board in which the square <code>(3,7)</code> containing a white knight is picked by the player. The picked square is visually recognizable via the green color. Additionally, all valid destinations of the white knight are highlighted in yellow color.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="images/chess-picked-square.png" alt="Picked square"></span></p>
</div>
<div class="paragraph">
<p>The class <code>Board</code>, as any class representing a React component, must extend <code>React.Component</code> and override the <code>render()</code> method.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">/**
* Board React component
*/
export public class Board extends React.Component&lt;BoardProps, Object&gt; {
/**
* Render the i-th square on the board 0 &lt;= i &lt;= 63
*/
private renderSquare(pos: Coordinate, isWhite: boolean, isPicked: boolean, isValidDestination: boolean, piece: Piece): React.Element&lt;?&gt; {
return (
&lt;div style={squareStyles}&gt;
&lt;Square
isWhite={isWhite}
isPicked={isPicked}
isValidDestination={isValidDestination}
piece={piece}
onClick={() =&gt; this.props.onClick(pos)}
/&gt;
&lt;/div&gt;
);
}
/**
* Render coordinate square
*/
private renderCoordinateSquare(label: string): React.Element&lt;?&gt; {
return (
&lt;div style={squareStyles}&gt;
&lt;CoordinateSquare
label={label}
/&gt;
&lt;/div&gt;
);
}
private renderSquares(): Array&lt;React.Element&lt;?&gt;&gt; {
const squares = new Array&lt;React.Element&lt;?&gt;&gt;();
let isWhiteInitial = true;
// Draw row coordinates: a b c ... h
squares.push(this.renderCoordinateSquare(''));
for (let i = 0; i &lt; 8; i++) {
squares.push(this.renderCoordinateSquare(String.fromCharCode('a'.charCodeAt(0) + i)));
}
squares.push(this.renderCoordinateSquare(''));
for (let row = 0; row &lt; 8; row++) {
// Draw column coordinate: 8 7 6 ... 1
squares.push(this.renderCoordinateSquare((8-row).toString()));
let isWhite = isWhiteInitial;
for (let col = 0; col &lt; 8; col++) {
const pos = new Coordinate({row: row, col: col});
const isPotentialDestination: boolean =
this.props.validDestinations.findIndex(potentialDest =&gt; potentialDest.equals(pos)) &gt;= 0;
squares.push(this.renderSquare(pos, isWhite,
this.props.pickedSquare &amp;&amp; this.props.pickedSquare.equals(pos)? true : false, isPotentialDestination, this.props.squares[pos.row][pos.col]
));
isWhite = !isWhite;
}
isWhiteInitial = !isWhiteInitial;
squares.push(this.renderCoordinateSquare((8-row).toString()));
}
// Draw row coordinates: a b c ... h
squares.push(this.renderCoordinateSquare(''));
for (let i = 0; i &lt; 8; i++) {
squares.push(this.renderCoordinateSquare(String.fromCharCode('a'.charCodeAt(0) + i)));
}
squares.push(this.renderCoordinateSquare(''));
return squares;
}
@Override
public render(): React.Element&lt;?&gt; {
return (
&lt;div style={boardStyles}&gt;
{ this.renderSquares() }
&lt;/div&gt;
);
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note that <code>React.Component</code> expects two type arguments: the first type argument is the type of props and the second type argument is the type of state. Here, in the <code>render</code> method we create 8x8 <code>Squares</code> components that make up the chess board. We also create two rows and two columns of <code>CoordinateSquare</code> displaying the chess board coordinates.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_game_react_component_root">Game React component (root)</h2>
<div class="sectionbody">
<div class="paragraph">
<p>This is the root React component of this application and hence does not have any props. Instead, it has a state represented by <code>GameState</code>. The game state consists of the history of the board as an array of <code>Snapshot</code>, among others.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">/**
* A history snapshot
*/
interface ~Snapshot {
public squares: Array&lt;Array&lt;Piece&gt;&gt;;
public lastMoves: Array&lt;Move&gt;;
public whiteKingMoved: boolean;
public leftWhiteRookMoved: boolean;
public rightWhiteRookMoved: boolean;
public blackKingMoved: boolean;
public leftBlackRookMoved: boolean;
public rightBlackRookMoved: boolean;
}
/**
* Game state
*/
interface ~GameState {
public history: Array&lt;Snapshot&gt;;
public stepNumber: int;
public whiteIsNext: boolean;
public pickedSquare: Coordinate;
public validDestinations: Array&lt;Coordinate&gt;;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>A snapshot of the history contains:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>squares</code>: a 2-dimensional array containing an arrangement of pieces on the chess board.</p>
</li>
<li>
<p><code>lastMoves</code>: contains the last moves leading to the arrangement of pieces. The reason why this is an array, instead of a single element, is that a <a href="https://en.wikipedia.org/wiki/Castling" target="_blank" rel="noopener">castling</a> move changes the positions of a king and a rook at the same time.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Further flags such as <code>whiteKingMoved</code> etc. remember if kings or rooks have been moved already. These kinds of information are relevant for handling castling.</p>
</div>
<div class="paragraph">
<p>You may ask what the tilde symbol means, for instance in <code>~Snapshot</code>? The tilde symbol here indicates that <em>structural subtyping</em> should be used during type checking. In essence, it means that when checking whether some object or instance is a subtype of <code>~Snapshot</code>, the type system only cares if that object or instance has all the public fields declared in <code>~Snapshot</code>. And if yes, the object is considered a subtype of <code>Snapshot</code>. This is exactly the behavior what we want here. You should read <a href="https://www.eclipse.org/n4js/features/nominal-and-structural-typing.html" target="_blank" rel="noopener">structural typing vs. nominal subtyping</a> for further explanation.</p>
</div>
<div class="paragraph">
<p><code>GameState</code> stores the entire state of the application and consists of:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>history</code>: array of snapshots capturing the entire history leading up to the current arrangement of the chess board.</p>
</li>
<li>
<p><code>stepNumber</code>: the current step number. Its initial value is <code>0</code>. Each time when a player places a move, it is increased by <code>1</code>.</p>
</li>
<li>
<p><code>whiteIsNext</code>: <code>true</code> if the white player is in turn and <code>false</code> otherwise.</p>
</li>
<li>
<p><code>pickedSquare</code>: the (row,column) coordinate indicating the currently picked square if exists and <code>null</code> otherwise.</p>
</li>
<li>
<p><code>validDestinations</code>: if <code>pickedSquare</code> exists, this array contains the coordinates of the squares being the valid destinations of the piece on the picked square.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Here, again thanks to type checking, the N4JS compiler will complain if we, for instance, access a non-existing field of <code>GameState</code> or use the wrong type of a certain field of <code>GameState</code> <em>at compile time</em>. In pure JavaScript, we would recognize those mistakes only at runtime.</p>
</div>
<div class="paragraph">
<p>The <code>Game</code> component is quite complex because it implements the game rules. In the next section, we will look at some of the implementations of the game rules.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_implementation_of_game_rules">Implementation of game rules</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The <code>Game</code> component contains logics for implementing the game rules. In this section, we will discuss logics for</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Calculating the set of squares being attacked by a certain piece.</p>
</li>
<li>
<p>Calculating the set of squares being valid destinations (squares) of a certain piece.</p>
</li>
<li>
<p>Checking checkmate.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>We can see that the set of squares being attacked by a certain piece and the set of squares being valid destinations of a certain piece are closely related. For rooks, knights, bishops, queens, these two sets are in fact almost identical with the exception that moving one of these pieces cannot cause the king to be in check. However, pawns are quite special because they
can attack diagonal squares but can only move forwards vertically. Kings have special castling moves that jump two squares.</p>
</div>
<div class="paragraph">
<p>As an example, we will have a look at the algorithm for calculating squares attacked by a bishop. The general movement rule for a bishop looks as follows:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>A bishop can move diagonally but the destination must lie within the border of the chess board.</p>
</li>
<li>
<p>A bishop cannot jump over other pieces on its movement.</p>
</li>
<li>
<p>If there is an opponent piece on its movement, a bishop can capture it.</p>
</li>
<li>
<p>A bishop (as any other piece) cannot move if its movement would cause the king (of the same color) to be in check</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The following screenshot shows an example highlighting valid destinations for the white bishop.
<span class="image"><img src="images/bishop-attacking-squares.png" alt="Squares attacked by bishop"></span></p>
</div>
<div class="paragraph">
<p>There are certainly tons of ways to calculate the set of squares/destinations attacked by a bishop in particular, and by a piece in general. In this tutorial, we have opted for a simple imperative implementation: starting from the current position, we iterate 4 different directions: north west, north east, south east, south west. In each direction, we keep moving forwards as far as possible. The implementation is as follows:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">private calculateDestinationsAttackedByBishop(squares: Array&lt;Array&lt;Piece&gt;&gt;,
figure: Piece, pos: Coordinate): Array&lt;Coordinate&gt; {
const row = pos.row;
const col = pos.col;
const result: Array&lt;Coordinate&gt; = new Array&lt;Coordinate&gt;();
// NORTH WEST, NORTH EAST, SOUTH EAST, SOUTH WEST
const deltas = [[-1,-1], [-1,1], [1,1], [1,-1]];
// Iterate 4 directions
for (let delta of deltas) {
let newPos = new Coordinate({row: row + delta[0], col: col + delta[1]});
while (this.isInsideBoard(newPos)) {
if (!squares[newPos.row][newPos.col]) {
// Square is not occupied
result.push(newPos);
} else {
// Square is occupied
if (this.isPositionOccupiedByFigureSameColor(squares, figure, newPos)) {
break;
}
if (this.isPositionOccupiedByFigureOtherColor(squares, figure, newPos)) {
result.push(newPos);
break;
}
}
newPos = new Coordinate({row: newPos.row + delta[0], col: newPos.col + delta[1]});
}
}
return result;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The set of all valid destinations of a bishop is the set of all squares attacked by the bishop with the condition that moving it does not cause the king to be in check. The method <code>isKingInCheckIfMove</code> in the <code>Game</code> component <em>simulates</em> a move of a piece and checks if the move would cause the king of the same color to be in check.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">/**
* Check whether the king is in check if the move is made
*/
private isKingInCheckIfMove(attemptedMove: Move) {
// Check if the move causes the king to be in check
const {squares: changedSquares} = this.move(attemptedMove);
const isWhite = this.isWhitepiece(attemptedMove.piece);
const kingPos = this.getKingPosition(changedSquares, isWhite);
if (!kingPos) {
return false;
}
return this.isKingInCheck(changedSquares, isWhite? Piece.WHITE_KING : Piece.BLACK_KING, kingPos)
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Checking whether a king is checkmated is interesting. A king is checkmated if all pieces cannot move anymore, i.e. have no valid destinations. This logics is implemented by the method <code>calculateWinner</code> in <code>Game.n4jsx</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-typescript" data-lang="typescript">/**
* Calculate the winner
*/
private calculateWinner(squares: Array&lt;Array&lt;Piece&gt;&gt;): string {
const isWhite = this.state.whiteIsNext;
const allPieces = this.getAllPiecesSameColor(squares, isWhite);
// Checkmate if all pieces have no valid destinations
const checkMate =
this.forAll(allPieces,
(p) =&gt; this.calculateValidDestinations(squares, p.piece, p.pos).length == 0
);
if (checkMate) {
return isWhite? 'Black': 'White';
} else {
return null;
}
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_build_with_webpack">Build with Webpack</h2>
<div class="sectionbody">
<div class="paragraph">
<p>We use Webpack to bundle all JavaScript files of the application, including dependencies such as React, into a single JavaScript file. Webpack is configured in <code>webpack.config.js</code>. The following diagram graphically depicts the build process with the help of Webpack.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="images/react-build-process.svg" alt="Build process"></span></p>
</div>
<div class="paragraph">
<p>The entry file used by Webpack to calculate the dependency graph is <code>src-gen/main.js</code> which depends on <code>react-dom</code> and <code>src-gen/Game.js</code> which depends on &#8230;&#8203; etc. The bundled JavaScript is stored in <code>public/dist/chess-app.js</code> which is then included in <code>index.html</code>.</p>
</div>
<div class="paragraph">
<p>The content of <code>webpack.config.js</code> is as follows:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-javascript" data-lang="javascript">const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack');
module.exports = {
mode: 'development',
entry: {
// Webpack starts calculating dependency graph from this file
app: './src-gen/main.js'
},
output: {
// The output concatenated file
filename: 'chess-app.js',
publicPath: 'dist/',
path: path.resolve(__dirname, 'public/dist')
},
devtool: 'inline-source-map',
/** Configure Webpack Dev server */
devServer: {
// Serve files from the `public` folder at localhost:8080
contentBase: path.join(__dirname, 'public'),
port: 8080,
hot: true,
inline: true
},
plugins: [
new CleanWebpackPlugin(),
new webpack.HotModuleReplacementPlugin()
],
resolve: {
alias: {
"n4js-tutorial-chess": __dirname
}
}
};</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note that we need to specify the entry point <code>./src-gen/main.js</code> instead of <code>./src/main.n4js</code> of course because Webpack and web browser only understand the generated JavaScript files. The concatenated JavaScript file is <code>public/dist/chess-app.js</code> which contains the entire chess application. We also configure a Webpack Dev server with hot loading enabled so that we can start the application locally.</p>
</div>
<div class="paragraph">
<p>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/themes/prism.min.css"></link>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/prism.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/components/prism-typescript.min.js"></script>
</p>
</div>
</div>
</div>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2019-05-10 15:02:13 +0200
</div>
</div>
</body>
</html>