Major update - simpler file structure, better layouts, moar content

This commit is contained in:
Eric Woodward 2022-09-23 02:40:26 -04:00
commit 8c024d74cd
346 changed files with 19555 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
node_modules/
out/
IDEAS.md
TODO.md

2
.prettierignore Normal file
View File

@ -0,0 +1,2 @@
*.ejs
*.min.js

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Douglas Matoso
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

19
README.md Normal file
View File

@ -0,0 +1,19 @@
# Mystic Site Builder (2021 Edition)
Micro static site generator in Node.js
Based on the ideas in this post: https://medium.com/douglas-matoso-english/build-static-site-generator-nodejs-8969ebe34b22
## Setup
```console
$ npm i
$ npm run build
$ npm run serve
```
Go to http://localhost:5000 to see the generated site.
## How to use
If you want to use NanoGen to generate your own site, just fork this repository and add your content to the `src` folder.

30
app.js Normal file
View File

@ -0,0 +1,30 @@
#!/usr/bin/env node
"use strict";
require("dotenv").config();
const path = require("path"),
build = require("./lib/build"),
serve = require("./lib/serve"),
watch = require("./lib/watch"),
{ log, readJsonIfExists } = require("./lib/utils"),
{ version } = require("./package.json"),
localConfig =
readJsonIfExists(path.resolve(process.cwd(), "site.config.json5")) ||
{},
siteOpts = require("./lib/loadConfig")(localConfig, "MULE"),
config = {
...siteOpts,
logFunction: log,
},
yargs = require("yargs")
.version(version)
.alias("v", "version")
.usage("Usage: $0 start|stop")
.demandCommand(1),
{ argv } = yargs;
if (argv._[0] === "build") return build(config);
else if (argv._[0] === "serve") return serve(config);
else if (argv._[0] === "watch") return watch(config);

370
lib/build.js Normal file
View File

