code:
.topBoards a, #divLatestImages img, #divLatestPosts .latestPostCell,
  .innerPost, .sideCatalogCell, .markedPost, .sideCatalogMarkedCell,
  .catalogCell {
  background: #282A2E;
  border-radius: 5px;
}

.theme_clear .topBoards a, .theme_clear #divLatestImages img,
  .theme_clear #divLatestPosts .latestPostCell, .theme_clear .innerPost,
  .theme_clear .sideCatalogCell, .theme_clear .markedPost, .theme_clear .sideCatalogMarkedCell,
  .theme_clear .catalogCell {
  background-color: #dddddd
}

.floatingMenu, #quick-reply table {
  background: #1d1f21;
}

.theme_clear .floatingMenu, .theme_clear #quick-reply table {
  background: #cccccc;
}

.markedPost, .sideCatalogMarkedCell {
  background: rgba(59, 22, 43, 0.4);
}

.theme_clear .markedPost, .theme_clear .sideCatalogMarkedCell {
  background: #868686;
}

#divLatestPosts .latestPostCell, .innerPost, .sideCatalogCell,
  .markedPost, .sideCatalogMarkedCell, .catalogCell {
  border: 1px solid #117743;
}

#newPostFieldset, #quick-reply table, .modalDecorationPanel,
  .floatingMenu, #settingsFieldset, .reportFieldset {
  border: 1px dashed #117743;
}

.logoImg {
  height: 250px;
  min-width: 1px;
}

.captchaImage {
  width: 300px;
  height: 100px;
  background-color: white;
}

.small {
  font-size: 75%;
  text-decoration: none;
}

.clearer {
  clear: both;
}

.small a {
  text-decoration: none;
}

#panelReferences a {
  display: block;
}

.imgLink img, .latestImageCell img, .mediaCell img, .catalogCell img {
  image-orientation: from-image;
}

.linkList a {
  display: block;
}

#themeSelector {
  font-size: 100%;
}

h3, p, label {
  margin: 0.25em 0;
}

hr {
  height: 0px;
  border-width: 1px medium medium;
  border-style: solid none none;
  border-color: #117743;
}

a, .coloredIcon, .unhideButton, .embedButton, .checkedFavouriteButton:before,
  #selectedTab, #showFormsButton {
  color: #FFB300;
  cursor: pointer
}

.theme_clear a, .theme_clear .coloredIcon, .theme_clear .unhideButton,
  .theme_clear .embedButton, .theme_clear .checkedFavouriteButton:before,
  .theme_clear #selectedTab, .theme_clear #showFormsButton {
  color: #000
}

.coloredIcon::before {
  font-family: 'Icons';
}

#navLinkSpan .coloredIcon:before, #navOptionsSpan .coloredIcon:before,
  #links .coloredIcon:before {
  margin-right: 0.25em;
}

a {
  text-decoration: none;
}

a:hover, .glowOnHover:hover {
  text-shadow: 0px 0px 5px #117743;
}

u {
  text-decoration: underline;
}

s {
  text-decoration: line-through;
}

strong {
  font-weight: bold;
}

em {
  font-style: italic;
}

input, select, textarea {
  border: 1px double #07371F;
  border-radius: 5px;
  background: #282A2E;
  color: #ACACAC;
  font-family: 'Hack', monospace, sans-serif;
  font-size: 80%;
}

.theme_clear input, .theme_clear select, .theme_clear textarea {
  background: #dddddd;
  color: #000;
}

input[type=button], input[type=submit], button, .dropzone, .selectedCell
  {
  border: 3px double #07371F;
  border-radius: 5px;
  background: #16171A;
  color: #ACACAC;
  padding-left: 0.25em;
  font-family: 'Hack', monospace, sans-serif;
  font-size: 80%;
  font-weight: bold;
  margin-top: 0.5em;
  margin-bottom: 0.5em;
  cursor: pointer;
}

.theme_clear input[type=button], .theme_clear input[type=submit],
  .theme_clear button, .theme_clear .dropzone, .theme_clear .selectedCell
  {
  background: #a7a7a7;
  color: #000;
}

.title, .unhideButton {
  font-weight: bold;
}

.fileBrowser {
  background: none;
}

/* import resources here; external CSS, fonts, etc */
@font-face {
  font-family: 'Hack';
  src: url('../hack-regular-webfont.eot?v=2.018');
  src: url('../hack-regular-webfont.eot?#iefix&v=2.018')
    format('embedded-opentype'),
    url('../hack-regular-webfont.woff2?v=2.018') format('woff2'),
    url('../hack-regular-webfont.woff?v=2.018') format('woff'),
    url('../hack-regular-webfont.ttf?v=2.018') format('truetype'),
    url('../hack-regular-webfont.svg?v=2.018#hackregular') format('svg');
  font-weight: normal;
  font-style: normal;
}

@font-face {
  font-family: 'Icons';
  src: url('../open-iconic.eot');
  src: url('../open-iconic.eot?#iconic-sm') format('embedded-opentype'),
    url('../open-iconic.woff') format('woff'), url('../open-iconic.ttf')
    format('truetype'), url('../open-iconic.otf') format('opentype'),
    url('../open-iconic.svg#iconic-sm') format('svg');
  font-weight: normal;
  font-style: normal;
}

/* body styles, inherited by whole page */
body {
  color: #ACACAC;
  background: #1D1F21;
  font-family: 'Hack', monospace, sans-serif;
  font-size: 100%;
  margin: 0px;
}

body.theme_clear {
  background-color: #cccccc;
  color: #000
}

/* header and nav / top of page styles */
header {
  margin: 3em auto 0 auto;
  text-align: center;
}

nav {
  height: 18px;
  position: fixed;
  top: 0;
  width: 100%;
  background-color: #151515;
  border-bottom: 1px solid #B0790A;
  padding-bottom: 3px;
  font-size: 70%;
  text-align: center;
  z-index: 1;
}

.theme_clear nav {
  background-color: #acacac
}

nav span, nav a {
  display: inline-block;
  text-decoration: none;
  margin: 0 0.2em;
}

#navLinkSpan {
  float: left;
}

#navOptionsSpan {
  float: right;
}

#navLinkHome:before {
  content: "\e078";
}

#navBoardList:before {
  content: "\e09b";
}

#linkOverboard:before, #navOverboard:before {
  content: "\e007";
}

#settingsButton:before {
  content: "\e041";
}

#navPosting:before {
  content: "\e09a";
}

#navCatalog:before {
  content: "\e072";
}

#linkRss:before {
  content: "\e0b7";
}

#linkTop:before {
  content: "\e012";
}

#linkBottom:before {
  content: "\e00f";
}

#linkBack:before {
  content: "\e003";
}

/* board list */
#divPages {
  display: inline-block;
}

#divPages a {
  text-decoration: none;
  padding: 0 0.25em;
  display: inline-block;
}

a.rules:after {
  font-family: Icons;
  content: "\e052";
  margin-right: 0.5em;
  color: #117743;
  height: 80%;
  font-size: 80%;
  padding-left: 0.25em;
  vertical-align: middle;
}

/* markdown */
.greenText {
  color: #789922;
}

.redText {
  color: #AF0A0F;
  font-weight: bold;
  font-size: 125%;
}

span.spoiler {
  background: #000;
  color: #000;
  padding: 0 1px;
}

.spoiler:hover {
  color: #ACACAC;
  background: none;
}

.red {
  color: #117743;
}

/* CSS for pages that deal with site and account settings and bans */
#settingsWrapper {
  text-align: center;
  width: 80%;
  margin: 2em auto;
}

#settingsFieldset {
  padding: 1em;
  display: inline-block;
  text-align: left;
}

.banners {
  margin: 1em;
  width: auto;
  padding: 0.5em;
}

#settingsFieldset textarea {
  display: block;
  height: 5em;
}

#settingsFieldset label {
  display: block;
}

#settingsFieldset label input {
  display: inline-block;
}

#settingsWrapper .captchaDiv input {
  display: inline-block;
}

.subCaptchaDiv {
  text-align: left;
}

.captchaTimer {
  font-size: 80%;
}

.wide, #postingForm input[type='text'], .modalTableBody input[type='text'],
  .modalTableBody select {
  width: 100%;
}

#redirect, #maint {
  text-align: center;
}

#labelCaptchaId {
  color: #ff0000;
}

#staticPageWrapper {
  margin: 2em auto;
  text-align: center;
}

/* footer styles */
footer {
  width: 100%;
  margin: 3em 0px 2em 0px;
  text-align: center;
  font-size: 75%;
}

.innerPost, .markedPost {
  display: inline-block;
  padding: 0.25em;
  max-width: 100%;
}

/* this has to go down here to override anything above it */
.hidden {
  display: none;
}

#settingsWrapper input.hidden {
  display: none;
}

.floatingMenu {
  padding: 0.25em;
}

.floatingMenu .headerLabel {
  font-size: 80%;
}

.floatingMenu .header, .floatingMenu .headerLabel {
  cursor: pointer;
}

#divRemember input {
  display: inline;
}

#ownedDiv a, #volunteeredDiv a {
  display: block;
}

#navBoardList::after {
  content: 'boards';
}

#navOverboard::after, #linkOverboard::after {
  content: 'overboard';
}

#linkSfwOver::after {
  content: 'overboard sfw';
}

#navPosting::after {
  content: 'help';
}

#navLinkHome::after {
  content: 'home';
}

#watcherButton::after {
  content: 'watched threads';
}

#settingsButton::after {
  content: 'settings';
}

#linkGlobalLogs::after {
  content: 'logs';
}

#linkArchives::after {
  content: 'archives';
}

#linkGraphs::after {
  content: 'daily graphs';
}

#linkGlobalRules::after {
  content: 'global rules';
}

#linkLinks::after {
  content: 'links';
}

#linkAbout::after {
  content: 'about';
}

#navOptionsSpan a{
  margin-top: 2px;
}

#linkContact::after {
  content: 'contact';
}

#linkAccount::after {
  content: 'account';
}

@media only screen and (max-width: 812px) {
  #navLinkSpan span, #navOptionsSpan span, legend, #settingsButton, #links span,
    .hideMobile {
    display: none;
  }
  #navLinkSpan a::after, #navOptionsSpan a::after, #links a::after {
    content: '';
  }
  nav {
    font-size: 115%;
    height: auto;
    padding: 2px 2px;
  }
  #themeSelector {
    max-width: 100px;
  }
  .logoImg {
    margin-top: 10px;
    height: 75px;
  }
  input, select, textarea {
    font-size: 100%;
  }
  body {
    font-size: 85%;
    margin-top: 5px;
    margin-left: 0;
    margin-right: 0;
    padding-top: 10px;
    padding-left: 0;
    padding-right: 0;
  }
  .captchaImage {
    max-width: 100%;
    height: auto;
    max-height: 100px;
  }
}


code:
/*Elements exclusive to the front-page*/
#indexWrapper {
  width: 80%;
  margin: 2em auto;
}

#logoBox {
  width: 100%;
  margin: 0 auto 1em auto;
  text-align: center;
}

#infoBox {
  text-align: center;
  width: 100%;
  padding: 0.5em;
  margin: 1em auto 2em;
  font-size: 120%;
}

#links, #divStats {
  padding: 0.5em;
  font-size: 75%;
  text-align: center;
}

#links a {
  text-decoration: none;
}

#linkGlobalLogs:before {
  content: "\e069";
}

#linkArchives:before {
  content: "\e021";
}

#linkGraphs:before {
  content: "\e018";
}

#linkAccount:before {
  content: "\e081";
}

#linkGlobalRules:before {
  content: "\e06f";
}

#linkAbout:before {
  content: "\e0b0";
}

#linkEngine:before {
  content: "\e064";
}

#linkLinks:before {
  content: "\e086";
}

#linkContact:before {
  content: "\e05c";
}

.topBoards {
  width: 100%;
  text-align: center;
  margin: 1em 0px;
}

.topBoards a {
  padding: 0.25em 0.5em;
  text-decoration: none;
  margin: 0.5em 0.25em;
  display: inline-block;
  font-size: 90%;
}

#divLatestPosts {
  width: 100%;
  margin: 1em;
  text-align: center;
}

#divLatestPosts .latestPostCell {
  display: inline-block;
  overflow: hidden;
  padding: 0.5em;
  margin: 0.5em;
  max-width: 15%;
  max-height: 8em;
  font-size: 75%;
  vertical-align: middle;
}

.latestPostCell a {
  display: block;
}

#divLatestImages {
  margin: 0 auto;
  text-align: center;
}

#divLatestImages .latestImageCell {
  display: inline-block;
  max-width: 15%;
  margin: 0 0.5em;
  vertical-align: middle;
}

#divLatestImages img {
  max-width: 125px;
  max-height: 125px;
  padding: 5px;
}

@media only screen and (max-width: 812px) {
  .topBoards, #divLatestPosts {
    margin: 0;
  }
  #indexWrapper {
    width: 99%;
  }
  #links a, #divStats {
    font-size: 153%;
  }
  #linkEngine {
    display: none;
  }
}

