cloudinary-video-player
Version:
Cloudinary Video Player
43 lines (35 loc) • 2.73 MB
JavaScript
/*!
* Cloudinary Video Player v3.2.1
* Built on 2025-08-12T18:54:00.175Z
* https://github.com/cloudinary/cloudinary-video-player
*/
/*
* ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
(self["cloudinaryVideoPlayerChunkLoading"] = self["cloudinaryVideoPlayerChunkLoading"] || []).push([["dash"],{
/***/ "../node_modules/global/document.js":
/*!******************************************!*\
!*** ../node_modules/global/document.js ***!
\******************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var topLevel = typeof __webpack_require__.g !== 'undefined' ? __webpack_require__.g :\n typeof window !== 'undefined' ? window : {}\nvar minDoc = __webpack_require__(/*! min-document */ \"?9835\");\n\nvar doccy;\n\nif (typeof document !== 'undefined') {\n doccy = document;\n} else {\n doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'];\n\n if (!doccy) {\n doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc;\n }\n}\n\nmodule.exports = doccy;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/global/document.js?");
/***/ }),
/***/ "../node_modules/global/window.js":
/*!****************************************!*\
!*** ../node_modules/global/window.js ***!
\****************************************/
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
eval("var win;\n\nif (typeof window !== \"undefined\") {\n win = window;\n} else if (typeof __webpack_require__.g !== \"undefined\") {\n win = __webpack_require__.g;\n} else if (typeof self !== \"undefined\"){\n win = self;\n} else {\n win = {};\n}\n\nmodule.exports = win;\n\n\n//# sourceURL=webpack://cloudinary-video-player/../node_modules/global/window.js?");
/***/ }),
/***/ "../node_modules/videojs-contrib-dash/dist/videojs-dash.es.js":
/*!********************************************************************!*\
!*** ../node_modules/videojs-contrib-dash/dist/videojs-dash.es.js ***!
\********************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ \"../node_modules/video.js/dist/alt/video.core-exposed.js\");\n/* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var global_window__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! global/window */ \"../node_modules/global/window.js\");\n/* harmony import */ var global_window__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(global_window__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var global_document__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! global/document */ \"../node_modules/global/document.js\");\n/* harmony import */ var global_document__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(global_document__WEBPACK_IMPORTED_MODULE_2__);\n/*! @name videojs-contrib-dash @version 5.1.1 @license Apache-2.0 */\n\n\n\n\nfunction unwrapExports (x) {\n\treturn x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;\n}\n\nfunction createCommonjsModule(fn, module) {\n\treturn module = { exports: {} }, fn(module, module.exports), module.exports;\n}\n\nvar dash_all_debug = createCommonjsModule(function (module, exports) {\n(function webpackUniversalModuleDefinition(root, factory) {\n\tmodule.exports = factory();\n})(window, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __nested_webpack_require_800__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __nested_webpack_require_800__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__nested_webpack_require_800__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__nested_webpack_require_800__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__nested_webpack_require_800__.d = function(exports, name, getter) {\n/******/ \t\tif(!__nested_webpack_require_800__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// define __esModule on exports\n/******/ \t__nested_webpack_require_800__.r = function(exports) {\n/******/ \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t}\n/******/ \t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t};\n/******/\n/******/ \t// create a fake namespace object\n/******/ \t// mode & 1: value is a module id, require it\n/******/ \t// mode & 2: merge all properties of value into the ns\n/******/ \t// mode & 4: return value when already ns object\n/******/ \t// mode & 8|1: behave like require\n/******/ \t__nested_webpack_require_800__.t = function(value, mode) {\n/******/ \t\tif(mode & 1) value = __nested_webpack_require_800__(value);\n/******/ \t\tif(mode & 8) return value;\n/******/ \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n/******/ \t\tvar ns = Object.create(null);\n/******/ \t\t__nested_webpack_require_800__.r(ns);\n/******/ \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n/******/ \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __nested_webpack_require_800__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n/******/ \t\treturn ns;\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__nested_webpack_require_800__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__nested_webpack_require_800__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__nested_webpack_require_800__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__nested_webpack_require_800__.p = \"/dist/\";\n/******/\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __nested_webpack_require_800__(__nested_webpack_require_800__.s = \"./index.js\");\n/******/ })\n/************************************************************************/\n/******/ ({\n\n/***/ \"./externals/base64.js\":\n/*!*****************************!*\\\n !*** ./externals/base64.js ***!\n \\*****************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n/* $Date: 2007-06-12 18:02:31 $ */\n// from: http://bannister.us/weblog/2007/06/09/simple-base64-encodedecode-javascript/\n// Handles encode/decode of ASCII and Unicode strings.\nvar UTF8 = {};\n\nUTF8.encode = function (s) {\n var u = [];\n\n for (var i = 0; i < s.length; ++i) {\n var c = s.charCodeAt(i);\n\n if (c < 0x80) {\n u.push(c);\n } else if (c < 0x800) {\n u.push(0xC0 | c >> 6);\n u.push(0x80 | 63 & c);\n } else if (c < 0x10000) {\n u.push(0xE0 | c >> 12);\n u.push(0x80 | 63 & c >> 6);\n u.push(0x80 | 63 & c);\n } else {\n u.push(0xF0 | c >> 18);\n u.push(0x80 | 63 & c >> 12);\n u.push(0x80 | 63 & c >> 6);\n u.push(0x80 | 63 & c);\n }\n }\n\n return u;\n};\n\nUTF8.decode = function (u) {\n var a = [];\n var i = 0;\n\n while (i < u.length) {\n var v = u[i++];\n\n if (v < 0x80) ; else if (v < 0xE0) {\n v = (31 & v) << 6;\n v |= 63 & u[i++];\n } else if (v < 0xF0) {\n v = (15 & v) << 12;\n v |= (63 & u[i++]) << 6;\n v |= 63 & u[i++];\n } else {\n v = (7 & v) << 18;\n v |= (63 & u[i++]) << 12;\n v |= (63 & u[i++]) << 6;\n v |= 63 & u[i++];\n }\n\n a.push(String.fromCharCode(v));\n }\n\n return a.join('');\n};\n\nvar BASE64 = {};\n\n(function (T) {\n var encodeArray = function encodeArray(u) {\n var i = 0;\n var a = [];\n var n = 0 | u.length / 3;\n\n while (0 < n--) {\n var v = (u[i] << 16) + (u[i + 1] << 8) + u[i + 2];\n i += 3;\n a.push(T.charAt(63 & v >> 18));\n a.push(T.charAt(63 & v >> 12));\n a.push(T.charAt(63 & v >> 6));\n a.push(T.charAt(63 & v));\n }\n\n if (2 == u.length - i) {\n var v = (u[i] << 16) + (u[i + 1] << 8);\n a.push(T.charAt(63 & v >> 18));\n a.push(T.charAt(63 & v >> 12));\n a.push(T.charAt(63 & v >> 6));\n a.push('=');\n } else if (1 == u.length - i) {\n var v = u[i] << 16;\n a.push(T.charAt(63 & v >> 18));\n a.push(T.charAt(63 & v >> 12));\n a.push('==');\n }\n\n return a.join('');\n };\n\n var R = function () {\n var a = [];\n\n for (var i = 0; i < T.length; ++i) {\n a[T.charCodeAt(i)] = i;\n }\n\n a['='.charCodeAt(0)] = 0;\n return a;\n }();\n\n var decodeArray = function decodeArray(s) {\n var i = 0;\n var u = [];\n var n = 0 | s.length / 4;\n\n while (0 < n--) {\n var v = (R[s.charCodeAt(i)] << 18) + (R[s.charCodeAt(i + 1)] << 12) + (R[s.charCodeAt(i + 2)] << 6) + R[s.charCodeAt(i + 3)];\n u.push(255 & v >> 16);\n u.push(255 & v >> 8);\n u.push(255 & v);\n i += 4;\n }\n\n if (u) {\n if ('=' == s.charAt(i - 2)) {\n u.pop();\n u.pop();\n } else if ('=' == s.charAt(i - 1)) {\n u.pop();\n }\n }\n\n return u;\n };\n\n var ASCII = {};\n\n ASCII.encode = function (s) {\n var u = [];\n\n for (var i = 0; i < s.length; ++i) {\n u.push(s.charCodeAt(i));\n }\n\n return u;\n };\n\n ASCII.decode = function (u) {\n for (var i = 0; i < s.length; ++i) {\n a[i] = String.fromCharCode(a[i]);\n }\n\n return a.join('');\n };\n\n BASE64.decodeArray = function (s) {\n var u = decodeArray(s);\n return new Uint8Array(u);\n };\n\n BASE64.encodeASCII = function (s) {\n var u = ASCII.encode(s);\n return encodeArray(u);\n };\n\n BASE64.decodeASCII = function (s) {\n var a = decodeArray(s);\n return ASCII.decode(a);\n };\n\n BASE64.encode = function (s) {\n var u = UTF8.encode(s);\n return encodeArray(u);\n };\n\n BASE64.decode = function (s) {\n var u = decodeArray(s);\n return UTF8.decode(u);\n };\n})(\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\");\n/*The following polyfills are not used in dash.js but have caused multiplayer integration issues.\n Therefore commenting them out.\nif (undefined === btoa) {\n var btoa = BASE64.encode;\n}\nif (undefined === atob) {\n var atob = BASE64.decode;\n}\n*/\n\n\n{\n exports.decode = BASE64.decode;\n exports.decodeArray = BASE64.decodeArray;\n exports.encode = BASE64.encode;\n exports.encodeASCII = BASE64.encodeASCII;\n}\n\n/***/ }),\n\n/***/ \"./externals/cea608-parser.js\":\n/*!************************************!*\\\n !*** ./externals/cea608-parser.js ***!\n \\************************************/\n/*! no static exports found */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n * The copyright in this software is being made available under the BSD License,\n * included below. This software may be subject to other third party and contributor\n * rights, including patent rights, and no such rights are granted under this license.\n *\n * Copyright (c) 2015-2016, DASH Industry Forum.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * 1. Redistributions of source code must retain the above copyright notice, this\n * list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation and/or\n * other materials provided with the distribution.\n * 2. Neither the name of Dash Industry Forum nor the names of its\n * contributors may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n(function (exports) {\n /**\n * Exceptions from regular ASCII. CodePoints are mapped to UTF-16 codes\n */\n\n var specialCea608CharsCodes = {\n 0x2a: 0xe1,\n // lowercase a, acute accent\n 0x5c: 0xe9,\n // lowercase e, acute accent\n 0x5e: 0xed,\n // lowercase i, acute accent\n 0x5f: 0xf3,\n // lowercase o, acute accent\n 0x60: 0xfa,\n // lowercase u, acute accent\n 0x7b: 0xe7,\n // lowercase c with cedilla\n 0x7c: 0xf7,\n // division symbol\n 0x7d: 0xd1,\n // uppercase N tilde\n 0x7e: 0xf1,\n // lowercase n tilde\n 0x7f: 0x2588,\n // Full block\n // THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS\n // THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F\n // THIS MEANS THAT \\x50 MUST BE ADDED TO THE VALUES\n 0x80: 0xae,\n // Registered symbol (R)\n 0x81: 0xb0,\n // degree sign\n 0x82: 0xbd,\n // 1/2 symbol\n 0x83: 0xbf,\n // Inverted (open) question mark\n 0x84: 0x2122,\n // Trademark symbol (TM)\n 0x85: 0xa2,\n // Cents symbol\n 0x86: 0xa3,\n // Pounds sterling\n 0x87: 0x266a,\n // Music 8'th note\n 0x88: 0xe0,\n // lowercase a, grave accent\n 0x89: 0x20,\n // transparent space (regular)\n 0x8a: 0xe8,\n // lowercase e, grave accent\n 0x8b: 0xe2,\n // lowercase a, circumflex accent\n 0x8c: 0xea,\n // lowercase e, circumflex accent\n 0x8d: 0xee,\n // lowercase i, circumflex accent\n 0x8e: 0xf4,\n // lowercase o, circumflex accent\n 0x8f: 0xfb,\n // lowercase u, circumflex accent\n // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS\n // THAT COME FROM HI BYTE=0x12 AND LOW BETWEEN 0x20 AND 0x3F\n 0x90: 0xc1,\n // capital letter A with acute\n 0x91: 0xc9,\n // capital letter E with acute\n 0x92: 0xd3,\n // capital letter O with acute\n 0x93: 0xda,\n // capital letter U with acute\n 0x94: 0xdc,\n // capital letter U with diaresis\n 0x95: 0xfc,\n // lowercase letter U with diaeresis\n 0x96: 0x2018,\n // opening single quote\n 0x97: 0xa1,\n // inverted exclamation mark\n 0x98: 0x2a,\n // asterisk\n 0x99: 0x2019,\n // closing single quote\n 0x9a: 0x2501,\n // box drawings heavy horizontal\n 0x9b: 0xa9,\n // copyright sign\n 0x9c: 0x2120,\n // Service mark\n 0x9d: 0x2022,\n // (round) bullet\n 0x9e: 0x201c,\n // Left double quotation mark\n 0x9f: 0x201d,\n // Right double quotation mark\n 0xa0: 0xc0,\n // uppercase A, grave accent\n 0xa1: 0xc2,\n // uppercase A, circumflex\n 0xa2: 0xc7,\n // uppercase C with cedilla\n 0xa3: 0xc8,\n // uppercase E, grave accent\n 0xa4: 0xca,\n // uppercase E, circumflex\n 0xa5: 0xcb,\n // capital letter E with diaresis\n 0xa6: 0xeb,\n // lowercase letter e with diaresis\n 0xa7: 0xce,\n // uppercase I, circumflex\n 0xa8: 0xcf,\n // uppercase I, with diaresis\n 0xa9: 0xef,\n // lowercase i, with diaresis\n 0xaa: 0xd4,\n // uppercase O, circumflex\n 0xab: 0xd9,\n // uppercase U, grave accent\n 0xac: 0xf9,\n // lowercase u, grave accent\n 0xad: 0xdb,\n // uppercase U, circumflex\n 0xae: 0xab,\n // left-pointing double angle quotation mark\n 0xaf: 0xbb,\n // right-pointing double angle quotation mark\n // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS\n // THAT COME FROM HI BYTE=0x13 AND LOW BETWEEN 0x20 AND 0x3F\n 0xb0: 0xc3,\n // Uppercase A, tilde\n 0xb1: 0xe3,\n // Lowercase a, tilde\n 0xb2: 0xcd,\n // Uppercase I, acute accent\n 0xb3: 0xcc,\n // Uppercase I, grave accent\n 0xb4: 0xec,\n // Lowercase i, grave accent\n 0xb5: 0xd2,\n // Uppercase O, grave accent\n 0xb6: 0xf2,\n // Lowercase o, grave accent\n 0xb7: 0xd5,\n // Uppercase O, tilde\n 0xb8: 0xf5,\n // Lowercase o, tilde\n 0xb9: 0x7b,\n // Open curly brace\n 0xba: 0x7d,\n // Closing curly brace\n 0xbb: 0x5c,\n // Backslash\n 0xbc: 0x5e,\n // Caret\n 0xbd: 0x5f,\n // Underscore\n 0xbe: 0x7c,\n // Pipe (vertical line)\n 0xbf: 0x223c,\n // Tilde operator\n 0xc0: 0xc4,\n // Uppercase A, umlaut\n 0xc1: 0xe4,\n // Lowercase A, umlaut\n 0xc2: 0xd6,\n // Uppercase O, umlaut\n 0xc3: 0xf6,\n // Lowercase o, umlaut\n 0xc4: 0xdf,\n // Esszett (sharp S)\n 0xc5: 0xa5,\n // Yen symbol\n 0xc6: 0xa4,\n // Generic currency sign\n 0xc7: 0x2503,\n // Box drawings heavy vertical\n 0xc8: 0xc5,\n // Uppercase A, ring\n 0xc9: 0xe5,\n // Lowercase A, ring\n 0xca: 0xd8,\n // Uppercase O, stroke\n 0xcb: 0xf8,\n // Lowercase o, strok\n 0xcc: 0x250f,\n // Box drawings heavy down and right\n 0xcd: 0x2513,\n // Box drawings heavy down and left\n 0xce: 0x2517,\n // Box drawings heavy up and right\n 0xcf: 0x251b // Box drawings heavy up and left\n\n };\n /**\n * Get Unicode Character from CEA-608 byte code\n */\n\n var getCharForByte = function getCharForByte(_byte) {\n var charCode = _byte;\n\n if (specialCea608CharsCodes.hasOwnProperty(_byte)) {\n charCode = specialCea608CharsCodes[_byte];\n }\n\n return String.fromCharCode(charCode);\n };\n\n var NR_ROWS = 15,\n NR_COLS = 32; // Tables to look up row from PAC data\n\n var rowsLowCh1 = {\n 0x11: 1,\n 0x12: 3,\n 0x15: 5,\n 0x16: 7,\n 0x17: 9,\n 0x10: 11,\n 0x13: 12,\n 0x14: 14\n };\n var rowsHighCh1 = {\n 0x11: 2,\n 0x12: 4,\n 0x15: 6,\n 0x16: 8,\n 0x17: 10,\n 0x13: 13,\n 0x14: 15\n };\n var rowsLowCh2 = {\n 0x19: 1,\n 0x1A: 3,\n 0x1D: 5,\n 0x1E: 7,\n 0x1F: 9,\n 0x18: 11,\n 0x1B: 12,\n 0x1C: 14\n };\n var rowsHighCh2 = {\n 0x19: 2,\n 0x1A: 4,\n 0x1D: 6,\n 0x1E: 8,\n 0x1F: 10,\n 0x1B: 13,\n 0x1C: 15\n };\n var backgroundColors = ['white', 'green', 'blue', 'cyan', 'red', 'yellow', 'magenta', 'black', 'transparent'];\n /**\n * Simple logger class to be able to write with time-stamps and filter on level.\n */\n\n var logger = {\n verboseFilter: {\n 'DATA': 3,\n 'DEBUG': 3,\n 'INFO': 2,\n 'WARNING': 2,\n 'TEXT': 1,\n 'ERROR': 0\n },\n time: null,\n verboseLevel: 0,\n // Only write errors\n setTime: function setTime(newTime) {\n this.time = newTime;\n },\n log: function log(severity, msg) {\n var minLevel = this.verboseFilter[severity];\n\n if (this.verboseLevel >= minLevel) {\n console.log(this.time + \" [\" + severity + \"] \" + msg);\n }\n }\n };\n\n var numArrayToHexArray = function numArrayToHexArray(numArray) {\n var hexArray = [];\n\n for (var j = 0; j < numArray.length; j++) {\n hexArray.push(numArray[j].toString(16));\n }\n\n return hexArray;\n };\n /**\n * State of CEA-608 pen or character\n * @constructor\n */\n\n\n var PenState = function PenState(foreground, underline, italics, background, flash) {\n this.foreground = foreground || \"white\";\n this.underline = underline || false;\n this.italics = italics || false;\n this.background = background || \"black\";\n this.flash = flash || false;\n };\n\n PenState.prototype = {\n reset: function reset() {\n this.foreground = \"white\";\n this.underline = false;\n this.italics = false;\n this.background = \"black\";\n this.flash = false;\n },\n setStyles: function setStyles(styles) {\n var attribs = [\"foreground\", \"underline\", \"italics\", \"background\", \"flash\"];\n\n for (var i = 0; i < attribs.length; i++) {\n var style = attribs[i];\n\n if (styles.hasOwnProperty(style)) {\n this[style] = styles[style];\n }\n }\n },\n isDefault: function isDefault() {\n return this.foreground === \"white\" && !this.underline && !this.italics && this.background === \"black\" && !this.flash;\n },\n equals: function equals(other) {\n return this.foreground === other.foreground && this.underline === other.underline && this.italics === other.italics && this.background === other.background && this.flash === other.flash;\n },\n copy: function copy(newPenState) {\n this.foreground = newPenState.foreground;\n this.underline = newPenState.underline;\n this.italics = newPenState.italics;\n this.background = newPenState.background;\n this.flash = newPenState.flash;\n },\n toString: function toString() {\n return \"color=\" + this.foreground + \", underline=\" + this.underline + \", italics=\" + this.italics + \", background=\" + this.background + \", flash=\" + this.flash;\n }\n };\n /**\n * Unicode character with styling and background.\n * @constructor\n */\n\n var StyledUnicodeChar = function StyledUnicodeChar(uchar, foreground, underline, italics, background, flash) {\n this.uchar = uchar || ' '; // unicode character\n\n this.penState = new PenState(foreground, underline, italics, background, flash);\n };\n\n StyledUnicodeChar.prototype = {\n reset: function reset() {\n this.uchar = ' ';\n this.penState.reset();\n },\n setChar: function setChar(uchar, newPenState) {\n this.uchar = uchar;\n this.penState.copy(newPenState);\n },\n setPenState: function setPenState(newPenState) {\n this.penState.copy(newPenState);\n },\n equals: function equals(other) {\n return this.uchar === other.uchar && this.penState.equals(other.penState);\n },\n copy: function copy(newChar) {\n this.uchar = newChar.uchar;\n this.penState.copy(newChar.penState);\n },\n isEmpty: function isEmpty() {\n return this.uchar === ' ' && this.penState.isDefault();\n }\n };\n /**\n * CEA-608 row consisting of NR_COLS instances of StyledUnicodeChar.\n * @constructor\n */\n\n var Row = function Row() {\n this.chars = [];\n\n for (var i = 0; i < NR_COLS; i++) {\n this.chars.push(new StyledUnicodeChar());\n }\n\n this.pos = 0;\n this.currPenState = new PenState();\n };\n\n Row.prototype = {\n equals: function equals(other) {\n var equal = true;\n\n for (var i = 0; i < NR_COLS; i++) {\n if (!this.chars[i].equals(other.chars[i])) {\n equal = false;\n break;\n }\n }\n\n return equal;\n },\n copy: function copy(other) {\n for (var i = 0; i < NR_COLS; i++) {\n this.chars[i].copy(other.chars[i]);\n }\n },\n isEmpty: function isEmpty() {\n var empty = true;\n\n for (var i = 0; i < NR_COLS; i++) {\n if (!this.chars[i].isEmpty()) {\n empty = false;\n break;\n }\n }\n\n return empty;\n },\n\n /**\n * Set the cursor to a valid column.\n */\n setCursor: function setCursor(absPos) {\n if (this.pos !== absPos) {\n this.pos = absPos;\n }\n\n if (this.pos < 0) {\n logger.log(\"ERROR\", \"Negative cursor position \" + this.pos);\n this.pos = 0;\n } else if (this.pos > NR_COLS) {\n logger.log(\"ERROR\", \"Too large cursor position \" + this.pos);\n this.pos = NR_COLS;\n }\n },\n\n /** \n * Move the cursor relative to current position.\n */\n moveCursor: function moveCursor(relPos) {\n var newPos = this.pos + relPos;\n\n if (relPos > 1) {\n for (var i = this.pos + 1; i < newPos + 1; i++) {\n this.chars[i].setPenState(this.currPenState);\n }\n }\n\n this.setCursor(newPos);\n },\n\n /**\n * Backspace, move one step back and clear character.\n */\n backSpace: function backSpace() {\n this.moveCursor(-1);\n this.chars[this.pos].setChar(' ', this.currPenState);\n },\n insertChar: function insertChar(_byte2) {\n if (_byte2 >= 0x90) {\n //Extended char\n this.backSpace();\n }\n\n var _char = getCharForByte(_byte2);\n\n if (this.pos >= NR_COLS) {\n logger.log(\"ERROR\", \"Cannot insert \" + _byte2.toString(16) + \" (\" + _char + \") at position \" + this.pos + \". Skipping it!\");\n return;\n }\n\n this.chars[this.pos].setChar(_char, this.currPenState);\n this.moveCursor(1);\n },\n clearFromPos: function clearFromPos(startPos) {\n var i;\n\n for (i = startPos; i < NR_COLS; i++) {\n this.chars[i].reset();\n }\n },\n clear: function clear() {\n this.clearFromPos(0);\n this.pos = 0;\n this.currPenState.reset();\n },\n clearToEndOfRow: function clearToEndOfRow() {\n this.clearFromPos(this.pos);\n },\n getTextString: function getTextString() {\n var chars = [];\n var empty = true;\n\n for (var i = 0; i < NR_COLS; i++) {\n var _char2 = this.chars[i].uchar;\n\n if (_char2 !== \" \") {\n empty = false;\n }\n\n chars.push(_char2);\n }\n\n if (empty) {\n return \"\";\n } else {\n return chars.join(\"\");\n }\n },\n setPenStyles: function setPenStyles(styles) {\n this.currPenState.setStyles(styles);\n var currChar = this.chars[this.pos];\n currChar.setPenState(this.currPenState);\n }\n };\n /**\n * Keep a CEA-608 screen of 32x15 styled characters\n * @constructor\n */\n\n var CaptionScreen = function CaptionScreen() {\n this.rows = [];\n\n for (var i = 0; i < NR_ROWS; i++) {\n this.rows.push(new Row()); // Note that we use zero-based numbering (0-14)\n }\n\n this.currRow = NR_ROWS - 1;\n this.nrRollUpRows = null;\n this.reset();\n };\n\n CaptionScreen.prototype = {\n reset: function reset() {\n for (var i = 0; i < NR_ROWS; i++) {\n this.rows[i].clear();\n }\n\n this.currRow = NR_ROWS - 1;\n },\n equals: function equals(other) {\n var equal = true;\n\n for (var i = 0; i < NR_ROWS; i++) {\n if (!this.rows[i].equals(other.rows[i])) {\n equal = false;\n break;\n }\n }\n\n return equal;\n },\n copy: function copy(other) {\n for (var i = 0; i < NR_ROWS; i++) {\n this.rows[i].copy(other.rows[i]);\n }\n },\n isEmpty: function isEmpty() {\n var empty = true;\n\n for (var i = 0; i < NR_ROWS; i++) {\n if (!this.rows[i].isEmpty()) {\n empty = false;\n break;\n }\n }\n\n return empty;\n },\n backSpace: function backSpace() {\n var row = this.rows[this.currRow];\n row.backSpace();\n },\n clearToEndOfRow: function clearToEndOfRow() {\n var row = this.rows[this.currRow];\n row.clearToEndOfRow();\n },\n\n /**\n * Insert a character (without styling) in the current row.\n */\n insertChar: function insertChar(_char3) {\n var row = this.rows[this.currRow];\n row.insertChar(_char3);\n },\n setPen: function setPen(styles) {\n var row = this.rows[this.currRow];\n row.setPenStyles(styles);\n },\n moveCursor: function moveCursor(relPos) {\n var row = this.rows[this.currRow];\n row.moveCursor(relPos);\n },\n setCursor: function setCursor(absPos) {\n logger.log(\"INFO\", \"setCursor: \" + absPos);\n var row = this.rows[this.currRow];\n row.setCursor(absPos);\n },\n setPAC: function setPAC(pacData) {\n logger.log(\"INFO\", \"pacData = \" + JSON.stringify(pacData));\n var newRow = pacData.row - 1;\n\n if (this.nrRollUpRows && newRow < this.nrRollUpRows - 1) {\n newRow = this.nrRollUpRows - 1;\n }\n\n this.currRow = newRow;\n var row = this.rows[this.currRow];\n\n if (pacData.indent !== null) {\n var indent = pacData.indent;\n var prevPos = Math.max(indent - 1, 0);\n row.setCursor(pacData.indent);\n pacData.color = row.chars[prevPos].penState.foreground;\n }\n\n var styles = {\n foreground: pacData.color,\n underline: pacData.underline,\n italics: pacData.italics,\n background: 'black',\n flash: false\n };\n this.setPen(styles);\n },\n\n /**\n * Set background/extra foreground, but first do back_space, and then insert space (backwards compatibility).\n */\n setBkgData: function setBkgData(bkgData) {\n logger.log(\"INFO\", \"bkgData = \" + JSON.stringify(bkgData));\n this.backSpace();\n this.setPen(bkgData);\n this.insertChar(0x20); //Space\n },\n setRollUpRows: function setRollUpRows(nrRows) {\n this.nrRollUpRows = nrRows;\n },\n rollUp: function rollUp() {\n if (this.nrRollUpRows === null) {\n logger.log(\"DEBUG\", \"roll_up but nrRollUpRows not set yet\");\n return; //Not properly setup\n }\n\n logger.log(\"TEXT\", this.getDisplayText());\n var topRowIndex = this.currRow + 1 - this.nrRollUpRows;\n var topRow = this.rows.splice(topRowIndex, 1)[0];\n topRow.clear();\n this.rows.splice(this.currRow, 0, topRow);\n logger.log(\"INFO\", \"Rolling up\"); //logger.log(\"TEXT\", this.get_display_text())\n },\n\n /**\n * Get all non-empty rows with as unicode text. \n */\n getDisplayText: function getDisplayText(asOneRow) {\n asOneRow = asOneRow || false;\n var displayText = [];\n var text = \"\";\n var rowNr = -1;\n\n for (var i = 0; i < NR_ROWS; i++) {\n var rowText = this.rows[i].getTextString();\n\n if (rowText) {\n rowNr = i + 1;\n\n if (asOneRow) {\n displayText.push(\"Row \" + rowNr + ': \"' + rowText + '\"');\n } else {\n displayText.push(rowText.trim());\n }\n }\n }\n\n if (displayText.length > 0) {\n if (asOneRow) {\n text = \"[\" + displayText.join(\" | \") + \"]\";\n } else {\n text = displayText.join(\"\\n\");\n }\n }\n\n return text;\n },\n getTextAndFormat: function getTextAndFormat() {\n return this.rows;\n }\n };\n /**\n * Handle a CEA-608 channel and send decoded data to outputFilter\n * @constructor\n * @param {Number} channelNumber (1 or 2)\n * @param {CueHandler} outputFilter Output from channel1 newCue(startTime, endTime, captionScreen)\n */\n\n var Cea608Channel = function Cea608Channel(channelNumber, outputFilter) {\n this.chNr = channelNumber;\n this.outputFilter = outputFilter;\n this.mode = null;\n this.verbose = 0;\n this.displayedMemory = new CaptionScreen();\n this.nonDisplayedMemory = new CaptionScreen();\n this.lastOutputScreen = new CaptionScreen();\n this.currRollUpRow = this.displayedMemory.rows[NR_ROWS - 1];\n this.writeScreen = this.displayedMemory;\n this.mode = null;\n this.cueStartTime = null; // Keeps track of where a cue started.\n };\n\n Cea608Channel.prototype = {\n modes: [\"MODE_ROLL-UP\", \"MODE_POP-ON\", \"MODE_PAINT-ON\", \"MODE_TEXT\"],\n reset: function reset() {\n this.mode = null;\n this.displayedMemory.reset();\n this.nonDisplayedMemory.reset();\n this.lastOutputScreen.reset();\n this.currRollUpRow = this.displayedMemory.rows[NR_ROWS - 1];\n this.writeScreen = this.displayedMemory;\n this.mode = null;\n this.cueStartTime = null;\n this.lastCueEndTime = null;\n },\n getHandler: function getHandler() {\n return this.outputFilter;\n },\n setHandler: function setHandler(newHandler) {\n this.outputFilter = newHandler;\n },\n setPAC: function setPAC(pacData) {\n this.writeScreen.setPAC(pacData);\n },\n setBkgData: function setBkgData(bkgData) {\n this.writeScreen.setBkgData(bkgData);\n },\n setMode: function setMode(newMode) {\n if (newMode === this.mode) {\n return;\n }\n\n this.mode = newMode;\n logger.log(\"INFO\", \"MODE=\" + newMode);\n\n if (this.mode == \"MODE_POP-ON\") {\n this.writeScreen = this.nonDisplayedMemory;\n } else {\n this.writeScreen = this.displayedMemory;\n this.writeScreen.reset();\n }\n\n if (this.mode !== \"MODE_ROLL-UP\") {\n this.displayedMemory.nrRollUpRows = null;\n this.nonDisplayedMemory.nrRollUpRows = null;\n }\n\n this.mode = newMode;\n },\n insertChars: function insertChars(chars) {\n for (var i = 0; i < chars.length; i++) {\n this.writeScreen.insertChar(chars[i]);\n }\n\n var screen = this.writeScreen === this.displayedMemory ? \"DISP\" : \"NON_DISP\";\n logger.log(\"INFO\", screen + \": \" + this.writeScreen.getDisplayText(true));\n\n if (this.mode === \"MODE_PAINT-ON\" || this.mode === \"MODE_ROLL-UP\") {\n logger.log(\"TEXT\", \"DISPLAYED: \" + this.displayedMemory.getDisplayText(true));\n this.outputDataUpdate();\n }\n },\n cc_RCL: function cc_RCL() {\n // Resume Caption Loading (switch mode to Pop On)\n logger.log(\"INFO\", \"RCL - Resume Caption Loading\");\n this.setMode(\"MODE_POP-ON\");\n },\n cc_BS: function cc_BS() {\n // BackSpace\n logger.log(\"INFO\", \"BS - BackSpace\");\n\n if (this.mode === \"MODE_TEXT\") {\n return;\n }\n\n this.writeScreen.backSpace();\n\n if (this.writeScreen === this.displayedMemory) {\n this.outputDataUpdate();\n }\n },\n cc_AOF: function cc_AOF() {\n // Reserved (formerly Alarm Off)\n return;\n },\n cc_AON: function cc_AON() {\n // Reserved (formerly Alarm On)\n return;\n },\n cc_DER: function cc_DER() {\n // Delete to End of Row\n logger.log(\"INFO\", \"DER- Delete to End of Row\");\n this.writeScreen.clearToEndOfRow();\n this.outputDataUpdate();\n },\n cc_RU: function cc_RU(nrRows) {\n //Roll-Up Captions-2,3,or 4 Rows\n logger.log(\"INFO\", \"RU(\" + nrRows + \") - Roll Up\");\n this.writeScreen = this.displayedMemory;\n this.setMode(\"MODE_ROLL-UP\");\n this.writeScreen.setRollUpRows(nrRows);\n },\n cc_FON: function cc_FON() {\n //Flash On\n logger.log(\"INFO\", \"FON - Flash On\");\n this.writeScreen.setPen({\n flash: true\n });\n },\n cc_RDC: function cc_RDC() {\n // Resume Direct Captioning (switch mode to PaintOn)\n logger.log(\"INFO\", \"RDC - Resume Direct Captioning\");\n this.setMode(\"MODE_PAINT-ON\");\n },\n cc_TR: function cc_TR() {\n // Text Restart in text mode (not supported, however)\n logger.log(\"INFO\", \"TR\");\n this.setMode(\"MODE_TEXT\");\n },\n cc_RTD: function cc_RTD() {\n // Resume Text Display in Text mode (not supported, however)\n logger.log(\"INFO\", \"RTD\");\n this.setMode(\"MODE_TEXT\");\n },\n cc_EDM: function cc_EDM() {\n // Erase Displayed Memory\n logger.log(\"INFO\", \"EDM - Erase Displayed Memory\");\n this.displayedMemory.reset();\n this.outputDataUpdate();\n },\n cc_CR: function cc_CR() {\n // Carriage Return\n logger.log(\"CR - Carriage Return\");\n this.writeScreen.rollUp();\n this.outputDataUpdate();\n },\n cc_ENM: function cc_ENM() {\n //Erase Non-Displayed Memory\n logger.log(\"INFO\", \"ENM - Erase Non-displayed Memory\");\n this.nonDisplayedMemory.reset();\n },\n cc_EOC: function cc_EOC() {\n //End of Caption (Flip Memories)\n logger.log(\"INFO\", \"EOC - End Of Caption\");\n\n if (this.mode === \"MODE_POP-ON\") {\n var tmp = this.displayedMemory;\n this.displayedMemory = this.nonDisplayedMemory;\n this.nonDisplayedMemory = tmp;\n this.writeScreen = this.nonDisplayedMemory;\n logger.log(\"TEXT\", \"DISP: \" + this.displayedMemory.getDisplayText());\n }\n\n this.outputDataUpdate();\n },\n cc_TO: function cc_TO(nrCols) {\n // Tab Offset 1,2, or 3 columns\n logger.log(\"INFO\", \"TO(\" + nrCols + \") - Tab Offset\");\n this.writeScreen.moveCursor(nrCols);\n },\n cc_MIDROW: function cc_MIDROW(secondByte) {\n // Parse MIDROW command\n var styles = {\n flash: false\n };\n styles.underline = secondByte % 2 === 1;\n styles.italics = secondByte >= 0x2e;\n\n if (!styles.italics) {\n var colorIndex = Math.floor(secondByte / 2) - 0x10;\n var colors = [\"white\", \"green\", \"blue\", \"cyan\", \"red\", \"yellow\", \"magenta\"];\n styles.foreground = colors[colorIndex];\n } else {\n styles.foreground = \"white\";\n }\n\n logger.log(\"INFO\", \"MIDROW: \" + JSON.stringify(styles));\n this.writeScreen.setPen(styles);\n },\n outputDataUpdate: function outputDataUpdate() {\n var t = logger.time;\n\n if (t === null) {\n return;\n }\n\n if (this.outputFilter) {\n if (this.outputFilter.updateData) {\n this.outputFilter.updateData(t, this.displayedMemory);\n }\n\n if (this.cueStartTime === null && !this.displayedMemory.isEmpty()) {\n // Start of a new cue\n this.cueStartTime = t;\n } else {\n if (!this.displayedMemory.equals(this.lastOutputScreen)) {\n if (this.outputFilter.newCue) {\n this.outputFilter.newCue(this.cueStartTime, t, this.lastOutputScreen);\n }\n\n this.cueStartTime = this.displayedMemory.isEmpty() ? null : t;\n }\n }\n\n this.lastOutputScreen.copy(this.displayedMemory);\n }\n },\n cueSplitAtTime: function cueSplitAtTime(t) {\n if (this.outputFilter) {\n if (!this.displayedMemory.isEmpty()) {\n if (this.outputFilter.newCue) {\n this.outputFilter.newCue(this.cueStartTime, t, this.displayedMemory);\n }\n\n this.cueStartTime = t;\n }\n }\n }\n };\n /**\n * Parse CEA-608 data and send decoded data to out1 and out2.\n * @constructor\n * @param {Number} field CEA-608 field (1 or 2)\n * @param {CueHandler} out1 Output from channel1 newCue(startTime, endTime, captionScreen)\n * @param {CueHandler} out2 Output from channel2 newCue(startTime, endTime, captionScreen)\n */\n\n var Cea608Parser = function Cea608Parser(field, out1, out2) {\n this.field = field || 1;\n this.outputs = [out1, out2];\n this.channels = [new Cea608Channel(1, out1), new Cea608Channel(2, out2)];\n this.currChNr = -1; // Will be 1 or 2\n\n this.lastCmdA = null; // First byte of last command\n\n this.lastCmdB = null; // Second byte of last command\n\n this.bufferedData = [];\n this.startTime = null;\n this.lastTime = null;\n this.dataCounters = {\n 'padding': 0,\n 'char': 0,\n 'cmd': 0,\n 'other': 0\n };\n };\n\n Cea608Parser.prototype = {\n getHandler: function getHandler(index) {\n return this.channels[index].getHandler();\n },\n setHandler: function setHandler(index, newHandler) {\n this.channels[index].setHandler(newHandler);\n },\n\n /**\n * Add data for time t in forms of list of bytes (unsigned ints). The bytes are treated as pairs.\n */\n addData: function addData(t, byteList) {\n var cmdFound,\n a,\n b,\n charsFound = false;\n this.lastTime = t;\n logger.setTime(t);\n\n for (var i = 0; i < byteList.length; i += 2) {\n a = byteList[i] & 0x7f;\n b = byteList[i + 1] & 0x7f;\n\n if (a >= 0x10 && a <= 0x1f && a === this.lastCmdA && b === this.lastCmdB) {\n this.lastCmdA = null;\n this.lastCmdB = null;\n logger.log(\"DEBUG\", \"Repeated command (\" + numArrayToHexArray([a, b]) + \") is dropped\");\n continue; // Repeated commands are dropped (once)\n }\n\n if (a === 0 && b === 0) {\n this.dataCounters.padding += 2;\n continue;\n } else {\n logger.log(\"DATA\", \"[\" + numArrayToHexArray([byteList[i], byteList[i + 1]]) + \"] -> (\" + numArrayToHexArray([a, b]) + \")\");\n }\n\n cmdFound = this.parseCmd(a, b);\n\n if (!cmdFound) {\n cmdFound = this.parseMidrow(a, b);\n }\n\n if (!cmdFound) {\n cmdFound = this.parsePAC(a, b);\n }\n\n if (!cmdFound) {\n cmdFound = this.parseBackgroundAttributes(a, b);\n }\n\n if (!cmdFound) {\n charsFound = this.parseChars(a, b);\n\n if (charsFound) {\n if (this.currChNr && this.currChNr >= 0) {\n var channel = this.channels[this.currChNr - 1];\n channel.insertChars(charsFound);\n } else {\n logger.log(\"WARNING\", \"No channel found yet. TEXT-MODE?\");\n }\n }\n }\n\n if (cmdFound) {\n this.dataCounters.cmd += 2;\n } else if (charsFound) {\n this.dataCounters[\"char\"] += 2;\n } else {\n this.dataCounters.other += 2;\n logger.log(\"WARNING\", \"Couldn't parse cleaned data \" + numArrayToHexArray([a, b]) + \" orig: \" + numArrayToHexArray([byteList[i], byteList[i + 1]]));\n }\n }\n },\n\n /**\n * Parse Command.\n * @returns {Boolean} Tells if a command was found\n */\n parseCmd: function parseCmd(a, b) {\n var chNr = null;\n var cond1 = (a === 0x14 || a === 0x15 || a === 0x1C || a === 0x1D) && 0x20 <= b && b <= 0x2F;\n var cond2 = (a === 0x17 || a === 0x1F) && 0x21 <= b && b <= 0x23;\n\n if (!(cond1 || cond2)) {\n return false;\n }\n\n if (a === 0x14 || a === 0x15 || a === 0x17) {\n chNr = 1;\n } else {\n chNr = 2; // (a === 0x1C || a === 0x1D || a=== 0x1f)\n }\n\n var channel = this.channels[chNr - 1];\n\n if (a === 0x14 || a === 0x15 || a === 0x1C || a === 0x1D) {\n if (b === 0x20) {\n channel.cc_RCL();\n } else if (b === 0x21) {\n channel.cc_BS();\n } else if (b === 0x22) {\n channel.cc_AOF();\n } else if (b === 0x23) {\n channel.cc_AON();\n } else if (b === 0x24) {\n channel.cc_DER();\n } else if (b === 0x25) {\n channel.cc_RU(2);\n } else if (b === 0x26) {\n channel.cc_RU(3);\n } else if (b === 0x27) {\n channel.cc_RU(4);\n } else if (b === 0x28) {\n channel.cc_FON();\n } else if (b === 0x29) {\n channel.cc_RDC();\n } else if (b === 0x2A) {\n channel.cc_TR();\n } else if (b === 0x2B) {\n channel.cc_RTD();\n } else if (b === 0x2C) {\n channel.cc_EDM();\n } else if (b === 0x2D) {\n channel.cc_CR();\n } else if (b === 0x2E) {\n channel.cc_ENM();\n } else if (b === 0x2F) {\n channel.cc_EOC();\n }\n } else {\n //a == 0x17 || a == 0x1F\n channel.cc_TO(b - 0x20);\n }\n\n this.lastCmdA = a;\n this.lastCmdB = b;\n this.currChNr = chNr;\n return true;\n },\n\n /**\n * Parse midrow styling command\n * @returns {Boolean}\n */\n parseMidrow: function parseMidrow(a, b) {\n var chNr = null;\n\n if ((a === 0x11 || a === 0x19) && 0x20 <= b && b <= 0x2f) {\n if (a === 0x11) {\n chNr = 1;\n } else {\n chNr = 2;\n }\n\n if (chNr !== this.currChNr) {\n logger.log(\"ERROR\", \"Mismatch channel in midrow parsing\");\n return false;\n }\n\n var channel = this.channels[chNr - 1]; // cea608 spec says midrow codes should inject a space\n\n channel.insertChars([0x20]);\n channel.cc_MIDROW(b);\n logger.log(\"DEBUG\", \"MIDROW (\" + numArrayToHexArray([a, b]) + \")\");\n this.lastCmdA = a;\n this.lastCmdB = b;\n return true;\n }\n\n return false;\n },\n\n /**\n * Parse Preable Access Codes (Table 53).\n * @returns {Boolean} Tells if PAC found\n */\n parsePAC: function parsePAC(a, b) {\n var chNr = null;\n var row = null;\n var case1 = (0x11 <= a && a <= 0x17 || 0x19 <= a && a <= 0x1F) && 0x40 <= b && b <= 0x7F;\n var case2 = (a === 0x10 || a === 0x18) && 0x40 <= b && b <= 0x5F;\n\n if (!(case1 || case2)) {\n return false;\n }\n\n chNr = a <= 0x17 ? 1 : 2;\n\n if (0x40 <= b && b <= 0x5F) {\n row = chNr === 1 ? rowsLowCh1[a] : rowsLowCh2[a];\n } else {\n // 0x60 <= b <= 0x7F\n row = chNr === 1 ? rowsHighCh1[a] : rowsHighCh2[a];\n }\n\n var pacData = this.interpretPAC(row, b);\n var channel = this.channels[chNr - 1];\n channel.setPAC(pacData);\n this.lastCmdA = a;\n this.lastCmdB = b;\n this.currChNr = chNr;\n return true;\n },\n\n /**\n * Interpret the second byte of the pac, and return the information.\n * @returns {Object} pacData with style parameters.\n */\n interpretPAC: function interpretPAC(row, _byte3) {\n var pacIndex = _byte3;\n var pacData = {\n color: null,\n italics: false,\n indent: null,\n underline: false,\n row: row\n };\n\n if (_byte3 > 0x5F) {\n pacIndex = _byte3 - 0x60;\n } else {\n pacIndex = _byte3 - 0x40;\n }\n\n pacData.underline = (pacIndex & 1) === 1;\n\n if (pacIndex <= 0xd) {\n pacData.color = ['white', 'green', 'blue', 'cyan', 'red', 'yellow', 'magenta', 'white'][Math.floor(pacIndex / 2)];\n } else if (pacIndex <= 0xf) {\n pacData.italics = true;\n pacData.color = 'white';\n } else {\n pacData.indent = Math.floor((pacIndex - 0x10) / 2) * 4;\n }\n\n return pacData; // Note that row has zero offset. The spec uses 1.\n },\n\n /**\n * Parse characters.\n * @returns An array with 1 to 2 codes corresponding to chars, if found. null otherwise.\n */\n parseChars: function parseChars(a, b) {\n var channelNr = null,\n charCodes = null,\n charCode1 = null;\n\n if (a >= 0x19) {\n channelNr = 2;\n charCode1 = a - 8;\n } else {\n channelNr = 1;\n charCode1 = a;\n }\n\n if (0x11 <= charCode1 && charCode1 <= 0x13) {\n // Special character\n var oneCode = b;\n\n if (charCode1 === 0x11) {\n oneCode = b + 0x50;\n } else if (charCode1 === 0x12) {\n oneCode = b + 0x70;\n } else {\n oneCode = b + 0x90;\n }\n\n logger.log(\"INFO\", \"Special char '\" + getCharForByte(oneCode) + \"' in channel \" + channelNr);\n charCodes = [oneCode];\n this.lastCmdA = a;\n this.lastCmdB = b;\n } else if (0x20 <= a && a <= 0x7f) {\n charCodes = b === 0 ? [a] :