@ -0,0 +1,370 @@
const { exists } = require("fs-extra/lib/fs");
module.exports = async (config) => {
const { promises: fs } = require("fs"),
fse = require("fs-extra"),
path = require("path"),
ejs = require("ejs"),
frontMatter = require("front-matter"),
glob = require("glob"),
hljs = require("highlight.js"),
md = require("markdown-it")({
highlight: (str, lang) => {
if (lang && hljs.getLanguage(lang)) {
try {
return hljs.highlight(str, { language: lang }).value;
} catch (__) {}
}
return ""; // use external default escaping
},
html: true,
linkify: true,
typographer: true,
xhtmlOut: true,
}),
emoji = require("markdown-it-emoji"),
// { readJsonIfExists } = require("./utils"),
{ build, isRebuild, logFunction: log = () => {} } = config || {},
{ outputPath, journalsPerPage = 5, srcPath } = build,
{ site } = config,
copyAssets = async (directory) => {
const assets = await fs.readdir(directory);
assets.forEach(async (asset) => {
// we no longer merge scripts and styles, thanks to http/2's parallel file handling
if (asset === "_root") {
fse.copy(path.join(srcPath, "assets", asset), outputPath);
} else {
fse.copy(
path.join(srcPath, "assets", asset),
path.join(outputPath, asset)
);
}
});
},
getReadTime = (text) => {
const WPM = 275,
fixedString = text.replace(/[^\w\s]+/g, ""),
count = fixedString.split(/\s+/).length;
if (count < WPM) return "less than 1 minute";
else return `${Math.ceil(count / WPM)} minutes`;
},
tagSorter = (a, b) => a.toLowerCase().localeCompare(b.toLowerCase()),
parseFile = (file, pagePath, siteData, isSupport) => {
const { dir, ext, name } = path.parse(file) || {},
hasExt = name.indexOf(".") > -1,
destPath = path.join(outputPath, dir),
filePath = path.join(pagePath, file),
// read page file
data = fse.readFileSync(filePath, "utf-8"),
// render page
{ attributes, body } = frontMatter(data),
{ content_type: contentType, tags: originalTags = [] } =
attributes,
// TODO: Look for tags in posts as well, link to them, and add them to tag pages
tags =
typeof originalTags === "string"
? originalTags.split(/\W+/)
: [].concat(originalTags),
innerTags = (
contentType === "journal"
? body.match(/\b#(\w+)/g) || []
: []
).map((val) => val.replace("#", "")),
allTags = [...tags, ...innerTags].sort(tagSorter),
updatedBody =
contentType === "journal"
? allTags.reduce(
(acc, tag) =>
acc.replace(
`#${tag}`,
`
<a href="/journal/tags/${tag}/index.html">
#<span class="p-category category">${tag}</span>
</a>`
),
body
)
: body;
return {
...config,
page: {
name,
...attributes,
body: updatedBody,
destPath,
filePath,
path: path.join(dir, hasExt ? name : `${name}.html`),
tags: [...tags, ...innerTags].sort(tagSorter),
ext,
},
site: {
...site,
pages: isSupport ? siteData : [],
},
};
},
parseContent = (page, siteData) => {
const {
body,
content_type: contentType,
filePath,
// tags,
} = page || {},
{ ext } = path.parse(filePath) || {},
{ pages, tags } = siteData || {};
let content = body,
readTime;
if (ext === ".md") {
if (contentType === "journal" && typeof body === "string") {
readTime = getReadTime(body);
}
content = md.render(body);
} else if (ext === ".ejs") {
content = ejs.render(
body,
{ page, site: { ...site, pages, tags } },
{ filename: filePath }
);
}
return { ...page, content, readTime };
},
renderFile = async (page, isSupport) => {
const {
content,
destPath,
layout,
path: pagePath,
pages,
siteTags,
tags,
} = page || {};
try {
const layoutFileName = `${srcPath}/layouts/${
layout || "default"
}.ejs`,
layoutData = await fs.readFile(layoutFileName, "utf-8"),
completePage = isSupport
? content
: ejs.render(layoutData, {
content,
page,
site: {
...site,
pages,
tags:
page.content_type === "journal"
? siteTags
: tags,
},
filename: layoutFileName,
});
if (!completePage) {
console.log("failed!", pagePath, content);
return;
}
// create destination directory
fse.mkdirsSync(destPath);
// save the html file
fse.writeFileSync(
path.join(outputPath, pagePath),
completePage
);
} catch (e) {
console.log("failed!", pagePath);
console.log("paths", destPath, outputPath);
console.error(e);
return;
}
};
md.use(emoji);
log(`${isRebuild ? "Reb" : "B"}uilding...`);
// clear destination folder
fse.emptyDirSync(outputPath);
// copy assets folder
await copyAssets(path.join(srcPath, "assets"));
const files = ["pages", "sitePosts"].reduce((acc, pageDir) => {
return [
...acc,
...glob
.sync("**/*.@(md|ejs|html)", {
cwd: path.join(srcPath, pageDir),
})
.map((file) =>
parseFile(file, path.join(srcPath, pageDir))
),
];
}, []),
sortByPubDate = (a, b) => {
if (a.date_pub && b.date_pub) {
let a_dt = new Date(a.date_pub).getTime(),
b_dt = new Date(b.date_pub).getTime();
if (a_dt < b_dt) {
return 1;
}
if (b_dt < a_dt) {
return -1;
}
return 0;
}
if (a.date_pub) return -1;
if (b.date_pub) return 1;
return 0;
},
pages = files.map(({ page }) => ({ ...page })).sort(sortByPubDate),
tagCloud = pages.reduce((acc, curr) => {
const { tags } = curr;
tags.forEach((tag) => {
if (acc[tag]) acc[tag]++;
else acc[tag] = 1;
});
return acc;
}, {}),
tags = Object.keys(tagCloud).sort(tagSorter),
yearCloud = pages
.filter(({ content_type = "" }) => content_type === "journal")
.reduce((acc, curr) => {
const { date_pub } = curr;
if (date_pub) {
const year = new Date(date_pub).getFullYear();
if (acc[year]) acc[year]++;
else acc[year] = 1;
}
return acc;
}, {}),
years = Object.keys(yearCloud).sort().reverse(),
pagesWithContent = pages.map((page) =>
parseContent(page, { pages, tags })
);
// add data for the whole site to each page as it's rendered
pagesWithContent.forEach((page) => {
renderFile({ ...page, pages: pagesWithContent, siteTags: tags });
});
/* Journal Stuff - Tags & Years */
// make page(s) for each tag
tags.forEach((tag) => {
// check counts
let postCount = tagCloud[tag],
pageCount = Math.ceil(postCount / journalsPerPage);
for (let i = 1; i <= pageCount; i++) {
const firstEntryIndex = journalsPerPage * (i - 1),
lastEntryIndex = journalsPerPage * i;
renderFile({
content: tag,
destPath: path.join(outputPath, "journal", "tags", tag),
entriesToList: pagesWithContent
.filter(
(p) =>
p && Array.isArray(p.tags) && p.tags.includes(tag)
)
.slice(firstEntryIndex, lastEntryIndex),
layout: "tag",
path: `journal/tags/${tag}/${
i === 1 ? "index.html" : `page${i}.html`
}`,
site: { ...site, pages: pagesWithContent, tags },
pageCount,
pageNum: i,
pages: pagesWithContent,
tag,
tags,
title: `Journal Entries Tagged with #${tag}`,
});
}
});
// make page(s) for each year
years.forEach((year) => {
// check counts
let postCount = yearCloud[year],
pageCount = Math.ceil(postCount / journalsPerPage);
for (let i = 1; i <= pageCount; i++) {
const firstEntryIndex = journalsPerPage * (i - 1),
lastEntryIndex = journalsPerPage * i;
// TODO: rethink the data passed in here - you're paging solution works (kinda), take it over the finish line!
renderFile({
content: year,
destPath: path.join(outputPath, "journal", year),
entriesToList: pagesWithContent
.filter(({ content_type = "", date_pub = "" }) => {
if (!date_pub || content_type !== "journal")
return false;
const p_dt = new Date(date_pub).getTime(),
y1_dt = new Date(
`${year}-01-01T00:00:00-0500`
).getTime(),
y2_dt = new Date(
`${year}-12-31T23:59:59-0500`
).getTime();
return p_dt >= y1_dt && p_dt <= y2_dt;
})
.slice(firstEntryIndex, lastEntryIndex),
layout: "journal-year",
path: `journal/${year}/${
i === 1 ? "index.html" : `page${i}.html`
}`,
site: { ...site, pages: pagesWithContent, tags },
pageCount,
pageNum: i,
pages: pagesWithContent,
tags,
title: `Journal Entries from ${year}`,
year,
});
}
});
/* Support pages - anything too weird / specific for markdown rendering */
// collect support pages
const support = ["support"].reduce((acc, pageDir) => {
return [
...acc,
...glob
.sync("**/*.@(md|ejs|html)", {
cwd: path.join(srcPath, pageDir),
})
.map((file) =>
parseFile(
file,
path.join(srcPath, pageDir),
pagesWithContent,
true
)
),
];
}, []);
// write each one out
support.forEach((fileData) => {
const { page } = fileData;
if (page?.ext === ".ejs") {
const pageAndContent = parseContent(page, {
pages: pagesWithContent,
tags,
});
return renderFile({ ...fileData, ...pageAndContent, tags }, true);
}
return renderFile(fileData, true);
});
};

19
lib/defaults.json5 Normal file
View File

@ -0,0 +1,19 @@
{
/*
*/
/** TACO Express Default Options **/
/*
The function used to log output (console.log, morgan, etc).
Should take one (or more) strings as arguments.
*/
logFunction: null,
build: {},
site: {},
serve: {
port: 5000,
},
}

43
lib/loadConfig.js Normal file
View File

@ -0,0 +1,43 @@
module.exports = (opts, envKey) => {
const
fs = require('fs'),
path = require('path'),
json5 = require('json5'),
{ convertCamelToUpperSnakeCase, readJsonIfExists } = require('./utils'),
{ cwd, env } = process,
def = readJsonIfExists(path.resolve(__dirname, 'defaults.json5')),
// gets value from ENV || options || defaults (in that order)
getVal = (envName) => {
const snakeEnvName = `${envKey}_${convertCamelToUpperSnakeCase(envName)}`;
if (env[snakeEnvName]) return env[snakeEnvName];
if (opts[envName]) return opts[envName];
return def[envName];
},
// gets array from ENV || options || defaults (in that order)
getArray = (envName, optName = '') => {
if (optName === '') {
optName = envName;
envName = convertCamelToUpperSnakeCase(envName);
}
envName = `${envKey}_${envName}`;
if (env[envName]) return env[envName].split(path.delimiter);
if (Array.isArray(opts[optName]) && opts[optName].length) return opts[optName];
return def[optName];
};
return {
...Object.keys(def).reduce((acc, curr) => {
if (Array.isArray(def[curr])) acc[curr] = getArray(curr);
else acc[curr] = getVal(curr);
return acc;
}, {}),
};
};

26
lib/serve.js Normal file
View File

@ -0,0 +1,26 @@
module.exports = async (config) => {
let isReady = false;
const
http = require('http'),
address = require('network-address'),
handler = require('serve-handler'),
build = require('./build'),
{ build: buildOpts, logFunction: log = () => {}, serve: serveOpts } = config || {},
{ outputPath, srcPath } = buildOpts || {},
{ port = 5000 } = serveOpts || {},
server = http.createServer((request, response) => {
// You pass two more arguments for config and middleware
// More details here: https://github.com/vercel/serve-handler#options
return handler(request, response, { public: outputPath });
});
await build(config);
server.listen(port, async () => {
log(`Running at http://${address()}:${port} / http://localhost:${port}`);
});
};

57
lib/utils.js Normal file
View File

@ -0,0 +1,57 @@
module.exports = (() => {
const
chalk = require('chalk'),
getTime = () => {
const
now = new Date(),
tzo = -now.getTimezoneOffset(),
dif = tzo >= 0 ? '+' : '-',
pad = (num) => {
const norm = Math.floor(Math.abs(num));
return `${norm < 10 ? '0' : ''}${norm}`;
};
return [
now.getFullYear(),
'-',
pad(now.getMonth() + 1),
'-',
pad(now.getDate()),
'T',
pad(now.getHours()),
':',
pad(now.getMinutes()),
':',
pad(now.getSeconds()),
dif,
pad(tzo / 60),
':',
pad(tzo % 60)
].join('');
};
return {
convertCamelToUpperSnakeCase:
str => str.replace(/[A-Z]/g, letter => `_${letter}`).toUpperCase(),
getTime,
log: (msg) => console.log(`${chalk.grey(`${getTime()}:`)} ${msg}`),
readJsonIfExists: (filePath) => {
const
fs = require('fs'),
json5 = require('json5');
try {
return json5.parse(fs.readFileSync(filePath, {encoding: 'utf8'}));
} catch (err) {
if (err.code === 'ENOENT') return {};
throw err;
}
},
};
})();

58
lib/watch.js Normal file
View File

@ -0,0 +1,58 @@
module.exports = async (config) => {
let isReady = false;
const
http = require('http'),
chokidar = require('chokidar'),
address = require('network-address'),
handler = require('serve-handler'),
build = require('./build'),
rebuild = (cfg) => {
isReady = false;
build({ ...cfg, isRebuild: true });
isReady = true;
},
{ build: buildOpts, logFunction: log = () => {}, serve: serveOpts } = config || {},
{ outputPath, srcPath } = buildOpts || {},
{ port = 5000 } = serveOpts || {},
watcher = chokidar.watch([srcPath, '*.json'], {
ignored: /(^|[\/\\])\../, // ignore dotfiles
persistent: true
})
.on('add', (path) => {
if (isReady) {
log(`File ${path} has been added`)
rebuild(config);
}
})
.on('change', (path) => {
if (isReady) {
log(`File ${path} has been changed`)
rebuild(config);
}
})
.on('ready', () => {
isReady = true;
})
.on('unlink', (path) => {
if (isReady) {
log(`File ${path} has been removed`)
rebuild(config);
}
}),
server = http.createServer((request, response) => {
// You pass two more arguments for config and middleware
// More details here: https://github.com/vercel/serve-handler#options
return handler(request, response, { public: outputPath });
});
await build(config);
server.listen(port, () => {
log(`Running at http://${address()}:${port} / http://localhost:${port}`);
});
};

2653
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

34
package.json Executable file
View File

@ -0,0 +1,34 @@
{
"name": "iew-site-builder",
"version": "0.9.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "node app.js build",
"build:prod": "cross-env NODE_ENV=production node ./lib/build",
"serve": "node app.js serve",
"watch": "node app.js watch"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"chalk": "^4.1.2",
"chokidar": "^3.4.3",
"dotenv": "^16.0.1",
"highlight.js": "^11.3.1",
"json5": "^2.1.3",
"markdown-it": "^13.0.1",
"markdown-it-emoji": "^2.0.0",
"network-address": "^1.1.2",
"serve-handler": "^6.1.3"
},
"devDependencies": {
"ejs": "^3.1.5",
"front-matter": "^4.0.2",
"fs-extra": "^10.0.0",
"glob": "^8.0.3",
"serve": "^13.0.2",
"yargs": "^17.3.1"
}
}