repo_name: milk/PenumbraLynx

license: mit


code:
/*Used for places where posts are displayed*/
.hideButton, .embedButton, #closeWatcherMenuButton, .watchButton,
  .watchedCellCloseButton, .hideFileButton, .extraMenuButton,
  #closeSettingsMenuButton {
  margin-left: 0.5em;
}

.imgExpanded {
  max-width: 100%;
}

video {
  max-width: 100%;
}

.imgLink, #selectedDivQr .selectedCell, #selectedDiv .selectedCell {
  float: left;
}

#selectedDivQr .nameLabel, #selectedDiv .nameLabel {
  display: inline-block;
  max-width: 70px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.reportFieldset {
  margin-top: 1em;
  padding: 0.5em;
  margin-bottom: 1em;
}

.labelId {
  color: #ffffff;
  padding: 0.25em;
  border-radius: 5px;
  text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;
}

.quoteTooltip {
  position: absolute;
  display: none
}

#formMore, #qrFormMore, #qrCaptchaButton, #qrFilesButton {
  cursor: pointer;
}

.unhideButton, .embedButton {
  font-size: 80%;
}

.extraMenu, .hideMenu {
  position: absolute;
  top: 0;
  left: 100%;
  margin-left: 10px;
  z-index: 1;
  font-weight: normal;
  white-space: nowrap;
  cursor: default;
  color: #ACACAC;
  text-shadow: none;
}

.theme_clear .extraMenu, .theme_clear .hideMenu {
  color: #000;
}

.hideMenu div, .extraMenu div {
  cursor: pointer;
}

.extraMenuButton, .hideButton {
  position: relative;
}

.hideButton::before {
  content: '\e017';
}

.postInfo, .opHead, .divMessage, .panelUploads, .panelIp, .panelProxyIp,
  .contentOmissionIndicator, .labelOmission, .labelId, .panelASN {
  font-size: 80%;
}

.divPosts {
  margin: 1em 0;
}

.postCell {
  margin: 0.25em 0;
}

.linkName {
  font-weight: bold;
  color: #34ED97;
}

.linkName:hover {
  color: #AA0000;
}

.noEmailName, .noEmailName:hover {
  color: #117743;
  text-shadow: none;
}

.quoteLink {
  color: #ff0000;
}

.linkSelf {
  color: #ACACAC;
  text-decoration: none;
}

.linkSelf:hover {
  color: #AA0000;
}

.linkQuote {
  color: #ACACAC;
  text-decoration: none;
}

.linkQuote:hover {
  color: #ff0000;
}

.labelSubject {
  color: #34ED3A;
  font-weight: bold;
  word-wrap: break-word;
}

.labelRole {
  color: #ff0000;
  font-weight: bold;
}

.labelRole:before {
  font-family: Icons;
  content: "\e0dc";
  color: #A00;
}

.divMessage {
  margin: 1em 1em 1em 3em;
  white-space: pre-wrap;
  word-wrap: break-word;
}

.divBanMessage {
  color: #ff0000;
  font-weight: bold;
  margin: 1em;
  font-size: 100%;
}

.divBanMessage:before {
  font-family: Icons;
  content: "\e0d8";
  color: #A00;
}

.uploadCell {
  margin: 0.25em 1em 0.25em 0.5em;
  float: none;
}

.uploadCell img {
  float: left;
  margin-right: 1em;
  margin-bottom: 1em;
}

/*Change the dimensions if you wish for larger thumbs*/
.uploadCell img:not(.imgExpanded) {
  max-width: 125px;
  height: 125px;
  object-fit: contain;
}

.multipleUploads {
  float: left;
  width: 100%;
}

.multipleUploads .uploadCell:not(.expandedCell) {
  max-width: 150px;
  float: left;
}

.uploadDetails {
  margin-bottom: 0.5em;
}

.originalNameLink {
  display: inline-block;
  vertical-align: top;
  max-width: 155px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.originalNameLink:hover {
  max-width: 100%;
}

.opCell {
  clear: left;
}

.panelBacklinks a {
  color: #AA0000;
  text-decoration: none;
}

.hideLink {
  vertical-align: top;
}

.aa {
  font-family: Mona, "MS PGothic", "ＭＳ Ｐゴシック", sans-serif;
  display: block !important;
  font-size: 12pt;
  line-height: 1.1;
}

.labelLastEdit {
  font-size: 80%;
  margin-top: 0.75em;
  margin-left: 0.75em;
}

.contentOmissionIndicator {
  margin: 1em 0;
}

.labelOmission {
  margin-top: 0.5em;
  margin-left: 0.5em;
}

.imgFlag {
  max-width: 16px;
  max-height: 16px;
}

/*Board header*/
.boardHeader p {
  color: #663E11;
}

.boardHeader p#labelName {
  font-size: 200%;
  display: inline-block;
}

.boardHeader #favouriteButton {
  font-size: 200%;
}

.boardHeader p#labelDescription {
  font-size: 100%;
}

.boardHeader a {
  font-size: 75%;
  display: inline-block;
  text-decoration: none;
}

.unhideButton {
  clear: left;
}

/*Actions form*/
#threadList {
  margin: 1em;
}

#divMessage {
  text-align: center;
  white-space: pre-wrap;
}

.multipleUploads .labelHash {
  word-wrap: anywhere;
}

.contentAction label, #divControls label, #transferControls label,
  #ipDelete label, #divArchive label {
  font-size: 80%;
}

.extraMenuButton::before {
  content: '\e02f';
}

.nameLink::after {
  content: 'Open file';
}

.hideFileButton::after {
  content: '(Hide file)';
}

.hiddenFile::after {
  content: '(Show file)';
}

.modalPanel {
  position: fixed;
  width: 100%;
  height: 100%;
  z-index: 200;
  display: table;
  text-align: center;
  background: rgba(29, 31, 33, 0.66);
  right: 0;
  top: 0;
}

.modalInnerPanel {
  vertical-align: middle;
  display: table-cell;
}

.modalDecorationPanel {
  background: #1D1F21;
  padding: 10px;
  display: inline-block;
}

.theme_clear .modalDecorationPanel {
  background: #cccccc;
}

.modalHeader {
  display: block;
  margin-bottom: 5px;
}

.modalCaptchaControls {
  display: block;
  text-align: left;
}

.modalCaptchaControls input, .modalOkButton {
  margin-right: 10px;
}

#postingForm th, .modalTableBody th {
  font-weight: bold;
  text-align: left;
  width: 100px;
  font-size: 80%;
  padding-left: 0.1em;
  cursor: default;
  border: 1px solid #117743;
  border-radius: 5px;
  background: #282A2E;
}

#postingForm td, .modalTableBody td {
  text-align: left;
}

#postingForm input:focus, #postingForm textarea:focus,
  .modalDecorationPanel input[type='text']:focus, #settingsMenu input[type='text']:focus,
  #settingsMenu textarea:focus {
  box-shadow: 0px 0px 5px 2px #117743;
}

.theme_clear #postingForm th, .theme_clear .modalTableBody th {
  background: #dddddd;
}

@media only screen and (max-width: 812px) {
  .uploadCell img:not(.imgExpanded) {
    max-width: 75px;
    max-height: 75px;
    object-fit: cover;
  }
  .multipleUploads {
    display: block;
  }
  .postInfo, .opHead, .divMessage, .panelUploads, .panelIp, .panelProxyIp,
    .contentOmissionIndicator, .labelOmission, .labelId {
    font-size: 100%;
  }
  .innerPost, .markedPost {
    width: 100%;
    padding: 0;
  }
  #threadList {
    margin: 0;
  }
  iframe {
    display: block;
    width: 100%;
  }
  .divPosts {
    margin: .25em;
  }
  .nameLink::after {
    content: 'Open';
  }
  .hideFileButton::after {
    content: '(Hide)';
  }
  .hiddenFile::after {
    content: '(Show)';
  }
  .originalNameLink, .labelCreated, .sizeLabel, .dimensionLabel {
    display: none;
  }
  .divMessage {
    margin-left: 1em;
  }
}


code:
#settingsMenu {
  position: fixed;
  left: 100px;
  top: 25px;
  z-index: 100;
}

#closeSettingsMenuButton {
  float: right;
}

#cssInput, #jsInput {
  width: 24em;
  height: 12em;
}

#closeSettingsMenuButton::before, .filterDeleteButton::before,
  #closeSideCatalogButton::before {
  content: '\e0db';
}

.settingsTab {
  font-size: 80%;
  cursor: pointer;
  margin: 0.5em;
}

#selectedTab {
  text-shadow: 0px 0px 5px #117743;
}

#settingsMenuContent {
  padding: 0.25em
}

#newFilterPanel * {
  margin: 0.5em
}

.settingsLabel, #labelExistingFilfterType, #labelExistingFilfterContent,
  .existingFilterTypeLabel, .existingFilterContentLabel {
  font-size: 80%;
}

#labelExistingFilfterType, .existingFilterTypeLabel {
  display: inline-block;
  width: 20%;
}

#labelExistingFilfterContent, .existingFilterContentLabel {
  width: 75%;
  display: inline-block;
}

#existingFiltersPanel {
  overflow: hidden;
  overflow-y: auto;
  height: 20em;
}


code:
#mainPanel, #sideCatalogDiv {
  overflow-y: auto;
  height: calc(100vh - 22px);
  margin-top: 22px;
}

#navSideCatalog:before {
  content: "\e088";
}

#sideCatalogDiv {
  float: right;
  padding: 0 10px 0 10px;
  max-width: 20%;
  margin-top: 0;
}

#sideCatalogBody hr {
  clear: both;
}

header {
  margin-top: 36px;
}

#closeSideCatalogButton {
  display: table-cell;
  text-align: right;
}

#sideCatalogHeader {
  display: table;
  width: 100%;
}

.sideCatalogCell, .sideCatalogMarkedCell {
  display: block;
  cursor: pointer;
  padding: 0.5em;
  font-size: 75%;
  overflow: hidden;
  margin-bottom: 10px;
}

#sideCatalogBody img {
  float: left;
  margin-right: 10px;
  max-width: 125px;
  max-height: 125px;
}

.sideCatalogCellText {
  vertical-align: top;
}

.sideCatalogCellText span {
  display: block;
}


code:
/*Elements that show on threads on both catalogs and regular posting places*/
.lockIndicator:before {
  font-family: Icons;
  content: "\e08a";
  color: #A00;
}

#galleryLink:before {
  content: "\e083";
}

.pinIndicator:after {
  font-family: Icons;
  content: "\e0a8";
  color: #A00;
}

.archiveIndicator:after {
  font-family: Icons;
  content: "\e023";
  color: #A00;
}

.cyclicIndicator:after {
  font-family: Icons;
  content: "\e08c";
  color: #A00;
}

.bumpLockIndicator:after {
  font-family: Icons;
  content: "\e0db";
  color: #A00;
}

.galleryImage {
  max-width: 100vw;
  max-height: 100vh;
}

.contentAction label, .contentAction img {
  display: block;
}

#selectedDiv, #selectedDivQr {
  max-height: 200px;
  display: inline-block;
  overflow-y: auto;
}


code:
/*Elements exclusive from the thread page*/
.divRefresh {
  padding: 0;
  height: 1.5em;
}

.labelId {
  cursor: pointer;
}

.divRefresh label, .divRefresh input {
  display: inline-block;
  margin: 0;
  font-size: 80%;
}

#divControls, #transferControls, #ipDelete, #divArchive {
  margin: 1em;
}

.post-table td {
  padding-bottom: 0.25em;
}

#quick-reply {
  position: fixed;
  float: right;
  padding: 0 0 0 0;
  width: 300px;
  z-index: 100;
  display: none;
}

#quick-reply #post-form-inner {
  min-width: 310px;
}

#quick-reply .post-table tr td:nth-child(2) {
  width: 40%;
  text-align: left;
  padding-left: 0.25em;
}

#quick-reply tr td:nth-child(2) input[type="submit"] {
  width: 99%;
}

.spoilerCheckbox {
  font-size: 80%;
}

#quick-reply th {
  text-align: center;
  padding: 2px 0;
  border: 1px solid #222;
}

#quick-reply th .handle {
  float: left;
  width: 100%;
  display: inline-block;
}

#quick-reply th .close-btn {
  float: right;
  padding: 0 5px;
}

#quick-reply input[type="text"], #quick-reply input[type="password"],
  #quick-reply select {
  width: 100%;
  padding: 2px;
  font-size: 10pt;
  box-sizing: border-box;
}

#quick-reply select {
  padding: 2px;
  font-size: 10pt;
  box-sizing: border-box;
  width: 85%;
}

#quick-reply textarea {
  min-width: 100%;
  box-sizing: border-box;
  font-size: 10pt;
  resize: both;
}

#quick-reply input[type="file"] {
  padding: 5px 2px;
}

#quick-reply .nonsense {
  display: none;
}

