aed1155d by brandonocasey

converted the hls project to generator conventions

added notifications back to travis
fixed sinon version in package.json
got unit tests working by modifying the karma config
Added back manifest/expected.js to the build pipeline
Added a script to build/watch/clean them
Added script execution to package.json
got switcher partially working again
1 parent 64aecaee
Showing 160 changed files with 637 additions and 935 deletions
# http://editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
# OS
Thumbs.db
ehthumbs.db
Desktop.ini
.DS_Store
dist/*
/node_modules/
._*
# Editors
*~
*.iml
*.ipr
*.iws
*.swp
tmp/**.*.swo
*.tmproj
*.tmproject
*.sublime-*
.idea/
.project/
.settings/
.vscode/
# Logs
logs
*.log
npm-debug.log*
# Dependency directories
bower_components/
node_modules/
# Yeoman meta-data
.yo-rc.json
# Build-related directories
dist/
dist-test/
docs/api/
es5/
tmp
test/data/manifests.js
test/data/expected.js
......
{
"curly": true,
"eqeqeq": true,
"immed": true,
"latedef": true,
"newcap": true,
"noarg": true,
"sub": true,
"undef": true,
"unused": true,
"boss": true,
"eqnull": true,
"node": true,
"camelcase": true,
"nonew": true,
"quotmark": "single",
"trailing": true,
"maxlen": 80
}
*~
*.iml
*.swp
tmp/**
test/**
# Intentionally left blank, so that npm does not ignore anything by default,
# but relies on the package.json "files" array to explicitly define what ends
# up in the package.
......
language: node_js
sudo: false
language: node_js
node_js:
- "stable"
install:
- npm install -g grunt-cli && npm install
- 'node'
- '4.2'
- '0.12'
- '0.10'
notifications:
hipchat:
rooms:
......@@ -12,12 +13,7 @@ notifications:
channels:
- "chat.freenode.net#videojs"
use_notice: true
# Set up a virtual screen for Firefox.
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
env:
global:
- secure: dM7svnHPPu5IiUMeFWW5zg+iuWNpwt6SSDi3MmVvhSclNMRLesQoRB+7Qq5J/LiKhmjpv1/GlNVV0CTsHMRhZNwQ3fo38eEuTXv99aAflEITXwSEh/VntKViHbGFubn06EnVkJoH6MX3zJ6kbiwc2QdSQbywKzS6l6quUEpWpd0=
- secure: AnduYGXka5ft1x7V3SuVYqvlKLvJGhUaRNFdy4UDJr3ZVuwpQjE4TMDG8REmJIJvXfHbh4qY4N1cFSGnXkZ4bH21Xk0v9DLhsxbarKz+X2BvPgXs+Af9EQ6vLEy/5S1vMLxfT5+y+Ec5bVNGOsdUZby8Y21CRzSg6ADN9kwPGlE=
addons:
sauce_connect: true
......
'use strict';
var
basename = require('path').basename,
mediaSourcesPath = 'node_modules/videojs-contrib-media-sources/dist/',
mediaSourcesDebug = mediaSourcesPath + 'videojs-media-sources.js';
module.exports = function(grunt) {
var pkg = grunt.file.readJSON('package.json');
// Project configuration.
grunt.initConfig({
// Metadata.
pkg: pkg,
banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %>\n' +
'* Copyright (c) <%= grunt.template.today("yyyy") %> Brightcove;' +
' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',
// Task configuration.
clean: {
files: ['build', 'dist', 'tmp']
},
concat: {
options: {
banner: '<%= banner %>',
stripBanners: true
},
dist: {
nonull: true,
src: [
mediaSourcesDebug,
'src/videojs-hls.js',
'src/xhr.js',
'src/stream.js',
'src/m3u8/m3u8-parser.js',
'src/playlist.js',
'src/playlist-loader.js',
'node_modules/pkcs7/dist/pkcs7.unpad.js',
'src/decrypter.js'
],
dest: 'dist/videojs.hls.js'
}
},
uglify: {
options: {
banner: '<%= banner %>'
},
dist: {
src: '<%= concat.dist.dest %>',
dest: 'dist/videojs.hls.min.js'
}
},
jshint: {
gruntfile: {
options: {
jshintrc: '.jshintrc'
},
src: 'Gruntfile.js'
},
src: {
options: {
jshintrc: 'src/.jshintrc'
},
src: ['src/**/*.js']
},
test: {
options: {
jshintrc: 'test/.jshintrc'
},
src: ['test/**/*.js',
'!test/tsSegment.js',
'!test/fixtures/*.js',
'!test/manifest/**',
'!test/muxer/**',
'!test/switcher/**']
}
},
connect: {
dev: {
options: {
hostname: '*',
port: 9999,
keepalive: true
}
},
test: {
options: {
hostname: '*',
port: 9999
}
}
},
open : {
dev : {
path: 'http://127.0.0.1:<%= connect.dev.options.port %>/example.html',
app: 'Google Chrome'
}
},
watch: {
build: {
files: '<%= concat.dist.src %>',
tasks: ['clean', 'concat', 'uglify']
},
gruntfile: {
files: '<%= jshint.gruntfile.src %>',
tasks: ['jshint:gruntfile']
},
src: {
files: '<%= jshint.src.src %>',
tasks: ['jshint:src', 'test']
},
test: {
files: '<%= jshint.test.src %>',
tasks: ['jshint:test', 'test']
}
},
concurrent: {
dev: {
tasks: ['connect', 'open', 'watch'],
options: {
logConcurrentOutput: true
}
}
},
version: {
project: {
src: ['package.json']
}
},
'github-release': {
options: {
repository: 'videojs/videojs-contrib-hls',
auth: {
user: process.env.VJS_GITHUB_USER,
password: process.env.VJS_GITHUB_TOKEN
},
release: {
'tag_name': 'v' + pkg.version,
name: pkg.version,
body: require('chg').find(pkg.version).changesRaw
}
},
files: {
'dist': ['videojs.hls.min.js']
}
},
karma: {
options: {
frameworks: ['qunit']
},
saucelabs: {
configFile: 'test/karma.conf.js',
autoWatch: true
},
dev: {
browsers: ['Chrome', 'Safari', 'Firefox',
'Opera', 'IE', 'PhantomJS', 'ChromeCanary'],
configFile: 'test/localkarma.conf.js',
autoWatch: true
},
chromecanary: {
options: {
browsers: ['ChromeCanary'],
configFile: 'test/localkarma.conf.js',
autoWatch: true
}
},
phantomjs: {
options: {
browsers: ['PhantomJS'],
configFile: 'test/localkarma.conf.js',
autoWatch: true
}
},
opera: {
options: {
browsers: ['Opera'],
configFile: 'test/localkarma.conf.js',
autoWatch: true
}
},
chrome: {
options: {
browsers: ['Chrome'],
configFile: 'test/localkarma.conf.js',
autoWatch: true
}
},
safari: {
options: {
browsers: ['Safari'],
configFile: 'test/localkarma.conf.js',
autoWatch: true
}
},
firefox: {
options: {
browsers: ['Firefox'],
configFile: 'test/localkarma.conf.js',
autoWatch: true
}
},
ie: {
options: {
browsers: ['IE'],
configFile: 'test/localkarma.conf.js',
autoWatch: true
}
},
ci: {
configFile: 'test/karma.conf.js',
autoWatch: false
}
},
protractor: {
options: {
configFile: 'test/functional/protractor.config.js',
webdriverManagerUpdate: process.env.TRAVIS ? false : true
},
chrome: {
options: {
args: {
capabilities: {
browserName: 'chrome'
}
}
}
},
firefox: {
options: {
args: {
capabilities: {
browserName: 'firefox'
}
}
}
},
safari: {
options: {
args: {
capabilities: {
browserName: 'safari'
}
}
}
},
ie: {
options: {
args: {
capabilities: {
browserName: 'internet explorer'
}
}
}
},
saucelabs:{}
}
});
// These plugins provide necessary tasks.
grunt.loadNpmTasks('grunt-karma');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-open');
grunt.loadNpmTasks('grunt-concurrent');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-github-releaser');
grunt.loadNpmTasks('grunt-version');
grunt.loadNpmTasks('grunt-protractor-runner');
grunt.loadNpmTasks('chg');
grunt.registerTask('manifests-to-js', 'Wrap the test fixtures and output' +
' so they can be loaded in a browser',
function() {
var
jsManifests = 'window.manifests = {\n',
jsExpected = 'window.expected = {\n';
grunt.file.recurse('test/manifest/',
function(abspath, root, sub, filename) {
if ((/\.m3u8$/).test(abspath)) {
// translate this manifest
jsManifests += ' \'' + basename(filename, '.m3u8') + '\': ' +
grunt.file.read(abspath)
.split(/\r\n|\n/)
// quote and concatenate
.map(function(line) {
return ' \'' + line + '\\n\' +\n';
}).join('')
// strip leading spaces and the trailing '+'
.slice(4, -3);
jsManifests += ',\n';
}
if ((/\.js$/).test(abspath)) {
// append the expected parse
jsExpected += ' "' + basename(filename, '.js') + '": ' +
grunt.file.read(abspath) + ',\n';
}
});
// clean up and close the objects
jsManifests = jsManifests.slice(0, -2);
jsManifests += '\n};\n';
jsExpected = jsExpected.slice(0, -2);
jsExpected += '\n};\n';
// write out the manifests
grunt.file.write('tmp/manifests.js', jsManifests);
grunt.file.write('tmp/expected.js', jsExpected);
});
// Launch a Development Environment
grunt.registerTask('dev', 'Launching Dev Environment', 'concurrent:dev');
grunt.registerTask('build',
['clean',
'concat',
'uglify']);
// Default task.
grunt.registerTask('default',
['test',
'build']);
// The test task will run `karma:saucelabs` when running in travis,
// otherwise, it'll default to running karma in chrome.
// You can specify which browsers to build with by using grunt-style arguments
// or separating them with a comma:
// grunt test:chrome:firefox # grunt-style
// grunt test:chrome,firefox # comma-separated
grunt.registerTask('test', function() {
var tasks = this.args;
grunt.task.run(['jshint', 'manifests-to-js']);
if (process.env.TRAVIS) {
if (process.env.TRAVIS_PULL_REQUEST === 'false') {
grunt.task.run(['karma:saucelabs']);
grunt.task.run(['connect:test', 'protractor:saucelabs']);
} else {
grunt.task.run(['karma:firefox']);
}
} else {
if (tasks.length === 0) {
tasks.push('chrome');
}
if (tasks.length === 1) {
tasks = tasks[0].split(',');
}
tasks = tasks.reduce(function(acc, el) {
acc.push('karma:' + el);
if (/chrome|firefox|safari|ie/.test(el)) {
acc.push('protractor:' + el);
}
return acc;
}, ['connect:test']);
grunt.task.run(tasks);
}
});
};
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [video.js HLS Source Handler](#videojs-hls-source-handler)
- [Getting Started](#getting-started)
- [Documentation](#documentation)
- [Options](#options)
- [withCredentials](#withcredentials)
- [Runtime Properties](#runtime-properties)
- [hls.playlists.master](#hlsplaylistsmaster)
- [hls.playlists.media](#hlsplaylistsmedia)
- [hls.segmentXhrTime](#hlssegmentxhrtime)
- [hls.bandwidth](#hlsbandwidth)
- [hls.bytesReceived](#hlsbytesreceived)
- [hls.selectPlaylist](#hlsselectplaylist)
- [Events](#events)
- [loadedmetadata](#loadedmetadata)
- [loadedplaylist](#loadedplaylist)
- [mediachange](#mediachange)
- [In-Band Metadata](#in-band-metadata)
- [Hosting Considerations](#hosting-considerations)
- [Testing](#testing)
- [Release History](#release-history)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
# video.js HLS Source Handler
Play back HLS with video.js, even where it's not natively supported.
......
......@@ -2,31 +2,8 @@
<html>
<head>
<meta charset="utf-8">
<title>video.js HLS Plugin Example</title>
<link href="node_modules/video.js/dist/video-js.css" rel="stylesheet">
<!-- video.js -->
<script src="node_modules/video.js/dist/video.js"></script>
<!-- Media Sources plugin -->
<script src="node_modules/videojs-contrib-media-sources/dist/videojs-media-sources.js"></script>
<!-- HLS plugin -->
<script src="src/videojs-hls.js"></script>
<!-- m3u8 handling -->
<script src="src/xhr.js"></script>
<script src="src/stream.js"></script>
<script src="src/m3u8/m3u8-parser.js"></script>
<script src="src/playlist.js"></script>
<script src="src/playlist-loader.js"></script>
<script src="node_modules/pkcs7/dist/pkcs7.unpad.js"></script>
<script src="src/decrypter.js"></script>
<script src="src/bin-utils.js"></script>
<title>videojs-contrib-hls Demo</title>
<link href="/node_modules/video.js/dist/video-js.css" rel="stylesheet">
<style>
body {
font-family: Arial, sans-serif;
......@@ -52,14 +29,8 @@
<p>The video below is an <a href="https://developer.apple.com/library/ios/documentation/networkinginternet/conceptual/streamingmediaguide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008332-CH1-SW1">HTTP Live Stream</a>. On desktop browsers other than Safari, the HLS plugin will polyfill support for the format on top of the video.js Flash tech.</p>
<p>Due to security restrictions in Flash, you will have to load this page over HTTP(S) to see the example in action.</p>
</div>
<video id="video"
class="video-js vjs-default-skin"
height="300"
width="600"
controls>
<source
src="http://solutions.brightcove.com/jwhisenant/hls/apple/bipbop/bipbopall.m3u8"
type="application/x-mpegURL">
<video id="videojs-contrib-hls-player" class="video-js vjs-default-skin" controls>
<source src="http://solutions.brightcove.com/jwhisenant/hls/apple/bipbop/bipbopall.m3u8" type="application/x-mpegURL">
</video>
<form id=load-url>
......@@ -70,11 +41,20 @@
<button type=submit>Load</button>
</form>
<script src="/node_modules/video.js/dist/video.js"></script>
<script src="/node_modules/videojs-contrib-media-sources/dist/videojs-media-sources.js"></script>
<script src="/node_modules/pkcs7/dist/pkcs7.unpad.js"></script>
<script src="/src/videojs-hls.js"></script>
<script src="/src/xhr.js"></script>
<script src="/src/stream.js"></script>
<script src="/src/m3u8/m3u8-parser.js"></script>
<script src="/src/playlist.js"></script>
<script src="/src/playlist-loader.js"></script>
<script src="/src/decrypter.js"></script>
<script src="/src/bin-utils.js"></script>
<script>
videojs.options.flash.swf = 'node_modules/videojs-swf/dist/video-js.swf';
// initialize the player
var player = videojs('video');
(function(window, videojs) {
var player = window.player = videojs('videojs-contrib-hls-player');
// hook up the video switcher
var loadUrl = document.getElementById('load-url');
var url = document.getElementById('url');
......@@ -86,6 +66,7 @@
});
return false;
});
}(window, window.videojs));
</script>
</body>
</html>
......
{
"name": "videojs-contrib-hls",
"version": "1.3.5",
"description": "Play back HLS with video.js, even where it's not natively supported",
"main": "es5/videojs-hls.js",
"engines": {
"node": ">= 0.10.12"
},
......@@ -8,47 +10,116 @@
"type": "git",
"url": "git@github.com:videojs/videojs-contrib-hls.git"
},
"license": "Apache-2.0",
"scripts": {
"test": "grunt test",
"prepublish": "if [ -z \"$TRAVIS\" ]; then grunt; fi"
"prebuild": "npm run clean",
"build": "npm-run-all -p build:*",
"build:manifest": "node -e \"var b=require('./scripts/manifest-data.js'); b.build();\"",
"build:js": "npm-run-all build:js:babel build:js:browserify build:js:bannerize build:js:uglify",
"build:js:babel": "babel src -d es5",
"build:js:bannerize": "bannerize dist/videojs-contrib-hls.js --banner=scripts/banner.ejs",
"build:js:browserify": "browserify . -s src/videojs-hls.js -o dist/videojs-contrib-hls.js",
"build:js:uglify": "uglifyjs dist/videojs-contrib-hls.js --comments --mangle --compress -o dist/videojs-contrib-hls.min.js",
"build:test": "node scripts/build-test.js",
"clean": "npm-run-all clean:*",
"clean:build": "node -e \"var s=require('shelljs'),d=['dist','dist-test','es5'];s.rm('-rf',d);s.mkdir('-p',d);\"",
"clean:manifest": "node -e \"var b=require('./scripts/manifest-data.js'); b.clean();\"",
"docs": "npm-run-all docs:*",
"docs:api": "jsdoc src -r -d docs/api",
"docs:toc": "doctoc README.md",
"lint": "vjsstandard :",
"prestart": "npm-run-all docs build",
"start": "npm-run-all -p start:* watch:*",
"start:serve": "babel-node scripts/server.js",
"pretest": "npm-run-all lint build",
"test": "karma start test/karma/detected.js",
"test:chrome": "npm run pretest && karma start test/karma/chrome.js",
"test:firefox": "npm run pretest && karma start test/karma/firefox.js",
"test:ie": "npm run pretest && karma start test/karma/ie.js",
"test:safari": "npm run pretest && karma start test/karma/safari.js",
"preversion": "npm test",
"version": "npm run build",
"watch": "npm-run-all -p watch:*",
"watch:manifest": "node -e \"var b=require('./scripts/manifest-data.js'); b.watch();\"",
"watch:js": "watchify src/videojs-hls.js -t babelify -v -o dist/videojs-contrib-hls.js",
"watch:test": "node scripts/watch-test.js",
"prepublish": "npm run build"
},
"keywords": [
"videojs",
"videojs-plugin"
],
"devDependencies": {
"chg": "^0.2.0",
"grunt": "^0.4.5",
"grunt-concurrent": "0.4.3",
"grunt-contrib-clean": "~0.4.0",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-connect": "~0.6.0",
"grunt-contrib-jshint": "~0.6.0",
"grunt-contrib-uglify": "~0.2.0",
"grunt-contrib-watch": "~0.4.0",
"grunt-github-releaser": "^0.1.17",
"grunt-karma": "~0.6.2",
"grunt-open": "0.2.3",
"grunt-protractor-runner": "forbesjo/grunt-protractor-runner.git#webdriverManagerUpdate",
"grunt-shell": "0.6.1",
"grunt-version": "^1.0.0",
"karma": "~0.10.0",
"karma-chrome-launcher": "~0.1.2",
"karma-firefox-launcher": "~0.1.3",
"karma-ie-launcher": "~0.1.1",
"karma-opera-launcher": "~0.1.0",
"karma-phantomjs-launcher": "^0.1.4",
"karma-qunit": "~0.1.1",
"karma-safari-launcher": "~0.1.1",
"karma-sauce-launcher": "~0.1.8",
"qunitjs": "^1.18.0",
"sinon": "1.10.2",
"video.js": "^5.2.1"
"author": "Brightcove, Inc",
"license": "Apache-2.0",
"browserify": {
"transform": [
"browserify-shim"
]
},
"browserify-shim": {
"qunit": "global:QUnit",
"sinon": "global:sinon",
"video.js": "global:videojs"
},
"vjsstandard": {
"ignore": [
"dist",
"dist-test",
"docs",
"es5",
"test/karma",
"scripts",
"utils",
"test/data"
]
},
"files": [
"CONTRIBUTING.md",
"dist-test/",
"dist/",
"docs/",
"es5/",
"index.html",
"scripts/",
"src/",
"test/",
"utils/"
],
"dependencies": {
"pkcs7": "^0.2.2",
"videojs-contrib-media-sources": "^2.4.0",
"videojs-swf": "^5.0.0"
"pkcs7": "^0.2.3",
"video.js": "^5.0.0",
"videojs-contrib-media-sources": "^2.4.4",
"videojs-swf": "^5.0.1"
},
"devDependencies": {
"babel": "^5.8.0",
"babelify": "^6.0.0",
"bannerize": "^1.0.0",
"browserify": "^11.0.0",
"browserify-shim": "^3.0.0",
"connect": "^3.4.0",
"cowsay": "^1.1.0",
"doctoc": "^0.15.0",
"glob": "^6.0.3",
"global": "^4.3.0",
"jsdoc": "^3.4.0",
"karma": "^0.13.0",
"karma-browserify": "^4.4.0",
"karma-chrome-launcher": "^0.2.0",
"karma-detect-browsers": "^2.0.0",
"karma-firefox-launcher": "^0.1.0",
"karma-ie-launcher": "^0.2.0",
"karma-qunit": "^0.1.9",
"karma-safari-launcher": "^0.1.0",
"lodash-compat": "^3.10.0",
"minimist": "^1.2.0",
"npm-run-all": "^1.2.0",
"portscanner": "^1.0.0",
"qunitjs": "^1.0.0",
"serve-static": "^1.10.0",
"shelljs": "^0.5.3",
"sinon": "1.10.2",
"uglify-js": "^2.5.0",
"videojs-standard": "^4.0.0",
"watchify": "^3.6.0"
}
}
......
/**
* <%- pkg.name %>
* @version <%- pkg.version %>
* @copyright <%- date.getFullYear() %> <%- pkg.author %>
* @license <%- pkg.license %>
*/
var browserify = require('browserify');
var fs = require('fs');
var glob = require('glob');
glob('test/**/*.test.js', function(err, files) {
browserify(files)
.transform('babelify')
.bundle()
.pipe(fs.createWriteStream('dist-test/videojs-contrib-hls.js'));
});
var fs = require('fs');
var path = require('path');
var basePath = path.resolve(__dirname + '/..');
var testDataDir = basePath + '/test/data';
var manifestDir = basePath + '/utils/manifest';
var manifestFilepath = testDataDir + '/manifests.js';
var expectedFilepath = testDataDir + '/expected.js';
var build = function() {
var manifests = 'window.manifests = {\n';
var expected = 'window.expected = {\n';
var files = fs.readdirSync(manifestDir);
while (files.length > 0) {
var file = path.resolve(manifestDir, files.shift());
var extname = path.extname(file);
if (extname === '.m3u8') {
// translate this manifest
manifests += ' \'' + path.basename(file, '.m3u8') + '\': ';
manifests += fs.readFileSync(file, 'utf8')
.split(/\r\n|\n/)
// quote and concatenate
.map(function(line) {
return ' \'' + line + '\\n\' +\n';
}).join('')
// strip leading spaces and the trailing '+'
.slice(4, -3);
manifests += ',\n';
} else if (extname === '.js') {
// append the expected parse
expected += ' "' + path.basename(file, '.js') + '": ';
expected += fs.readFileSync(file, 'utf8');
expected += ',\n';
} else {
console.log('Unknown file ' + file + ' found in manifest dir ' + manifestDir);
}
}
// clean up and close the objects
manifests = manifests.slice(0, -2);
manifests += '\n};\n';
expected = expected.slice(0, -2);
expected += '\n};\n';
fs.writeFileSync(manifestFilepath, manifests);
fs.writeFileSync(expectedFilepath, expected);
console.log('Wrote test data file ' + manifestFilepath);
console.log('Wrote test data file ' + expectedFilepath);
};
var watch = function() {
build();
fs.watch(manifestDir, function(event, filename) {
console.log('files in manifest dir were changed rebuilding manifest data');
build();
});
};
var clean = function() {
try {
fs.unlinkSync(manifestFilepath);
} catch(e) {
// ignore error, must not exist
}
try {
fs.unlinkSync(expectedFilepath);
} catch(e) {
// ignore error, must not exist
}
}
module.exports = {
build: build,
watch: watch,
clean: clean
};
import connect from 'connect';
import cowsay from 'cowsay';
import path from 'path';
import portscanner from 'portscanner';
import serveStatic from 'serve-static';
// Configuration for the server.
const PORT = 9999;
const MAX_PORT = PORT + 100;
const HOST = '127.0.0.1';
const app = connect();
const verbs = [
'Chewing the cud',
'Grazing',
'Mooing',
'Lowing',
'Churning the cream'
];
app.use(serveStatic(path.join(__dirname, '..')));
portscanner.findAPortNotInUse(PORT, MAX_PORT, HOST, (error, port) => {
if (error) {
throw error;
}
process.stdout.write(cowsay.say({
text: `${verbs[Math.floor(Math.random() * 5)]} on ${HOST}:${port}`
}) + '\n\n');
app.listen(port);
});
var browserify = require('browserify');
var fs = require('fs');
var glob = require('glob');
var watchify = require('watchify');
glob('test/**/*.test.js', function(err, files) {
var b = browserify(files, {
cache: {},
packageCache: {},
plugin: [watchify]
}).transform('babelify');
var bundle = function() {
b.bundle().pipe(fs.createWriteStream('dist-test/videojs-contrib-hls.js'));
};
b.on('log', function(msg) {
process.stdout.write(msg + '\n');
});
b.on('update', bundle);
bundle();
});
{
"curly": true,
"eqeqeq": true,
"immed": true,
"latedef": true,
"newcap": true,
"noarg": true,
"sub": true,
"undef": true,
"unused": true,
"boss": true,
"eqnull": true,
"browser": true,
"node": true,
"predef": [
"QUnit",
"module",
"test",
"asyncTest",
"expect",
"start",
"stop",
"ok",
"equal",
"notEqual",
"deepEqual",
"notDeepEqual",
"strictEqual",
"notStrictEqual",
"throws",
"sinon",
"process"
]
}
......@@ -32,7 +32,7 @@ var stringFromBytes = function(bytes) {
return result;
};
module('Decryption');
QUnit.module('Decryption');
test('decrypts a single AES-128 with PKCS7 block', function() {
var
......@@ -74,7 +74,7 @@ test('decrypts multiple AES-128 blocks with CBC', function() {
var clock;
module('Incremental Processing', {
QUnit.module('Incremental Processing', {
setup: function() {
clock = sinon.useFakeTimers();
},
......@@ -114,7 +114,7 @@ test('executes callback in series', function() {
var decrypter;
module('Incremental Decryption', {
QUnit.module('Incremental Decryption', {
setup: function() {
clock = sinon.useFakeTimers();
},
......
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>video.js HLS Plugin Test Suite</title>
<link rel="stylesheet" href="/node_modules/qunitjs/qunit/qunit.css" media="screen">
<link rel="stylesheet" href="/node_modules/video.js/dist/video-js.css" media="screen">
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<!-- NOTE in order for test to pass we require sinon 1.10.2 exactly -->
<script src="/node_modules/sinon/pkg/sinon.js"></script>
<script src="/node_modules/qunitjs/qunit/qunit.js"></script>
<script src="/node_modules/pkcs7/dist/pkcs7.unpad.js"></script>
<script src="/node_modules/video.js/dist/video.js"></script>
<script src="/node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js"></script>
<script src="/src/videojs-hls.js"></script>
<script src="/src/xhr.js"></script>
<script src="/src/stream.js"></script>
<script src="/src/m3u8/m3u8-parser.js"></script>
<script src="/src/playlist.js"></script>
<script src="/src/playlist-loader.js"></script>
<script src="/src/decrypter.js"></script>
<script src="/src/bin-utils.js"></script>
<script src="/test/data/manifests.js"></script>
<script src="/test/data/expected.js"></script>
<script src="/test/data/ts-segment-bc.js"></script>
<script src="/test/videojs-hls.test.js"></script>
<script src="/test/m3u8.test.js"></script>
<script src="/test/playlist.test.js"></script>
<script src="/test/playlist-loader.test.js"></script>
<script src="/test/decrypter.test.js"></script>
</body>
</html>
var fixture = document.createElement('div');
fixture.id = 'qunit-fixture';
document.body.appendChild(fixture);
// Karma example configuration file
// NOTE: To configure Karma tests, do the following:
// 1. Copy this file and rename the copy with a .conf.js extension, for example: karma.conf.js
// 2. Configure the properties below in your conf.js copy
// 3. Run your tests
module.exports = function(config) {
var customLaunchers = {
chrome_sl: {
singleRun: true,
base: 'SauceLabs',
browserName: 'chrome',
platform: 'Windows 7'
},
firefox_sl: {
singleRun: true,
base: 'SauceLabs',
browserName: 'firefox',
platform: 'Windows 8'
},
safari_sl: {
singleRun: true,
base: 'SauceLabs',
browserName: 'safari',
platform: 'OS X 10.8'
},
ipad_sl: {
singleRun: true,
base: 'SauceLabs',
browserName: 'ipad',
platform:'OS X 10.9',
version: '7.1'
},
android_sl: {
singleRun: true,
base: 'SauceLabs',
browserName: 'android',
platform:'Linux'
}
};
config.set({
// base path, that will be used to resolve files and exclude
basePath: '',
frameworks: ['qunit'],
// Set autoWatch to true if you plan to run `grunt karma` continuously, to automatically test changes as you make them.
autoWatch: false,
// Setting singleRun to true here will start up your specified browsers, run tests, and then shut down the browsers. Helpful to have in a CI environment, where you don't want to leave browsers running continuously.
singleRun: true,
// custom launchers for sauce labs
//define SL browsers
customLaunchers: customLaunchers,
// Start these browsers
browsers: ['chrome_sl'], //Object.keys(customLaunchers),
// List of files / patterns to load in the browser
// Add any new src files to this list.
// If you add new unit tests, they will be picked up automatically by Karma,
// unless you've added them to a nested directory, in which case you should
// add their paths to this list.
files: [
'../node_modules/sinon/pkg/sinon.js',
'../node_modules/video.js/dist/video-js.css',
'../node_modules/video.js/dist/video.js',
'../node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js',
'../node_modules/pkcs7/dist/pkcs7.unpad.js',
'../test/karma-qunit-shim.js',
'../src/videojs-hls.js',
'../src/stream.js',
'../src/m3u8/m3u8-parser.js',
'../src/xhr.js',
'../src/playlist.js',
'../src/playlist-loader.js',
'../src/decrypter.js',
'../tmp/manifests.js',
'../tmp/expected.js',
'tsSegment-bc.js',
'../src/bin-utils.js',
'../test/*.js',
],
plugins: [
'karma-qunit',
'karma-chrome-launcher',
'karma-firefox-launcher',
'karma-ie-launcher',
'karma-opera-launcher',
'karma-phantomjs-launcher',
'karma-safari-launcher',
'karma-sauce-launcher'
],
// test results reporter to use
// possible values: 'dots', 'progress', 'junit'
reporters: ['dots', 'progress'],
// web server port
port: 9876,
// cli runner port
runnerPort: 9100,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
//logLevel: config.LOG_INFO,
// If browser does not capture in given timeout [ms], kill it
captureTimeout: 60000,
// global config for SauceLabs
sauceLabs: {
startConnect: false,
tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER,
build: process.env.TRAVIS_BUILD_NUMBER,
testName: process.env.TRAVIS_BUILD_NUMBER + process.env.TRAVIS_BRANCH,
recordScreenshots: false
}
});
};
var common = require('./common');
module.exports = function(config) {
config.set(common({
plugins: ['karma-chrome-launcher'],
browsers: ['Chrome']
}));
};
var merge = require('lodash-compat/object/merge');
var DEFAULTS = {
basePath: '../..',
//frameworks: ['browserify', 'qunit'],
frameworks: ['qunit'],
files: [
'node_modules/sinon/pkg/sinon.js',
'node_modules/sinon/pkg/sinon-ie.js',
'node_modules/video.js/dist/video.js',
'node_modules/video.js/dist/video-js.css',
// REMOVE ME WHEN BROWSERIFIED
'node_modules/pkcs7/dist/pkcs7.unpad.js',
'node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js',
'src/videojs-hls.js',
'src/xhr.js',
'src/stream.js',
'src/m3u8/m3u8-parser.js',
'src/playlist.js',
'src/playlist-loader.js',
'src/decrypter.js',
'src/bin-utils.js',
'test/data/manifests.js',
'test/data/expected.js',
'test/data/ts-segment-bc.js',
'test/videojs-hls.test.js',
'test/m3u8.test.js',
'test/playlist.test.js',
'test/playlist-loader.test.js',
'test/decrypter.test.js',
// END REMOVE ME
// 'test/**/*.js'
],
exclude: [
'test/bundle.js',
// 'test/data/**'
],
plugins: [
// 'karma-browserify',
'karma-qunit'
],
preprocessors: {
// 'test/**/*.js': ['browserify']
},
reporters: ['dots'],
port: 9876,
colors: true,
autoWatch: false,
singleRun: true,
concurrency: Infinity,
/*
browserify: {
debug: true,
transform: [
'babelify',
'browserify-shim'
],
noparse: [
'test/data/**',
]
}
*/
};
/**
* Customizes target/source merging with lodash merge.
*
* @param {Mixed} target
* @param {Mixed} source
* @return {Mixed}
*/
var customizer = function(target, source) {
if (Array.isArray(target)) {
return target.concat(source);
}
};
/**
* Generates a new Karma config with a common set of base configuration.
*
* @param {Object} custom
* Configuration that will be deep-merged. Arrays will be
* concatenated.
* @return {Object}
*/
module.exports = function(custom) {
return merge({}, custom, DEFAULTS, customizer);
};
var common = require('./common');
// Runs default testing configuration in multiple environments.
module.exports = function(config) {
// Travis CI should run in its available Firefox headless browser.
if (process.env.TRAVIS) {
config.set(common({
browsers: ['Firefox'],
plugins: ['karma-firefox-launcher']
}))
} else {
config.set(common({
frameworks: ['detectBrowsers'],
plugins: [
'karma-chrome-launcher',
'karma-detect-browsers',
'karma-firefox-launcher',
'karma-ie-launcher',
'karma-safari-launcher'
],
detectBrowsers: {
// disable safari as it was not previously supported and causes test failures
postDetection: function(availableBrowsers) {
var safariIndex = availableBrowsers.indexOf('Safari');
if(safariIndex !== -1) {
availableBrowsers.splice(safariIndex, 1);
}
return availableBrowsers;
},
usePhantomJS: false
}
}));
}
};
var common = require('./common');
module.exports = function(config) {
config.set(common({
plugins: ['karma-firefox-launcher'],
browsers: ['Firefox']
}));
};
var common = require('./common');
module.exports = function(config) {
config.set(common({
plugins: ['karma-ie-launcher'],
browsers: ['IE']
}));
};
var common = require('./common');
module.exports = function(config) {
config.set(common({
plugins: ['karma-safari-launcher'],
browsers: ['Safari']
}));
};
// Karma example configuration file
// NOTE: To configure Karma tests, do the following:
// 1. Copy this file and rename the copy with a .conf.js extension, for example: karma.conf.js
// 2. Configure the properties below in your conf.js copy
// 3. Run your tests
module.exports = function(config) {
config.set({
// base path, that will be used to resolve files and exclude
basePath: '',
frameworks: ['qunit'],
// Set autoWatch to true if you plan to run `grunt karma` continuously, to automatically test changes as you make them.
autoWatch: false,
// Setting singleRun to true here will start up your specified browsers, run tests, and then shut down the browsers. Helpful to have in a CI environment, where you don't want to leave browsers running continuously.
singleRun: true,
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
// Example usage:
// browsers: [],
// List of files / patterns to load in the browser
// Add any new src files to this list.
// If you add new unit tests, they will be picked up automatically by Karma,
// unless you've added them to a nested directory, in which case you should
// add their paths to this list.
files: [
'../node_modules/sinon/pkg/sinon.js',
'../node_modules/video.js/dist/video-js.css',
'../node_modules/video.js/dist/video.js',
'../node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js',
'../node_modules/pkcs7/dist/pkcs7.unpad.js',
'../test/karma-qunit-shim.js',
'../src/videojs-hls.js',
'../src/stream.js',
'../src/m3u8/m3u8-parser.js',
'../src/xhr.js',
'../src/playlist.js',
'../src/playlist-loader.js',
'../src/decrypter.js',
'../tmp/manifests.js',
'../tmp/expected.js',
'tsSegment-bc.js',
'../src/bin-utils.js',
'../test/*.js',
],
plugins: [
'karma-qunit',
'karma-chrome-launcher',
'karma-firefox-launcher',
'karma-ie-launcher',
'karma-opera-launcher',
'karma-phantomjs-launcher',
'karma-safari-launcher'
],
// list of files to exclude
exclude: [
],
// test results reporter to use
// possible values: 'dots', 'progress', 'junit'
reporters: ['progress'],
// web server port
port: 9876,
// cli runner port
runnerPort: 9100,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_DISABLE,
// If browser does not capture in given timeout [ms], kill it
captureTimeout: 60000
});
};
......@@ -13,7 +13,7 @@
M3U8 Test Suite
*/
module('LineStream', {
QUnit.module('LineStream', {
setup: function() {
lineStream = new LineStream();
}
......@@ -83,7 +83,7 @@
strictEqual(2, permanentLines.length, 'new events are still received');
});
module('ParseStream', {
QUnit.module('ParseStream', {
setup: function() {
lineStream = new LineStream();
parseStream = new ParseStream();
......@@ -622,13 +622,13 @@
ok(!event, 'no event is triggered');
});
module('m3u8 parser');
QUnit.module('m3u8 parser');
test('can be constructed', function() {
notStrictEqual(new Parser(), undefined, 'parser is defined');
});
module('m3u8s');
QUnit.module('m3u8s');
test('parses static manifests as expected', function() {
var key;
......
<!doctype html>
<html>
<head>
<title>MPEG-TS Parser Performance Workbench</title>
<!-- video.js -->
<script src="../node_modules/video.js/video.dev.js"></script>
<!-- HLS plugin -->
<script src="../src/video-js-hls.js"></script>
<script src="../src/flv-tag.js"></script>
<script src="../src/exp-golomb.js"></script>
<script src="../src/h264-stream.js"></script>
<script src="../src/aac-stream.js"></script>
<script src="../src/segment-parser.js"></script>
<!-- MPEG-TS segment -->
<script src="tsSegment-bc.js"></script>
<style>
.desc {
background-color: #ddd;
border: thin solid #333;
padding: 8px;
}
</style>
</head>
<body>
<p class="desc">Select your number of iterations and then press "Run" to begin parsing MPEG-TS packets into FLV tags. This page can be handy for identifying segment parser performance bottlenecks.</p>
<form>
<input name="iterations" min="1" type="number" value="1">
<button type="sumbit">Run</button>
</form>
<table>
<thead>
<th>Iterations</th><th>Time</th><th>MB/second</th>
</thead>
<tbody class="results"></tbody>
</table>
<script>
var
button = document.querySelector('button'),
input = document.querySelector('input'),
results = document.querySelector('.results'),
reportResults = function(count, elapsed) {
var
row = document.createElement('tr'),
countCell = document.createElement('td'),
elapsedCell = document.createElement('td'),
throughputCell = document.createElement('td');
countCell.innerText = count;
elapsedCell.innerText = elapsed;
throughputCell.innerText = (((bcSegment.byteLength * count * 1000) / elapsed) / (Math.pow(2, 20))).toFixed(3);
row.appendChild(countCell);
row.appendChild(elapsedCell);
row.appendChild(throughputCell);
results.insertBefore(row, results.firstChild);
};
button.addEventListener('click', function(event) {
var
iterations = input.value,
parser = new window.videojs.hls.SegmentParser(),
start;
// setup
start = +new Date();
while (iterations--) {
// parse the segment
parser.parseSegmentBinaryData(window.bcSegment);
// finalize all the FLV tags
while (parser.tagsAvailable()) {
parser.getNextTag();
}
}
// report
reportResults(input.value, (+new Date()) - start);
// don't actually submit the form
event.preventDefault();
}, false);
</script>
</body>
</html>
......@@ -16,7 +16,7 @@
.join('/');
};
module('Playlist Loader', {
QUnit.module('Playlist Loader', {
setup: function() {
// fake XHRs
sinonXhr = sinon.useFakeXMLHttpRequest();
......
......@@ -3,7 +3,7 @@
'use strict';
var Playlist = videojs.Hls.Playlist;
module('Playlist Duration');
QUnit.module('Playlist Duration');
test('total duration for live playlists is Infinity', function() {
var duration = Playlist.duration({
......@@ -16,7 +16,7 @@
equal(duration, Infinity, 'duration is infinity');
});
module('Playlist Interval Duration');
QUnit.module('Playlist Interval Duration');
test('accounts for non-zero starting VOD media sequences', function() {
var duration = Playlist.duration({
......@@ -266,7 +266,7 @@
equal(Playlist.duration(playlist, -1), 0, 'negative length duration is zero');
});
module('Playlist Seekable');
QUnit.module('Playlist Seekable');
test('calculates seekable time ranges from the available segments', function() {
var playlist = {
......
import document from 'global/document';
import QUnit from 'qunit';
import sinon from 'sinon';
import videojs from 'video.js';
QUnit.module('videojs-contrib-hls - sanity', {
beforeEach() {
this.fixture = document.getElementById('qunit-fixture');
this.video = document.createElement('video');
this.fixture.appendChild(this.video);
this.player = videojs(this.video);
// Mock the environment's timers because certain things - particularly
// player readiness - are asynchronous in video.js 5.
this.clock = sinon.useFakeTimers();
},
afterEach() {
// The clock _must_ be restored before disposing the player; otherwise,
// certain timeout listeners that happen inside video.js may throw errors.
this.clock.restore();
this.player.dispose();
}
});
QUnit.test('the environment is sane', function(assert) {
assert.strictEqual(typeof Array.isArray, 'function', 'es5 exists');
assert.strictEqual(typeof sinon, 'object', 'sinon exists');
assert.strictEqual(typeof videojs, 'function', 'videojs exists');
assert.strictEqual(typeof videojs.MediaSource, 'object', 'MediaSource is an object');
assert.strictEqual(typeof videojs.URL, 'object', 'URL is an object');
assert.strictEqual(typeof videojs.Hls, 'object', 'Hls is an object');
assert.strictEqual(typeof videojs.HlsSourceHandler,'function', 'HlsSourceHandler is a function');
assert.strictEqual(typeof videojs.HlsHandler, 'function', 'HlsHandler is a function');
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>video.js HLS Plugin Test Suite</title>
<!-- Load sinon server for fakeXHR -->
<script src="../node_modules/sinon/pkg/sinon.js"></script>
<!-- Load local QUnit. -->
<link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css" media="screen">
<script src="../node_modules/qunitjs/qunit/qunit.js"></script>
<!-- video.js -->
<script src="../node_modules/video.js/dist/video.js"></script>
<link rel="stylesheet" href="../node_modules/video.js/dist/video-js.css" media="screen">
<script src="../node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js"></script>
<!-- HLS plugin -->
<script src="../src/videojs-hls.js"></script>
<script src="../src/xhr.js"></script>
<script src="../src/stream.js"></script>
<!-- M3U8 -->
<script src="../src/m3u8/m3u8-parser.js"></script>
<script src="../src/playlist.js"></script>
<script src="../src/playlist-loader.js"></script>
<script src="../node_modules/pkcs7/dist/pkcs7.unpad.js"></script>
<script src="../src/decrypter.js"></script>
<!-- M3U8 TEST DATA -->
<script src="../tmp/manifests.js"></script>
<script src="../tmp/expected.js"></script>
<!-- M3U8 -->
<!-- SEGMENT -->
<script src="tsSegment-bc.js"></script>
<script src="../src/bin-utils.js"></script>
<!-- Test cases -->
<script>
module('environment');
test('is sane', function() {
expect(1);
ok(true);
});
</script>
<script src="videojs-hls_test.js"></script>
<script src="m3u8_test.js"></script>
<script src="playlist_test.js"></script>
<script src="playlist-loader_test.js"></script>
<script src="decrypter_test.js"></script>
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture">
<span>test markup</span>
</div>
</body>
</html>
......@@ -206,7 +206,7 @@ var
MockMediaSource.open = function() {};
module('HLS', {
QUnit.module('HLS', {
beforeEach: function() {
oldMediaSource = videojs.MediaSource;
videojs.MediaSource = MockMediaSource;
......@@ -2906,7 +2906,7 @@ test('does not download segments if preload option set to none', function() {
equal(requests.length, 0, 'did not download any segments');
});
module('Buffer Inspection');
QUnit.module('Buffer Inspection');
test('detects time range end-point changed by updates', function() {
var edge;
......
......@@ -20,7 +20,7 @@ if (process.env.SAUCE_USERNAME) {
config.maxDuration = 300;
}
config.baseUrl = 'http://127.0.0.1:9999/example.html';
config.baseUrl = 'http://127.0.0.1:9999/';
config.specs = ['spec.js'];
config.framework = 'jasmine2';
......
......@@ -12,7 +12,7 @@
<link rel="stylesheet" href="css/normalize.min.css">
<link rel="stylesheet" href="css/main.css">
<link rel="stylesheet" href="../../node_modules/video.js/dist/video-js/video-js.css">
<link rel="stylesheet" href="../../node_modules/video.js/dist/video-js.css">
<script src="js/vendor/modernizr-2.6.2.min.js"></script>
</head>
......@@ -120,13 +120,17 @@
<script src="../../node_modules/sinon/lib/sinon/util/fake_timers.js"></script>
<script src="js/vendor/d3.min.js"></script>
<script src="../../node_modules/video.js/dist/video-js/video.js"></script>
<script src="../../node_modules/videojs-contrib-media-sources/src/videojs-media-sources.js"></script>
<script src="../../src/videojs-hls.js"></script>
<script src="../../src/xhr.js"></script>
<script src="../../src/stream.js"></script>
<script src="../../src/m3u8/m3u8-parser.js"></script>
<script src="../../src/playlist-loader.js"></script>
<script src="/node_modules/video.js/dist/video.js"></script>
<script src="/node_modules/videojs-contrib-media-sources/dist/videojs-media-sources.js"></script>
<script src="/node_modules/pkcs7/dist/pkcs7.unpad.js"></script>
<script src="/src/videojs-hls.js"></script>
<script src="/src/xhr.js"></script>
<script src="/src/stream.js"></script>
<script src="/src/m3u8/m3u8-parser.js"></script>
<script src="/src/playlist.js"></script>
<script src="/src/playlist-loader.js"></script>
<script src="/src/decrypter.js"></script>
<script src="/src/bin-utils.js"></script>
<script src="js/switcher.js"></script>
</body>
......
......@@ -142,6 +142,7 @@
// mock out the environment
clock = sinon.useFakeTimers();
fakeXhr = sinon.useFakeXMLHttpRequest();
videojs.xhr.XMLHttpRequest = fakeXhr;
requests = [];
fakeXhr.onCreate = function(xhr) {
xhr.startTime = +new Date();
......@@ -156,7 +157,6 @@
video.controls = true;
fixture.appendChild(video);
player = videojs(video, {
techOrder: ['hls'],
sources: [{
src: 'http://example.com/master.m3u8',
type: 'application/x-mpegurl'
......@@ -295,6 +295,8 @@
done(null, results);
}, 0);
});
/// trigger the ready function through set timeout
clock.tick(1);
};
runButton = document.getElementById('run-simulation');
runButton.addEventListener('click', function() {
......