26
site.config.json5 Normal file
View File

@ -0,0 +1,26 @@
{
site: {
title: "It's Eric Woodward (dotcom)",
author: {
name: "Eric Woodward",
email: "redacted@nunyodam.com", // not used
photo: "/images/eric-8bit.gif",
site: "https://itsericwoodward.com",
},
base_uri: "",
robots: "index,follow",
language: "en-us",
copyright: "Copyright 2014-2022 Eric Woodward, licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.",
basePath: "",
uri: "https://www.itsericwoodward.com",
},
build: {
journalsPerPage: 5,
srcPath: "src",
outputPath: "out",
},
serve: {
port: 4997,
},
}

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig><msapplication><tile><square70x70logo src="/images/favicons/ms-icon-70x70.png"/><square150x150logo src="/images/favicons/ms-icon-150x150.png"/><square310x310logo src="/images/favicons/ms-icon-310x310.png"/><TileColor>#0d1852</TileColor></tile></msapplication></browserconfig>

Binary file not shown.

View File

@ -0,0 +1,348 @@
/*!
* jQLite JavaScript Library v1.1.1 (http://code.google.com/p/jqlite/)
* Copyright (c) 2010 Brett Fattori (bfattori@gmail.com)
* Licensed under the MIT license
* http://www.opensource.org/licenses/mit-license.php
*
* Many thanks to the jQuery team's efforts. Some code is
* Copyright (c) 2010, John Resig. See
* http://jquery.org/license
*
* @author Brett Fattori (bfattori@gmail.com)
* @author $Author: bfattori $
* @version $Revision: 145 $
*
* Created: 03/29/2010
* Modified: $Date: 2010-06-21 11:08:14 -0400 (Mon, 21 Jun 2010) $
*/
(function(){function B(){return+new Date}var D=function(a,b){if(a===""&&b)return b;var d=a.split(" "),c=d.shift(),e;if(c.charAt(0)=="#"){var g=i.getElementById(c.substring(1));e=g?[g]:[]}else{e=c.charAt(0)!=="."?c.split(".")[0]:"*";var h=c.split("."),j=null;if(e.indexOf("[")!=-1){j=e;e=e.substr(0,e.indexOf("["))}g=function(o){var n=arguments.callee,k;if(!(k=!n.needClass)){k=n.classes;if(o.className.length==0)k=false;else{for(var r=o.className.split(" "),l=k.length,p=0;p<k.length;p++)f.inArray(k[p],
r)!=-1&&l--;k=l==0}}if(k=k){if(!(k=!n.needAttribute)){n=n.attributes;k=true;for(r=0;r<n.length;r++){l=n[r].split("=");p=l[0].indexOf("!")!=-1||l[0].indexOf("*")!=-1?l[0].charAt(l[0].length-1)+"=":"=";if(p!="=")l[0]=l[0].substring(0,l[0].length-1);switch(p){case "=":k&=o.getAttribute(l[0])===l[1];break;case "!=":k&=o.getAttribute(l[0])!==l[1];break;case "*=":k&=o.getAttribute(l[0]).indexOf(l[1])!=-1;break;default:k=false}}k=k}k=k}if(k)return o};for(var u=[],s=0;s<b.length;s++)for(var C=b[s].getElementsByTagName(e),
v=0;v<C.length;v++)u.push(C[v]);h&&h.shift();e=[];g.classes=h;if(j!=null){var w=j.indexOf("[");s=j.lastIndexOf("]");w=j.substring(w+1,s).split("][")}g.attributes=j!=null?w:null;g.needClass=c.indexOf(".")!=-1&&h.length>0;g.needAttribute=j!=null;for(c=0;c<u.length;c++)g(u[c])&&e.push(u[c])}return D(d.join(" "),e)},Q=function(a,b){b=b||i;if(a.nodeType&&a.nodeType===E){a=i.body;if(a===null)return[i]}if(a.nodeType&&a.nodeType===m)return[a];if(a.jquery&&typeof a.jquery==="string")return a.toArray();if(b)b=
F(b);if(f.isArray(a))return a;else if(typeof a==="string"){for(var d=[],c=0;c<b.length;c++){var e=[b[c]];if(!f.forceSimpleSelectorEngine&&e[0].querySelectorAll){e=e[0].querySelectorAll(a);for(var g=0;g<e.length;g++)d.push(e.item(g))}else d=d.concat(D(a,e))}return d}else return null},G=false;setTimeout(function(){var a=i.body;if(a){var b=i.createElement("script"),d="i"+(new Date).getTime();b.type="text/javascript";try{b.appendChild(i.createTextNode("window."+d+"=1;"))}catch(c){}a.insertBefore(b,a.firstChild);
var e=true;if(window[d])delete window[d];else e=false;a.removeChild(b);G=e}else setTimeout(arguments.callee,33)},33);var H=function(a){var b=i.createElement("div");b.innerHTML=a;return{scripts:b.getElementsByTagName("script"),data:a}},I=function(a){a=a.replace(/-/g," ");a=a;var b=true;b=b||false;a=!a?"":a.toString().replace(/^\s*|\s*$/g,"");var d="";if(a.length<=0)a="";else{var c=false;d+=b?a.charAt(0):a.charAt(0).toUpperCase();for(b=1;b<a.length;b++){d+=c?a.charAt(b).toUpperCase():a.charAt(b).toLowerCase();
var e=a.charCodeAt(b);c=e==32||e==45||e==46;if(e==99||e==67)if(a.charCodeAt(b-1)==77||a.charCodeAt(b-1)==109)c=true}a=d}return a.replace(/ /g,"")},J={click:"MouseEvents",dblclick:"MouseEvents",mousedown:"MouseEvents",mouseup:"MouseEvents",mouseover:"MouseEvents",mousemove:"MouseEvents",mouseout:"MouseEvents",contextmenu:"MouseEvents",keypress:"KeyEvents",keydown:"KeyEvents",keyup:"KeyEvents",load:"HTMLEvents",unload:"HTMLEvents",abort:"HTMLEvents",error:"HTMLEvents",resize:"HTMLEvents",scroll:"HTMLEvents",
select:"HTMLEvents",change:"HTMLEvents",submit:"HTMLEvents",reset:"HTMLEvents",focus:"HTMLEvents",blur:"HTMLEvents",touchstart:"MouseEvents",touchend:"MouseEvents",touchmove:"MouseEvents"},K=function(a,b,d){if(f.isFunction(d)){if(typeof b==="string")b=b.toLowerCase();var c=J[b];if(b.indexOf("on")==0)b=b.substring(2);if(c){c=function(e){var g=arguments.callee,h=e.data||[];h.unshift(e);g=g.fn.apply(a,h);if(typeof g!="undefined"&&g===false){if(e.preventDefault&&e.stopPropagation){e.preventDefault();
e.stopPropagation()}else{e.returnValue=false;e.cancelBubble=true}return false}return true};c.fn=d;a.addEventListener?a.addEventListener(b,c,false):a.attachEvent("on"+b,c)}else{if(!a._handlers)a._handlers={};c=a._handlers[b]||[];c.push(d);a._handlers[b]=c}}},f=function(a,b){return(new x).init(a,b)},i=window.document,y=Object.prototype.hasOwnProperty,z=Object.prototype.toString,L=Array.prototype.push,R=Array.prototype.slice,m=1,E=9,A=[],M=false,N=false,q;f.forceSimpleSelectorEngine=false;f.each=function(a,
b){var d,c=0,e=a.length;if(e===undefined||f.isFunction(a))for(d in a){if(b.call(a[d],d,a[d])===false)break}else for(d=a[0];c<e&&b.call(d,c,d)!==false;d=a[++c]);return a};f.noop=function(){};f.isFunction=function(a){return z.call(a)==="[object Function]"};f.isArray=function(a){return z.call(a)==="[object Array]"};f.isPlainObject=function(a){if(!a||z.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!y.call(a,"constructor")&&!y.call(a.constructor.prototype,"isPrototypeOf"))return false;
var b;for(b in a);return b===undefined||y.call(a,b)};f.merge=function(a,b){var d=a.length,c=0;if(typeof b.length==="number")for(var e=b.length;c<e;c++)a[d++]=b[c];else for(;b[c]!==undefined;)a[d++]=b[c++];a.length=d;return a};f.param=function(a){var b="";a&&f.each(a,function(d,c){b+=(b.length!=0?"&":"")+c+"="+encodeURIComponent(d)});return b};f.evalScripts=function(a){for(var b=i.getElementsByTagName("head")[0]||i.documentElement,d=0;d<a.length;d++){var c=i.createElement("script");c.type="text/javascript";
if(G)c.appendChild(i.createTextNode(a[d].text));else c.text=a[d].text;b.insertBefore(c,b.firstChild);b.removeChild(c)}};f.ready=function(){for(M=true;A.length>0;)A.shift()()};var t="jQuery"+B(),S=0,O={};f.noData={embed:true,object:true,applet:true};f.cache={};f.data=function(a,b,d){if(!(a.nodeName&&jQuery.noData[a.nodeName.toLowerCase()])){a=a==window?O:a;var c=a[t];c||(c=a[t]=++S);if(b&&!jQuery.cache[c])jQuery.cache[c]={};if(d!==undefined)jQuery.cache[c][b]=d;return b?jQuery.cache[c][b]:c}};f.removeData=
function(a,b){a=a==window?O:a;var d=a[t];if(b){if(jQuery.cache[d]){delete jQuery.cache[d][b];b="";for(b in jQuery.cache[d])break;b||jQuery.removeData(a)}}else{try{delete a[t]}catch(c){a.removeAttribute&&a.removeAttribute(t)}delete jQuery.cache[d]}};f.ajax={status:-1,statusText:"",responseText:null,responseXML:null,send:function(a,b,d){if(f.isFunction(b)){d=b;b={}}if(a){var c=true,e=null,g=null;if(typeof b.async!=="undefined"){c=b.async;delete b.async}if(typeof b.username!=="undefined"){e=b.username;
delete b.username}if(typeof b.password!=="undefined"){g=b.password;delete b.password}b=f.param(b);if(b.length!=0)a+=(a.indexOf("?")==-1?"?":"&")+b;b=new XMLHttpRequest;b.open("GET",a,c,e,g);b.send();if(c){a=function(h){var j=arguments.callee;h.status==200?f.ajax.complete(h,j.cb):f.ajax.error(h,j.cb)};a.cb=d;d=function(){var h=arguments.callee;h.req.readyState!=4?setTimeout(h,250):h.xcb(h.req)};d.req=b;d.xcb=a;setTimeout(d,250)}}},complete:function(a,b){f.ajax.status=a.status;f.ajax.responseText=a.responseText;
f.ajax.responseXML=a.responseXML;f.isFunction(b)&&b(a.responseText,a.status)},error:function(a,b){f.ajax.status=a.status;f.ajax.statusText=a.statusText;f.isFunction(b)&&b(a.status,a.statusText)}};f.makeArray=function(a,b){var d=b||[];if(a!=null)a.length==null||typeof a==="string"||jQuery.isFunction(a)||typeof a!=="function"&&a.setInterval?L.call(d,a):f.merge(d,a);return d};f.inArray=function(a,b){for(var d=0;d<b.length;d++)if(b[d]===a)return d;return-1};f.trim=function(a){return a!=null?a.toString().replace(/^\s*|\s*$/g,
""):""};var x=function(){};x.prototype={selector:"",context:null,length:0,jquery:"jqlite-1.1.1",init:function(a,b){if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1}else if(typeof a==="function")this.ready(a);else{var d=[];if(a.jquery&&typeof a.jquery==="string")d=a.toArray();else if(f.isArray(a))d=a;else if(typeof a==="string"&&f.trim(a).indexOf("<")==0&&f.trim(a).indexOf(">")!=-1){d=f.trim(a).toLowerCase();d=d.indexOf("<option")==0?"SELECT":d.indexOf("<li")==0?"UL":d.indexOf("<tr")==
0?"TBODY":d.indexOf("<td")==0?"TR":"DIV";d=i.createElement(d);d.innerHTML=a;d=[d.removeChild(d.firstChild)]}else{if(a.indexOf(",")!=-1){d=a.split(",");for(var c=0;c<d.length;c++)d[c]=f.trim(d[c])}else d=[a];c=[];for(var e=0;e<d.length;e++)c=c.concat(Q(d[e],b));d=c}L.apply(this,d)}return this},each:function(a){return f.each(this,a)},size:function(){return this.length},toArray:function(){return R.call(this,0)},ready:function(a){if(M)a();else{A.push(a);return this}},data:function(a,b){if(typeof a===
"undefined"&&this.length)return jQuery.data(this[0]);else if(typeof a==="object")return this.each(function(){jQuery.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===undefined){if(data===undefined&&this.length)data=jQuery.data(this[0],a);return data===undefined&&d[1]?this.data(d[0]):data}else return this.each(function(){jQuery.data(this,a,b)})},removeData:function(a){return this.each(function(){jQuery.removeData(this,a)})},addClass:function(a){return this.each(function(){if(this.className.length!=
0){var b=this.className.split(" ");if(f.inArray(a,b)==-1){b.push(a);this.className=b.join(" ")}}else this.className=a})},removeClass:function(a){return this.each(function(){if(this.className.length!=0){var b=this.className.split(" "),d=f.inArray(a,b);if(d!=-1){b.splice(d,1);this.className=b.join(" ")}}})},hasClass:function(a){if(this[0].className.length==0)return false;return f.inArray(a,this[0].className.split(" "))!=-1},isElementName:function(a){return this[0].nodeName.toLowerCase()===a.toLowerCase()},
toggleClass:function(a){return this.each(function(){if(this.className.length==0)this.className=a;else{var b=this.className.split(" "),d=f.inArray(a,b);d!=-1?b.splice(d,1):b.push(a);this.className=b.join(" ")}})},hide:function(a){return this.each(function(){if(this.style&&this.style.display!=null)if(this.style.display.toString()!="none"){this._oldDisplay=this.style.display.toString()||(this.nodeName!="span"?"block":"inline");this.style.display="none"}f.isFunction(a)&&a(this)})},show:function(a){return this.each(function(){this.style.display=
(this._oldDisplay&&this._oldDisplay!=""?this._oldDisplay:null)||(this.nodeName!="span"?"block":"inline");f.isFunction(a)&&a(this)})},css:function(a,b){if(typeof a==="string"&&b==null)return this[0].style[I(a)];else{a=typeof a==="string"?P(a,b):a;return this.each(function(){var d=this;typeof d.style!="undefined"&&f.each(a,function(c,e){e=typeof e==="number"?e+"px":e;var g=I(c);d.style[g]||(g=c);d.style[g]=e})})}},load:function(a,b,d){if(f.isFunction(b)){d=b;b={}}return this.each(function(){var c=function(e,
g){var h=arguments.callee;if(e){var j=H(e);h.elem.innerHTML=j.data;f.evalScripts(j.scripts)}f.isFunction(h.cback)&&h.cback(e,g)};c.cback=d;c.elem=this;f.ajax.send(a,b,c)})},html:function(a){return a?this.each(function(){var b=H(a);this.innerHTML=b.data;f.evalScripts(b.scripts)}):this[0].innerHTML},attr:function(a,b){return typeof a==="string"&&b==null?this[0]?this[0].getAttribute(a):"":this.each(function(){a=typeof a==="string"?P(a,b):a;for(var d in a)this.setAttribute(d,a[d])})},eq:function(a){var b=
this.toArray();this.context=this[0]=a<0?b[b.length+a]:b[a];this.length=1;return this},first:function(){this.context=this[0]=this.toArray()[0];this.length=1;return this},last:function(){var a=this.toArray();this.context=this[0]=a[a.length-1];this.length=1;return this},index:function(a){var b=-1;if(this.length!=0){var d=this[0];if(a){var c=f(a)[0];this.each(function(g){if(this===c){b=g;return false}})}else{a=this.parent()[0].firstChild;for(var e=[];a!=null;){a.nodeType===m&&e.push(a);a=a.nextSibling}f.each(a,
function(g){if(this===d){b=g;return false}})}}return b},next:function(a){var b=[];if(a){var d=f(a);this.each(function(){for(var c=this.nextSibling;c!=null&&c.nodeType!==m;)c=c.nextSibling;if(c!=null){var e=false;d.each(function(){if(this==c){e=true;return false}});e&&b.push(c)}})}else this.each(function(){for(var c=this.nextSibling;c!=null&&c.nodeType!==m;)c=c.nextSibling;c!=null&&b.push(c)});return f(b)},prev:function(a){var b=[];if(a){var d=f(a);this.each(function(){for(var c=this.previousSibling;c!=
null&&c.nodeType!==m;)c=c.previousSibling;if(c!=null){var e=false;d.each(function(){if(this==c){e=true;return false}});e&&b.push(c)}})}else this.each(function(){for(var c=this.previousSibling;c!=null&&c.nodeType!==m;)c=c.previousSibling;c!=null&&b.push(c)});return f(b)},parent:function(a){var b=[];if(a){var d=f(a);this.each(function(){var c=this.parentNode,e=false;d.each(function(){if(this==c){e=true;return false}});e&&b.push(c)})}else this.each(function(){b.push(this.parentNode)});return f(b)},parents:function(a){var b=
[];if(a){var d=f(a);this.each(function(){for(var c=this;c!=i.body;){d.each(function(){this==c&&b.push(c)});c=c.parentNode}})}else this.each(function(){for(var c=this;c!=i.body;){c=c.parentNode;b.push(c)}});return f(b)},children:function(a){var b=[];if(a){var d=f(a);this.each(function(){for(var c=this.firstChild;c!=null;){c.nodeType==m&&d.each(function(){this===c&&b.push(c)});c=c.nextSibling}})}else this.each(function(){for(var c=this.firstChild;c!=null;){c.nodeType==m&&b.push(c);c=c.nextSibling}});
return f(b)},append:function(a){a=F(a);return this.each(function(){for(var b=0;b<a.length;b++)this.appendChild(a[b])})},remove:function(a){return this.each(function(){a?$(a,this).remove():this.parentNode.removeChild(this)})},empty:function(){return this.each(function(){this.innerHTML=""})},val:function(a){if(a==null){var b=null;if(this&&this.length!=0&&typeof this[0].value!="undefined")b=this[0].value;return b}else return this.each(function(){if(typeof this.value!="undefined")this.value=a})},bind:function(a,
b){return this.each(function(){K(this,a,b)})},trigger:function(a,b){return this.each(function(){var d;var c;c=a;if(typeof c==="string")c=c.toLowerCase();var e=null,g=J[c]||"Event";if(i.createEvent){e=i.createEvent(g);e._eventClass=g;c&&e.initEvent(c,true,true)}if(i.createEventObject){e=i.createEventObject();if(c){e.type=c;e._eventClass=g}}c=e;if(c._eventClass!=="Event"){c.data=b;d=this.dispatchEvent(c)}else if(e=(this._handlers||{})[a])for(g=0;g<e.length;g++){var h=f.isArray(b)?b:[];h.unshift(c);
h=e[g].apply(this,h);if(!(typeof h=="undefined"?true:h))break}return d})},submit:function(a){return this.each(function(){if(f.isFunction(a))K(this,"onsubmit",a);else this.submit&&this.submit()})}};if(i.addEventListener)q=function(){i.removeEventListener("DOMContentLoaded",q,false);f.ready()};else if(i.attachEvent)q=function(){if(i.readyState==="complete"){i.detachEvent("onreadystatechange",q);f.ready()}};if(!N){N=true;if(i.readyState==="complete")return f.ready();if(i.addEventListener){i.addEventListener("DOMContentLoaded",
q,false);window.addEventListener("load",f.ready,false)}else if(i.attachEvent){i.attachEvent("onreadystatechange",q);window.attachEvent("onload",f.ready)}}var P=function(a,b){var d={};d[a]=b;return d},F=function(a){if(a.nodeType&&(a.nodeType===m||a.nodeType===E))a=[a];else if(typeof a==="string")a=f(a).toArray();else if(a.jquery&&typeof a.jquery==="string")a=a.toArray();return a};if(typeof window.jQuery=="undefined"){window.jQuery=f;window.jQuery.fn=x.prototype;window.$=window.jQuery;window.now=B}jQuery.extend=
jQuery.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,c=false,e,g,h,j;if(typeof a==="boolean"){c=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!jQuery.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(g in e){h=a[g];j=e[g];if(a!==j)if(c&&j&&(jQuery.isPlainObject(j)||jQuery.isArray(j))){h=h&&(jQuery.isPlainObject(h)||jQuery.isArray(h))?h:jQuery.isArray(j)?[]:{};a[g]=jQuery.extend(c,h,j)}else if(j!==undefined)a[g]=j}return a};jQuery.each("click,dblclick,mouseover,mouseout,mousedown,mouseup,keydown,keypress,keyup,focus,blur,change,select,error,load,unload,scroll,resize,touchstart,touchend,touchmove".split(","),
function(a,b){jQuery.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)}})})();
(function() {
this.Dosbox = (function() {
function Dosbox(options) {
this.onload = options.onload;
this.onrun = options.onrun;
this.ui = new Dosbox.UI(options);
this.module = new Dosbox.Module({
canvas: this.ui.canvas
});
this.ui.onStart((function(_this) {
return function() {
_this.ui.showLoader();
return _this.downloadScript();
};
})(this));
}
Dosbox.prototype.run = function(archiveUrl, executable) {
return new Dosbox.Mount(this.module, archiveUrl, {
success: (function(_this) {
return function() {
var func, hide;
_this.ui.updateMessage("Launching " + executable);
hide = function() {
return _this.ui.hideLoader();
};
func = function() {
return _this._dosbox_main(_this, executable);
};
setTimeout(func, 1000);
return setTimeout(hide, 3000);
};
})(this),
progress: (function(_this) {
return function(total, current) {
return _this.ui.updateMessage("Mount " + executable + " (" + (current * 100 / total | 0) + "%)");
};
})(this)
});
};
Dosbox.prototype.requestFullScreen = function() {
if (this.module.requestFullScreen) {
return this.module.requestFullScreen(true, false);
}
};
Dosbox.prototype.downloadScript = function() {
this.module.setStatus('Downloading js-dos');
this.ui.updateMessage('Downloading js-dos');
return new Dosbox.Xhr('https://js-dos.com/cdn/js-dos-v3.js', {
success: (function(_this) {
return function(script) {
var func;
_this.ui.updateMessage('Initializing dosbox');
func = function() {
return _this._jsdos_init(_this.module, script, _this.onload);
};
return setTimeout(func, 1000);
};
})(this),
progress: (function(_this) {
return function(total, current) {
return _this.ui.updateMessage("Downloading js-dos (" + (current * 100 / total | 0) + "%)");
};
})(this)
});
};
Dosbox.prototype._jsdos_init = function(module, script, onload) {
var Module;
Module = module;
eval(script);
if (onload) {
return onload(this);
}
};
Dosbox.prototype._dosbox_main = function(dosbox, executable) {
var exception, func;
try {
if (dosbox.onrun) {
func = function() {
return dosbox.onrun(dosbox, executable);
};
setTimeout(func, 1000);
}
return dosbox.module.ccall('dosbox_main', 'int', ['string'], [executable]);
} catch (error) {
exception = error;
if (exception === 'SimulateInfiniteLoop') {
} else {
return typeof console !== "undefined" && console !== null ? typeof console.error === "function" ? console.error(exception) : void 0 : void 0;
}
}
};
return Dosbox;
})();
}).call(this);
(function() {
Dosbox.Module = (function() {
function Module(options) {
this.elCanvas = options.canvas;
this.canvas = this.elCanvas[0];
}
Module.prototype.preRun = [];
Module.prototype.postRun = [];
Module.prototype.totalDependencies = 0;
Module.prototype.print = function(text) {
text = Array.prototype.slice.call(arguments).join(' ');
return typeof console !== "undefined" && console !== null ? typeof console.log === "function" ? console.log(text) : void 0 : void 0;
};
Module.prototype.printErr = function(text) {
text = Array.prototype.slice.call(arguments).join(' ');
return typeof console !== "undefined" && console !== null ? typeof console.error === "function" ? console.error(text) : void 0 : void 0;
};
Module.prototype.setStatus = function(text) {
return typeof console !== "undefined" && console !== null ? typeof console.log === "function" ? console.log(text) : void 0 : void 0;
};
Module.prototype.monitorRunDependencies = function(left) {
var status;
this.totalDependencies = Math.max(this.totalDependencies, left);
status = left ? "Preparing... (" + (this.totalDependencies - left) + "/" + this.totalDependencies + ")" : 'All downloads complete.';
return this.setStatus(status);
};
return Module;
})();
}).call(this);
(function() {
Dosbox.Mount = (function() {
function Mount(module, url, options) {
this.module = module;
new Dosbox.Xhr(url, {
success: (function(_this) {
return function(data) {
var bytes;
bytes = _this._toArray(data);
if (_this._mountZip(bytes)) {
return options.success();
} else {
return typeof console !== "undefined" && console !== null ? typeof console.error === "function" ? console.error('Unable to mount', url) : void 0 : void 0;
}
};
})(this),
progress: options.progress
});
}
Mount.prototype._mountZip = function(bytes) {
var buffer, extracted;
buffer = this.module._malloc(bytes.length);
this.module.HEAPU8.set(bytes, buffer);
extracted = this.module.ccall('extract_zip', 'int', ['number', 'number'], [buffer, bytes.length]);
this.module._free(buffer);
return extracted === 0;
};
Mount.prototype._toArray = function(data) {
var arr, i, len;
if (typeof data === 'string') {
arr = new Array(data.length);
i = 0;
len = data.length;
while (i < len) {
arr[i] = data.charCodeAt(i);
++i;
}
return arr;
}
return data;
};
return Mount;
})();
}).call(this);
(function() {
Dosbox.UI = (function() {
function UI(options) {
this.appendCss();
this.div = $('#' + (options.id || 'dosbox'));
this.wrapper = $('<div class="dosbox-container">');
this.canvas = $('<canvas class="dosbox-canvas" oncontextmenu="event.preventDefault()">');
this.overlay = $('<div class="dosbox-overlay">');
this.loaderMessage = $('<div class="dosbox-loader-message">');
this.loader = $('<div class="dosbox-loader">').append($('<div class="st-loader">').append($('<span class="equal">'))).append(this.loaderMessage);
this.start = $('<div class="dosbox-start">Click to start');
this.div.append(this.wrapper);
this.wrapper.append(this.canvas);
this.wrapper.append(this.loader);
this.wrapper.append(this.overlay);
this.overlay.append($('<div class="dosbox-powered">Powered by &nbsp;').append($('<a href="http://js-dos.com">js-dos.com')));
this.overlay.append(this.start);
}
UI.prototype.onStart = function(fun) {
return this.start.click((function(_this) {
return function() {
fun();
return _this.overlay.hide();
};
})(this));
};
UI.prototype.appendCss = function() {
var head, style;
head = document.head || document.getElementsByTagName('head')[0];
style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = this.css;
} else {
style.appendChild(document.createTextNode(this.css));
}
return head.appendChild(style);
};
UI.prototype.showLoader = function() {
this.loader.show();
return this.loaderMessage.html('');
};
UI.prototype.updateMessage = function(message) {
return this.loaderMessage.html(message);
};
UI.prototype.hideLoader = function() {
return this.loader.hide();
};
UI.prototype.css = '.dosbox-container { position: relative; min-width: 320px; min-height: 200px; } .dosbox-canvas { } .dosbox-overlay, .dosbox-loader { position: absolute; left: 0; right: 0; top: 0; bottom: 0; background-color: #333; } .dosbox-start { text-align: center; position: absolute; left: 0; right: 0; bottom: 50%; color: #f80; font-size: 1.5em; text-decoration: underline; cursor: pointer; } .dosbox-overlay a { color: #f80; } .dosbox-loader { display: none; } .dosbox-powered { position: absolute; right: 1em; bottom: 1em; font-size: 0.8em; color: #9C9C9C; } .dosbox-loader-message { text-align: center; position: absolute; left: 0; right: 0; bottom: 50%; margin: 0 0 -3em 0; box-sizing: border-box; color: #f80; font-size: 1.5em; } @-moz-keyframes loading { 0% { left: 0; } 50% { left: 8.33333em; } 100% { left: 0; } } @-webkit-keyframes loading { 0% { left: 0; } 50% { left: 8.33333em; } 100% { left: 0; } } @keyframes loading { 0% { left: 0; } 50% { left: 8.33333em; } 100% { left: 0; } } .st-loader { width: 10em; height: 2.5em; position: absolute; top: 50%; left: 50%; margin: -1.25em 0 0 -5em; box-sizing: border-box; } .st-loader:before, .st-loader:after { content: ""; display: block; position: absolute; top: 0; bottom: 0; width: 1.25em; box-sizing: border-box; border: 0.25em solid #f80; } .st-loader:before { left: -0.76923em; border-right: 0; } .st-loader:after { right: -0.76923em; border-left: 0; } .st-loader .equal { display: block; position: absolute; top: 50%; margin-top: -0.5em; left: 4.16667em; height: 1em; width: 1.66667em; border: 0.25em solid #f80; box-sizing: border-box; border-width: 0.25em 0; -moz-animation: loading 1.5s infinite ease-in-out; -webkit-animation: loading 1.5s infinite ease-in-out; animation: loading 1.5s infinite ease-in-out; }';
return UI;
})();
}).call(this);
(function() {
Dosbox.Xhr = (function() {
function Xhr(url, options) {
var e;
this.success = options.success;
this.progress = options.progress;
if (window.ActiveXObject) {
try {
this.xhr = new ActiveXObject('Microsoft.XMLHTTP');
} catch (error) {
e = error;
this.xhr = null;
}
} else {
this.xhr = new XMLHttpRequest();
}
this.xhr.open('GET', url, true);
this.xhr.overrideMimeType('text/plain; charset=x-user-defined');
this.xhr.addEventListener('progress', (function(_this) {
return function(evt) {
if (_this.progress) {
return _this.progress(evt.total, evt.loaded);
}
};
})(this));
this.xhr.onreadystatechange = (function(_this) {
return function() {
return _this._onReadyStateChange();
};
})(this);
this.xhr.send();
}
Xhr.prototype._onReadyStateChange = function() {
if (this.xhr.readyState === 4 && this.success) {
return this.success(this.xhr.responseText);
}
};
return Xhr;
})();
}).call(this);

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,41 @@
{
"name": "Its Eric Woodward! (dotcom)",
"icons": [
{
"src": "\/images\/favicons\/android-icon-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": "0.75"
},
{
"src": "\/images\/favicons\/android-icon-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": "1.0"
},
{
"src": "\/images\/favicons\/android-icon-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": "1.5"
},
{
"src": "\/images\/favicons\/android-icon-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": "2.0"
},
{
"src": "\/images\/favicons\/android-icon-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": "3.0"
},
{
"src": "\/images\/favicons\/android-icon-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": "4.0"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

View File

@ -0,0 +1,422 @@
┌─────┐ ┌──────┐ ┌───────┐ ┌─────┐ ┌─┐ ┌─┐ ┌──────┐ ┌─────┐ ┌─────┐ ┌─┐ ┌─┐
│ ┌─┐ │ │ ┌──┐ │ │ ┌┐ ┌┐ │ │ ┌─┐ │ │ │ │ │ │ ┌──┐ │ │ ┌─┐ │ │ ┌─┐ │ │ │ │ │
│ │ └─┘ │ └──┘ │ │ ││ ││ │ │ └─┘ │ │ └─┘ │ │ └──┘ │ │ └─┘ │ │ └─┘ │ │ └─┘ │
│ │ ┌─┐ │ ┌──┐ │ │ │└─┘│ │ │ ┌───┘ │ ┌─┐ │ │ ┌──┐ │ │ ┌───┘ │ ┌───┘ └─┐ ┌─┘
│ └─┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
└─────┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘ └─┘
┌───┐ ┌─────┐ ┌─┐ ┌──────┐ ┌───┐ ┌─┐ ┌──────┐