#quick-reply td.recaptcha {
  text-align: center;
  padding: 0 0 1px 0;
}

#quick-reply td.recaptcha span {
  display: inline-block;
  width: 100%;
  background: white;
  border: 1px solid #ccc;
  cursor: pointer;
}

#quick-reply td.recaptcha-response {
  padding: 0 0 1px 0;
}

#quick-reply table {
  padding: 0.25em;
  margin: 0;
  width: 100%;
  margin: 0;
}

.handle {
  cursor: move;
}


code:
#watcherButton::before {
  content: '\e065';
  margin-right: 0.25em;
}

.watchButton::before {
  content: '\e065';
}

#closeWatcherMenuButton::before, .close-btn::before,
  .watchedCellCloseButton::before {
  content: '\e0db';
}

.watchedCell {
  display: table;
  width: 100%;
}

.watchedCellLabel {
  display: table-cell;
  width: 90%;
}

.watchedNotification::before {
  font-family: 'Icons';
  content: '\e0D8';
  margin-left: 0.25em;
  color: #A00;
}

#watchedMenu {
  position: fixed;
  left: 100px;
  top: 25px;
  z-index: 100;
}

#watchedMenu label {
  font-size: 80%;
  cursor: pointer;
}

@media only screen and (max-width: 812px) {
  .mobileAlert {
    color: #A00;
  }
}


code:
var account = {};

account.settingsRelation = {
  checkboxAlwaysSign : 'alwaysSignRole',
  checkboxReportNotify : 'reportNotify'
};

account.init = function() {

  if (document.getElementById('requestConfirmationFormButton')) {
    api.convertButton('requestConfirmationFormButton',
        account.requestConfirmation);
  }

  api.convertButton('passwordFormButton', account.changePassword,
      'passwordChangeField');

  api.convertButton('deleteAccountFormButton', account.deleteAccount,
      'deleteAccountField');

  api.convertButton('saveFormButton', account.save, 'settingsField');

  api.convertButton('logoutFormButton', account.logout);

  if (document.getElementById('boardCreationDiv')) {
    api.convertButton('newBoardFormButton', account.createBoard,
        'creationField');
  }

};

account.deleteAccount = function() {

  var confirmed = document.getElementById('confirmationCheckbox').checked;

  if (!confirmed) {
    alert('You must confirm that you wish to delete your account.');
  } else {

    api.formApiRequest('deleteAccount', {
      confirmation : confirmed
    }, function requestComplete(status, data) {

      if (status === 'ok') {
        window.location = '/';
      } else {
        alert(status + ': ' + JSON.stringify(data));
      }
    });

  }

};

account.requestConfirmation = function() {

  api.formApiRequest('requestEmailConfirmation', {}, function requestComplete(
      status, data) {

    if (status === 'ok') {
      alert('Confirmation requested.');
    } else {
      alert(status + ': ' + JSON.stringify(data));
    }

  });

};

account.logout = function() {

  document.cookie = 'login=invalid+login';
  document.cookie = 'hash=invalid+hash; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';

  window.location.pathname = '/login.html';

};

account.changePassword = function() {

  var typedPassword = document.getElementById('fieldPassword').value;
  var typedNewPassword = document.getElementById('fieldNewPassword').value;
  var typedConfirmation = document.getElementById('fieldConfirmation').value;

  if (!typedPassword.length) {
    alert('You must provide your current password.');
  } else if (typedConfirmation !== typedNewPassword) {
    alert('Password confirmation does no match')
  } else if (!typedNewPassword.length) {
    alert('You cannot provide a blank password.');
  } else {
    api.formApiRequest('changeAccountPassword', {
      password : typedPassword,
      newPassword : typedNewPassword,
      confirmation : typedConfirmation
    }, function requestComplete(status, data) {

      if (status === 'ok') {

        alert('Password changed.');

        document.getElementById('fieldPassword').value = '';
        document.getElementById('fieldNewPassword').value = '';
        document.getElementById('fieldConfirmation').value = '';

      } else {
        alert(status + ': ' + JSON.stringify(data));
      }
    });
  }

};

account.save = function() {

  var parameters = {};

  for ( var key in account.settingsRelation) {
    parameters[account.settingsRelation[key]] = document.getElementById(key).checked;
  }

  var typedEmail = document.getElementById('emailField').value.trim();

  if (typedEmail.length > 64) {
    alert('Email too long, keep it under 64 characters');
  } else {

    parameters.email = typedEmail

    api.formApiRequest('changeAccountSettings', parameters,
        function requestComplete(status, data) {

          if (status === 'ok') {
            alert('Settings changed.');
          } else {
            alert(status + ': ' + JSON.stringify(data));
          }
        });

  }

};

account.createBoard = function() {

  var typedUri = document.getElementById('newBoardFieldUri').value.trim();
  var typedName = document.getElementById('newBoardFieldName').value.trim();
  var typedDescription = document.getElementById('newBoardFieldDescription').value
      .trim();
  var typedCaptcha = document.getElementById('fieldCaptcha').value.trim();

  if (!typedUri.length || !typedName.length) {
    alert('Uri and name are mandatory.');
  } else if (/\W/.test(typedUri)) {
    alert('Invalid uri.');
    return;
  } else if (typedCaptcha.length !== 6 && typedCaptcha.length !== 24) {
    alert('Captchas are exactly 6 (24 if no cookies) characters long.');
    return;
  } else if (/\W/.test(typedCaptcha)) {
    alert('Invalid captcha.');
    return;
  } else {
    api.formApiRequest('createBoard', {
      boardUri : typedUri,
      boardName : typedName,
      boardDescription : typedDescription,
      captcha : typedCaptcha
    }, function requestComplete(status, data) {

      if (status === 'ok') {
        window.location.pathname = '/' + typedUri + '/';
      } else {
        alert(status + ': ' + JSON.stringify(data));
      }
    });
  }

};

account.init();


code:
var accountManagement = {};

accountManagement.init = function() {

  api.convertButton('deleteAccountFormButton', accountManagement.deleteAccount,
      'deleteAccountField');

};

accountManagement.deleteAccount = function() {

  var confirmed = document.getElementById('confirmationCheckbox').checked;

  if (!confirmed) {
    alert('You must confirm that you wish to delete this account.');
  } else {

    api.formApiRequest('deleteAccount', {
      confirmation : confirmed,
      account : document.getElementById('userIdentifier').value
    }, function requestComplete(status, data) {

      if (status === 'ok') {
        window.location = '/accounts.js';
      } else {
        alert(status + ': ' + JSON.stringify(data));
      }
    });

  }

};

accountManagement.init();


code:
var accounts = {};

accounts.init = function() {

  accounts.divAccounts = document.getElementById('divAccounts');

  api.convertButton('addAccountFormButton', accounts.addAccount,
      'addAccountField');

};

accounts.addAccount = function() {

  var typedLogin = document.getElementById('fieldLogin').value.trim();
  var typedPassword = document.getElementById('fieldPassword').value;
  var typedEmail = document.getElementById('fieldEmail').value;

  if (!typedLogin.length || !typedPassword.length) {
    alert('Both login and password are mandatory.');
  } else if (typedLogin.length > 16) {
    alert('Login too long, keep it under 16 characters.');
  } else if (/\W/.test(typedLogin)) {
    alert('Invalid login.');
  } else {

    api.formApiRequest('addAccount', {
      login : typedLogin,
      password : typedPassword,
      email : typedEmail
    }, function requestComplete(status, data) {

      if (status === 'ok') {

        var newLink = document.createElement('a');
        newLink.innerHTML = typedLogin;
        newLink.href = '/accountManagement.js?account=' + typedLogin;
        accounts.divAccounts.appendChild(newLink);

        document.getElementById('fieldLogin').value = '';
        document.getElementById('fieldPassword').value = '';
        document.getElementById('fieldEmail').value = '';

      } else {
        alert(status + ': ' + JSON.stringify(data));
      }
    });

  }

};

accounts.init();


code:
var api = {};

api.mobile = window.innerWidth < 812;

api.padDateField = function(value) {

  if (value < 10) {
    value = '0' + value;
  }

  return value;

};

api.formatDateToDisplay = function(d, local) {

  var day = api.padDateField(d[local ? 'getDate' : 'getUTCDate']());

  var weekDays = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ];

  var month = api.padDateField(d[local ? 'getMonth' : 'getUTCMonth']() + 1);

  var year = d[local ? 'getFullYear' : 'getUTCFullYear']();

  var weekDay = weekDays[d[local ? 'getDay' : 'getUTCDay']()];

  var hour = api.padDateField(d[local ? 'getHours' : 'getUTCHours']());

  var minute = api.padDateField(d[local ? 'getMinutes' : 'getUTCMinutes']());

  var second = api.padDateField(d.getUTCSeconds());

  var toReturn = month + '/' + day + '/' + year;

  return toReturn + ' (' + weekDay + ') ' + hour + ':' + minute + ':' + second;

};

api.htmlReplaceTable = {
  '<' : '<',
  '>' : '>',
  '\"' : '"',
  '\'' : '''
};

api.removeIndicator = function(className, thread) {

  var elements = (thread || document).getElementsByClassName(className);

  if (!elements.length) {
    return;
  }

  elements[0].nextSibling.remove();
  elements[0].remove();

};

api.addIndicator = function(className, title, thread) {

  var spanId = (thread || document).getElementsByClassName('spanId')[0];

  if (!spanId) {
    spanId = (thread || document).getElementsByClassName('labelCreated')[0];
  }

  var indicator = document.createElement('span');
  indicator.className = className;
  indicator.title = title;

  spanId.parentNode.insertBefore(indicator, spanId.nextSibling);
  spanId.parentNode.insertBefore(document.createTextNode(' '),
      spanId.nextSibling);

};

api.resetIndicators = function(data, thread) {

  api.removeIndicator('lockIndicator', thread);
  api.removeIndicator('pinIndicator', thread);
  api.removeIndicator('cyclicIndicator', thread);
  api.removeIndicator('archiveIndicator', thread);

  api.addIndicator('cyclicIndicator', 'Cyclical Thread', thread);
  api.addIndicator('pinIndicator', 'Sticky', thread);
  api.addIndicator('lockIndicator', 'Locked', thread);
  api.addIndicator('archiveIndicator', 'Archived', thread);

  if (!data.locked) {
    api.removeIndicator('lockIndicator', thread);
  }

  if (!data.pinned) {
    api.removeIndicator('pinIndicator', thread);
  }

  if (!data.cyclic) {
    api.removeIndicator('cyclicIndicator', thread);
  }

  if (!data.archived) {
    api.removeIndicator('archiveIndicator', thread);
  }

};

api.addEnterEvent = function(element, onclick) {

  element.addEventListener('keydown', function(event) {

    if (event.key === 'Enter') {
      onclick();
      event.preventDefault();
    }

  });

};

api.convertButton = function(button, onclick, inputs) {

  if (typeof (button) === 'string') {
    button = document.getElementById(button);
  }

  button.type = 'button';
  button.onclick = onclick;

  if (!inputs) {
    return;
  }

  inputs = document.getElementsByClassName(inputs);

  for (var i = 0; i < inputs.length; i++) {
    api.addEnterEvent(inputs[i], onclick);
  }

};

api.getCookies = function() {

  var parsedCookies = {};

  var cookies = document.cookie.split(';');

  for (var i = 0; i < cookies.length; i++) {

    var cookie = cookies[i];

    var parts = cookie.split('=');
    parsedCookies[parts.shift().trim()] = decodeURI(parts.join('='));

  }

  return parsedCookies;

};

api.handleConnectionResponse = function(xhr, callback, silent) {

  var response;

  try {
    response = JSON.parse(xhr.responseText);
  } catch (error) {
    if (!silent) {
      alert('Error in parsing response.');
    }
    return;
  }

  if (response.status === 'error') {

    if (!silent) {
      alert(response.data);
    }

  } else if (response.status === 'hashBan') {

    var desc = '';

    var bans = response.data;

    for (var i = 0; i < bans.length; i++) {
      var ban = bans[i];

      if (i) {
        desc += '\n';
      }

      desc += 'File ' + ban.file + ' is banned from '
          + (ban.boardUri ? '/' + ban.boardUri + '/' : 'all boards.');

    }

    alert(desc);
  } else if (response.status === 'bypassable') {

    postCommon.displayBlockBypassPrompt(function() {
      alert('You may now post');
    });

  } else if (response.status === 'maintenance') {

    if (!silent) {
      alert('The site is going under maintenance and all of it\'s functionalities are disabled temporarily.');
    }

  } else if (response.status === 'banned') {

    var message;

    if (response.data.range) {
      message = 'Your ip range ' + response.data.range
          + ' has been banned from ' + response.data.board + '.';
    } else if (response.data.asn) {
      message = 'Your ASN ' + response.data.asn + ' has been banned from '
          + response.data.board + '.';
    } else if (response.data.warning) {
      message = 'You have been warned on ' + response.data.board + '.';
    } else {
      message = 'You are banned from ' + response.data.board + '.';
    }

    if (response.data.reason) {
      message += '\nReason: "' + response.data.reason + '".';
    }

    if (response.data.warning) {
      return alert(message);
    }

    if (response.data.expiration) {

      message += '\nThis ban will expire at '
          + new Date(response.data.expiration).toString() + '.';

    } else {
      message += '\nThis ban will not expire.'
    }

    message += '\nYour ban id: ' + response.data.banId + '.';

    if (!response.data.appealled) {
      message += '\nYou may appeal this ban.';

      var appeal = prompt(message, 'Write your appeal');

      if (appeal) {

        api.formApiRequest('appealBan', {
          appeal : appeal,
          banId : response.data.banId
        }, function appealed(status, data) {

          if (status !== 'ok') {
            alert(data);
          } else {
            alert('Ban appealed');
          }

        });

      }

    } else {
      alert(message);
    }

  } else {
    callback(response.status, response.data);
  }

};

api.formApiRequest = function(page, parameters, callback, silent, getParameters) {

  var silent;

  page += '.js?json=1';

  getParameters = getParameters || {};

  for ( var parameter in getParameters) {
    page += '&' + parameter + '='
        + encodeURIComponent(getParameters[parameter]);
  }

  var xhr = new XMLHttpRequest();

  if ('withCredentials' in xhr) {
    xhr.open('POST', '/' + page, true);
  } else if (typeof XDomainRequest != 'undefined') {

    xhr = new XDomainRequest();
    xhr.open('POST', '/' + page);
  } else {
    alert('Update your browser or turn off javascript.');

    return;
  }

  if (callback.hasOwnProperty('progress')) {
    xhr.upload.onprogress = callback.progress;
  }

  xhr.onreadystatechange = function connectionStateChanged() {

    if (xhr.readyState !== 4) {
      return;
    }

    if (parameters.captcha) {
      captchaUtils.reloadCaptcha();
    }

    if (callback.hasOwnProperty('stop')) {
      callback.stop();
    }

    if (xhr.status != 200) {
      if (!silent) {
        alert('Connection failed.');
      }

      return;
    }

    api.handleConnectionResponse(xhr, callback, silent);

  };

  var form = new FormData();

  for ( var entry in parameters) {

    if (!parameters[entry] && typeof (parameters[entry] !== 'number')) {
      continue;
    }

    if (entry !== 'files') {
      form.append(entry, parameters[entry]);
    } else {

      var files = parameters.files;

      for (var i = 0; i < files.length; i++) {

        var file = files[i];

        if (file.md5 && file.mime) {
          form.append('fileMd5', file.md5);
          form.append('fileMime', file.mime);
          form.append('fileSpoiler', file.spoiler || '');
          form.append('fileName', file.name);
        }

        if (file.content) {
          form.append('files', file.content, file.name);
        }

      }

    }

  }

  xhr.send(form);

};

api.localRequest = function(address, callback) {

  var xhr = new XMLHttpRequest();

  if ('withCredentials' in xhr) {
    xhr.open('GET', address, true);
  } else if (typeof XDomainRequest != 'undefined') {

    xhr = new XDomainRequest();
    xhr.open('GET', address);
  } else {
    alert('Update your browser or turn off javascript.');
    return;
  }

  xhr.onreadystatechange = function connectionStateChanged() {

    if (xhr.readyState == 4) {

      if (callback.hasOwnProperty('stop')) {
        callback.stop();
      }

      if (xhr.status != 200) {
        callback('Connection failed');
      } else {
        callback(null, xhr.responseText);
      }

    }
  };

  xhr.send();

};


code:
var asnBans = {};

asnBans.init = function() {

  var boardIdentifier = document.getElementById('boardIdentifier');

  if (boardIdentifier) {
    api.boardUri = boardIdentifier.value;
  }

  api.convertButton('createFormButton', asnBans.placeAsnBan, 'asnBanField');

  var rangeBanCells = document.getElementsByClassName('asnBanCell');

  for (var j = 0; j < rangeBanCells.length; j++) {
    asnBans.processAsnBanCell(rangeBanCells[j]);
  }

  asnBans.bansDiv = document.getElementById('asnBansDiv');

};

asnBans.processAsnBanCell = function(cell) {

  var button = cell.getElementsByClassName('liftFormButton')[0];

  api.convertButton(button, function() {
    asnBans.liftBan(cell);
  });

};

asnBans.liftBan = function(cell) {

  api.formApiRequest('liftBan', {
    banId : cell.getElementsByClassName('idIdentifier')[0].value
  }, function requestComplete(status, data) {

    if (status === 'ok') {
      cell.remove();
    } else {
      alert(status + ': ' + JSON.stringify(data));
    }
  });

};

asnBans.showNewAsnBan = function(typedRange, id) {

  var form = document.createElement('form');
  form.className = 'asnBanCell';
  form.action = '/liftBan.js';
  form.method = 'post';
  form.enctype = 'multipart/form-data';
  asnBans.bansDiv.appendChild(form);

  form.appendChild(document.createElement('hr'));

  var asnPara = document.createElement('p');
  asnPara.innerHTML = 'Asn: ';
  form.appendChild(asnPara);

  var rangeLabel = document.createElement('span');
  rangeLabel.innerHTML = typedRange;
  rangeLabel.className = 'asnLabel';
  asnPara.appendChild(rangeLabel);

  var idIdentifier = document.createElement('input');
  idIdentifier.className = 'idIdentifier';
  idIdentifier.type = 'hidden';
  form.appendChild(idIdentifier);
  idIdentifier.value = id;

  var liftButton = document.createElement('button');
  liftButton.type = 'submit';
  liftButton.innerHTML = 'Lift ban';
  liftButton.className = 'liftFormButton';
  form.appendChild(liftButton);

  asnBans.processAsnBanCell(form);

};

asnBans.placeAsnBan = function() {

  var typedAsn = document.getElementById('asnField').value.trim();
  var typedDuration = document.getElementById('durationField').value.trim();
  var typedReason = document.getElementById('reasonField').value.trim();

  var parameters = {
    asn : typedAsn,
    boardUri : api.boardUri,
    duration : typedDuration,
    reason : typedReason
  };

  api.formApiRequest('placeAsnBan', parameters, function requestComplete(
      status, data) {

    if (status === 'ok') {

      document.getElementById('asnField').value = '';
      asnBans.showNewAsnBan(typedAsn, data);

    } else {
      alert(status + ': ' + JSON.stringify(data));
    }
  });

};

asnBans.init();


code:
var bannerManagement = {};

bannerManagement.init = function() {

  if (document.getElementById('boardIdentifier')) {
    api.boardUri = document.getElementById('boardIdentifier').value;
  }

  api.convertButton('addFormButton', bannerManagement.addBanner);

  var bannersDiv = document.getElementById('bannersDiv');

  for (var j = 0; j < bannersDiv.childNodes.length; j++) {
    bannerManagement.processBannerCell(bannersDiv.childNodes[j]);
  }

  bannerManagement.bannersDiv = bannersDiv;

};

bannerManagement.processBannerCell = function(cell) {

  var button = cell.getElementsByClassName('deleteFormButton')[0];

  api.convertButton(button, function() {
    bannerManagement.removeBanner(cell);
  });

};

bannerManagement.showNewBanner = function(data) {

  var form = document.createElement('form');
  form.className = 'bannerCell';
  form.action = '/deleteBanner.js';
  form.method = 'post';
  form.enctype = 'multipart/form-data';

  var img = document.createElement('img');
  img.className = 'bannerImage';
  img.src = data.path;
  form.appendChild(img);

  form.appendChild(document.createElement('br'));

  var identifier = document.createElement('input');
  identifier.name = 'bannerId';
  identifier.className = 'bannerIdentifier';
  identifier.value = data.id;
  identifier.type = 'hidden';
  form.appendChild(identifier);

  var button = document.createElement('button');
  button.type = 'button';
  button.className = 'deleteFormButton';
  button.innerHTML = 'Delete banner';
  form.appendChild(button);

  form.appendChild(document.createElement('hr'));

  bannerManagement.bannersDiv.appendChild(form);

  bannerManagement.processBannerCell(form);

};

bannerManagement.addBanner = function() {

  var filePicker = document.getElementById('files');

  var files = [];

  for (var i = 0; i < filePicker.files.length; i++) {
    files.push({
      content : filePicker.files[i]
    });
  }

  if (!files.length) {
    alert('You must select a file');
    return;
  }

  api.formApiRequest('createBanners', {
    files : files,
    boardUri : api.boardUri,
  }, function requestComplete(status, data) {

    if (status === 'ok') {

      filePicker.type = 'text';
      filePicker.type = 'file';

      for (var i = 0; i < data.length; i++) {
        bannerManagement.showNewBanner(data[i]);
      }

    } else {
      alert(status + ': ' + JSON.stringify(data));
    }
  });

};

bannerManagement.removeBanner = function(cell) {

  api.formApiRequest('deleteBanner', {
    bannerId : cell.getElementsByClassName('bannerIdentifier')[0].value,
  }, function requestComplete(status, data) {

    if (status === 'ok') {
      cell.remove();
    } else {
      alert(status + ': ' + JSON.stringify(data));
    }
  });

};

bannerManagement.init();


code:
var bans = {};

bans.init = function() {

  var banCells = document.getElementsByClassName('banCell');

  for (var j = 0; j < banCells.length; j++) {
    bans.processBanCell(banCells[j]);
  }

};

bans.processBanCell = function(cell) {

  var liftButton = cell.getElementsByClassName('liftFormButton')[0];

  api.convertButton(liftButton, function() {
    bans.liftBan(cell);
  });

  if (cell.getElementsByClassName('denyForm')[0]) {

    var denyButton = cell.getElementsByClassName('denyFormButton')[0];

    api.convertButton(denyButton, function() {
      bans.denyAppeal(cell);
    });

  }

};

bans.denyAppeal = function(cell) {

  api.formApiRequest('denyAppeal', {
    banId : cell.getElementsByClassName('denyIdentifier')[0].value
  }, function requestComplete(status, data) {

    if (status === 'ok') {

      if (api.management) {
        cell.remove();
      } else {
        cell.getElementsByClassName('denyFormButton')[0].remove();
      }

    } else {
      alert(status + ': ' + JSON.stringify(data));
    }
  });

};

bans.liftBan = function(cell) {

  api.formApiRequest('liftBan', {
    banId : cell.getElementsByClassName('liftIdentifier')[0].value
  }, function requestComplete(status, data) {

    if (status === 'ok') {
      cell.remove();
    } else {
      alert(status + ': ' + JSON.stringify(data));
    }
  });

};

bans.init();


code:
api.isBoard = true;

var board = {};

board.init = function() {

  api.mod = !!document.getElementById('divMod');
  api.hiddenCaptcha = !document.getElementById('captchaDiv');

  var identifierElement = document.getElementById('boardIdentifier');
  api.boardUri = identifierElement ? identifierElement.value : null;

  if (!api.boardUri) {

    var altIdentifierElement = document.getElementById('labelBoard');

    api.boardUri = altIdentifierElement ? altIdentifierElement.innerHTML
        .replace(/\//g, '') : null;

  }

  if (identifierElement) {

    board.messageLimit = +document.getElementById('labelMessageLength').innerHTML;

    board.postButton = document.getElementById('formButton');

    api.convertButton(board.postButton, board.postThread);

    board.postButton.disabled = false;

  }

  if (api.mod) {
    api.convertButton('inputBan', posting.banPosts, 'banField');
    api.convertButton('inputIpDelete', posting.deleteFromIpOnBoard);
    api.convertButton('inputSpoil', posting.spoilFiles);
  }

};

board.postCallback = function(status, data) {

  if (status === 'ok') {

    postCommon.storeUsedPostingPassword(api.boardUri, data);

    window.location.pathname = '/' + api.boardUri + '/res/' + data + '.html';
  } else {
    alert(status + ': ' + JSON.stringify(data));
  }
};

board.postCallback.stop = function() {
  board.postButton.innerHTML = board.originalButtonText;
  board.postButton.disabled = false;
};

board.postCallback.progress = function(info) {

  if (info.lengthComputable) {
    var newText = 'Uploading ' + Math.floor((info.loaded / info.total) * 100)
        + '%';
    board.postButton.innerHTML = newText;
  }
};

board.sendThreadData = function(files, captchaId) {

  var hiddenFlags = !document.getElementById('flagsDiv');

  if (!hiddenFlags) {
    var combo = document.getElementById('flagCombobox');

    var selectedFlag = combo.options[combo.selectedIndex].value;

    postCommon.savedSelectedFlag(selectedFlag);
  }

  var forcedAnon = !document.getElementById('fieldName');

  if (!forcedAnon) {
    var typedName = document.getElementById('fieldName').value.trim();

    localStorage.setItem('name', typedName);

  }

  var typedEmail = document.getElementById('fieldEmail').value.trim();
  var typedMessage = document.getElementById('fieldMessage').value.trim();
  var typedSubject = document.getElementById('fieldSubject').value.trim();
  var typedPassword = document.getElementById('fieldPostingPassword').value
      .trim();

  if (!typedMessage.length) {
    alert('A message is mandatory.');
    return;
  } else if (!forcedAnon && typedName.length > 32) {
    alert('Name is too long, keep it under 32 characters.');
    return;
  } else if (typedMessage.length > board.messageLimit) {
    alert('Message is too long, keep it under ' + board.messageLimit
        + ' characters.');
    return;
  } else if (typedEmail.length > 64) {
    alert('Email is too long, keep it under 64 characters.');
    return;
  } else if (typedSubject.length > 128) {
    alert('Subject is too long, keep it under 128 characters.');
    return;
  } else if (typedPassword.length > 8) {
    alert('Password is too long, keep it under 8 characters.');
    return;
  }

  if (!typedPassword) {
    typedPassword = Math.random().toString(36).substring(2, 10);
  }

  localStorage.setItem('deletionPassword', typedPassword);

  board.originalButtonText = board.postButton.innerHTML;
  board.postButton.innerHTML = 'Uploading 0%';
  board.postButton.disabled = true;

  var spoilerCheckBox = document.getElementById('checkboxSpoiler');

  var noFlagCheckBox = document.getElementById('checkboxNoFlag');

  api.formApiRequest('newThread', {
    name : forcedAnon ? null : typedName,
    flag : hiddenFlags ? null : selectedFlag,
    captcha : captchaId,
    password : typedPassword,
    noFlag : noFlagCheckBox ? noFlagCheckBox.checked : false,
    spoiler : spoilerCheckBox ? spoilerCheckBox.checked : false,
    subject : typedSubject,
    message : typedMessage,
    email : typedEmail,
    files : files,
    boardUri : api.boardUri
  }, board.postCallback);

};

board.processFilesToPost = function(captchaId) {

  postCommon.newGetFilesToUpload(function gotFiles(files) {
    board.sendThreadData(files, captchaId);
  });

};

board.processThreadRequest = function() {

  if (api.hiddenCaptcha) {
    board.processFilesToPost();
  } else {
    var typedCaptcha = document.getElementById('fieldCaptcha').value.trim();

    if (typedCaptcha.length !== 6 && typedCaptcha.length !== 24) {
      alert('Captchas are exactly 6 (24 if no cookies) characters long.');
      return;
    } else if (/\W/.test(typedCaptcha)) {
      alert('Invalid captcha.');
      return;
    }

    if (typedCaptcha.length == 24) {
      board.processFilesToPost(typedCaptcha);
    } else {
      var parsedCookies = api.getCookies();

      api.formApiRequest('solveCaptcha', {
        captchaId : parsedCookies.captchaid,
        answer : typedCaptcha
      }, function solvedCaptcha(status, data) {

        if (status !== 'ok') {
          alert(status);
          return;
        }

        board.processFilesToPost(parsedCookies.captchaid);
      });
    }

  }

};

board.postThread = function() {

  api.formApiRequest('blockBypass', {},
      function checked(status, data) {

        if (status !== 'ok') {
          alert(data);
          return;
        }

        var alwaysUseBypass = document
            .getElementById('alwaysUseBypassCheckBox').checked;

        if (!data.valid
            && (data.mode == 2 || (data.mode == 1 && alwaysUseBypass))) {

          postCommon.displayBlockBypassPrompt(function() {
            board.processThreadRequest();
          });

        } else {
          board.processThreadRequest();
        }

      });

};

board.init();


code:
var boardManagement = {};

boardManagement.init = function() {

  api.management = true;

  var volunteerCellTemplate = ' ';
  volunteerCellTemplate += '<input ';
  volunteerCellTemplate += 'type="hidden" ';
  volunteerCellTemplate += 'class="userIdentifier" ';
  volunteerCellTemplate += 'name="login">';
  volunteerCellTemplate += '<input ';
  volunteerCellTemplate += 'type="hidden" ';
  volunteerCellTemplate += 'class="boardIdentifier" ';
  volunteerCellTemplate += 'name="boardUri">';
  volunteerCellTemplate += '<input ';
  volunteerCellTemplate += 'type="hidden" ';
  volunteerCellTemplate += 'name="add" ';
  volunteerCellTemplate += 'value=false>';
  volunteerCellTemplate += '<button ';
  volunteerCellTemplate += 'type="submit" ';
  volunteerCellTemplate += 'class="removeFormButton" ';
  volunteerCellTemplate += '>Remove Volunteer</button';

  boardManagement.volunteerCellTemplate = volunteerCellTemplate;

  var resetLockButton = document.getElementById('resetLockButton');

  if (resetLockButton) {
    resetLockButton.type = 'button';
    resetLockButton.onclick = boardManagement.resetLock;
  }

  if (document.getElementById('ownerControlDiv')) {

    api.convertButton('spoilerFormButton', boardManagement.setSpoiler);
    api.convertButton('cssFormButton', boardManagement.setCss);
    api.convertButton('deleteBoardFormButton', boardManagement.deleteBoard,
        'deleteBoardField');
    api.convertButton('addVolunteerFormButton', boardManagement.addVolunteer,
        'addVolunteerField');
    api.convertButton('transferBoardFormButton', boardManagement.transferBoard,
        'transferBoardField');

    if (document.getElementById('customJsForm')) {
      api.convertButton('jsFormButton', boardManagement.setJs);
    }

    var volunteerDiv = document.getElementById('volunteersDiv');

    for (var i = 0; i < volunteerDiv.childNodes.length; i++) {
      boardManagement.processVolunteerCell(volunteerDiv.childNodes[i]);
    }
  }

  api.convertButton('closeReportsFormButton', reports.closeReports,
      'closeReportsField');

  var settingsIdentifier = document.getElementById('boardSettingsIdentifier');

  if (!settingsIdentifier) {
    return;
  }

  api.boardUri = settingsIdentifier.value;

  api.convertButton('saveSettingsFormButton', boardManagement.saveSettings,
      'boardSettingsField');

};

boardManagement.resetLock = function() {

  api.formApiRequest('resetBoardLock', {
    boardUri : api.boardUri,
  }, function requestComplete(status, data) {

    if (status === 'ok') {
      document.getElementById('resetBoardLockForm').remove();
    } else {
      alert(status + ': ' + JSON.stringify(data));
    }
  });

};

boardManagement.setJs = function() {

  var file = document.getElementById('JsFiles').files[0];

  api.formApiRequest('setCustomJs', {
    files : [ {
      content : file
    } ],
    boardUri : api.boardUri,
  }, function requestComplete(status, data) {

    document.getElementById('JsFiles').type = 'text';
    document.getElementById('JsFiles').type = 'file';

    if (status === 'ok') {

      if (file) {
        alert('New javascript set.');
      } else {
        alert('Javascript deleted.');
      }

    } else {
      alert(status + ': ' + JSON.stringify(data));
    }
  });

};

boardManagement.setIndicatorForRequest = function(obtainedSpoiler) {

  var spoilerIndicator = document.getElementById('customSpoilerIndicator');

  var haveSpoiler = spoilerIndicator ? true : false;

  if (haveSpoiler !== obtainedSpoiler) {

    if (obtainedSpoiler) {

      var marker = document.getElementById('indicatorMarker');

      var indicator = document.createElement('div');
      indicator.id = 'customSpoilerIndicator';
      marker.parentNode.insertBefore(indicator, marker);

      var indicatorText = document.createElement('p');
      indicatorText.innerHTML = 'There is a custom spoiler saved for this board';
      indicator.appendChild(indicatorText);

    } else {
      spoilerIndicator.remove();
    }

  } else if (obtainedSpoiler) {
    alert('New spoiler uploaded.');
  }

};

boardManagement.setSpoiler = function() {

  var file = document.getElementById('filesSpoiler').files[0];

  api.formApiRequest('setCustomSpoiler', {
    files : [ {
      content : file
    } ],
    boardUri : api.boardUri,
  }, function requestComplete(status, data) {

    if (status === 'ok') {
      boardManagement.setIndicatorForRequest(!!file);
    } else {
      alert(status + ': ' + JSON.stringify(data));
    }

    document.getElementById('filesSpoiler').type = 'text';
    document.getElementById('filesSpoiler').type = 'file';

  });

};

boardManagement.setCss = function() {

  var file = document.getElementById('files').files[0];

  api.formApiRequest('setCustomCss', {
    files : [ {
      content : file
    } ],
    boardUri : api.boardUri,
  }, function requestComplete(status, data) {

    document.getElementById('files').type = 'text';
    document.getElementById('files').type = 'file';

    if (status === 'ok') {

      if (file) {
        alert('New CSS set.');
      } else {
        alert('CSS deleted.');
      }

    } else {
      alert(status + ': ' + JSON.stringify(data));
    }
  });

};

boardManagement.saveSettings = function() {

  var typedName = document.getElementById('boardNameField').value.trim();
  var typedDescription = document.getElementById('boardDescriptionField').value
      .trim();
  var typedMessage = document.getElementById('boardMessageField').value.trim();
  var typedAnonymousName = document.getElementById('anonymousNameField').value
      .trim();
  var typedHourlyLimit = document.getElementById('hourlyThreadLimitField').value
      .trim();
  var typedAutoCaptcha = document.getElementById('autoCaptchaThresholdField').value
      .trim();
  var typedMaxBumpAge = document.getElementById('maxBumpAgeField').value.trim();
  var typedAutoSage = document.getElementById('autoSageLimitField').value
      .trim();
  var typedFileLimit = document.getElementById('maxFilesField').value.trim();
  var typedFileSize = document.getElementById('maxFileSizeField').value.trim();
  var typedTypedMimes = document.getElementById('validMimesField').value
      .split(',');
  var typedThreadLimit = document.getElementById('maxThreadsField').value
      .trim();

  if (typedHourlyLimit.length && isNaN(typedHourlyLimit)) {
    alert('Invalid hourly limit.');
    return;
  } else if (typedMaxBumpAge.length && isNaN(typedMaxBumpAge)) {
    alert('Invalid maximum age for bumping.');
    return;
  } else if (typedAutoCaptcha.length && isNaN(typedAutoCaptcha)) {
    alert('Invalid auto captcha treshold.');
    return;
  } else if (!typedName) {
    alert('Name is mandatory.');
    return;
  } else if (typedMessage.length > 256) {
    alert('Message too long, keep it under 256 characters.');
    return;
  }

  var typedTags = document.getElementById('tagsField').value.split(',');

  var combo = document.getElementById('captchaModeComboBox');

  var locationCombo = document.getElementById('locationComboBox');

  var langCombo = document.getElementById('languageCombobox');

  var parameters = {
    boardName : typedName,
    preferredLanguage : langCombo[langCombo.selectedIndex].value,
    captchaMode : combo.options[combo.selectedIndex].value,
    boardMessage : typedMessage,
    autoCaptchaLimit : typedAutoCaptcha,
    locationFlagMode : locationCombo.options[locationCombo.selectedIndex].value,
    hourlyThreadLimit : typedHourlyLimit,
    tags : typedTags,
    anonymousName : typedAnonymousName,
    boardDescription : typedDescription,
    boardUri : api.boardUri,
    autoSageLimit : typedAutoSage,
    maxThreadCount : typedThreadLimit,
    maxFileSizeMB : typedFileSize,
    acceptedMimes : typedTypedMimes,
    maxFiles : typedFileLimit,
    maxBumpAge : typedMaxBumpAge
  };

  parameters.blockDeletion = document.getElementById('blockDeletionCheckbox').checked;
  parameters.disableIds = document.getElementById('disableIdsCheckbox').checked;
  parameters.requireThreadFile = document.getElementById('requireFileCheckbox').checked;
  parameters.allowCode = document.getElementById('allowCodeCheckbox').checked;
  parameters.early404 = document.getElementById('early404Checkbox').checked;
  parameters.uniquePosts = document.getElementById('uniquePostsCheckbox').checked;
  parameters.uniqueFiles = document.getElementById('uniqueFilesCheckbox').checked;
  parameters.unindex = document.getElementById('unindexCheckbox').checked;
  parameters.forceAnonymity = document.getElementById('forceAnonymityCheckbox').checked;
  parameters.textBoard = document.getElementById('textBoardCheckbox').checked;

  api.formApiRequest('setBoardSettings', parameters, function requestComplete(
      status, data) {

    if (status === 'ok') {
      alert('Settings saved.');
    } else {
      alert(status + ': ' + JSON.stringify(data));
    }

  });

};

boardManagement.processVolunteerCell = function(cell) {

  var button = cell.getElementsByClassName('removeFormButton')[0];

  api.convertButton(button, function() {
    boardManagement.setVolunteer(
        cell.getElementsByClassName('userIdentifier')[0].value, false);
  });

};

boardManagement.addVolunteer = function() {

  boardManagement.setVolunteer(document
      .getElementById('addVolunteerFieldLogin').value.trim(), true, function(
      error) {

    if (error) {
      alert(error);
    } else {
      document.getElementById('addVolunteerFieldLogin').value = '';
    }

  });

};

boardManagement.setVolunteersDiv = function(volunteers) {

  var volunteersDiv = document.getElementById('volunteersDiv');

  while (volunteersDiv.firstChild) {
    volunteersDiv.removeChild(volunteersDiv.firstChild);
  }

  for (var i = 0; i < volunteers.length; i++) {

    var cell = document.createElement('form');
    cell.innerHTML = boardManagement.volunteerCellTemplate;

    cell.getElementsByClassName('userIdentifier')[0].setAttribute('value',
        volunteers[i]);

    cell.getElementsByClassName('userLabel')[0].innerHTML = volunteers[i];

    cell.getElementsByClassName('boardIdentifier')[0].setAttribute('value',
        api.boardUri);

    boardManagement.processVolunteerCell(cell);

    volunteersDiv.appendChild(cell);
  }

};

boardManagement.refreshVolunteers = function() {

  api.formApiRequest('boardManagement', {}, function gotData(status, data) {

    if (status !== 'ok') {
      return;
    }

    boardManagement.setVolunteersDiv(data.volunteers);

  }, false, {
    boardUri : api.boardUri
  });

};

boardManagement.setVolunteer = function(user, add, callback) {

  api.formApiRequest('setVolunteer', {
    login : user,
    add : add,
    boardUri : api.boardUri
  }, function requestComplete(status, data) {

    if (status === 'ok') {

      if (callback) {
        callback();
      }

      boardManagement.refreshVolunteers();

    } else {
      alert(status + ': ' + JSON.stringify(data));
    }
  });

};

boardManagement.transferBoard = function() {

  api.formApiRequest('transferBoardOwnership', {
    login : document.getElementById('transferBoardFieldLogin').value.trim(),
    boardUri : api.boardUri
  }, function requestComplete(status, data) {

    if (status === 'ok') {
      window.location.pathname = '/' + api.boardUri + '/';
    } else {
      alert(status + ': ' + JSON.stringify(data));
    }
  });

};

boardManagement.deleteBoard = function() {

  if (!document.getElementById('confirmDelCheckbox').checked) {
    alert('You must confirm that you wish to delete this board.')
    return;
  }

  api.formApiRequest('deleteBoard', {
    boardUri : api.boardUri,
    confirmDeletion : true
  }, function requestComplete(status, data) {

    if (status === 'ok') {
      window.location.pathname = '/';
    } else {
      alert(status + ': ' + JSON.stringify(data));
    }
  });

};

boardManagement.init();


code:
var boardModeration = {};

boardModeration.init = function() {

  api.convertButton('saveSpecialFormButton',
      boardModeration.saveSpecialSettings, 'specialSettingsField');

  api.convertButton('deleteFormButton', boardModeration.deleteBoard,
      'deleteBoardField');

  api.convertButton('transferFormButton', boardModeration.transferBoard,
      'transferField');

  api.boardUri = document.getElementById('boardTransferIdentifier').value;

};

boardModeration.transferBoard = function() {

  api.formApiRequest('transferBoardOwnership', {
    login : document.getElementById('fieldTransferLogin').value.trim(),
    boardUri : api.boardUri
  }, function requestComplete(status, data) {

    if (status === 'ok') {
      window.location.pathname = '/' + api.boardUri + '/';
    } else {
      alert(status + ': ' + JSON.stringify(data));
    }
  });

};

boardModeration.deleteBoard = function() {

  if (!document.getElementById('confirmDelCheckbox').checked) {
    alert('You must confirm that you wish to delete this board.')
    return;
  }

  api.formApiRequest('deleteBoard', {
    boardUri : api.boardUri,
    confirmDeletion : true
  }, function requestComplete(status, data) {

    if (status === 'ok') {
      window.location.pathname = '/';
    } else {
      alert(status + ': ' + JSON.stringify(data));
    }
  });

};

boardModeration.saveSpecialSettings = function() {

  var parameters = {
    boardUri : api.boardUri
  };

  parameters.sfw = document.getElementById('checkboxSfw').checked;
  parameters.locked = document.getElementById('checkboxLocked').checked;

  api.formApiRequest('setSpecialBoardSettings', parameters,
      function requestComplete(status, data) {

        if (status === 'ok') {
          alert('Special settings saved');
        } else {
          alert(status + ': ' + JSON.stringify(data));
        }

      });

};

boardModeration.init();


code:
var bottomForms = {};

bottomForms.init = function() {

  var forms = document.getElementById('actionsForm');

  if (!forms) {
    forms = document.getElementById('bottomForms');
  }

  forms.classList.toggle('hidden');

  var showFormsButton = document.createElement('a');
  showFormsButton.innerHTML = 'Show forms';
  showFormsButton.id = 'showFormsButton';

  forms.parentElement.insertBefore(showFormsButton, forms);

  showFormsButton.onclick = function() {
    forms.classList.toggle('hidden');
    showFormsButton.remove();
  };

};

bottomForms.init();


code:
var bypass = {};

bypass.init = function() {
  api.convertButton('bypassFormButton', bypass.blockBypass, 'bypassField');
};

bypass.blockBypass = function() {

  var typedCaptcha = document.getElementById('fieldCaptcha').value.trim();

  if (typedCaptcha.length !== 6 && typedCaptcha.length !== 24) {
    alert('Captchas are exactly 6 (24 if no cookies) characters long.');
    return;
  } else if (/\W/.test(typedCaptcha)) {
    alert('Invalid captcha.');
    return;
  }

  api.formApiRequest('renewBypass', {
    captcha : typedCaptcha
  }, function requestComplete(status, data) {

    if (status === 'ok') {

      var paragraph = document.getElementsByTagName('p')[0];

      var span = document.createElement('span');
      span.innerHTML = 'You have a valid block bypass.';
      span.id = 'indicatorValidBypass';
      paragraph.appendChild(span);

      document.getElementById('fieldCaptcha').value = '';

    } else {
      alert(status + ': ' + JSON.stringify(data));
    }
  });

};

bypass.init();


code:
var captchaModal = {};

captchaModal.addModalRow = function(label, element, action) {

  var tableBody = document.getElementsByClassName('modalTableBody')[0];

  var tableRow = document.createElement('tr');
  tableBody.appendChild(tableRow);

  var labelElement = document.createElement('th');
  labelElement.innerHTML = label;

  tableRow.appendChild(labelElement);

  var fieldHolder = document.createElement('td');

  fieldHolder.appendChild(element);

  tableRow.appendChild(fieldHolder);

  if (action) {

    element.addEventListener('keydown', function(event) {

      if (event.key === 'Enter') {

        action();

        event.preventDefault();
      }

    });

  }

};

captchaModal.getCaptchaModal = function(header, noCaptcha) {

  var outerPanel = document.createElement('div');
  outerPanel.className = 'modalPanel';
  document.body.appendChild(outerPanel);

  var innerPanel = document.createElement('div');
  innerPanel.className = 'modalInnerPanel';
  outerPanel.appendChild(innerPanel);

  var decorationPanel = document.createElement('div');
  decorationPanel.className = 'modalDecorationPanel';
  innerPanel.appendChild(decorationPanel);

  var topLabel = document.createElement('span');
  topLabel.className = 'modalHeader';
  topLabel.innerHTML = header;
  decorationPanel.appendChild(topLabel);

  if (!noCaptcha) {
    var captchaImage = document.createElement('img');
    captchaImage.src = '/captcha.js?d=' + new Date().toString();
    captchaImage.className = 'captchaImage';
    decorationPanel.appendChild(captchaImage);

    var captchaControls = document.createElement('span');
    captchaControls.className = 'modalCaptchaControls';
    decorationPanel.appendChild(captchaControls);

    var reloadButton = document.createElement('input');
    reloadButton.value = 'Reload';
    reloadButton.addEventListener('click', function() {
      captchaUtils.reloadCaptcha()
    });
    reloadButton.type = 'button';
    captchaControls.appendChild(reloadButton);

    var reloadTimer = document.createElement('span');
    reloadTimer.className = 'captchaTimer';
    captchaControls.appendChild(reloadTimer);

  }

  var captchaTable = document.createElement('table');
  var tableBody = document.createElement('tbody');
  tableBody.className = 'modalTableBody';
  captchaTable.appendChild(tableBody);
  decorationPanel.appendChild(captchaTable);

  var okButton = document.createElement('input');
  okButton.type = 'button';
  okButton.className = 'modalOkButton';
  okButton.value = 'Ok';

  if (!noCaptcha) {

    var captchaField = document.createElement('input');
    captchaField.type = 'text';
    captchaField.className = 'modalAnswer';

    captchaModal.addModalRow('Answer', captchaField, function() {
      okButton.onclick();
    });

  }

  var responseButtonsPanel = document.createElement('span');
  decorationPanel.appendChild(responseButtonsPanel);

  responseButtonsPanel.appendChild(okButton);

  var cancelButton = document.createElement('input');
  cancelButton.type = 'button';
  cancelButton.value = 'Cancel';
  cancelButton.onclick = function() {
    outerPanel.remove();
  };
  responseButtonsPanel.appendChild(cancelButton);

  return outerPanel;

};


code:
var captchaUtils = {};

captchaUtils.init = function() {

  var reloadButtons = document.getElementsByClassName('reloadCaptchaButton');

  for (var i = 0; i < reloadButtons.length; i++) {
    reloadButtons[i].style.display = 'inline-block';
  }

  captchaUtils.updateFunction();

};

captchaUtils.captchaTimers = document.getElementsByClassName('captchaTimer');

captchaUtils.reloadCaptcha = function() {

  document.cookie = 'captchaid=; path=/;';

  var captchaImages = document.getElementsByClassName('captchaImage');

  for (var i = 0; i < captchaImages.length; i++) {
    captchaImages[i].src = '/captcha.js?d=' + new Date().toString();
  }

  var captchaFields = document.getElementsByClassName('captchaField');

  for (var i = 0; i < captchaFields.length; i++) {
    captchaFields[i].value = '';
  }

};

captchaUtils.updateFunction = function updateElements() {

  var cookies = api.getCookies();

  if (!cookies.captchaexpiration) {
    setTimeout(captchaUtils.updateFunction, 1000);
    return;
  }

  var captchaExpiration = new Date(cookies.captchaexpiration);

  var delta = captchaExpiration.getTime() - new Date().getTime();

  var time = '';

  if (delta > 1000) {
    time = Math.floor(delta / 1000);

    captchaUtils.reloading = false;

  } else {

    time = 'Reloading';

    if (!captchaUtils.reloading) {

      captchaUtils.reloading = true;

      captchaUtils.reloadCaptcha();

    }
  }

  for (var i = 0; i < captchaUtils.captchaTimers.length; i++) {
    captchaUtils.captchaTimers[i].innerHTML = time;
  }

  setTimeout(captchaUtils.updateFunction, 1000);

};

captchaUtils.init();

function testReload() {

  captchaUtils.reloadCaptcha();

};


code:
var catalog = {};

catalog.init = function() {

  catalog.catalogDiv = document.getElementById('divThreads');

  catalog.indicatorsRelation = {
    pinned : 'pinIndicator',
    locked : 'lockIndicator',
    cyclic : 'cyclicIndicator',
    autoSage : 'bumpLockIndicator'
  };

  catalog.refreshCheckBox = document
      .getElementById('autoCatalogRefreshCheckBox');
  catalog.refreshLabel = document.getElementById('catalogRefreshLabel');
  catalog.originalAutoRefreshText = catalog.refreshLabel.innerHTML;
  catalog.searchField = document.getElementById('catalogSearchField');

  var catalogCellTemplate = '';
  catalogCellTemplate += '
R: ';
  catalogCellTemplate += ' / I: ';
  catalogCellTemplate += ' / P: ';
  catalogCellTemplate += ' ';
  catalogCellTemplate += ' ';
  catalogCellTemplate += ' ';
  catalogCellTemplate += ' ';
  catalogCellTemplate += '';
  catalogCellTemplate += '

';
  catalogCellTemplate += '

';

  catalog.catalogCellTemplate = catalogCellTemplate;

  var storedHidingData = localStorage.hidingData;

  if (storedHidingData) {
    storedHidingData = JSON.parse(storedHidingData);
  } else {
    storedHidingData = {};
  }

  catalog.storedHidingData = storedHidingData;

  catalog.initCatalog();

};

catalog.startTimer = function(time) {

  if (time > 600) {
    time = 600;
  }

  catalog.currentRefresh = time;
  catalog.lastRefresh = time;
  catalog.refreshLabel.innerHTML = catalog.originalAutoRefreshText + ' '
      + catalog.currentRefresh;
  catalog.refreshTimer = setInterval(function checkTimer() {
    catalog.currentRefresh--;

    if (!catalog.currentRefresh) {
      clearInterval(catalog.refreshTimer);
      catalog.refreshCatalog();
      catalog.refreshLabel.innerHTML = catalog.originalAutoRefreshText;
    } else {
      catalog.refreshLabel.innerHTML = catalog.originalAutoRefreshText + ' '
          + catalog.currentRefresh;
    }

  }, 1000);
};

catalog.changeCatalogRefresh = function() {

  catalog.autoRefresh = catalog.refreshCheckBox.checked;

  if (!catalog.autoRefresh) {
    catalog.refreshLabel.innerHTML = catalog.originalAutoRefreshText;
    clearInterval(catalog.refreshTimer);
  } else {
    catalog.startTimer(5);
  }

};

catalog.getHiddenMedia = function() {

  var hiddenMedia = localStorage.hiddenMedia;

  if (hiddenMedia) {
    hiddenMedia = JSON.parse(hiddenMedia);
  } else {
    hiddenMedia = [];
  }

  return hiddenMedia;

};

catalog.refreshCatalog = function(manual) {

  if (catalog.autoRefresh) {
    clearInterval(catalog.refreshTimer);
  }

  var currentData = JSON.stringify(catalog.catalogThreads);

  catalog.getCatalogData(function refreshed(error) {

    if (error) {
      return;
    }

    var changed = currentData != JSON.stringify(catalog.catalogThreads);

    if (catalog.autoRefresh) {
      catalog.startTimer(manual || changed ? 5 : catalog.lastRefresh * 2);
    }

    catalog.search();

  });

};

catalog.initCatalog = function() {

  catalog.changeCatalogRefresh();

  api.boardUri = window.location.toString().match(/\/(\w+)\/catalog.html/)[1];

  document.getElementById('divTools').style.display = 'inline-block';

  catalog.searchField.addEventListener('input', function() {

    if (catalog.searchTimer) {
      clearTimeout(catalog.searchTimer);
    }

    catalog.searchTimer = setTimeout(function() {
      delete catalog.searchTime;
      catalog.search();
    }, 1000);

  });

  var postingForm = document.getElementById('newPostFieldset');

  if (postingForm) {

    var toggleLink = document.getElementById('togglePosting');
    toggleLink.style.display = 'inline-block';
    postingForm.style.display = 'none';

    toggleLink.onclick = function() {
      toggleLink.style.display = 'none';
      postingForm.style.display = 'inline-block';
    };
  }

  var links = document.getElementsByClassName('linkThumb');

  for (var i = 0; i < links.length; i++) {

    var link = links[i];

    var child = link.childNodes[0];

    var matches = link.href.match(/(\w+)\/res\/(\d+)/);

    var board = matches[1];
    var thread = matches[2];

    var boardData = catalog.storedHidingData[board];

    if (boardData && boardData.threads.indexOf(thread) > -1) {
      var cell = link.parentNode;

      cell.parentNode.removeChild(cell);
    } else if (child.tagName === 'IMG') {
      catalog.checkForFileHiding(child);
    }

  }

  catalog.getCatalogData();

};

catalog.checkForFileHiding = function(child) {

  var srcParts = child.src.split('/');

  var hiddenMedia = catalog.getHiddenMedia();

  var finalPart = srcParts[srcParts.length - 1].substr(2);

  for (var j = 0; j < hiddenMedia.length; j++) {

    if (hiddenMedia[j].indexOf(finalPart) > -1) {
      child.parentNode.innerHTML = 'Open';
      break;
    }

  }
};

catalog.setCellThumb = function(thumbLink, thread) {
  thumbLink.href = '/' + api.boardUri + '/res/' + thread.threadId + '.html';

  if (thread.thumb) {
    var thumbImage = document.createElement('img');

    thumbImage.src = thread.thumb;
    thumbLink.appendChild(thumbImage);
    catalog.checkForFileHiding(thumbImage);
  } else {
    thumbLink.innerHTML = 'Open';
  }
};

catalog.setCatalogCellIndicators = function(thread, cell) {

  for ( var key in catalog.indicatorsRelation) {
    if (!thread[key]) {
      cell.getElementsByClassName(catalog.indicatorsRelation[key])[0].remove();
    }
  }

};

catalog.setCell = function(thread) {

  var cell = document.createElement('div');

  cell.innerHTML = catalog.catalogCellTemplate;
  cell.className = 'catalogCell';

  catalog.setCellThumb(cell.getElementsByClassName('linkThumb')[0], thread);

  var labelReplies = cell.getElementsByClassName('labelReplies')[0];
  labelReplies.innerHTML = thread.postCount || 0;

  var labelImages = cell.getElementsByClassName('labelImages')[0];
  labelImages.innerHTML = thread.fileCount || 0;
  cell.getElementsByClassName('labelPage')[0].innerHTML = thread.page;

  if (thread.subject) {
    cell.getElementsByClassName('labelSubject')[0].innerHTML = thread.subject;
  }

  catalog.setCatalogCellIndicators(thread, cell);

  cell.getElementsByClassName('divMessage')[0].innerHTML = thread.markdown;

  return cell;

};

catalog.search = function() {

  if (!catalog.catalogThreads) {
    return;
  }

  var term = catalog.searchField.value.toLowerCase();

  while (catalog.catalogDiv.firstChild) {
    catalog.catalogDiv.removeChild(catalog.catalogDiv.firstChild);
  }

  var boardData = catalog.storedHidingData[api.boardUri];

  for (var i = 0; i < catalog.catalogThreads.length; i++) {

    var thread = catalog.catalogThreads[i];

    if ((boardData && boardData.threads.indexOf(thread.threadId.toString()) > -1)
        || (term.length && thread.message.toLowerCase().indexOf(term) < 0 && (thread.subject || '')
            .toLowerCase().indexOf(term) < 0)) {
      continue;
    }

    catalog.catalogDiv.appendChild(catalog.setCell(thread));

  }

};

catalog.getCatalogData = function(callback) {

  if (catalog.loadingData) {
    return;
  }

  catalog.loadingData = true;

  api.localRequest('/' + api.boardUri + '/catalog.json', function gotBoardData(
      error, data) {

    catalog.loadingData = false;

    if (error) {
      if (callback) {
        callback(error);
      } else {
        console.log(error);
      }
      return;
    }

    catalog.catalogThreads = JSON.parse(data);
    if (callback) {
      callback();
    }

  });

};

catalog.init();


code:
(function(factory) {
  if (typeof exports === 'object') {
    // Node/CommonJS
    module.exports = factory();
  } else if (typeof define === 'function' && define.amd) {
    // AMD
    define(factory);
  } else {
    // Browser globals (with support for web workers)
    var glob;

    try {
      glob = window;
    } catch (e) {
      glob = self;
    }

    glob.SparkMD5 = factory();
  }
}
    (function(undefined) {

      'use strict';

      /*
       * Fastest md5 implementation around (JKM md5). Credits: Joseph Myers
       *
       * @see http://www.myersdaily.org/joseph/javascript/md5-text.html
       * @see http://jsperf.com/md5-shootout/7
       */

      /*
       * this function is much faster, so if possible we use it. Some IEs are
       * the only ones I know of that need the idiotic second function,
       * generated by an if clause.
       */
      var add32 = function(a, b) {
        return (a + b) & 0xFFFFFFFF;
      }, hex_chr = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a',
          'b', 'c', 'd', 'e', 'f' ];

      function cmn(q, a, b, x, s, t) {
        a = add32(add32(a, q), add32(x, t));
        return add32((a << s) | (a >>> (32 - s)), b);
      }

      function ff(a, b, c, d, x, s, t) {
        return cmn((b & c) | ((~b) & d), a, b, x, s, t);
      }

      function gg(a, b, c, d, x, s, t) {
        return cmn((b & d) | (c & (~d)), a, b, x, s, t);
      }

      function hh(a, b, c, d, x, s, t) {
        return cmn(b ^ c ^ d, a, b, x, s, t);
      }

      function ii(a, b, c, d, x, s, t) {
        return cmn(c ^ (b | (~d)), a, b, x, s, t);
      }

      function md5cycle(x, k) {
        var a = x[0], b = x[1], c = x[2], d = x[3];

        a = ff(a, b, c, d, k[0], 7, -680876936);
        d = ff(d, a, b, c, k[1], 12, -389564586);
        c = ff(c, d, a, b, k[2], 17, 606105819);
        b = ff(b, c, d, a, k[3], 22, -1044525330);
        a = ff(a, b, c, d, k[4], 7, -176418897);
        d = ff(d, a, b, c, k[5], 12, 1200080426);
        c = ff(c, d, a, b, k[6], 17, -1473231341);
        b = ff(b, c, d, a, k[7], 22, -45705983);
        a = ff(a, b, c, d, k[8], 7, 1770035416);
        d = ff(d, a, b, c, k[9], 12, -1958414417);
        c = ff(c, d, a, b, k[10], 17, -42063);
        b = ff(b, c, d, a, k[11], 22, -1990404162);
        a = ff(a, b, c, d, k[12], 7, 1804603682);
        d = ff(d, a, b, c, k[13], 12, -40341101);
        c = ff(c, d, a, b, k[14], 17, -1502002290);
        b = ff(b, c, d, a, k[15], 22, 1236535329);

        a = gg(a, b, c, d, k[1], 5, -165796510);
        d = gg(d, a, b, c, k[6], 9, -1069501632);
        c = gg(c, d, a, b, k[11], 14, 643717713);
        b = gg(b, c, d, a, k[0], 20, -373897302);
        a = gg(a, b, c, d, k[5], 5, -701558691);
        d = gg(d, a, b, c, k[10], 9, 38016083);
        c = gg(c, d, a, b, k[15], 14, -660478335);
        b = gg(b, c, d, a, k[4], 20, -405537848);
        a = gg(a, b, c, d, k[9], 5, 568446438);
        d = gg(d, a, b, c, k[14], 9, -1019803690);
        c = gg(c, d, a, b, k[3], 14, -187363961);
        b = gg(b, c, d, a, k[8], 20, 1163531501);
        a = gg(a, b, c, d, k[13], 5, -1444681467);
        d = gg(d, a, b, c, k[2], 9, -51403784);
        c = gg(c, d, a, b, k[7], 14, 1735328473);
        b = gg(b, c, d, a, k[12], 20, -1926607734);

        a = hh(a, b, c, d, k[5], 4, -378558);
        d = hh(d, a, b, c, k[8], 11, -2022574463);
        c = hh(c, d, a, b, k[11], 16, 1839030562);
        b = hh(b, c, d, a, k[14], 23, -35309556);
        a = hh(a, b, c, d, k[1], 4, -1530992060);
        d = hh(d, a, b, c, k[4], 11, 1272893353);
        c = hh(c, d, a, b, k[7], 16, -155497632);
        b = hh(b, c, d, a, k[10], 23, -1094730640);
        a = hh(a, b, c, d, k[13], 4, 681279174);
        d = hh(d, a, b, c, k[0], 11, -358537222);
        c = hh(c, d, a, b, k[3], 16, -722521979);
        b = hh(b, c, d, a, k[6], 23, 76029189);
        a = hh(a, b, c, d, k[9], 4, -640364487);
        d = hh(d, a, b, c, k[12], 11, -421815835);
        c = hh(c, d, a, b, k[15], 16, 530742520);
        b = hh(b, c, d, a, k[2], 23, -995338651);

        a = ii(a, b, c, d, k[0], 6, -198630844);
        d = ii(d, a, b, c, k[7], 10, 1126891415);
        c = ii(c, d, a, b, k[14], 15, -1416354905);
        b = ii(b, c, d, a, k[5], 21, -57434055);
        a = ii(a, b, c, d, k[12], 6, 1700485571);
        d = ii(d, a, b, c, k[3], 10, -1894986606);
        c = ii(c, d, a, b, k[10], 15, -1051523);
        b = ii(b, c, d, a, k[1], 21, -2054922799);
        a = ii(a, b, c, d, k[8], 6, 1873313359);
        d = ii(d, a, b, c, k[15], 10, -30611744);
        c = ii(c, d, a, b, k[6], 15, -1560198380);
        b = ii(b, c, d, a, k[13], 21, 1309151649);
        a = ii(a, b, c, d, k[4], 6, -145523070);
        d = ii(d, a, b, c, k[11], 10, -1120210379);
        c = ii(c, d, a, b, k[2], 15, 718787259);
        b = ii(b, c, d, a, k[9], 21, -343485551);

        x[0] = add32(a, x[0]);
        x[1] = add32(b, x[1]);
        x[2] = add32(c, x[2]);
        x[3] = add32(d, x[3]);
      }

      function md5blk(s) {
        var md5blks = [], i; /* Andy King said do it this way. */

        for (i = 0; i < 64; i += 4) {
          md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8)
              + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
        }
        return md5blks;
      }

      function md5blk_array(a) {
        var md5blks = [], i; /* Andy King said do it this way. */

        for (i = 0; i < 64; i += 4) {
          md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16)
              + (a[i + 3] << 24);
        }
        return md5blks;
      }

      function md51(s) {
        var n = s.length, state = [ 1732584193, -271733879, -1732584194,
            271733878 ], i, length, tail, tmp, lo, hi;

        for (i = 64; i <= n; i += 64) {
          md5cycle(state, md5blk(s.substring(i - 64, i)));
        }
        s = s.substring(i - 64);
        length = s.length;
        tail = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
        for (i = 0; i < length; i += 1) {
          tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);
        }
        tail[i >> 2] |= 0x80 << ((i % 4) << 3);
        if (i > 55) {
          md5cycle(state, tail);
          for (i = 0; i < 16; i += 1) {
            tail[i] = 0;
          }
        }

        // Beware that the final length might not fit in 32 bits so we take care
        // of that
        tmp = n * 8;
        tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
        lo = parseInt(tmp[2], 16);
        hi = parseInt(tmp[1], 16) || 0;

        tail[14] = lo;
        tail[15] = hi;

        md5cycle(state, tail);
        return state;
      }

      function md51_array(a) {
        var n = a.length, state = [ 1732584193, -271733879, -1732584194,
            271733878 ], i, length, tail, tmp, lo, hi;

        for (i = 64; i <= n; i += 64) {
          md5cycle(state, md5blk_array(a.subarray(i - 64, i)));
        }

        // Not sure if it is a bug, however IE10 will always produce a sub array
        // of length 1
        // containing the last element of the parent array if the sub array
        // specified starts
        // beyond the length of the parent array - weird.
        // https://connect.microsoft.com/IE/feedback/details/771452/typed-array-subarray-issue
        a = (i - 64) < n ? a.subarray(i - 64) : new Uint8Array(0);

        length = a.length;
        tail = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
        for (i = 0; i < length; i += 1) {
          tail[i >> 2] |= a[i] << ((i % 4) << 3);
        }

        tail[i >> 2] |= 0x80 << ((i % 4) << 3);
        if (i > 55) {
          md5cycle(state, tail);
          for (i = 0; i < 16; i += 1) {
            tail[i] = 0;
          }
        }

        // Beware that the final length might not fit in 32 bits so we take care
        // of that
        tmp = n * 8;
        tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
        lo = parseInt(tmp[2], 16);
        hi = parseInt(tmp[1], 16) || 0;

        tail[14] = lo;
        tail[15] = hi;

        md5cycle(state, tail);

        return state;
      }

      function rhex(n) {
        var s = '', j;
        for (j = 0; j < 4; j += 1) {
          s += hex_chr[(n >> (j * 8 + 4)) & 0x0F]
              + hex_chr[(n >> (j * 8)) & 0x0F];
        }
        return s;
      }

      function hex(x) {
        var i;
        for (i = 0; i < x.length; i += 1) {
          x[i] = rhex(x[i]);
        }
        return x.join('');
      }

      // In some cases the fast add32 function cannot be used..
      if (hex(md51('hello')) !== '5d41402abc4b2a76b9719d911017c592') {
        add32 = function(x, y) {
          var lsw = (x & 0xFFFF) + (y & 0xFFFF), msw = (x >> 16) + (y >> 16)
              + (lsw >> 16);
          return (msw << 16) | (lsw & 0xFFFF);
        };
      }

      // ---------------------------------------------------

      /**
       * ArrayBuffer slice polyfill.
       *
       * @see https://github.com/ttaubert/node-arraybuffer-slice
       */

      if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) {
        (function() {
          function clamp(val, length) {
            val = (val | 0) || 0;

            if (val < 0) {
              return Math.max(val + length, 0);
            }

            return Math.min(val, length);
          }

          ArrayBuffer.prototype.slice = function(from, to) {
            var length = this.byteLength, begin = clamp(from, length), end = length, num, target, targetArray, sourceArray;

            if (to !== undefined) {
              end = clamp(to, length);
            }

            if (begin > end) {
              return new ArrayBuffer(0);
            }

            num = end - begin;
            target = new ArrayBuffer(num);
            targetArray = new Uint8Array(target);

            sourceArray = new Uint8Array(this, begin, num);
            targetArray.set(sourceArray);

            return target;
          };
        })();
      }

      // ---------------------------------------------------

      /**
       * Helpers.
       */

      function toUtf8(str) {
        if (/[\u0080-\uFFFF]/.test(str)) {
          str = unescape(encodeURIComponent(str));
        }

        return str;
      }

      function utf8Str2ArrayBuffer(str, returnUInt8Array) {
        var length = str.length, buff = new ArrayBuffer(length), arr = new Uint8Array(
            buff), i;

        for (i = 0; i < length; i += 1) {
          arr[i] = str.charCodeAt(i);
        }

        return returnUInt8Array ? arr : buff;
      }

      function arrayBuffer2Utf8Str(buff) {
        return String.fromCharCode.apply(null, new Uint8Array(buff));
      }

      function concatenateArrayBuffers(first, second, returnUInt8Array) {
        var result = new Uint8Array(first.byteLength + second.byteLength);

        result.set(new Uint8Array(first));
        result.set(new Uint8Array(second), first.byteLength);

        return returnUInt8Array ? result : result.buffer;
      }

      function hexToBinaryString(hex) {
        var bytes = [], length = hex.length, x;

        for (x = 0; x < length - 1; x += 2) {
          bytes.push(parseInt(hex.substr(x, 2), 16));
        }

        return String.fromCharCode.apply(String, bytes);
      }

      // ---------------------------------------------------

      /**
       * SparkMD5 OOP implementation.
       *
       * Use this class to perform an incremental md5, otherwise use the static
       * methods instead.
       */

      function SparkMD5() {
        // call reset to init the instance
        this.reset();
      }

      /**
       * Appends a string. A conversion will be applied if an utf8 string is
       * detected.
       *
       * @param {String}
       *          str The string to be appended
       *
       * @return {SparkMD5} The instance itself
       */
      SparkMD5.prototype.append = function(str) {
        // Converts the string to utf8 bytes if necessary
        // Then append as binary
        this.appendBinary(toUtf8(str));

        return this;
      };

      /**
       * Appends a binary string.
       *
       * @param {String}
       *          contents The binary string to be appended
       *
       * @return {SparkMD5} The instance itself
       */
      SparkMD5.prototype.appendBinary = function(contents) {
        this._buff += contents;
        this._length += contents.length;

        var length = this._buff.length, i;

        for (i = 64; i <= length; i += 64) {
          md5cycle(this._hash, md5blk(this._buff.substring(i - 64, i)));
        }

        this._buff = this._buff.substring(i - 64);

        return this;
      };

      /**
       * Finishes the incremental computation, reseting the internal state and
       * returning the result.
       *
       * @param {Boolean}
       *          raw True to get the raw string, false to get the hex string
       *
       * @return {String} The result
       */
      SparkMD5.prototype.end = function(raw) {
        var buff = this._buff, length = buff.length, i, tail = [ 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], ret;

        for (i = 0; i < length; i += 1) {
          tail[i >> 2] |= buff.charCodeAt(i) << ((i % 4) << 3);
        }

        this._finish(tail, length);
        ret = hex(this._hash);

        if (raw) {
          ret = hexToBinaryString(ret);
        }

        this.reset();

        return ret;
      };

      /**
       * Resets the internal state of the computation.
       *
       * @return {SparkMD5} The instance itself
       */
      SparkMD5.prototype.reset = function() {
        this._buff = '';
        this._length = 0;
        this._hash = [ 1732584193, -271733879, -1732584194, 271733878 ];

        return this;
      };

      /**
       * Gets the internal state of the computation.
       *
       * @return {Object} The state
       */
      SparkMD5.prototype.getState = function() {
        return {
          buff : this._buff,
          length : this._length,
          hash : this._hash
        };
      };

      /**
       * Gets the internal state of the computation.
       *
       * @param {Object}
       *          state The state
       *
       * @return {SparkMD5} The instance itself
       */
      SparkMD5.prototype.setState = function(state) {
        this._buff = state.buff;
        this._length = state.length;
        this._hash = state.hash;

        return this;
      };

      /**
       * Releases memory used by the incremental buffer and other additional
       * resources. If you plan to use the instance again, use reset instead.
       */
      SparkMD5.prototype.destroy = function() {
        delete this._hash;
        delete this._buff;
        delete this._length;
      };

      /**
       * Finish the final calculation based on the tail.
       *
       * @param {Array}
       *          tail The tail (will be modified)
       * @param {Number}
       *          length The length of the remaining buffer
       */
      SparkMD5.prototype._finish = function(tail, length) {
        var i = length, tmp, lo, hi;

        tail[i >> 2] |= 0x80 << ((i % 4) << 3);
        if (i > 55) {
          md5cycle(this._hash, tail);
          for (i = 0; i < 16; i += 1) {
            tail[i] = 0;
          }
        }

        // Do the final computation based on the tail and length
        // Beware that the final length may not fit in 32 bits so we take care
        // of that
        tmp = this._length * 8;
        tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
        lo = parseInt(tmp[2], 16);
        hi = parseInt(tmp[1], 16) || 0;

        tail[14] = lo;
        tail[15] = hi;
        md5cycle(this._hash, tail);
      };

      /**
       * Performs the md5 hash on a string. A conversion will be applied if utf8
       * string is detected.
       *
       * @param {String}
       *          str The string
       * @param {Boolean}
       *          raw True to get the raw string, false to get the hex string
       *
       * @return {String} The result
       */
      SparkMD5.hash = function(str, raw) {
        // Converts the string to utf8 bytes if necessary
        // Then compute it using the binary function
        return SparkMD5.hashBinary(toUtf8(str), raw);
      };

      /**
       * Performs the md5 hash on a binary string.
       *
       * @param {String}
       *          content The binary string
       * @param {Boolean}
       *          raw True to get the raw string, false to get the hex string
       *
       * @return {String} The result
       */
      SparkMD5.hashBinary = function(content, raw) {
        var hash = md51(content), ret = hex(hash);

        return raw ? hexToBinaryString(ret) : ret;
      };

      // ---------------------------------------------------

      /**
       * SparkMD5 OOP implementation for array buffers.
       *
       * Use this class to perform an incremental md5 ONLY for array buffers.
       */
      SparkMD5.ArrayBuffer = function() {
        // call reset to init the instance
        this.reset();
      };

      /**
       * Appends an array buffer.
       *
       * @param {ArrayBuffer}
       *          arr The array to be appended
       *
       * @return {SparkMD5.ArrayBuffer} The instance itself
       */
      SparkMD5.ArrayBuffer.prototype.append = function(arr) {
        var buff = concatenateArrayBuffers(this._buff.buffer, arr, true), length = buff.length, i;

        this._length += arr.byteLength;

        for (i = 64; i <= length; i += 64) {
          md5cycle(this._hash, md5blk_array(buff.subarray(i - 64, i)));
        }

        this._buff = (i - 64) < length ? new Uint8Array(buff.buffer
            .slice(i - 64)) : new Uint8Array(0);

        return this;
      };

      /**
       * Finishes the incremental computation, reseting the internal state and
       * returning the result.
       *
       * @param {Boolean}
       *          raw True to get the raw string, false to get the hex string
       *
       * @return {String} The result
       */
      SparkMD5.ArrayBuffer.prototype.end = function(raw) {
        var buff = this._buff, length = buff.length, tail = [ 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], i, ret;

        for (i = 0; i < length; i += 1) {
          tail[i >> 2] |= buff[i] << ((i % 4) << 3);
        }

        this._finish(tail, length);
        ret = hex(this._hash);

        if (raw) {
          ret = hexToBinaryString(ret);
        }

        this.reset();

        return ret;
      };

      /**
       * Resets the internal state of the computation.
       *
       * @return {SparkMD5.ArrayBuffer} The instance itself
       */
      SparkMD5.ArrayBuffer.prototype.reset = function() {
        this._buff = new Uint8Array(0);
        this._length = 0;
        this._hash = [ 1732584193, -271733879, -1732584194, 271733878 ];

        return this;
      };

      /**
       * Gets the internal state of the computation.
       *
       * @return {Object} The state
       */
      SparkMD5.ArrayBuffer.prototype.getState = function() {
        var state = SparkMD5.prototype.getState.call(this);

        // Convert buffer to a string
        state.buff = arrayBuffer2Utf8Str(state.buff);

        return state;
      };

      /**
       * Gets the internal state of the computation.
       *
       * @param {Object}
       *          state The state
       *
       * @return {SparkMD5.ArrayBuffer} The instance itself
       */
      SparkMD5.ArrayBuffer.prototype.setState = function(state) {
        // Convert string to buffer
        state.buff = utf8Str2ArrayBuffer(state.buff, true);

        return SparkMD5.prototype.setState.call(this, state);
      };

      SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;

      SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;

      /**
       * Performs the md5 hash on an array buffer.
       *
       * @param {ArrayBuffer}
       *          arr The array buffer
       * @param {Boolean}
       *          raw True to get the raw string, false to get the hex one
       *
       * @return {String} The result
       */
      SparkMD5.ArrayBuffer.hash = function(arr, raw) {
        var hash = md51_array(new Uint8Array(arr)), ret = hex(hash);

        return raw ? hexToBinaryString(ret) : ret;
      };

      return SparkMD5;
    }));