Merge branch 'Refactor3'
This commit is contained in:
commit
f135e184e4
|
@ -1,17 +0,0 @@
|
||||||
# Auto detect text files and perform LF normalization
|
|
||||||
* text=auto
|
|
||||||
|
|
||||||
# Custom for Visual Studio
|
|
||||||
*.cs diff=csharp
|
|
||||||
|
|
||||||
# Standard to msysgit
|
|
||||||
*.doc diff=astextplain
|
|
||||||
*.DOC diff=astextplain
|
|
||||||
*.docx diff=astextplain
|
|
||||||
*.DOCX diff=astextplain
|
|
||||||
*.dot diff=astextplain
|
|
||||||
*.DOT diff=astextplain
|
|
||||||
*.pdf diff=astextplain
|
|
||||||
*.PDF diff=astextplain
|
|
||||||
*.rtf diff=astextplain
|
|
||||||
*.RTF diff=astextplain
|
|
|
@ -1,6 +1,3 @@
|
||||||
node_modules
|
|
||||||
package-lock.json
|
|
||||||
|
|
||||||
# Windows image file caches
|
# Windows image file caches
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
ehthumbs.db
|
ehthumbs.db
|
||||||
|
@ -53,8 +50,10 @@ Temporary Items
|
||||||
*.zip
|
*.zip
|
||||||
itch*
|
itch*
|
||||||
|
|
||||||
# node
|
|
||||||
node_modules
|
|
||||||
|
|
||||||
# IDE stuff
|
# IDE stuff
|
||||||
.idea
|
.idea
|
||||||
|
|
||||||
|
/Cargo.lock
|
||||||
|
/dist/
|
||||||
|
/index.html
|
||||||
|
/includes/style.css
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "pixsy"
|
||||||
|
version = "0.72.7"
|
||||||
|
description = "convert images to Bitsy rooms"
|
||||||
|
authors = ["Max Bradbury <max@tinybird.info>"]
|
||||||
|
edition = "2018"
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://tinybird.dev/max/image-to-bitsy"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
base64 = "^0.12.3"
|
||||||
|
bitsy-parser = "^0.72.5"
|
||||||
|
image = "^0.23.7"
|
||||||
|
json = "^0.12.4"
|
||||||
|
lazy_static = "^1.4.0"
|
||||||
|
wasm-bindgen = "=0.2.64" # newer versions are bugged...
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Max Bradbury
|
||||||
|
|
||||||
|
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.
|
|
@ -0,0 +1,6 @@
|
||||||
|
# todo
|
||||||
|
|
||||||
|
* tile reuse
|
||||||
|
* noise reduction (remove lonely pixels)
|
||||||
|
* implement Atkinson and Bayer dithering options
|
||||||
|
* fix weird problem with pixels flipping (see test::example)
|
|
@ -1 +0,0 @@
|
||||||
theme: jekyll-theme-dinky
|
|
5
build.sh
5
build.sh
|
@ -1,4 +1,5 @@
|
||||||
#!/usr/bin/env bash
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
pug index.pug index.html
|
pug index.pug
|
||||||
lessc includes/style.less includes/style.css
|
lessc includes/style.less includes/style.css
|
||||||
|
wasm-pack build --target web
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#!/usr/bin/env bash
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
zip -r image-to-bitsy.zip readme.md index.html includes/
|
rm -rf dist
|
||||||
butler push image-to-bitsy.zip ruin/image-to-bitsy:html
|
mkdir dist
|
||||||
|
cp -r README.md LICENSE index.html script.js pkg includes old dist
|
||||||
|
butler push dist ruin/pixsy:html
|
||||||
|
|
Binary file not shown.
1596
includes/croppie.js
1596
includes/croppie.js
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -1,84 +0,0 @@
|
||||||
Write your game's title here
|
|
||||||
|
|
||||||
# BITSY VERSION 5.3
|
|
||||||
|
|
||||||
! ROOM_FORMAT 1
|
|
||||||
|
|
||||||
PAL 0
|
|
||||||
0,82,204
|
|
||||||
128,159,255
|
|
||||||
255,255,255
|
|
||||||
|
|
||||||
ROOM 0
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
|
||||||
0,a,a,a,a,a,a,a,a,a,a,a,a,a,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,a,a,a,a,a,a,a,a,a,a,a,a,a,0
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
|
||||||
PAL 0
|
|
||||||
|
|
||||||
TIL a
|
|
||||||
11111111
|
|
||||||
10000001
|
|
||||||
10000001
|
|
||||||
10011001
|
|
||||||
10011001
|
|
||||||
10000001
|
|
||||||
10000001
|
|
||||||
11111111
|
|
||||||
|
|
||||||
SPR A
|
|
||||||
00011000
|
|
||||||
00011000
|
|
||||||
00011000
|
|
||||||
00111100
|
|
||||||
01111110
|
|
||||||
10111101
|
|
||||||
00100100
|
|
||||||
00100100
|
|
||||||
POS 0 4,4
|
|
||||||
|
|
||||||
SPR a
|
|
||||||
00000000
|
|
||||||
00000000
|
|
||||||
01010001
|
|
||||||
01110001
|
|
||||||
01110010
|
|
||||||
01111100
|
|
||||||
00111100
|
|
||||||
00100100
|
|
||||||
DLG SPR_0
|
|
||||||
POS 0 8,12
|
|
||||||
|
|
||||||
ITM 0
|
|
||||||
00000000
|
|
||||||
00000000
|
|
||||||
00000000
|
|
||||||
00111100
|
|
||||||
01100100
|
|
||||||
00100100
|
|
||||||
00011000
|
|
||||||
00000000
|
|
||||||
NAME tea
|
|
||||||
DLG ITM_0
|
|
||||||
|
|
||||||
DLG SPR_0
|
|
||||||
I'm a cat
|
|
||||||
|
|
||||||
DLG ITM_0
|
|
||||||
You found a nice warm cup of tea
|
|
||||||
|
|
||||||
VAR a
|
|
||||||
42
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,136 +0,0 @@
|
||||||
/**
|
|
||||||
* @license
|
|
||||||
* Lodash lodash.com/license | Underscore.js 1.8.3 underscorejs.org/LICENSE
|
|
||||||
*/
|
|
||||||
;(function(){function n(n,t){return n.set(t[0],t[1]),n}function t(n,t){return n.add(t),n}function r(n,t,r){switch(r.length){case 0:return n.call(t);case 1:return n.call(t,r[0]);case 2:return n.call(t,r[0],r[1]);case 3:return n.call(t,r[0],r[1],r[2])}return n.apply(t,r)}function e(n,t,r,e){for(var u=-1,i=null==n?0:n.length;++u<i;){var o=n[u];t(e,o,r(o),n)}return e}function u(n,t){for(var r=-1,e=null==n?0:n.length;++r<e&&false!==t(n[r],r,n););return n}function i(n,t){for(var r=null==n?0:n.length;r--&&false!==t(n[r],r,n););
|
|
||||||
return n}function o(n,t){for(var r=-1,e=null==n?0:n.length;++r<e;)if(!t(n[r],r,n))return false;return true}function f(n,t){for(var r=-1,e=null==n?0:n.length,u=0,i=[];++r<e;){var o=n[r];t(o,r,n)&&(i[u++]=o)}return i}function c(n,t){return!(null==n||!n.length)&&-1<d(n,t,0)}function a(n,t,r){for(var e=-1,u=null==n?0:n.length;++e<u;)if(r(t,n[e]))return true;return false}function l(n,t){for(var r=-1,e=null==n?0:n.length,u=Array(e);++r<e;)u[r]=t(n[r],r,n);return u}function s(n,t){for(var r=-1,e=t.length,u=n.length;++r<e;)n[u+r]=t[r];
|
|
||||||
return n}function h(n,t,r,e){var u=-1,i=null==n?0:n.length;for(e&&i&&(r=n[++u]);++u<i;)r=t(r,n[u],u,n);return r}function p(n,t,r,e){var u=null==n?0:n.length;for(e&&u&&(r=n[--u]);u--;)r=t(r,n[u],u,n);return r}function _(n,t){for(var r=-1,e=null==n?0:n.length;++r<e;)if(t(n[r],r,n))return true;return false}function v(n,t,r){var e;return r(n,function(n,r,u){if(t(n,r,u))return e=r,false}),e}function g(n,t,r,e){var u=n.length;for(r+=e?1:-1;e?r--:++r<u;)if(t(n[r],r,n))return r;return-1}function d(n,t,r){if(t===t)n:{
|
|
||||||
--r;for(var e=n.length;++r<e;)if(n[r]===t){n=r;break n}n=-1}else n=g(n,b,r);return n}function y(n,t,r,e){--r;for(var u=n.length;++r<u;)if(e(n[r],t))return r;return-1}function b(n){return n!==n}function x(n,t){var r=null==n?0:n.length;return r?k(n,t)/r:P}function j(n){return function(t){return null==t?F:t[n]}}function w(n){return function(t){return null==n?F:n[t]}}function m(n,t,r,e,u){return u(n,function(n,u,i){r=e?(e=false,n):t(r,n,u,i)}),r}function A(n,t){var r=n.length;for(n.sort(t);r--;)n[r]=n[r].c;
|
|
||||||
return n}function k(n,t){for(var r,e=-1,u=n.length;++e<u;){var i=t(n[e]);i!==F&&(r=r===F?i:r+i)}return r}function E(n,t){for(var r=-1,e=Array(n);++r<n;)e[r]=t(r);return e}function O(n,t){return l(t,function(t){return[t,n[t]]})}function S(n){return function(t){return n(t)}}function I(n,t){return l(t,function(t){return n[t]})}function R(n,t){return n.has(t)}function z(n,t){for(var r=-1,e=n.length;++r<e&&-1<d(t,n[r],0););return r}function W(n,t){for(var r=n.length;r--&&-1<d(t,n[r],0););return r}function B(n){
|
|
||||||
return"\\"+Tn[n]}function L(n){var t=-1,r=Array(n.size);return n.forEach(function(n,e){r[++t]=[e,n]}),r}function U(n,t){return function(r){return n(t(r))}}function C(n,t){for(var r=-1,e=n.length,u=0,i=[];++r<e;){var o=n[r];o!==t&&"__lodash_placeholder__"!==o||(n[r]="__lodash_placeholder__",i[u++]=r)}return i}function D(n){var t=-1,r=Array(n.size);return n.forEach(function(n){r[++t]=n}),r}function M(n){var t=-1,r=Array(n.size);return n.forEach(function(n){r[++t]=[n,n]}),r}function T(n){if(Bn.test(n)){
|
|
||||||
for(var t=zn.lastIndex=0;zn.test(n);)++t;n=t}else n=tt(n);return n}function $(n){return Bn.test(n)?n.match(zn)||[]:n.split("")}var F,N=1/0,P=NaN,Z=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]],q=/\b__p\+='';/g,V=/\b(__p\+=)''\+/g,K=/(__e\(.*?\)|\b__t\))\+'';/g,G=/&(?:amp|lt|gt|quot|#39);/g,H=/[&<>"']/g,J=RegExp(G.source),Y=RegExp(H.source),Q=/<%-([\s\S]+?)%>/g,X=/<%([\s\S]+?)%>/g,nn=/<%=([\s\S]+?)%>/g,tn=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,rn=/^\w*$/,en=/^\./,un=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,on=/[\\^$.*+?()[\]{}|]/g,fn=RegExp(on.source),cn=/^\s+|\s+$/g,an=/^\s+/,ln=/\s+$/,sn=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,hn=/\{\n\/\* \[wrapped with (.+)\] \*/,pn=/,? & /,_n=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,vn=/\\(\\)?/g,gn=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,dn=/\w*$/,yn=/^[-+]0x[0-9a-f]+$/i,bn=/^0b[01]+$/i,xn=/^\[object .+?Constructor\]$/,jn=/^0o[0-7]+$/i,wn=/^(?:0|[1-9]\d*)$/,mn=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,An=/($^)/,kn=/['\n\r\u2028\u2029\\]/g,En="[\\ufe0e\\ufe0f]?(?:[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|\\ud83c[\\udffb-\\udfff])?(?:\\u200d(?:[^\\ud800-\\udfff]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff])[\\ufe0e\\ufe0f]?(?:[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|\\ud83c[\\udffb-\\udfff])?)*",On="(?:[\\u2700-\\u27bf]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff])"+En,Sn="(?:[^\\ud800-\\udfff][\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]?|[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|(?:\\ud83c[\\udde6-\\uddff]){2}|[\\ud800-\\udbff][\\udc00-\\udfff]|[\\ud800-\\udfff])",In=RegExp("['\u2019]","g"),Rn=RegExp("[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]","g"),zn=RegExp("\\ud83c[\\udffb-\\udfff](?=\\ud83c[\\udffb-\\udfff])|"+Sn+En,"g"),Wn=RegExp(["[A-Z\\xc0-\\xd6\\xd8-\\xde]?[a-z\\xdf-\\xf6\\xf8-\\xff]+(?:['\u2019](?:d|ll|m|re|s|t|ve))?(?=[\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000]|[A-Z\\xc0-\\xd6\\xd8-\\xde]|$)|(?:[A-Z\\xc0-\\xd6\\xd8-\\xde]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?(?=[\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000]|[A-Z\\xc0-\\xd6\\xd8-\\xde](?:[a-z\\xdf-\\xf6\\xf8-\\xff]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])|$)|[A-Z\\xc0-\\xd6\\xd8-\\xde]?(?:[a-z\\xdf-\\xf6\\xf8-\\xff]|[^\\ud800-\\udfff\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000\\d+\\u2700-\\u27bfa-z\\xdf-\\xf6\\xf8-\\xffA-Z\\xc0-\\xd6\\xd8-\\xde])+(?:['\u2019](?:d|ll|m|re|s|t|ve))?|[A-Z\\xc0-\\xd6\\xd8-\\xde]+(?:['\u2019](?:D|LL|M|RE|S|T|VE))?|\\d*(?:(?:1ST|2ND|3RD|(?![123])\\dTH)\\b)|\\d*(?:(?:1st|2nd|3rd|(?![123])\\dth)\\b)|\\d+",On].join("|"),"g"),Bn=RegExp("[\\u200d\\ud800-\\udfff\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff\\ufe0e\\ufe0f]"),Ln=/[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Un="Array Buffer DataView Date Error Float32Array Float64Array Function Int8Array Int16Array Int32Array Map Math Object Promise RegExp Set String Symbol TypeError Uint8Array Uint8ClampedArray Uint16Array Uint32Array WeakMap _ clearTimeout isFinite parseInt setTimeout".split(" "),Cn={};
|
|
||||||
Cn["[object Float32Array]"]=Cn["[object Float64Array]"]=Cn["[object Int8Array]"]=Cn["[object Int16Array]"]=Cn["[object Int32Array]"]=Cn["[object Uint8Array]"]=Cn["[object Uint8ClampedArray]"]=Cn["[object Uint16Array]"]=Cn["[object Uint32Array]"]=true,Cn["[object Arguments]"]=Cn["[object Array]"]=Cn["[object ArrayBuffer]"]=Cn["[object Boolean]"]=Cn["[object DataView]"]=Cn["[object Date]"]=Cn["[object Error]"]=Cn["[object Function]"]=Cn["[object Map]"]=Cn["[object Number]"]=Cn["[object Object]"]=Cn["[object RegExp]"]=Cn["[object Set]"]=Cn["[object String]"]=Cn["[object WeakMap]"]=false;
|
|
||||||
var Dn={};Dn["[object Arguments]"]=Dn["[object Array]"]=Dn["[object ArrayBuffer]"]=Dn["[object DataView]"]=Dn["[object Boolean]"]=Dn["[object Date]"]=Dn["[object Float32Array]"]=Dn["[object Float64Array]"]=Dn["[object Int8Array]"]=Dn["[object Int16Array]"]=Dn["[object Int32Array]"]=Dn["[object Map]"]=Dn["[object Number]"]=Dn["[object Object]"]=Dn["[object RegExp]"]=Dn["[object Set]"]=Dn["[object String]"]=Dn["[object Symbol]"]=Dn["[object Uint8Array]"]=Dn["[object Uint8ClampedArray]"]=Dn["[object Uint16Array]"]=Dn["[object Uint32Array]"]=true,
|
|
||||||
Dn["[object Error]"]=Dn["[object Function]"]=Dn["[object WeakMap]"]=false;var Mn,Tn={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},$n=parseFloat,Fn=parseInt,Nn=typeof global=="object"&&global&&global.Object===Object&&global,Pn=typeof self=="object"&&self&&self.Object===Object&&self,Zn=Nn||Pn||Function("return this")(),qn=typeof exports=="object"&&exports&&!exports.nodeType&&exports,Vn=qn&&typeof module=="object"&&module&&!module.nodeType&&module,Kn=Vn&&Vn.exports===qn,Gn=Kn&&Nn.process;
|
|
||||||
n:{try{Mn=Gn&&Gn.binding&&Gn.binding("util");break n}catch(n){}Mn=void 0}var Hn=Mn&&Mn.isArrayBuffer,Jn=Mn&&Mn.isDate,Yn=Mn&&Mn.isMap,Qn=Mn&&Mn.isRegExp,Xn=Mn&&Mn.isSet,nt=Mn&&Mn.isTypedArray,tt=j("length"),rt=w({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I",
|
|
||||||
"\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C",
|
|
||||||
"\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i",
|
|
||||||
"\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S",
|
|
||||||
"\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe",
|
|
||||||
"\u0149":"'n","\u017f":"s"}),et=w({"&":"&","<":"<",">":">",'"':""","'":"'"}),ut=w({"&":"&","<":"<",">":">",""":'"',"'":"'"}),it=function w(En){function On(n){if(xu(n)&&!af(n)&&!(n instanceof Mn)){if(n instanceof zn)return n;if(ci.call(n,"__wrapped__"))return Pe(n)}return new zn(n)}function Sn(){}function zn(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=F}function Mn(n){this.__wrapped__=n,this.__actions__=[],this.__dir__=1,
|
|
||||||
this.__filtered__=false,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}function Tn(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function Nn(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function Pn(n){var t=-1,r=null==n?0:n.length;for(this.clear();++t<r;){var e=n[t];this.set(e[0],e[1])}}function qn(n){var t=-1,r=null==n?0:n.length;for(this.__data__=new Pn;++t<r;)this.add(n[t])}function Vn(n){
|
|
||||||
this.size=(this.__data__=new Nn(n)).size}function Gn(n,t){var r,e=af(n),u=!e&&cf(n),i=!e&&!u&&sf(n),o=!e&&!u&&!i&&gf(n),u=(e=e||u||i||o)?E(n.length,ri):[],f=u.length;for(r in n)!t&&!ci.call(n,r)||e&&("length"==r||i&&("offset"==r||"parent"==r)||o&&("buffer"==r||"byteLength"==r||"byteOffset"==r)||Re(r,f))||u.push(r);return u}function tt(n){var t=n.length;return t?n[cr(0,t-1)]:F}function ot(n,t){return Te(Mr(n),gt(t,0,n.length))}function ft(n){return Te(Mr(n))}function ct(n,t,r){(r===F||hu(n[t],r))&&(r!==F||t in n)||_t(n,t,r);
|
|
||||||
}function at(n,t,r){var e=n[t];ci.call(n,t)&&hu(e,r)&&(r!==F||t in n)||_t(n,t,r)}function lt(n,t){for(var r=n.length;r--;)if(hu(n[r][0],t))return r;return-1}function st(n,t,r,e){return oo(n,function(n,u,i){t(e,n,r(n),i)}),e}function ht(n,t){return n&&Tr(t,Lu(t),n)}function pt(n,t){return n&&Tr(t,Uu(t),n)}function _t(n,t,r){"__proto__"==t&&Ei?Ei(n,t,{configurable:true,enumerable:true,value:r,writable:true}):n[t]=r}function vt(n,t){for(var r=-1,e=t.length,u=Hu(e),i=null==n;++r<e;)u[r]=i?F:Wu(n,t[r]);return u;
|
|
||||||
}function gt(n,t,r){return n===n&&(r!==F&&(n=n<=r?n:r),t!==F&&(n=n>=t?n:t)),n}function dt(n,t,r,e,i,o){var f,c=1&t,a=2&t,l=4&t;if(r&&(f=i?r(n,e,i,o):r(n)),f!==F)return f;if(!bu(n))return n;if(e=af(n)){if(f=Ee(n),!c)return Mr(n,f)}else{var s=yo(n),h="[object Function]"==s||"[object GeneratorFunction]"==s;if(sf(n))return Wr(n,c);if("[object Object]"==s||"[object Arguments]"==s||h&&!i){if(f=a||h?{}:Oe(n),!c)return a?Fr(n,pt(f,n)):$r(n,ht(f,n))}else{if(!Dn[s])return i?n:{};f=Se(n,s,dt,c)}}if(o||(o=new Vn),
|
|
||||||
i=o.get(n))return i;o.set(n,f);var a=l?a?ye:de:a?Uu:Lu,p=e?F:a(n);return u(p||n,function(e,u){p&&(u=e,e=n[u]),at(f,u,dt(e,t,r,u,n,o))}),f}function yt(n){var t=Lu(n);return function(r){return bt(r,n,t)}}function bt(n,t,r){var e=r.length;if(null==n)return!e;for(n=ni(n);e--;){var u=r[e],i=t[u],o=n[u];if(o===F&&!(u in n)||!i(o))return false}return true}function xt(n,t,r){if(typeof n!="function")throw new ei("Expected a function");return jo(function(){n.apply(F,r)},t)}function jt(n,t,r,e){var u=-1,i=c,o=true,f=n.length,s=[],h=t.length;
|
|
||||||
if(!f)return s;r&&(t=l(t,S(r))),e?(i=a,o=false):200<=t.length&&(i=R,o=false,t=new qn(t));n:for(;++u<f;){var p=n[u],_=null==r?p:r(p),p=e||0!==p?p:0;if(o&&_===_){for(var v=h;v--;)if(t[v]===_)continue n;s.push(p)}else i(t,_,e)||s.push(p)}return s}function wt(n,t){var r=true;return oo(n,function(n,e,u){return r=!!t(n,e,u)}),r}function mt(n,t,r){for(var e=-1,u=n.length;++e<u;){var i=n[e],o=t(i);if(null!=o&&(f===F?o===o&&!Au(o):r(o,f)))var f=o,c=i}return c}function At(n,t){var r=[];return oo(n,function(n,e,u){
|
|
||||||
t(n,e,u)&&r.push(n)}),r}function kt(n,t,r,e,u){var i=-1,o=n.length;for(r||(r=Ie),u||(u=[]);++i<o;){var f=n[i];0<t&&r(f)?1<t?kt(f,t-1,r,e,u):s(u,f):e||(u[u.length]=f)}return u}function Et(n,t){return n&&co(n,t,Lu)}function Ot(n,t){return n&&ao(n,t,Lu)}function St(n,t){return f(t,function(t){return gu(n[t])})}function It(n,t){t=Rr(t,n);for(var r=0,e=t.length;null!=n&&r<e;)n=n[$e(t[r++])];return r&&r==e?n:F}function Rt(n,t,r){return t=t(n),af(n)?t:s(t,r(n))}function zt(n){if(null==n)n=n===F?"[object Undefined]":"[object Null]";else if(ki&&ki in ni(n)){
|
|
||||||
var t=ci.call(n,ki),r=n[ki];try{n[ki]=F;var e=true}catch(n){}var u=si.call(n);e&&(t?n[ki]=r:delete n[ki]),n=u}else n=si.call(n);return n}function Wt(n,t){return n>t}function Bt(n,t){return null!=n&&ci.call(n,t)}function Lt(n,t){return null!=n&&t in ni(n)}function Ut(n,t,r){for(var e=r?a:c,u=n[0].length,i=n.length,o=i,f=Hu(i),s=1/0,h=[];o--;){var p=n[o];o&&t&&(p=l(p,S(t))),s=Mi(p.length,s),f[o]=!r&&(t||120<=u&&120<=p.length)?new qn(o&&p):F}var p=n[0],_=-1,v=f[0];n:for(;++_<u&&h.length<s;){var g=p[_],d=t?t(g):g,g=r||0!==g?g:0;
|
|
||||||
if(v?!R(v,d):!e(h,d,r)){for(o=i;--o;){var y=f[o];if(y?!R(y,d):!e(n[o],d,r))continue n}v&&v.push(d),h.push(g)}}return h}function Ct(n,t,r){var e={};return Et(n,function(n,u,i){t(e,r(n),u,i)}),e}function Dt(n,t,e){return t=Rr(t,n),n=2>t.length?n:It(n,vr(t,0,-1)),t=null==n?n:n[$e(Ge(t))],null==t?F:r(t,n,e)}function Mt(n){return xu(n)&&"[object Arguments]"==zt(n)}function Tt(n){return xu(n)&&"[object ArrayBuffer]"==zt(n)}function $t(n){return xu(n)&&"[object Date]"==zt(n)}function Ft(n,t,r,e,u){if(n===t)t=true;else if(null==n||null==t||!xu(n)&&!xu(t))t=n!==n&&t!==t;else n:{
|
|
||||||
var i=af(n),o=af(t),f=i?"[object Array]":yo(n),c=o?"[object Array]":yo(t),f="[object Arguments]"==f?"[object Object]":f,c="[object Arguments]"==c?"[object Object]":c,a="[object Object]"==f,o="[object Object]"==c;if((c=f==c)&&sf(n)){if(!sf(t)){t=false;break n}i=true,a=false}if(c&&!a)u||(u=new Vn),t=i||gf(n)?_e(n,t,r,e,Ft,u):ve(n,t,f,r,e,Ft,u);else{if(!(1&r)&&(i=a&&ci.call(n,"__wrapped__"),f=o&&ci.call(t,"__wrapped__"),i||f)){n=i?n.value():n,t=f?t.value():t,u||(u=new Vn),t=Ft(n,t,r,e,u);break n}if(c)t:if(u||(u=new Vn),
|
|
||||||
i=1&r,f=de(n),o=f.length,c=de(t).length,o==c||i){for(a=o;a--;){var l=f[a];if(!(i?l in t:ci.call(t,l))){t=false;break t}}if((c=u.get(n))&&u.get(t))t=c==t;else{c=true,u.set(n,t),u.set(t,n);for(var s=i;++a<o;){var l=f[a],h=n[l],p=t[l];if(e)var _=i?e(p,h,l,t,n,u):e(h,p,l,n,t,u);if(_===F?h!==p&&!Ft(h,p,r,e,u):!_){c=false;break}s||(s="constructor"==l)}c&&!s&&(r=n.constructor,e=t.constructor,r!=e&&"constructor"in n&&"constructor"in t&&!(typeof r=="function"&&r instanceof r&&typeof e=="function"&&e instanceof e)&&(c=false)),
|
|
||||||
u.delete(n),u.delete(t),t=c}}else t=false;else t=false}}return t}function Nt(n){return xu(n)&&"[object Map]"==yo(n)}function Pt(n,t,r,e){var u=r.length,i=u,o=!e;if(null==n)return!i;for(n=ni(n);u--;){var f=r[u];if(o&&f[2]?f[1]!==n[f[0]]:!(f[0]in n))return false}for(;++u<i;){var f=r[u],c=f[0],a=n[c],l=f[1];if(o&&f[2]){if(a===F&&!(c in n))return false}else{if(f=new Vn,e)var s=e(a,l,c,n,t,f);if(s===F?!Ft(l,a,3,e,f):!s)return false}}return true}function Zt(n){return!(!bu(n)||li&&li in n)&&(gu(n)?_i:xn).test(Fe(n))}function qt(n){
|
|
||||||
return xu(n)&&"[object RegExp]"==zt(n)}function Vt(n){return xu(n)&&"[object Set]"==yo(n)}function Kt(n){return xu(n)&&yu(n.length)&&!!Cn[zt(n)]}function Gt(n){return typeof n=="function"?n:null==n?Nu:typeof n=="object"?af(n)?Xt(n[0],n[1]):Qt(n):Vu(n)}function Ht(n){if(!Le(n))return Ci(n);var t,r=[];for(t in ni(n))ci.call(n,t)&&"constructor"!=t&&r.push(t);return r}function Jt(n,t){return n<t}function Yt(n,t){var r=-1,e=pu(n)?Hu(n.length):[];return oo(n,function(n,u,i){e[++r]=t(n,u,i)}),e}function Qt(n){
|
|
||||||
var t=me(n);return 1==t.length&&t[0][2]?Ue(t[0][0],t[0][1]):function(r){return r===n||Pt(r,n,t)}}function Xt(n,t){return We(n)&&t===t&&!bu(t)?Ue($e(n),t):function(r){var e=Wu(r,n);return e===F&&e===t?Bu(r,n):Ft(t,e,3)}}function nr(n,t,r,e,u){n!==t&&co(t,function(i,o){if(bu(i)){u||(u=new Vn);var f=u,c=n[o],a=t[o],l=f.get(a);if(l)ct(n,o,l);else{var l=e?e(c,a,o+"",n,t,f):F,s=l===F;if(s){var h=af(a),p=!h&&sf(a),_=!h&&!p&&gf(a),l=a;h||p||_?af(c)?l=c:_u(c)?l=Mr(c):p?(s=false,l=Wr(a,true)):_?(s=false,l=Lr(a,true)):l=[]:wu(a)||cf(a)?(l=c,
|
|
||||||
cf(c)?l=Ru(c):(!bu(c)||r&&gu(c))&&(l=Oe(a))):s=false}s&&(f.set(a,l),nr(l,a,r,e,f),f.delete(a)),ct(n,o,l)}}else f=e?e(n[o],i,o+"",n,t,u):F,f===F&&(f=i),ct(n,o,f)},Uu)}function tr(n,t){var r=n.length;if(r)return t+=0>t?r:0,Re(t,r)?n[t]:F}function rr(n,t,r){var e=-1;return t=l(t.length?t:[Nu],S(je())),n=Yt(n,function(n){return{a:l(t,function(t){return t(n)}),b:++e,c:n}}),A(n,function(n,t){var e;n:{e=-1;for(var u=n.a,i=t.a,o=u.length,f=r.length;++e<o;){var c=Ur(u[e],i[e]);if(c){e=e>=f?c:c*("desc"==r[e]?-1:1);
|
|
||||||
break n}}e=n.b-t.b}return e})}function er(n,t){return ur(n,t,function(t,r){return Bu(n,r)})}function ur(n,t,r){for(var e=-1,u=t.length,i={};++e<u;){var o=t[e],f=It(n,o);r(f,o)&&pr(i,Rr(o,n),f)}return i}function ir(n){return function(t){return It(t,n)}}function or(n,t,r,e){var u=e?y:d,i=-1,o=t.length,f=n;for(n===t&&(t=Mr(t)),r&&(f=l(n,S(r)));++i<o;)for(var c=0,a=t[i],a=r?r(a):a;-1<(c=u(f,a,c,e));)f!==n&&wi.call(f,c,1),wi.call(n,c,1);return n}function fr(n,t){for(var r=n?t.length:0,e=r-1;r--;){var u=t[r];
|
|
||||||
if(r==e||u!==i){var i=u;Re(u)?wi.call(n,u,1):mr(n,u)}}}function cr(n,t){return n+zi(Fi()*(t-n+1))}function ar(n,t){var r="";if(!n||1>t||9007199254740991<t)return r;do t%2&&(r+=n),(t=zi(t/2))&&(n+=n);while(t);return r}function lr(n,t){return wo(Ce(n,t,Nu),n+"")}function sr(n){return tt(Du(n))}function hr(n,t){var r=Du(n);return Te(r,gt(t,0,r.length))}function pr(n,t,r,e){if(!bu(n))return n;t=Rr(t,n);for(var u=-1,i=t.length,o=i-1,f=n;null!=f&&++u<i;){var c=$e(t[u]),a=r;if(u!=o){var l=f[c],a=e?e(l,c,f):F;
|
|
||||||
a===F&&(a=bu(l)?l:Re(t[u+1])?[]:{})}at(f,c,a),f=f[c]}return n}function _r(n){return Te(Du(n))}function vr(n,t,r){var e=-1,u=n.length;for(0>t&&(t=-t>u?0:u+t),r=r>u?u:r,0>r&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0,r=Hu(u);++e<u;)r[e]=n[e+t];return r}function gr(n,t){var r;return oo(n,function(n,e,u){return r=t(n,e,u),!r}),!!r}function dr(n,t,r){var e=0,u=null==n?e:n.length;if(typeof t=="number"&&t===t&&2147483647>=u){for(;e<u;){var i=e+u>>>1,o=n[i];null!==o&&!Au(o)&&(r?o<=t:o<t)?e=i+1:u=i}return u}return yr(n,t,Nu,r);
|
|
||||||
}function yr(n,t,r,e){t=r(t);for(var u=0,i=null==n?0:n.length,o=t!==t,f=null===t,c=Au(t),a=t===F;u<i;){var l=zi((u+i)/2),s=r(n[l]),h=s!==F,p=null===s,_=s===s,v=Au(s);(o?e||_:a?_&&(e||h):f?_&&h&&(e||!p):c?_&&h&&!p&&(e||!v):p||v?0:e?s<=t:s<t)?u=l+1:i=l}return Mi(i,4294967294)}function br(n,t){for(var r=-1,e=n.length,u=0,i=[];++r<e;){var o=n[r],f=t?t(o):o;if(!r||!hu(f,c)){var c=f;i[u++]=0===o?0:o}}return i}function xr(n){return typeof n=="number"?n:Au(n)?P:+n}function jr(n){if(typeof n=="string")return n;
|
|
||||||
if(af(n))return l(n,jr)+"";if(Au(n))return uo?uo.call(n):"";var t=n+"";return"0"==t&&1/n==-N?"-0":t}function wr(n,t,r){var e=-1,u=c,i=n.length,o=true,f=[],l=f;if(r)o=false,u=a;else if(200<=i){if(u=t?null:po(n))return D(u);o=false,u=R,l=new qn}else l=t?[]:f;n:for(;++e<i;){var s=n[e],h=t?t(s):s,s=r||0!==s?s:0;if(o&&h===h){for(var p=l.length;p--;)if(l[p]===h)continue n;t&&l.push(h),f.push(s)}else u(l,h,r)||(l!==f&&l.push(h),f.push(s))}return f}function mr(n,t){return t=Rr(t,n),n=2>t.length?n:It(n,vr(t,0,-1)),
|
|
||||||
null==n||delete n[$e(Ge(t))]}function Ar(n,t,r,e){for(var u=n.length,i=e?u:-1;(e?i--:++i<u)&&t(n[i],i,n););return r?vr(n,e?0:i,e?i+1:u):vr(n,e?i+1:0,e?u:i)}function kr(n,t){var r=n;return r instanceof Mn&&(r=r.value()),h(t,function(n,t){return t.func.apply(t.thisArg,s([n],t.args))},r)}function Er(n,t,r){var e=n.length;if(2>e)return e?wr(n[0]):[];for(var u=-1,i=Hu(e);++u<e;)for(var o=n[u],f=-1;++f<e;)f!=u&&(i[u]=jt(i[u]||o,n[f],t,r));return wr(kt(i,1),t,r)}function Or(n,t,r){for(var e=-1,u=n.length,i=t.length,o={};++e<u;)r(o,n[e],e<i?t[e]:F);
|
|
||||||
return o}function Sr(n){return _u(n)?n:[]}function Ir(n){return typeof n=="function"?n:Nu}function Rr(n,t){return af(n)?n:We(n,t)?[n]:mo(zu(n))}function zr(n,t,r){var e=n.length;return r=r===F?e:r,!t&&r>=e?n:vr(n,t,r)}function Wr(n,t){if(t)return n.slice();var r=n.length,r=yi?yi(r):new n.constructor(r);return n.copy(r),r}function Br(n){var t=new n.constructor(n.byteLength);return new di(t).set(new di(n)),t}function Lr(n,t){return new n.constructor(t?Br(n.buffer):n.buffer,n.byteOffset,n.length)}function Ur(n,t){
|
|
||||||
if(n!==t){var r=n!==F,e=null===n,u=n===n,i=Au(n),o=t!==F,f=null===t,c=t===t,a=Au(t);if(!f&&!a&&!i&&n>t||i&&o&&c&&!f&&!a||e&&o&&c||!r&&c||!u)return 1;if(!e&&!i&&!a&&n<t||a&&r&&u&&!e&&!i||f&&r&&u||!o&&u||!c)return-1}return 0}function Cr(n,t,r,e){var u=-1,i=n.length,o=r.length,f=-1,c=t.length,a=Di(i-o,0),l=Hu(c+a);for(e=!e;++f<c;)l[f]=t[f];for(;++u<o;)(e||u<i)&&(l[r[u]]=n[u]);for(;a--;)l[f++]=n[u++];return l}function Dr(n,t,r,e){var u=-1,i=n.length,o=-1,f=r.length,c=-1,a=t.length,l=Di(i-f,0),s=Hu(l+a);
|
|
||||||
for(e=!e;++u<l;)s[u]=n[u];for(l=u;++c<a;)s[l+c]=t[c];for(;++o<f;)(e||u<i)&&(s[l+r[o]]=n[u++]);return s}function Mr(n,t){var r=-1,e=n.length;for(t||(t=Hu(e));++r<e;)t[r]=n[r];return t}function Tr(n,t,r,e){var u=!r;r||(r={});for(var i=-1,o=t.length;++i<o;){var f=t[i],c=e?e(r[f],n[f],f,r,n):F;c===F&&(c=n[f]),u?_t(r,f,c):at(r,f,c)}return r}function $r(n,t){return Tr(n,vo(n),t)}function Fr(n,t){return Tr(n,go(n),t)}function Nr(n,t){return function(r,u){var i=af(r)?e:st,o=t?t():{};return i(r,n,je(u,2),o);
|
|
||||||
}}function Pr(n){return lr(function(t,r){var e=-1,u=r.length,i=1<u?r[u-1]:F,o=2<u?r[2]:F,i=3<n.length&&typeof i=="function"?(u--,i):F;for(o&&ze(r[0],r[1],o)&&(i=3>u?F:i,u=1),t=ni(t);++e<u;)(o=r[e])&&n(t,o,e,i);return t})}function Zr(n,t){return function(r,e){if(null==r)return r;if(!pu(r))return n(r,e);for(var u=r.length,i=t?u:-1,o=ni(r);(t?i--:++i<u)&&false!==e(o[i],i,o););return r}}function qr(n){return function(t,r,e){var u=-1,i=ni(t);e=e(t);for(var o=e.length;o--;){var f=e[n?o:++u];if(false===r(i[f],f,i))break;
|
|
||||||
}return t}}function Vr(n,t,r){function e(){return(this&&this!==Zn&&this instanceof e?i:n).apply(u?r:this,arguments)}var u=1&t,i=Hr(n);return e}function Kr(n){return function(t){t=zu(t);var r=Bn.test(t)?$(t):F,e=r?r[0]:t.charAt(0);return t=r?zr(r,1).join(""):t.slice(1),e[n]()+t}}function Gr(n){return function(t){return h($u(Tu(t).replace(In,"")),n,"")}}function Hr(n){return function(){var t=arguments;switch(t.length){case 0:return new n;case 1:return new n(t[0]);case 2:return new n(t[0],t[1]);case 3:
|
|
||||||
return new n(t[0],t[1],t[2]);case 4:return new n(t[0],t[1],t[2],t[3]);case 5:return new n(t[0],t[1],t[2],t[3],t[4]);case 6:return new n(t[0],t[1],t[2],t[3],t[4],t[5]);case 7:return new n(t[0],t[1],t[2],t[3],t[4],t[5],t[6])}var r=io(n.prototype),t=n.apply(r,t);return bu(t)?t:r}}function Jr(n,t,e){function u(){for(var o=arguments.length,f=Hu(o),c=o,a=xe(u);c--;)f[c]=arguments[c];return c=3>o&&f[0]!==a&&f[o-1]!==a?[]:C(f,a),o-=c.length,o<e?fe(n,t,Xr,u.placeholder,F,f,c,F,F,e-o):r(this&&this!==Zn&&this instanceof u?i:n,this,f);
|
|
||||||
}var i=Hr(n);return u}function Yr(n){return function(t,r,e){var u=ni(t);if(!pu(t)){var i=je(r,3);t=Lu(t),r=function(n){return i(u[n],n,u)}}return r=n(t,r,e),-1<r?u[i?t[r]:r]:F}}function Qr(n){return ge(function(t){var r=t.length,e=r,u=zn.prototype.thru;for(n&&t.reverse();e--;){var i=t[e];if(typeof i!="function")throw new ei("Expected a function");if(u&&!o&&"wrapper"==be(i))var o=new zn([],true)}for(e=o?e:r;++e<r;)var i=t[e],u=be(i),f="wrapper"==u?_o(i):F,o=f&&Be(f[0])&&424==f[1]&&!f[4].length&&1==f[9]?o[be(f[0])].apply(o,f[3]):1==i.length&&Be(i)?o[u]():o.thru(i);
|
|
||||||
return function(){var n=arguments,e=n[0];if(o&&1==n.length&&af(e))return o.plant(e).value();for(var u=0,n=r?t[u].apply(this,n):e;++u<r;)n=t[u].call(this,n);return n}})}function Xr(n,t,r,e,u,i,o,f,c,a){function l(){for(var d=arguments.length,y=Hu(d),b=d;b--;)y[b]=arguments[b];if(_){var x,j=xe(l),b=y.length;for(x=0;b--;)y[b]===j&&++x}if(e&&(y=Cr(y,e,u,_)),i&&(y=Dr(y,i,o,_)),d-=x,_&&d<a)return j=C(y,j),fe(n,t,Xr,l.placeholder,r,y,j,f,c,a-d);if(j=h?r:this,b=p?j[n]:n,d=y.length,f){x=y.length;for(var w=Mi(f.length,x),m=Mr(y);w--;){
|
|
||||||
var A=f[w];y[w]=Re(A,x)?m[A]:F}}else v&&1<d&&y.reverse();return s&&c<d&&(y.length=c),this&&this!==Zn&&this instanceof l&&(b=g||Hr(b)),b.apply(j,y)}var s=128&t,h=1&t,p=2&t,_=24&t,v=512&t,g=p?F:Hr(n);return l}function ne(n,t){return function(r,e){return Ct(r,n,t(e))}}function te(n,t){return function(r,e){var u;if(r===F&&e===F)return t;if(r!==F&&(u=r),e!==F){if(u===F)return e;typeof r=="string"||typeof e=="string"?(r=jr(r),e=jr(e)):(r=xr(r),e=xr(e)),u=n(r,e)}return u}}function re(n){return ge(function(t){
|
|
||||||
return t=l(t,S(je())),lr(function(e){var u=this;return n(t,function(n){return r(n,u,e)})})})}function ee(n,t){t=t===F?" ":jr(t);var r=t.length;return 2>r?r?ar(t,n):t:(r=ar(t,Ri(n/T(t))),Bn.test(t)?zr($(r),0,n).join(""):r.slice(0,n))}function ue(n,t,e,u){function i(){for(var t=-1,c=arguments.length,a=-1,l=u.length,s=Hu(l+c),h=this&&this!==Zn&&this instanceof i?f:n;++a<l;)s[a]=u[a];for(;c--;)s[a++]=arguments[++t];return r(h,o?e:this,s)}var o=1&t,f=Hr(n);return i}function ie(n){return function(t,r,e){
|
|
||||||
e&&typeof e!="number"&&ze(t,r,e)&&(r=e=F),t=Eu(t),r===F?(r=t,t=0):r=Eu(r),e=e===F?t<r?1:-1:Eu(e);var u=-1;r=Di(Ri((r-t)/(e||1)),0);for(var i=Hu(r);r--;)i[n?r:++u]=t,t+=e;return i}}function oe(n){return function(t,r){return typeof t=="string"&&typeof r=="string"||(t=Iu(t),r=Iu(r)),n(t,r)}}function fe(n,t,r,e,u,i,o,f,c,a){var l=8&t,s=l?o:F;o=l?F:o;var h=l?i:F;return i=l?F:i,t=(t|(l?32:64))&~(l?64:32),4&t||(t&=-4),u=[n,t,u,h,s,i,o,f,c,a],r=r.apply(F,u),Be(n)&&xo(r,u),r.placeholder=e,De(r,n,t)}function ce(n){
|
|
||||||
var t=Xu[n];return function(n,r){if(n=Iu(n),r=null==r?0:Mi(Ou(r),292)){var e=(zu(n)+"e").split("e"),e=t(e[0]+"e"+(+e[1]+r)),e=(zu(e)+"e").split("e");return+(e[0]+"e"+(+e[1]-r))}return t(n)}}function ae(n){return function(t){var r=yo(t);return"[object Map]"==r?L(t):"[object Set]"==r?M(t):O(t,n(t))}}function le(n,t,r,e,u,i,o,f){var c=2&t;if(!c&&typeof n!="function")throw new ei("Expected a function");var a=e?e.length:0;if(a||(t&=-97,e=u=F),o=o===F?o:Di(Ou(o),0),f=f===F?f:Ou(f),a-=u?u.length:0,64&t){
|
|
||||||
var l=e,s=u;e=u=F}var h=c?F:_o(n);return i=[n,t,r,e,u,l,s,i,o,f],h&&(r=i[1],n=h[1],t=r|n,e=128==n&&8==r||128==n&&256==r&&i[7].length<=h[8]||384==n&&h[7].length<=h[8]&&8==r,131>t||e)&&(1&n&&(i[2]=h[2],t|=1&r?0:4),(r=h[3])&&(e=i[3],i[3]=e?Cr(e,r,h[4]):r,i[4]=e?C(i[3],"__lodash_placeholder__"):h[4]),(r=h[5])&&(e=i[5],i[5]=e?Dr(e,r,h[6]):r,i[6]=e?C(i[5],"__lodash_placeholder__"):h[6]),(r=h[7])&&(i[7]=r),128&n&&(i[8]=null==i[8]?h[8]:Mi(i[8],h[8])),null==i[9]&&(i[9]=h[9]),i[0]=h[0],i[1]=t),n=i[0],t=i[1],
|
|
||||||
r=i[2],e=i[3],u=i[4],f=i[9]=i[9]===F?c?0:n.length:Di(i[9]-a,0),!f&&24&t&&(t&=-25),De((h?lo:xo)(t&&1!=t?8==t||16==t?Jr(n,t,f):32!=t&&33!=t||u.length?Xr.apply(F,i):ue(n,t,r,e):Vr(n,t,r),i),n,t)}function se(n,t,r,e){return n===F||hu(n,ii[r])&&!ci.call(e,r)?t:n}function he(n,t,r,e,u,i){return bu(n)&&bu(t)&&(i.set(t,n),nr(n,t,F,he,i),i.delete(t)),n}function pe(n){return wu(n)?F:n}function _e(n,t,r,e,u,i){var o=1&r,f=n.length,c=t.length;if(f!=c&&!(o&&c>f))return false;if((c=i.get(n))&&i.get(t))return c==t;var c=-1,a=true,l=2&r?new qn:F;
|
|
||||||
for(i.set(n,t),i.set(t,n);++c<f;){var s=n[c],h=t[c];if(e)var p=o?e(h,s,c,t,n,i):e(s,h,c,n,t,i);if(p!==F){if(p)continue;a=false;break}if(l){if(!_(t,function(n,t){if(!R(l,t)&&(s===n||u(s,n,r,e,i)))return l.push(t)})){a=false;break}}else if(s!==h&&!u(s,h,r,e,i)){a=false;break}}return i.delete(n),i.delete(t),a}function ve(n,t,r,e,u,i,o){switch(r){case"[object DataView]":if(n.byteLength!=t.byteLength||n.byteOffset!=t.byteOffset)break;n=n.buffer,t=t.buffer;case"[object ArrayBuffer]":if(n.byteLength!=t.byteLength||!i(new di(n),new di(t)))break;
|
|
||||||
return true;case"[object Boolean]":case"[object Date]":case"[object Number]":return hu(+n,+t);case"[object Error]":return n.name==t.name&&n.message==t.message;case"[object RegExp]":case"[object String]":return n==t+"";case"[object Map]":var f=L;case"[object Set]":if(f||(f=D),n.size!=t.size&&!(1&e))break;return(r=o.get(n))?r==t:(e|=2,o.set(n,t),t=_e(f(n),f(t),e,u,i,o),o.delete(n),t);case"[object Symbol]":if(eo)return eo.call(n)==eo.call(t)}return false}function ge(n){return wo(Ce(n,F,Ve),n+"")}function de(n){
|
|
||||||
return Rt(n,Lu,vo)}function ye(n){return Rt(n,Uu,go)}function be(n){for(var t=n.name+"",r=Ji[t],e=ci.call(Ji,t)?r.length:0;e--;){var u=r[e],i=u.func;if(null==i||i==n)return u.name}return t}function xe(n){return(ci.call(On,"placeholder")?On:n).placeholder}function je(){var n=On.iteratee||Pu,n=n===Pu?Gt:n;return arguments.length?n(arguments[0],arguments[1]):n}function we(n,t){var r=n.__data__,e=typeof t;return("string"==e||"number"==e||"symbol"==e||"boolean"==e?"__proto__"!==t:null===t)?r[typeof t=="string"?"string":"hash"]:r.map;
|
|
||||||
}function me(n){for(var t=Lu(n),r=t.length;r--;){var e=t[r],u=n[e];t[r]=[e,u,u===u&&!bu(u)]}return t}function Ae(n,t){var r=null==n?F:n[t];return Zt(r)?r:F}function ke(n,t,r){t=Rr(t,n);for(var e=-1,u=t.length,i=false;++e<u;){var o=$e(t[e]);if(!(i=null!=n&&r(n,o)))break;n=n[o]}return i||++e!=u?i:(u=null==n?0:n.length,!!u&&yu(u)&&Re(o,u)&&(af(n)||cf(n)))}function Ee(n){var t=n.length,r=n.constructor(t);return t&&"string"==typeof n[0]&&ci.call(n,"index")&&(r.index=n.index,r.input=n.input),r}function Oe(n){
|
|
||||||
return typeof n.constructor!="function"||Le(n)?{}:io(bi(n))}function Se(r,e,u,i){var o=r.constructor;switch(e){case"[object ArrayBuffer]":return Br(r);case"[object Boolean]":case"[object Date]":return new o(+r);case"[object DataView]":return e=i?Br(r.buffer):r.buffer,new r.constructor(e,r.byteOffset,r.byteLength);case"[object Float32Array]":case"[object Float64Array]":case"[object Int8Array]":case"[object Int16Array]":case"[object Int32Array]":case"[object Uint8Array]":case"[object Uint8ClampedArray]":
|
|
||||||
case"[object Uint16Array]":case"[object Uint32Array]":return Lr(r,i);case"[object Map]":return e=i?u(L(r),1):L(r),h(e,n,new r.constructor);case"[object Number]":case"[object String]":return new o(r);case"[object RegExp]":return e=new r.constructor(r.source,dn.exec(r)),e.lastIndex=r.lastIndex,e;case"[object Set]":return e=i?u(D(r),1):D(r),h(e,t,new r.constructor);case"[object Symbol]":return eo?ni(eo.call(r)):{}}}function Ie(n){return af(n)||cf(n)||!!(mi&&n&&n[mi])}function Re(n,t){return t=null==t?9007199254740991:t,
|
|
||||||
!!t&&(typeof n=="number"||wn.test(n))&&-1<n&&0==n%1&&n<t}function ze(n,t,r){if(!bu(r))return false;var e=typeof t;return!!("number"==e?pu(r)&&Re(t,r.length):"string"==e&&t in r)&&hu(r[t],n)}function We(n,t){if(af(n))return false;var r=typeof n;return!("number"!=r&&"symbol"!=r&&"boolean"!=r&&null!=n&&!Au(n))||(rn.test(n)||!tn.test(n)||null!=t&&n in ni(t))}function Be(n){var t=be(n),r=On[t];return typeof r=="function"&&t in Mn.prototype&&(n===r||(t=_o(r),!!t&&n===t[0]))}function Le(n){var t=n&&n.constructor;
|
|
||||||
return n===(typeof t=="function"&&t.prototype||ii)}function Ue(n,t){return function(r){return null!=r&&(r[n]===t&&(t!==F||n in ni(r)))}}function Ce(n,t,e){return t=Di(t===F?n.length-1:t,0),function(){for(var u=arguments,i=-1,o=Di(u.length-t,0),f=Hu(o);++i<o;)f[i]=u[t+i];for(i=-1,o=Hu(t+1);++i<t;)o[i]=u[i];return o[t]=e(f),r(n,this,o)}}function De(n,t,r){var e=t+"";t=wo;var u,i=Ne;return u=(u=e.match(hn))?u[1].split(pn):[],r=i(u,r),(i=r.length)&&(u=i-1,r[u]=(1<i?"& ":"")+r[u],r=r.join(2<i?", ":" "),
|
|
||||||
e=e.replace(sn,"{\n/* [wrapped with "+r+"] */\n")),t(n,e)}function Me(n){var t=0,r=0;return function(){var e=Ti(),u=16-(e-r);if(r=e,0<u){if(800<=++t)return arguments[0]}else t=0;return n.apply(F,arguments)}}function Te(n,t){var r=-1,e=n.length,u=e-1;for(t=t===F?e:t;++r<t;){var e=cr(r,u),i=n[e];n[e]=n[r],n[r]=i}return n.length=t,n}function $e(n){if(typeof n=="string"||Au(n))return n;var t=n+"";return"0"==t&&1/n==-N?"-0":t}function Fe(n){if(null!=n){try{return fi.call(n)}catch(n){}return n+""}return"";
|
|
||||||
}function Ne(n,t){return u(Z,function(r){var e="_."+r[0];t&r[1]&&!c(n,e)&&n.push(e)}),n.sort()}function Pe(n){if(n instanceof Mn)return n.clone();var t=new zn(n.__wrapped__,n.__chain__);return t.__actions__=Mr(n.__actions__),t.__index__=n.__index__,t.__values__=n.__values__,t}function Ze(n,t,r){var e=null==n?0:n.length;return e?(r=null==r?0:Ou(r),0>r&&(r=Di(e+r,0)),g(n,je(t,3),r)):-1}function qe(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=e-1;return r!==F&&(u=Ou(r),u=0>r?Di(e+u,0):Mi(u,e-1)),
|
|
||||||
g(n,je(t,3),u,true)}function Ve(n){return(null==n?0:n.length)?kt(n,1):[]}function Ke(n){return n&&n.length?n[0]:F}function Ge(n){var t=null==n?0:n.length;return t?n[t-1]:F}function He(n,t){return n&&n.length&&t&&t.length?or(n,t):n}function Je(n){return null==n?n:Ni.call(n)}function Ye(n){if(!n||!n.length)return[];var t=0;return n=f(n,function(n){if(_u(n))return t=Di(n.length,t),true}),E(t,function(t){return l(n,j(t))})}function Qe(n,t){if(!n||!n.length)return[];var e=Ye(n);return null==t?e:l(e,function(n){
|
|
||||||
return r(t,F,n)})}function Xe(n){return n=On(n),n.__chain__=true,n}function nu(n,t){return t(n)}function tu(){return this}function ru(n,t){return(af(n)?u:oo)(n,je(t,3))}function eu(n,t){return(af(n)?i:fo)(n,je(t,3))}function uu(n,t){return(af(n)?l:Yt)(n,je(t,3))}function iu(n,t,r){return t=r?F:t,t=n&&null==t?n.length:t,le(n,128,F,F,F,F,t)}function ou(n,t){var r;if(typeof t!="function")throw new ei("Expected a function");return n=Ou(n),function(){return 0<--n&&(r=t.apply(this,arguments)),1>=n&&(t=F),
|
|
||||||
r}}function fu(n,t,r){return t=r?F:t,n=le(n,8,F,F,F,F,F,t),n.placeholder=fu.placeholder,n}function cu(n,t,r){return t=r?F:t,n=le(n,16,F,F,F,F,F,t),n.placeholder=cu.placeholder,n}function au(n,t,r){function e(t){var r=c,e=a;return c=a=F,_=t,s=n.apply(e,r)}function u(n){var r=n-p;return n-=_,p===F||r>=t||0>r||g&&n>=l}function i(){var n=Jo();if(u(n))return o(n);var r,e=jo;r=n-_,n=t-(n-p),r=g?Mi(n,l-r):n,h=e(i,r)}function o(n){return h=F,d&&c?e(n):(c=a=F,s)}function f(){var n=Jo(),r=u(n);if(c=arguments,
|
|
||||||
a=this,p=n,r){if(h===F)return _=n=p,h=jo(i,t),v?e(n):s;if(g)return h=jo(i,t),e(p)}return h===F&&(h=jo(i,t)),s}var c,a,l,s,h,p,_=0,v=false,g=false,d=true;if(typeof n!="function")throw new ei("Expected a function");return t=Iu(t)||0,bu(r)&&(v=!!r.leading,l=(g="maxWait"in r)?Di(Iu(r.maxWait)||0,t):l,d="trailing"in r?!!r.trailing:d),f.cancel=function(){h!==F&&ho(h),_=0,c=p=a=h=F},f.flush=function(){return h===F?s:o(Jo())},f}function lu(n,t){function r(){var e=arguments,u=t?t.apply(this,e):e[0],i=r.cache;return i.has(u)?i.get(u):(e=n.apply(this,e),
|
|
||||||
r.cache=i.set(u,e)||i,e)}if(typeof n!="function"||null!=t&&typeof t!="function")throw new ei("Expected a function");return r.cache=new(lu.Cache||Pn),r}function su(n){if(typeof n!="function")throw new ei("Expected a function");return function(){var t=arguments;switch(t.length){case 0:return!n.call(this);case 1:return!n.call(this,t[0]);case 2:return!n.call(this,t[0],t[1]);case 3:return!n.call(this,t[0],t[1],t[2])}return!n.apply(this,t)}}function hu(n,t){return n===t||n!==n&&t!==t}function pu(n){return null!=n&&yu(n.length)&&!gu(n);
|
|
||||||
}function _u(n){return xu(n)&&pu(n)}function vu(n){if(!xu(n))return false;var t=zt(n);return"[object Error]"==t||"[object DOMException]"==t||typeof n.message=="string"&&typeof n.name=="string"&&!wu(n)}function gu(n){return!!bu(n)&&(n=zt(n),"[object Function]"==n||"[object GeneratorFunction]"==n||"[object AsyncFunction]"==n||"[object Proxy]"==n)}function du(n){return typeof n=="number"&&n==Ou(n)}function yu(n){return typeof n=="number"&&-1<n&&0==n%1&&9007199254740991>=n}function bu(n){var t=typeof n;return null!=n&&("object"==t||"function"==t);
|
|
||||||
}function xu(n){return null!=n&&typeof n=="object"}function ju(n){return typeof n=="number"||xu(n)&&"[object Number]"==zt(n)}function wu(n){return!(!xu(n)||"[object Object]"!=zt(n))&&(n=bi(n),null===n||(n=ci.call(n,"constructor")&&n.constructor,typeof n=="function"&&n instanceof n&&fi.call(n)==hi))}function mu(n){return typeof n=="string"||!af(n)&&xu(n)&&"[object String]"==zt(n)}function Au(n){return typeof n=="symbol"||xu(n)&&"[object Symbol]"==zt(n)}function ku(n){if(!n)return[];if(pu(n))return mu(n)?$(n):Mr(n);
|
|
||||||
if(Ai&&n[Ai]){n=n[Ai]();for(var t,r=[];!(t=n.next()).done;)r.push(t.value);return r}return t=yo(n),("[object Map]"==t?L:"[object Set]"==t?D:Du)(n)}function Eu(n){return n?(n=Iu(n),n===N||n===-N?1.7976931348623157e308*(0>n?-1:1):n===n?n:0):0===n?n:0}function Ou(n){n=Eu(n);var t=n%1;return n===n?t?n-t:n:0}function Su(n){return n?gt(Ou(n),0,4294967295):0}function Iu(n){if(typeof n=="number")return n;if(Au(n))return P;if(bu(n)&&(n=typeof n.valueOf=="function"?n.valueOf():n,n=bu(n)?n+"":n),typeof n!="string")return 0===n?n:+n;
|
|
||||||
n=n.replace(cn,"");var t=bn.test(n);return t||jn.test(n)?Fn(n.slice(2),t?2:8):yn.test(n)?P:+n}function Ru(n){return Tr(n,Uu(n))}function zu(n){return null==n?"":jr(n)}function Wu(n,t,r){return n=null==n?F:It(n,t),n===F?r:n}function Bu(n,t){return null!=n&&ke(n,t,Lt)}function Lu(n){return pu(n)?Gn(n):Ht(n)}function Uu(n){if(pu(n))n=Gn(n,true);else if(bu(n)){var t,r=Le(n),e=[];for(t in n)("constructor"!=t||!r&&ci.call(n,t))&&e.push(t);n=e}else{if(t=[],null!=n)for(r in ni(n))t.push(r);n=t}return n}function Cu(n,t){
|
|
||||||
if(null==n)return{};var r=l(ye(n),function(n){return[n]});return t=je(t),ur(n,r,function(n,r){return t(n,r[0])})}function Du(n){return null==n?[]:I(n,Lu(n))}function Mu(n){return Nf(zu(n).toLowerCase())}function Tu(n){return(n=zu(n))&&n.replace(mn,rt).replace(Rn,"")}function $u(n,t,r){return n=zu(n),t=r?F:t,t===F?Ln.test(n)?n.match(Wn)||[]:n.match(_n)||[]:n.match(t)||[]}function Fu(n){return function(){return n}}function Nu(n){return n}function Pu(n){return Gt(typeof n=="function"?n:dt(n,1))}function Zu(n,t,r){
|
|
||||||
var e=Lu(t),i=St(t,e);null!=r||bu(t)&&(i.length||!e.length)||(r=t,t=n,n=this,i=St(t,Lu(t)));var o=!(bu(r)&&"chain"in r&&!r.chain),f=gu(n);return u(i,function(r){var e=t[r];n[r]=e,f&&(n.prototype[r]=function(){var t=this.__chain__;if(o||t){var r=n(this.__wrapped__);return(r.__actions__=Mr(this.__actions__)).push({func:e,args:arguments,thisArg:n}),r.__chain__=t,r}return e.apply(n,s([this.value()],arguments))})}),n}function qu(){}function Vu(n){return We(n)?j($e(n)):ir(n)}function Ku(){return[]}function Gu(){
|
|
||||||
return false}En=null==En?Zn:it.defaults(Zn.Object(),En,it.pick(Zn,Un));var Hu=En.Array,Ju=En.Date,Yu=En.Error,Qu=En.Function,Xu=En.Math,ni=En.Object,ti=En.RegExp,ri=En.String,ei=En.TypeError,ui=Hu.prototype,ii=ni.prototype,oi=En["__core-js_shared__"],fi=Qu.prototype.toString,ci=ii.hasOwnProperty,ai=0,li=function(){var n=/[^.]+$/.exec(oi&&oi.keys&&oi.keys.IE_PROTO||"");return n?"Symbol(src)_1."+n:""}(),si=ii.toString,hi=fi.call(ni),pi=Zn._,_i=ti("^"+fi.call(ci).replace(on,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),vi=Kn?En.Buffer:F,gi=En.Symbol,di=En.Uint8Array,yi=vi?vi.f:F,bi=U(ni.getPrototypeOf,ni),xi=ni.create,ji=ii.propertyIsEnumerable,wi=ui.splice,mi=gi?gi.isConcatSpreadable:F,Ai=gi?gi.iterator:F,ki=gi?gi.toStringTag:F,Ei=function(){
|
|
||||||
try{var n=Ae(ni,"defineProperty");return n({},"",{}),n}catch(n){}}(),Oi=En.clearTimeout!==Zn.clearTimeout&&En.clearTimeout,Si=Ju&&Ju.now!==Zn.Date.now&&Ju.now,Ii=En.setTimeout!==Zn.setTimeout&&En.setTimeout,Ri=Xu.ceil,zi=Xu.floor,Wi=ni.getOwnPropertySymbols,Bi=vi?vi.isBuffer:F,Li=En.isFinite,Ui=ui.join,Ci=U(ni.keys,ni),Di=Xu.max,Mi=Xu.min,Ti=Ju.now,$i=En.parseInt,Fi=Xu.random,Ni=ui.reverse,Pi=Ae(En,"DataView"),Zi=Ae(En,"Map"),qi=Ae(En,"Promise"),Vi=Ae(En,"Set"),Ki=Ae(En,"WeakMap"),Gi=Ae(ni,"create"),Hi=Ki&&new Ki,Ji={},Yi=Fe(Pi),Qi=Fe(Zi),Xi=Fe(qi),no=Fe(Vi),to=Fe(Ki),ro=gi?gi.prototype:F,eo=ro?ro.valueOf:F,uo=ro?ro.toString:F,io=function(){
|
|
||||||
function n(){}return function(t){return bu(t)?xi?xi(t):(n.prototype=t,t=new n,n.prototype=F,t):{}}}();On.templateSettings={escape:Q,evaluate:X,interpolate:nn,variable:"",imports:{_:On}},On.prototype=Sn.prototype,On.prototype.constructor=On,zn.prototype=io(Sn.prototype),zn.prototype.constructor=zn,Mn.prototype=io(Sn.prototype),Mn.prototype.constructor=Mn,Tn.prototype.clear=function(){this.__data__=Gi?Gi(null):{},this.size=0},Tn.prototype.delete=function(n){return n=this.has(n)&&delete this.__data__[n],
|
|
||||||
this.size-=n?1:0,n},Tn.prototype.get=function(n){var t=this.__data__;return Gi?(n=t[n],"__lodash_hash_undefined__"===n?F:n):ci.call(t,n)?t[n]:F},Tn.prototype.has=function(n){var t=this.__data__;return Gi?t[n]!==F:ci.call(t,n)},Tn.prototype.set=function(n,t){var r=this.__data__;return this.size+=this.has(n)?0:1,r[n]=Gi&&t===F?"__lodash_hash_undefined__":t,this},Nn.prototype.clear=function(){this.__data__=[],this.size=0},Nn.prototype.delete=function(n){var t=this.__data__;return n=lt(t,n),!(0>n)&&(n==t.length-1?t.pop():wi.call(t,n,1),
|
|
||||||
--this.size,true)},Nn.prototype.get=function(n){var t=this.__data__;return n=lt(t,n),0>n?F:t[n][1]},Nn.prototype.has=function(n){return-1<lt(this.__data__,n)},Nn.prototype.set=function(n,t){var r=this.__data__,e=lt(r,n);return 0>e?(++this.size,r.push([n,t])):r[e][1]=t,this},Pn.prototype.clear=function(){this.size=0,this.__data__={hash:new Tn,map:new(Zi||Nn),string:new Tn}},Pn.prototype.delete=function(n){return n=we(this,n).delete(n),this.size-=n?1:0,n},Pn.prototype.get=function(n){return we(this,n).get(n);
|
|
||||||
},Pn.prototype.has=function(n){return we(this,n).has(n)},Pn.prototype.set=function(n,t){var r=we(this,n),e=r.size;return r.set(n,t),this.size+=r.size==e?0:1,this},qn.prototype.add=qn.prototype.push=function(n){return this.__data__.set(n,"__lodash_hash_undefined__"),this},qn.prototype.has=function(n){return this.__data__.has(n)},Vn.prototype.clear=function(){this.__data__=new Nn,this.size=0},Vn.prototype.delete=function(n){var t=this.__data__;return n=t.delete(n),this.size=t.size,n},Vn.prototype.get=function(n){
|
|
||||||
return this.__data__.get(n)},Vn.prototype.has=function(n){return this.__data__.has(n)},Vn.prototype.set=function(n,t){var r=this.__data__;if(r instanceof Nn){var e=r.__data__;if(!Zi||199>e.length)return e.push([n,t]),this.size=++r.size,this;r=this.__data__=new Pn(e)}return r.set(n,t),this.size=r.size,this};var oo=Zr(Et),fo=Zr(Ot,true),co=qr(),ao=qr(true),lo=Hi?function(n,t){return Hi.set(n,t),n}:Nu,so=Ei?function(n,t){return Ei(n,"toString",{configurable:true,enumerable:false,value:Fu(t),writable:true})}:Nu,ho=Oi||function(n){
|
|
||||||
return Zn.clearTimeout(n)},po=Vi&&1/D(new Vi([,-0]))[1]==N?function(n){return new Vi(n)}:qu,_o=Hi?function(n){return Hi.get(n)}:qu,vo=Wi?function(n){return null==n?[]:(n=ni(n),f(Wi(n),function(t){return ji.call(n,t)}))}:Ku,go=Wi?function(n){for(var t=[];n;)s(t,vo(n)),n=bi(n);return t}:Ku,yo=zt;(Pi&&"[object DataView]"!=yo(new Pi(new ArrayBuffer(1)))||Zi&&"[object Map]"!=yo(new Zi)||qi&&"[object Promise]"!=yo(qi.resolve())||Vi&&"[object Set]"!=yo(new Vi)||Ki&&"[object WeakMap]"!=yo(new Ki))&&(yo=function(n){
|
|
||||||
var t=zt(n);if(n=(n="[object Object]"==t?n.constructor:F)?Fe(n):"")switch(n){case Yi:return"[object DataView]";case Qi:return"[object Map]";case Xi:return"[object Promise]";case no:return"[object Set]";case to:return"[object WeakMap]"}return t});var bo=oi?gu:Gu,xo=Me(lo),jo=Ii||function(n,t){return Zn.setTimeout(n,t)},wo=Me(so),mo=function(n){n=lu(n,function(n){return 500===t.size&&t.clear(),n});var t=n.cache;return n}(function(n){var t=[];return en.test(n)&&t.push(""),n.replace(un,function(n,r,e,u){
|
|
||||||
t.push(e?u.replace(vn,"$1"):r||n)}),t}),Ao=lr(function(n,t){return _u(n)?jt(n,kt(t,1,_u,true)):[]}),ko=lr(function(n,t){var r=Ge(t);return _u(r)&&(r=F),_u(n)?jt(n,kt(t,1,_u,true),je(r,2)):[]}),Eo=lr(function(n,t){var r=Ge(t);return _u(r)&&(r=F),_u(n)?jt(n,kt(t,1,_u,true),F,r):[]}),Oo=lr(function(n){var t=l(n,Sr);return t.length&&t[0]===n[0]?Ut(t):[]}),So=lr(function(n){var t=Ge(n),r=l(n,Sr);return t===Ge(r)?t=F:r.pop(),r.length&&r[0]===n[0]?Ut(r,je(t,2)):[]}),Io=lr(function(n){var t=Ge(n),r=l(n,Sr);return(t=typeof t=="function"?t:F)&&r.pop(),
|
|
||||||
r.length&&r[0]===n[0]?Ut(r,F,t):[]}),Ro=lr(He),zo=ge(function(n,t){var r=null==n?0:n.length,e=vt(n,t);return fr(n,l(t,function(n){return Re(n,r)?+n:n}).sort(Ur)),e}),Wo=lr(function(n){return wr(kt(n,1,_u,true))}),Bo=lr(function(n){var t=Ge(n);return _u(t)&&(t=F),wr(kt(n,1,_u,true),je(t,2))}),Lo=lr(function(n){var t=Ge(n),t=typeof t=="function"?t:F;return wr(kt(n,1,_u,true),F,t)}),Uo=lr(function(n,t){return _u(n)?jt(n,t):[]}),Co=lr(function(n){return Er(f(n,_u))}),Do=lr(function(n){var t=Ge(n);return _u(t)&&(t=F),
|
|
||||||
Er(f(n,_u),je(t,2))}),Mo=lr(function(n){var t=Ge(n),t=typeof t=="function"?t:F;return Er(f(n,_u),F,t)}),To=lr(Ye),$o=lr(function(n){var t=n.length,t=1<t?n[t-1]:F,t=typeof t=="function"?(n.pop(),t):F;return Qe(n,t)}),Fo=ge(function(n){function t(t){return vt(t,n)}var r=n.length,e=r?n[0]:0,u=this.__wrapped__;return!(1<r||this.__actions__.length)&&u instanceof Mn&&Re(e)?(u=u.slice(e,+e+(r?1:0)),u.__actions__.push({func:nu,args:[t],thisArg:F}),new zn(u,this.__chain__).thru(function(n){return r&&!n.length&&n.push(F),
|
|
||||||
n})):this.thru(t)}),No=Nr(function(n,t,r){ci.call(n,r)?++n[r]:_t(n,r,1)}),Po=Yr(Ze),Zo=Yr(qe),qo=Nr(function(n,t,r){ci.call(n,r)?n[r].push(t):_t(n,r,[t])}),Vo=lr(function(n,t,e){var u=-1,i=typeof t=="function",o=pu(n)?Hu(n.length):[];return oo(n,function(n){o[++u]=i?r(t,n,e):Dt(n,t,e)}),o}),Ko=Nr(function(n,t,r){_t(n,r,t)}),Go=Nr(function(n,t,r){n[r?0:1].push(t)},function(){return[[],[]]}),Ho=lr(function(n,t){if(null==n)return[];var r=t.length;return 1<r&&ze(n,t[0],t[1])?t=[]:2<r&&ze(t[0],t[1],t[2])&&(t=[t[0]]),
|
|
||||||
rr(n,kt(t,1),[])}),Jo=Si||function(){return Zn.Date.now()},Yo=lr(function(n,t,r){var e=1;if(r.length)var u=C(r,xe(Yo)),e=32|e;return le(n,e,t,r,u)}),Qo=lr(function(n,t,r){var e=3;if(r.length)var u=C(r,xe(Qo)),e=32|e;return le(t,e,n,r,u)}),Xo=lr(function(n,t){return xt(n,1,t)}),nf=lr(function(n,t,r){return xt(n,Iu(t)||0,r)});lu.Cache=Pn;var tf=lr(function(n,t){t=1==t.length&&af(t[0])?l(t[0],S(je())):l(kt(t,1),S(je()));var e=t.length;return lr(function(u){for(var i=-1,o=Mi(u.length,e);++i<o;)u[i]=t[i].call(this,u[i]);
|
|
||||||
return r(n,this,u)})}),rf=lr(function(n,t){return le(n,32,F,t,C(t,xe(rf)))}),ef=lr(function(n,t){return le(n,64,F,t,C(t,xe(ef)))}),uf=ge(function(n,t){return le(n,256,F,F,F,t)}),of=oe(Wt),ff=oe(function(n,t){return n>=t}),cf=Mt(function(){return arguments}())?Mt:function(n){return xu(n)&&ci.call(n,"callee")&&!ji.call(n,"callee")},af=Hu.isArray,lf=Hn?S(Hn):Tt,sf=Bi||Gu,hf=Jn?S(Jn):$t,pf=Yn?S(Yn):Nt,_f=Qn?S(Qn):qt,vf=Xn?S(Xn):Vt,gf=nt?S(nt):Kt,df=oe(Jt),yf=oe(function(n,t){return n<=t}),bf=Pr(function(n,t){
|
|
||||||
if(Le(t)||pu(t))Tr(t,Lu(t),n);else for(var r in t)ci.call(t,r)&&at(n,r,t[r])}),xf=Pr(function(n,t){Tr(t,Uu(t),n)}),jf=Pr(function(n,t,r,e){Tr(t,Uu(t),n,e)}),wf=Pr(function(n,t,r,e){Tr(t,Lu(t),n,e)}),mf=ge(vt),Af=lr(function(n){return n.push(F,se),r(jf,F,n)}),kf=lr(function(n){return n.push(F,he),r(Rf,F,n)}),Ef=ne(function(n,t,r){n[t]=r},Fu(Nu)),Of=ne(function(n,t,r){ci.call(n,t)?n[t].push(r):n[t]=[r]},je),Sf=lr(Dt),If=Pr(function(n,t,r){nr(n,t,r)}),Rf=Pr(function(n,t,r,e){nr(n,t,r,e)}),zf=ge(function(n,t){
|
|
||||||
var r={};if(null==n)return r;var e=false;t=l(t,function(t){return t=Rr(t,n),e||(e=1<t.length),t}),Tr(n,ye(n),r),e&&(r=dt(r,7,pe));for(var u=t.length;u--;)mr(r,t[u]);return r}),Wf=ge(function(n,t){return null==n?{}:er(n,t)}),Bf=ae(Lu),Lf=ae(Uu),Uf=Gr(function(n,t,r){return t=t.toLowerCase(),n+(r?Mu(t):t)}),Cf=Gr(function(n,t,r){return n+(r?"-":"")+t.toLowerCase()}),Df=Gr(function(n,t,r){return n+(r?" ":"")+t.toLowerCase()}),Mf=Kr("toLowerCase"),Tf=Gr(function(n,t,r){return n+(r?"_":"")+t.toLowerCase();
|
|
||||||
}),$f=Gr(function(n,t,r){return n+(r?" ":"")+Nf(t)}),Ff=Gr(function(n,t,r){return n+(r?" ":"")+t.toUpperCase()}),Nf=Kr("toUpperCase"),Pf=lr(function(n,t){try{return r(n,F,t)}catch(n){return vu(n)?n:new Yu(n)}}),Zf=ge(function(n,t){return u(t,function(t){t=$e(t),_t(n,t,Yo(n[t],n))}),n}),qf=Qr(),Vf=Qr(true),Kf=lr(function(n,t){return function(r){return Dt(r,n,t)}}),Gf=lr(function(n,t){return function(r){return Dt(n,r,t)}}),Hf=re(l),Jf=re(o),Yf=re(_),Qf=ie(),Xf=ie(true),nc=te(function(n,t){return n+t},0),tc=ce("ceil"),rc=te(function(n,t){
|
|
||||||
return n/t},1),ec=ce("floor"),uc=te(function(n,t){return n*t},1),ic=ce("round"),oc=te(function(n,t){return n-t},0);return On.after=function(n,t){if(typeof t!="function")throw new ei("Expected a function");return n=Ou(n),function(){if(1>--n)return t.apply(this,arguments)}},On.ary=iu,On.assign=bf,On.assignIn=xf,On.assignInWith=jf,On.assignWith=wf,On.at=mf,On.before=ou,On.bind=Yo,On.bindAll=Zf,On.bindKey=Qo,On.castArray=function(){if(!arguments.length)return[];var n=arguments[0];return af(n)?n:[n]},
|
|
||||||
On.chain=Xe,On.chunk=function(n,t,r){if(t=(r?ze(n,t,r):t===F)?1:Di(Ou(t),0),r=null==n?0:n.length,!r||1>t)return[];for(var e=0,u=0,i=Hu(Ri(r/t));e<r;)i[u++]=vr(n,e,e+=t);return i},On.compact=function(n){for(var t=-1,r=null==n?0:n.length,e=0,u=[];++t<r;){var i=n[t];i&&(u[e++]=i)}return u},On.concat=function(){var n=arguments.length;if(!n)return[];for(var t=Hu(n-1),r=arguments[0];n--;)t[n-1]=arguments[n];return s(af(r)?Mr(r):[r],kt(t,1))},On.cond=function(n){var t=null==n?0:n.length,e=je();return n=t?l(n,function(n){
|
|
||||||
if("function"!=typeof n[1])throw new ei("Expected a function");return[e(n[0]),n[1]]}):[],lr(function(e){for(var u=-1;++u<t;){var i=n[u];if(r(i[0],this,e))return r(i[1],this,e)}})},On.conforms=function(n){return yt(dt(n,1))},On.constant=Fu,On.countBy=No,On.create=function(n,t){var r=io(n);return null==t?r:ht(r,t)},On.curry=fu,On.curryRight=cu,On.debounce=au,On.defaults=Af,On.defaultsDeep=kf,On.defer=Xo,On.delay=nf,On.difference=Ao,On.differenceBy=ko,On.differenceWith=Eo,On.drop=function(n,t,r){var e=null==n?0:n.length;
|
|
||||||
return e?(t=r||t===F?1:Ou(t),vr(n,0>t?0:t,e)):[]},On.dropRight=function(n,t,r){var e=null==n?0:n.length;return e?(t=r||t===F?1:Ou(t),t=e-t,vr(n,0,0>t?0:t)):[]},On.dropRightWhile=function(n,t){return n&&n.length?Ar(n,je(t,3),true,true):[]},On.dropWhile=function(n,t){return n&&n.length?Ar(n,je(t,3),true):[]},On.fill=function(n,t,r,e){var u=null==n?0:n.length;if(!u)return[];for(r&&typeof r!="number"&&ze(n,t,r)&&(r=0,e=u),u=n.length,r=Ou(r),0>r&&(r=-r>u?0:u+r),e=e===F||e>u?u:Ou(e),0>e&&(e+=u),e=r>e?0:Su(e);r<e;)n[r++]=t;
|
|
||||||
return n},On.filter=function(n,t){return(af(n)?f:At)(n,je(t,3))},On.flatMap=function(n,t){return kt(uu(n,t),1)},On.flatMapDeep=function(n,t){return kt(uu(n,t),N)},On.flatMapDepth=function(n,t,r){return r=r===F?1:Ou(r),kt(uu(n,t),r)},On.flatten=Ve,On.flattenDeep=function(n){return(null==n?0:n.length)?kt(n,N):[]},On.flattenDepth=function(n,t){return null!=n&&n.length?(t=t===F?1:Ou(t),kt(n,t)):[]},On.flip=function(n){return le(n,512)},On.flow=qf,On.flowRight=Vf,On.fromPairs=function(n){for(var t=-1,r=null==n?0:n.length,e={};++t<r;){
|
|
||||||
var u=n[t];e[u[0]]=u[1]}return e},On.functions=function(n){return null==n?[]:St(n,Lu(n))},On.functionsIn=function(n){return null==n?[]:St(n,Uu(n))},On.groupBy=qo,On.initial=function(n){return(null==n?0:n.length)?vr(n,0,-1):[]},On.intersection=Oo,On.intersectionBy=So,On.intersectionWith=Io,On.invert=Ef,On.invertBy=Of,On.invokeMap=Vo,On.iteratee=Pu,On.keyBy=Ko,On.keys=Lu,On.keysIn=Uu,On.map=uu,On.mapKeys=function(n,t){var r={};return t=je(t,3),Et(n,function(n,e,u){_t(r,t(n,e,u),n)}),r},On.mapValues=function(n,t){
|
|
||||||
var r={};return t=je(t,3),Et(n,function(n,e,u){_t(r,e,t(n,e,u))}),r},On.matches=function(n){return Qt(dt(n,1))},On.matchesProperty=function(n,t){return Xt(n,dt(t,1))},On.memoize=lu,On.merge=If,On.mergeWith=Rf,On.method=Kf,On.methodOf=Gf,On.mixin=Zu,On.negate=su,On.nthArg=function(n){return n=Ou(n),lr(function(t){return tr(t,n)})},On.omit=zf,On.omitBy=function(n,t){return Cu(n,su(je(t)))},On.once=function(n){return ou(2,n)},On.orderBy=function(n,t,r,e){return null==n?[]:(af(t)||(t=null==t?[]:[t]),
|
|
||||||
r=e?F:r,af(r)||(r=null==r?[]:[r]),rr(n,t,r))},On.over=Hf,On.overArgs=tf,On.overEvery=Jf,On.overSome=Yf,On.partial=rf,On.partialRight=ef,On.partition=Go,On.pick=Wf,On.pickBy=Cu,On.property=Vu,On.propertyOf=function(n){return function(t){return null==n?F:It(n,t)}},On.pull=Ro,On.pullAll=He,On.pullAllBy=function(n,t,r){return n&&n.length&&t&&t.length?or(n,t,je(r,2)):n},On.pullAllWith=function(n,t,r){return n&&n.length&&t&&t.length?or(n,t,F,r):n},On.pullAt=zo,On.range=Qf,On.rangeRight=Xf,On.rearg=uf,On.reject=function(n,t){
|
|
||||||
return(af(n)?f:At)(n,su(je(t,3)))},On.remove=function(n,t){var r=[];if(!n||!n.length)return r;var e=-1,u=[],i=n.length;for(t=je(t,3);++e<i;){var o=n[e];t(o,e,n)&&(r.push(o),u.push(e))}return fr(n,u),r},On.rest=function(n,t){if(typeof n!="function")throw new ei("Expected a function");return t=t===F?t:Ou(t),lr(n,t)},On.reverse=Je,On.sampleSize=function(n,t,r){return t=(r?ze(n,t,r):t===F)?1:Ou(t),(af(n)?ot:hr)(n,t)},On.set=function(n,t,r){return null==n?n:pr(n,t,r)},On.setWith=function(n,t,r,e){return e=typeof e=="function"?e:F,
|
|
||||||
null==n?n:pr(n,t,r,e)},On.shuffle=function(n){return(af(n)?ft:_r)(n)},On.slice=function(n,t,r){var e=null==n?0:n.length;return e?(r&&typeof r!="number"&&ze(n,t,r)?(t=0,r=e):(t=null==t?0:Ou(t),r=r===F?e:Ou(r)),vr(n,t,r)):[]},On.sortBy=Ho,On.sortedUniq=function(n){return n&&n.length?br(n):[]},On.sortedUniqBy=function(n,t){return n&&n.length?br(n,je(t,2)):[]},On.split=function(n,t,r){return r&&typeof r!="number"&&ze(n,t,r)&&(t=r=F),r=r===F?4294967295:r>>>0,r?(n=zu(n))&&(typeof t=="string"||null!=t&&!_f(t))&&(t=jr(t),
|
|
||||||
!t&&Bn.test(n))?zr($(n),0,r):n.split(t,r):[]},On.spread=function(n,t){if(typeof n!="function")throw new ei("Expected a function");return t=null==t?0:Di(Ou(t),0),lr(function(e){var u=e[t];return e=zr(e,0,t),u&&s(e,u),r(n,this,e)})},On.tail=function(n){var t=null==n?0:n.length;return t?vr(n,1,t):[]},On.take=function(n,t,r){return n&&n.length?(t=r||t===F?1:Ou(t),vr(n,0,0>t?0:t)):[]},On.takeRight=function(n,t,r){var e=null==n?0:n.length;return e?(t=r||t===F?1:Ou(t),t=e-t,vr(n,0>t?0:t,e)):[]},On.takeRightWhile=function(n,t){
|
|
||||||
return n&&n.length?Ar(n,je(t,3),false,true):[]},On.takeWhile=function(n,t){return n&&n.length?Ar(n,je(t,3)):[]},On.tap=function(n,t){return t(n),n},On.throttle=function(n,t,r){var e=true,u=true;if(typeof n!="function")throw new ei("Expected a function");return bu(r)&&(e="leading"in r?!!r.leading:e,u="trailing"in r?!!r.trailing:u),au(n,t,{leading:e,maxWait:t,trailing:u})},On.thru=nu,On.toArray=ku,On.toPairs=Bf,On.toPairsIn=Lf,On.toPath=function(n){return af(n)?l(n,$e):Au(n)?[n]:Mr(mo(zu(n)))},On.toPlainObject=Ru,
|
|
||||||
On.transform=function(n,t,r){var e=af(n),i=e||sf(n)||gf(n);if(t=je(t,4),null==r){var o=n&&n.constructor;r=i?e?new o:[]:bu(n)&&gu(o)?io(bi(n)):{}}return(i?u:Et)(n,function(n,e,u){return t(r,n,e,u)}),r},On.unary=function(n){return iu(n,1)},On.union=Wo,On.unionBy=Bo,On.unionWith=Lo,On.uniq=function(n){return n&&n.length?wr(n):[]},On.uniqBy=function(n,t){return n&&n.length?wr(n,je(t,2)):[]},On.uniqWith=function(n,t){return t=typeof t=="function"?t:F,n&&n.length?wr(n,F,t):[]},On.unset=function(n,t){return null==n||mr(n,t);
|
|
||||||
},On.unzip=Ye,On.unzipWith=Qe,On.update=function(n,t,r){return null==n?n:pr(n,t,Ir(r)(It(n,t)),void 0)},On.updateWith=function(n,t,r,e){return e=typeof e=="function"?e:F,null!=n&&(n=pr(n,t,Ir(r)(It(n,t)),e)),n},On.values=Du,On.valuesIn=function(n){return null==n?[]:I(n,Uu(n))},On.without=Uo,On.words=$u,On.wrap=function(n,t){return rf(Ir(t),n)},On.xor=Co,On.xorBy=Do,On.xorWith=Mo,On.zip=To,On.zipObject=function(n,t){return Or(n||[],t||[],at)},On.zipObjectDeep=function(n,t){return Or(n||[],t||[],pr);
|
|
||||||
},On.zipWith=$o,On.entries=Bf,On.entriesIn=Lf,On.extend=xf,On.extendWith=jf,Zu(On,On),On.add=nc,On.attempt=Pf,On.camelCase=Uf,On.capitalize=Mu,On.ceil=tc,On.clamp=function(n,t,r){return r===F&&(r=t,t=F),r!==F&&(r=Iu(r),r=r===r?r:0),t!==F&&(t=Iu(t),t=t===t?t:0),gt(Iu(n),t,r)},On.clone=function(n){return dt(n,4)},On.cloneDeep=function(n){return dt(n,5)},On.cloneDeepWith=function(n,t){return t=typeof t=="function"?t:F,dt(n,5,t)},On.cloneWith=function(n,t){return t=typeof t=="function"?t:F,dt(n,4,t)},
|
|
||||||
On.conformsTo=function(n,t){return null==t||bt(n,t,Lu(t))},On.deburr=Tu,On.defaultTo=function(n,t){return null==n||n!==n?t:n},On.divide=rc,On.endsWith=function(n,t,r){n=zu(n),t=jr(t);var e=n.length,e=r=r===F?e:gt(Ou(r),0,e);return r-=t.length,0<=r&&n.slice(r,e)==t},On.eq=hu,On.escape=function(n){return(n=zu(n))&&Y.test(n)?n.replace(H,et):n},On.escapeRegExp=function(n){return(n=zu(n))&&fn.test(n)?n.replace(on,"\\$&"):n},On.every=function(n,t,r){var e=af(n)?o:wt;return r&&ze(n,t,r)&&(t=F),e(n,je(t,3));
|
|
||||||
},On.find=Po,On.findIndex=Ze,On.findKey=function(n,t){return v(n,je(t,3),Et)},On.findLast=Zo,On.findLastIndex=qe,On.findLastKey=function(n,t){return v(n,je(t,3),Ot)},On.floor=ec,On.forEach=ru,On.forEachRight=eu,On.forIn=function(n,t){return null==n?n:co(n,je(t,3),Uu)},On.forInRight=function(n,t){return null==n?n:ao(n,je(t,3),Uu)},On.forOwn=function(n,t){return n&&Et(n,je(t,3))},On.forOwnRight=function(n,t){return n&&Ot(n,je(t,3))},On.get=Wu,On.gt=of,On.gte=ff,On.has=function(n,t){return null!=n&&ke(n,t,Bt);
|
|
||||||
},On.hasIn=Bu,On.head=Ke,On.identity=Nu,On.includes=function(n,t,r,e){return n=pu(n)?n:Du(n),r=r&&!e?Ou(r):0,e=n.length,0>r&&(r=Di(e+r,0)),mu(n)?r<=e&&-1<n.indexOf(t,r):!!e&&-1<d(n,t,r)},On.indexOf=function(n,t,r){var e=null==n?0:n.length;return e?(r=null==r?0:Ou(r),0>r&&(r=Di(e+r,0)),d(n,t,r)):-1},On.inRange=function(n,t,r){return t=Eu(t),r===F?(r=t,t=0):r=Eu(r),n=Iu(n),n>=Mi(t,r)&&n<Di(t,r)},On.invoke=Sf,On.isArguments=cf,On.isArray=af,On.isArrayBuffer=lf,On.isArrayLike=pu,On.isArrayLikeObject=_u,
|
|
||||||
On.isBoolean=function(n){return true===n||false===n||xu(n)&&"[object Boolean]"==zt(n)},On.isBuffer=sf,On.isDate=hf,On.isElement=function(n){return xu(n)&&1===n.nodeType&&!wu(n)},On.isEmpty=function(n){if(null==n)return true;if(pu(n)&&(af(n)||typeof n=="string"||typeof n.splice=="function"||sf(n)||gf(n)||cf(n)))return!n.length;var t=yo(n);if("[object Map]"==t||"[object Set]"==t)return!n.size;if(Le(n))return!Ht(n).length;for(var r in n)if(ci.call(n,r))return false;return true},On.isEqual=function(n,t){return Ft(n,t);
|
|
||||||
},On.isEqualWith=function(n,t,r){var e=(r=typeof r=="function"?r:F)?r(n,t):F;return e===F?Ft(n,t,F,r):!!e},On.isError=vu,On.isFinite=function(n){return typeof n=="number"&&Li(n)},On.isFunction=gu,On.isInteger=du,On.isLength=yu,On.isMap=pf,On.isMatch=function(n,t){return n===t||Pt(n,t,me(t))},On.isMatchWith=function(n,t,r){return r=typeof r=="function"?r:F,Pt(n,t,me(t),r)},On.isNaN=function(n){return ju(n)&&n!=+n},On.isNative=function(n){if(bo(n))throw new Yu("Unsupported core-js use. Try https://npms.io/search?q=ponyfill.");
|
|
||||||
return Zt(n)},On.isNil=function(n){return null==n},On.isNull=function(n){return null===n},On.isNumber=ju,On.isObject=bu,On.isObjectLike=xu,On.isPlainObject=wu,On.isRegExp=_f,On.isSafeInteger=function(n){return du(n)&&-9007199254740991<=n&&9007199254740991>=n},On.isSet=vf,On.isString=mu,On.isSymbol=Au,On.isTypedArray=gf,On.isUndefined=function(n){return n===F},On.isWeakMap=function(n){return xu(n)&&"[object WeakMap]"==yo(n)},On.isWeakSet=function(n){return xu(n)&&"[object WeakSet]"==zt(n)},On.join=function(n,t){
|
|
||||||
return null==n?"":Ui.call(n,t)},On.kebabCase=Cf,On.last=Ge,On.lastIndexOf=function(n,t,r){var e=null==n?0:n.length;if(!e)return-1;var u=e;if(r!==F&&(u=Ou(r),u=0>u?Di(e+u,0):Mi(u,e-1)),t===t){for(r=u+1;r--&&n[r]!==t;);n=r}else n=g(n,b,u,true);return n},On.lowerCase=Df,On.lowerFirst=Mf,On.lt=df,On.lte=yf,On.max=function(n){return n&&n.length?mt(n,Nu,Wt):F},On.maxBy=function(n,t){return n&&n.length?mt(n,je(t,2),Wt):F},On.mean=function(n){return x(n,Nu)},On.meanBy=function(n,t){return x(n,je(t,2))},On.min=function(n){
|
|
||||||
return n&&n.length?mt(n,Nu,Jt):F},On.minBy=function(n,t){return n&&n.length?mt(n,je(t,2),Jt):F},On.stubArray=Ku,On.stubFalse=Gu,On.stubObject=function(){return{}},On.stubString=function(){return""},On.stubTrue=function(){return true},On.multiply=uc,On.nth=function(n,t){return n&&n.length?tr(n,Ou(t)):F},On.noConflict=function(){return Zn._===this&&(Zn._=pi),this},On.noop=qu,On.now=Jo,On.pad=function(n,t,r){n=zu(n);var e=(t=Ou(t))?T(n):0;return!t||e>=t?n:(t=(t-e)/2,ee(zi(t),r)+n+ee(Ri(t),r))},On.padEnd=function(n,t,r){
|
|
||||||
n=zu(n);var e=(t=Ou(t))?T(n):0;return t&&e<t?n+ee(t-e,r):n},On.padStart=function(n,t,r){n=zu(n);var e=(t=Ou(t))?T(n):0;return t&&e<t?ee(t-e,r)+n:n},On.parseInt=function(n,t,r){return r||null==t?t=0:t&&(t=+t),$i(zu(n).replace(an,""),t||0)},On.random=function(n,t,r){if(r&&typeof r!="boolean"&&ze(n,t,r)&&(t=r=F),r===F&&(typeof t=="boolean"?(r=t,t=F):typeof n=="boolean"&&(r=n,n=F)),n===F&&t===F?(n=0,t=1):(n=Eu(n),t===F?(t=n,n=0):t=Eu(t)),n>t){var e=n;n=t,t=e}return r||n%1||t%1?(r=Fi(),Mi(n+r*(t-n+$n("1e-"+((r+"").length-1))),t)):cr(n,t);
|
|
||||||
},On.reduce=function(n,t,r){var e=af(n)?h:m,u=3>arguments.length;return e(n,je(t,4),r,u,oo)},On.reduceRight=function(n,t,r){var e=af(n)?p:m,u=3>arguments.length;return e(n,je(t,4),r,u,fo)},On.repeat=function(n,t,r){return t=(r?ze(n,t,r):t===F)?1:Ou(t),ar(zu(n),t)},On.replace=function(){var n=arguments,t=zu(n[0]);return 3>n.length?t:t.replace(n[1],n[2])},On.result=function(n,t,r){t=Rr(t,n);var e=-1,u=t.length;for(u||(u=1,n=F);++e<u;){var i=null==n?F:n[$e(t[e])];i===F&&(e=u,i=r),n=gu(i)?i.call(n):i;
|
|
||||||
}return n},On.round=ic,On.runInContext=w,On.sample=function(n){return(af(n)?tt:sr)(n)},On.size=function(n){if(null==n)return 0;if(pu(n))return mu(n)?T(n):n.length;var t=yo(n);return"[object Map]"==t||"[object Set]"==t?n.size:Ht(n).length},On.snakeCase=Tf,On.some=function(n,t,r){var e=af(n)?_:gr;return r&&ze(n,t,r)&&(t=F),e(n,je(t,3))},On.sortedIndex=function(n,t){return dr(n,t)},On.sortedIndexBy=function(n,t,r){return yr(n,t,je(r,2))},On.sortedIndexOf=function(n,t){var r=null==n?0:n.length;if(r){
|
|
||||||
var e=dr(n,t);if(e<r&&hu(n[e],t))return e}return-1},On.sortedLastIndex=function(n,t){return dr(n,t,true)},On.sortedLastIndexBy=function(n,t,r){return yr(n,t,je(r,2),true)},On.sortedLastIndexOf=function(n,t){if(null==n?0:n.length){var r=dr(n,t,true)-1;if(hu(n[r],t))return r}return-1},On.startCase=$f,On.startsWith=function(n,t,r){return n=zu(n),r=null==r?0:gt(Ou(r),0,n.length),t=jr(t),n.slice(r,r+t.length)==t},On.subtract=oc,On.sum=function(n){return n&&n.length?k(n,Nu):0},On.sumBy=function(n,t){return n&&n.length?k(n,je(t,2)):0;
|
|
||||||
},On.template=function(n,t,r){var e=On.templateSettings;r&&ze(n,t,r)&&(t=F),n=zu(n),t=jf({},t,e,se),r=jf({},t.imports,e.imports,se);var u,i,o=Lu(r),f=I(r,o),c=0;r=t.interpolate||An;var a="__p+='";r=ti((t.escape||An).source+"|"+r.source+"|"+(r===nn?gn:An).source+"|"+(t.evaluate||An).source+"|$","g");var l="sourceURL"in t?"//# sourceURL="+t.sourceURL+"\n":"";if(n.replace(r,function(t,r,e,o,f,l){return e||(e=o),a+=n.slice(c,l).replace(kn,B),r&&(u=true,a+="'+__e("+r+")+'"),f&&(i=true,a+="';"+f+";\n__p+='"),
|
|
||||||
e&&(a+="'+((__t=("+e+"))==null?'':__t)+'"),c=l+t.length,t}),a+="';",(t=t.variable)||(a="with(obj){"+a+"}"),a=(i?a.replace(q,""):a).replace(V,"$1").replace(K,"$1;"),a="function("+(t||"obj")+"){"+(t?"":"obj||(obj={});")+"var __t,__p=''"+(u?",__e=_.escape":"")+(i?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+a+"return __p}",t=Pf(function(){return Qu(o,l+"return "+a).apply(F,f)}),t.source=a,vu(t))throw t;return t},On.times=function(n,t){if(n=Ou(n),1>n||9007199254740991<n)return[];
|
|
||||||
var r=4294967295,e=Mi(n,4294967295);for(t=je(t),n-=4294967295,e=E(e,t);++r<n;)t(r);return e},On.toFinite=Eu,On.toInteger=Ou,On.toLength=Su,On.toLower=function(n){return zu(n).toLowerCase()},On.toNumber=Iu,On.toSafeInteger=function(n){return n?gt(Ou(n),-9007199254740991,9007199254740991):0===n?n:0},On.toString=zu,On.toUpper=function(n){return zu(n).toUpperCase()},On.trim=function(n,t,r){return(n=zu(n))&&(r||t===F)?n.replace(cn,""):n&&(t=jr(t))?(n=$(n),r=$(t),t=z(n,r),r=W(n,r)+1,zr(n,t,r).join("")):n;
|
|
||||||
},On.trimEnd=function(n,t,r){return(n=zu(n))&&(r||t===F)?n.replace(ln,""):n&&(t=jr(t))?(n=$(n),t=W(n,$(t))+1,zr(n,0,t).join("")):n},On.trimStart=function(n,t,r){return(n=zu(n))&&(r||t===F)?n.replace(an,""):n&&(t=jr(t))?(n=$(n),t=z(n,$(t)),zr(n,t).join("")):n},On.truncate=function(n,t){var r=30,e="...";if(bu(t))var u="separator"in t?t.separator:u,r="length"in t?Ou(t.length):r,e="omission"in t?jr(t.omission):e;n=zu(n);var i=n.length;if(Bn.test(n))var o=$(n),i=o.length;if(r>=i)return n;if(i=r-T(e),1>i)return e;
|
|
||||||
if(r=o?zr(o,0,i).join(""):n.slice(0,i),u===F)return r+e;if(o&&(i+=r.length-i),_f(u)){if(n.slice(i).search(u)){var f=r;for(u.global||(u=ti(u.source,zu(dn.exec(u))+"g")),u.lastIndex=0;o=u.exec(f);)var c=o.index;r=r.slice(0,c===F?i:c)}}else n.indexOf(jr(u),i)!=i&&(u=r.lastIndexOf(u),-1<u&&(r=r.slice(0,u)));return r+e},On.unescape=function(n){return(n=zu(n))&&J.test(n)?n.replace(G,ut):n},On.uniqueId=function(n){var t=++ai;return zu(n)+t},On.upperCase=Ff,On.upperFirst=Nf,On.each=ru,On.eachRight=eu,On.first=Ke,
|
|
||||||
Zu(On,function(){var n={};return Et(On,function(t,r){ci.call(On.prototype,r)||(n[r]=t)}),n}(),{chain:false}),On.VERSION="4.17.4",u("bind bindKey curry curryRight partial partialRight".split(" "),function(n){On[n].placeholder=On}),u(["drop","take"],function(n,t){Mn.prototype[n]=function(r){r=r===F?1:Di(Ou(r),0);var e=this.__filtered__&&!t?new Mn(this):this.clone();return e.__filtered__?e.__takeCount__=Mi(r,e.__takeCount__):e.__views__.push({size:Mi(r,4294967295),type:n+(0>e.__dir__?"Right":"")}),e},Mn.prototype[n+"Right"]=function(t){
|
|
||||||
return this.reverse()[n](t).reverse()}}),u(["filter","map","takeWhile"],function(n,t){var r=t+1,e=1==r||3==r;Mn.prototype[n]=function(n){var t=this.clone();return t.__iteratees__.push({iteratee:je(n,3),type:r}),t.__filtered__=t.__filtered__||e,t}}),u(["head","last"],function(n,t){var r="take"+(t?"Right":"");Mn.prototype[n]=function(){return this[r](1).value()[0]}}),u(["initial","tail"],function(n,t){var r="drop"+(t?"":"Right");Mn.prototype[n]=function(){return this.__filtered__?new Mn(this):this[r](1);
|
|
||||||
}}),Mn.prototype.compact=function(){return this.filter(Nu)},Mn.prototype.find=function(n){return this.filter(n).head()},Mn.prototype.findLast=function(n){return this.reverse().find(n)},Mn.prototype.invokeMap=lr(function(n,t){return typeof n=="function"?new Mn(this):this.map(function(r){return Dt(r,n,t)})}),Mn.prototype.reject=function(n){return this.filter(su(je(n)))},Mn.prototype.slice=function(n,t){n=Ou(n);var r=this;return r.__filtered__&&(0<n||0>t)?new Mn(r):(0>n?r=r.takeRight(-n):n&&(r=r.drop(n)),
|
|
||||||
t!==F&&(t=Ou(t),r=0>t?r.dropRight(-t):r.take(t-n)),r)},Mn.prototype.takeRightWhile=function(n){return this.reverse().takeWhile(n).reverse()},Mn.prototype.toArray=function(){return this.take(4294967295)},Et(Mn.prototype,function(n,t){var r=/^(?:filter|find|map|reject)|While$/.test(t),e=/^(?:head|last)$/.test(t),u=On[e?"take"+("last"==t?"Right":""):t],i=e||/^find/.test(t);u&&(On.prototype[t]=function(){function t(n){return n=u.apply(On,s([n],f)),e&&h?n[0]:n}var o=this.__wrapped__,f=e?[1]:arguments,c=o instanceof Mn,a=f[0],l=c||af(o);
|
|
||||||
l&&r&&typeof a=="function"&&1!=a.length&&(c=l=false);var h=this.__chain__,p=!!this.__actions__.length,a=i&&!h,c=c&&!p;return!i&&l?(o=c?o:new Mn(this),o=n.apply(o,f),o.__actions__.push({func:nu,args:[t],thisArg:F}),new zn(o,h)):a&&c?n.apply(this,f):(o=this.thru(t),a?e?o.value()[0]:o.value():o)})}),u("pop push shift sort splice unshift".split(" "),function(n){var t=ui[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:pop|shift)$/.test(n);On.prototype[n]=function(){var n=arguments;if(e&&!this.__chain__){
|
|
||||||
var u=this.value();return t.apply(af(u)?u:[],n)}return this[r](function(r){return t.apply(af(r)?r:[],n)})}}),Et(Mn.prototype,function(n,t){var r=On[t];if(r){var e=r.name+"";(Ji[e]||(Ji[e]=[])).push({name:t,func:r})}}),Ji[Xr(F,2).name]=[{name:"wrapper",func:F}],Mn.prototype.clone=function(){var n=new Mn(this.__wrapped__);return n.__actions__=Mr(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=Mr(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=Mr(this.__views__),
|
|
||||||
n},Mn.prototype.reverse=function(){if(this.__filtered__){var n=new Mn(this);n.__dir__=-1,n.__filtered__=true}else n=this.clone(),n.__dir__*=-1;return n},Mn.prototype.value=function(){var n,t=this.__wrapped__.value(),r=this.__dir__,e=af(t),u=0>r,i=e?t.length:0;n=i;for(var o=this.__views__,f=0,c=-1,a=o.length;++c<a;){var l=o[c],s=l.size;switch(l.type){case"drop":f+=s;break;case"dropRight":n-=s;break;case"take":n=Mi(n,f+s);break;case"takeRight":f=Di(f,n-s)}}if(n={start:f,end:n},o=n.start,f=n.end,n=f-o,
|
|
||||||
o=u?f:o-1,f=this.__iteratees__,c=f.length,a=0,l=Mi(n,this.__takeCount__),!e||!u&&i==n&&l==n)return kr(t,this.__actions__);e=[];n:for(;n--&&a<l;){for(o+=r,u=-1,i=t[o];++u<c;){var h=f[u],s=h.type,h=(0,h.iteratee)(i);if(2==s)i=h;else if(!h){if(1==s)continue n;break n}}e[a++]=i}return e},On.prototype.at=Fo,On.prototype.chain=function(){return Xe(this)},On.prototype.commit=function(){return new zn(this.value(),this.__chain__)},On.prototype.next=function(){this.__values__===F&&(this.__values__=ku(this.value()));
|
|
||||||
var n=this.__index__>=this.__values__.length;return{done:n,value:n?F:this.__values__[this.__index__++]}},On.prototype.plant=function(n){for(var t,r=this;r instanceof Sn;){var e=Pe(r);e.__index__=0,e.__values__=F,t?u.__wrapped__=e:t=e;var u=e,r=r.__wrapped__}return u.__wrapped__=n,t},On.prototype.reverse=function(){var n=this.__wrapped__;return n instanceof Mn?(this.__actions__.length&&(n=new Mn(this)),n=n.reverse(),n.__actions__.push({func:nu,args:[Je],thisArg:F}),new zn(n,this.__chain__)):this.thru(Je);
|
|
||||||
},On.prototype.toJSON=On.prototype.valueOf=On.prototype.value=function(){return kr(this.__wrapped__,this.__actions__)},On.prototype.first=On.prototype.head,Ai&&(On.prototype[Ai]=tu),On}();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(Zn._=it, define(function(){return it})):Vn?((Vn.exports=it)._=it,qn._=it):Zn._=it}).call(this);
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,551 +0,0 @@
|
||||||
$(document).ready(function() {
|
|
||||||
// todo define things like 16x16, 128x128 etc. as constants?
|
|
||||||
// also script debounce/throttle times
|
|
||||||
let animationTime = 400; // defined in bitsy.js
|
|
||||||
|
|
||||||
let bitsyData = {};
|
|
||||||
|
|
||||||
let palette = {
|
|
||||||
id: 0,
|
|
||||||
background: {
|
|
||||||
red: 62,
|
|
||||||
green: 43,
|
|
||||||
blue: 32
|
|
||||||
},
|
|
||||||
tile: {
|
|
||||||
red: 208,
|
|
||||||
green: 112,
|
|
||||||
blue: 56
|
|
||||||
},
|
|
||||||
sprite: {
|
|
||||||
red: 229,
|
|
||||||
green: 92,
|
|
||||||
blue: 68
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let room = [];
|
|
||||||
|
|
||||||
let tileMatchThreshold = 64;
|
|
||||||
|
|
||||||
let croptions = {
|
|
||||||
url: 'https://i.imgur.com/ThQZ94v.jpg',
|
|
||||||
viewport: {width: 128, height: 128, type: 'square'},
|
|
||||||
boundary: {width: 256, height: 256},
|
|
||||||
zoom: 0
|
|
||||||
};
|
|
||||||
|
|
||||||
let $croppie = $('#croppie');
|
|
||||||
|
|
||||||
$croppie.croppie(croptions);
|
|
||||||
|
|
||||||
function colourDifference(colour1, colour2) {
|
|
||||||
let difference = {};
|
|
||||||
|
|
||||||
_.each(['red', 'green', 'blue'], function(key) {
|
|
||||||
difference[key] = Math.abs(colour1[key] - colour2[key]);
|
|
||||||
});
|
|
||||||
|
|
||||||
return _.toInteger(_.sum(_.toArray(difference)));
|
|
||||||
}
|
|
||||||
|
|
||||||
function zeroPad(input, desiredLength) {
|
|
||||||
while (input.length < desiredLength) {
|
|
||||||
input = "0" + input;
|
|
||||||
}
|
|
||||||
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
function colourToHex(colour) {
|
|
||||||
return '#' + zeroPad(Number(colour.red ).toString(16), 2)
|
|
||||||
+ zeroPad(Number(colour.green).toString(16), 2)
|
|
||||||
+ zeroPad(Number(colour.blue ).toString(16), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
function hexToColour(hex) {
|
|
||||||
let rgb = hex.match(/[\da-f]{2}/gi);
|
|
||||||
|
|
||||||
return {
|
|
||||||
red: parseInt(rgb[0], 16),
|
|
||||||
green: parseInt(rgb[1], 16),
|
|
||||||
blue: parseInt(rgb[2], 16)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getClosestColour(initialColour, colourOptions) {
|
|
||||||
// ditch sprite colour as we're not using it atm
|
|
||||||
delete colourOptions.sprite;
|
|
||||||
|
|
||||||
_.each(palette, function(colour, name) {
|
|
||||||
colourOptions[name].name = name;
|
|
||||||
colourOptions[name].difference = colourDifference(initialColour, colour);
|
|
||||||
});
|
|
||||||
|
|
||||||
// lowest difference (closest) wins
|
|
||||||
return _.first(_.sortBy(colourOptions, 'difference'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function newTileName() {
|
|
||||||
let tileNames = _.map(bitsyData.tiles, 'name');
|
|
||||||
|
|
||||||
let i = 1; // start with 1 as 0 is an implicit tile
|
|
||||||
|
|
||||||
while (tileNames.indexOf(i.toString(36)) > -1) {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// base 36 = 0-9a-z
|
|
||||||
return i.toString(36);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleBitsyGameData() {
|
|
||||||
let input = $bitsyData.val();
|
|
||||||
|
|
||||||
if ( ! input) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bitsyData = {};
|
|
||||||
|
|
||||||
// get palettes
|
|
||||||
let palettes = input.match(/PAL ([^\n]*)\n(NAME ([^\n]*)\n)?(([0-9,]+){3}\n){3,}/g);
|
|
||||||
|
|
||||||
bitsyData.palettes = {};
|
|
||||||
|
|
||||||
// do palettes always go 0..n?
|
|
||||||
// will this cause problems if not?
|
|
||||||
_.each(palettes, function(palette, n) {
|
|
||||||
let name = "";
|
|
||||||
|
|
||||||
if (palette.match(/NAME (.+)\n/)) {
|
|
||||||
name = palette.match(/NAME (.+)\n/)[0].replace('NAME ', '');
|
|
||||||
} else if (palette.match(/PAL (\d+)\n/)) {
|
|
||||||
name = palette.match(/PAL (\d+)\n/)[0].replace("PAL", "palette");
|
|
||||||
}
|
|
||||||
|
|
||||||
let colours = palette.match(/\d+,\d+,\d+/g);
|
|
||||||
|
|
||||||
colours = _.map(colours, function(colour) {
|
|
||||||
let rgb = colour.split(',');
|
|
||||||
|
|
||||||
return {red: rgb[0], green: rgb[1], blue: rgb[2]};
|
|
||||||
});
|
|
||||||
|
|
||||||
bitsyData.palettes[name] = {
|
|
||||||
id: n,
|
|
||||||
background: colours[0],
|
|
||||||
tile: colours[1],
|
|
||||||
sprite: colours[2]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// get tiles
|
|
||||||
|
|
||||||
bitsyData.tiles = [];
|
|
||||||
|
|
||||||
// tile 0 (background colour only) is implicit in bitsy rather than being stored in the game data
|
|
||||||
// so, make our own version
|
|
||||||
bitsyData.tiles.push({
|
|
||||||
name: "0",
|
|
||||||
bitmap: _.chunk(_.times(64, _.constant(0)), 8),
|
|
||||||
new: false // this could also be used to stop it from being added to the game data, wooo
|
|
||||||
});
|
|
||||||
|
|
||||||
// everything after > is an optional second animation frame
|
|
||||||
// todo: handle multiple animation frames! more than 2 are allowed (but not via the standard editor)
|
|
||||||
let tiles = input.match(/TIL (.*)\n([01]{8}\n){8}(>\n([01]{8}\n){8})?/g);
|
|
||||||
|
|
||||||
_.each(tiles, function(tile) {
|
|
||||||
let name = tile.match(/TIL .*/)[0].replace('TIL ', '');
|
|
||||||
|
|
||||||
tile = tile.replace(/TIL .*\n/, '');
|
|
||||||
|
|
||||||
let bitmap = _.map(tile.match(/[01]/g), _.toInteger);
|
|
||||||
|
|
||||||
let newTile = {
|
|
||||||
name: name,
|
|
||||||
new: false
|
|
||||||
};
|
|
||||||
|
|
||||||
// todo make this agnostic? i.e. tile.frames = _.chunk(bitmap, 64)
|
|
||||||
|
|
||||||
if (bitmap.length === 64) { // normal tile
|
|
||||||
newTile.bitmap = _.chunk(bitmap, 8);
|
|
||||||
} else if (bitmap.length === 128) { // animated tile
|
|
||||||
newTile.bitmap = _.chunk(_.take( bitmap, 64), 8);
|
|
||||||
newTile.secondAnimationFrame = _.chunk(_.takeRight(bitmap, 64), 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
bitsyData.tiles.push(newTile);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (_.find(bitsyData.palettes, {'id': palette.id})) {
|
|
||||||
// user has already selected a palette, leave it be
|
|
||||||
|
|
||||||
// in case this is the first run:
|
|
||||||
palette = _.find(bitsyData.palettes, {'id': palette.id})
|
|
||||||
|
|
||||||
// if we just set the palette to the newly imported palette with the same ID,
|
|
||||||
// we will lose any changes the user has made to the palettes
|
|
||||||
// is this a big issue considering that the palettes cannot be currently saved anyway?
|
|
||||||
} else {
|
|
||||||
// set palette to first imported palette and redraw
|
|
||||||
palette = _.first(_.sortBy(bitsyData.palettes, 'id'));
|
|
||||||
}
|
|
||||||
|
|
||||||
renderDebounced();
|
|
||||||
|
|
||||||
// update palette picker
|
|
||||||
$('tr.palette').remove();
|
|
||||||
|
|
||||||
_.each(bitsyData.palettes, function(palette, name) {
|
|
||||||
$('#palette tbody').append(
|
|
||||||
'<tr class="palette">'
|
|
||||||
+ '<td>'
|
|
||||||
+ '<input type="radio" name="palette" id="palette-' + name + '">'
|
|
||||||
+ '<input type="hidden" name="id" value="' + palette.id + '">'
|
|
||||||
+ '</td>'
|
|
||||||
+ '<td><label for="palette-' + name + '">' + name + '</label></td>'
|
|
||||||
+ '<td><input type="color" name="background" value="' + colourToHex(palette.background) + '"></td>'
|
|
||||||
+ '<td><input type="color" name="tile" value="' + colourToHex(palette.tile) + '"></td>'
|
|
||||||
+ '<td><input type="color" name="sprite" value="' + colourToHex(palette.sprite) + '" disabled></td>'
|
|
||||||
+ '</tr>'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('input[name="id"][value="' + palette.id + '"]').siblings(':radio').trigger('click');
|
|
||||||
}
|
|
||||||
|
|
||||||
function readFile(input, callback) {
|
|
||||||
if (input.files && input.files[0]) {
|
|
||||||
let reader = new FileReader();
|
|
||||||
|
|
||||||
reader.onload = callback;
|
|
||||||
|
|
||||||
reader.readAsDataURL(input.files[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function readTextFile(input, callback) {
|
|
||||||
if (input.files && input.files[0]) {
|
|
||||||
let reader = new FileReader();
|
|
||||||
|
|
||||||
reader.onload = callback;
|
|
||||||
|
|
||||||
reader.readAsText(input.files[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function render() {
|
|
||||||
$croppie.croppie('result', {
|
|
||||||
type: 'rawcanvas',
|
|
||||||
size: 'viewport'
|
|
||||||
}).then(function (result) {
|
|
||||||
let imageData = result.getContext('2d').getImageData(0, 0, 128, 128);
|
|
||||||
let rawData = imageData.data;
|
|
||||||
let monochrome = [];
|
|
||||||
|
|
||||||
let brightnessAdjustment = parseFloat($('#brightness').val());
|
|
||||||
|
|
||||||
// for each pixel
|
|
||||||
for (let i = 0; i < rawData.length; i += 4) {
|
|
||||||
// this brightness adjustment is pretty crude but whatever
|
|
||||||
let pixel = {
|
|
||||||
red: _.clamp(rawData[i ] + brightnessAdjustment, 0, 255),
|
|
||||||
green: _.clamp(rawData[i + 1] + brightnessAdjustment, 0, 255),
|
|
||||||
blue: _.clamp(rawData[i + 2] + brightnessAdjustment, 0, 255)
|
|
||||||
};
|
|
||||||
|
|
||||||
let targetColour = getClosestColour(pixel, palette);
|
|
||||||
|
|
||||||
if (targetColour.name === "background") {
|
|
||||||
monochrome.push(0);
|
|
||||||
} else { // tile
|
|
||||||
monochrome.push(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
rawData[i ] = targetColour.red;
|
|
||||||
rawData[i + 1] = targetColour.green;
|
|
||||||
rawData[i + 2] = targetColour.blue;
|
|
||||||
rawData[i + 3] = 255; // alpha
|
|
||||||
}
|
|
||||||
|
|
||||||
// split monochrome bitmap into equal chunks for easier x:y access
|
|
||||||
monochrome = _.chunk(monochrome, 128);
|
|
||||||
|
|
||||||
document.getElementById('preview').getContext('2d').putImageData(imageData, 0, 0);
|
|
||||||
|
|
||||||
// tiled output
|
|
||||||
|
|
||||||
room = [];
|
|
||||||
|
|
||||||
_.times(16, function(tileY) {
|
|
||||||
_.times(16, function(tileX) {
|
|
||||||
// make pseudo-tile from monochrome bitmap
|
|
||||||
let pseudoTile = [];
|
|
||||||
|
|
||||||
_.times(8, function(y) {
|
|
||||||
pseudoTile.push(
|
|
||||||
_.slice(monochrome[(tileY * 8) + y], (tileX * 8), (tileX * 8) + 8)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
let bestMatch;
|
|
||||||
|
|
||||||
// if we want to always create new tiles, don't bother trying to check matches
|
|
||||||
if (tileMatchThreshold === 64) {
|
|
||||||
// even if we want to "always create new tiles" we still don't want to create duplicates
|
|
||||||
bestMatch = _.find(bitsyData.tiles, function(tile) {
|
|
||||||
return _.isEqual(tile.bitmap, pseudoTile);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (bestMatch) {
|
|
||||||
bestMatch.match = 64;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_.each(bitsyData.tiles, function(tile) {
|
|
||||||
tile.match = 0;
|
|
||||||
|
|
||||||
_.each(tile.bitmap, function(row, y) {
|
|
||||||
_.each(row, function(pixel, x) {
|
|
||||||
if (parseInt(pixel) === parseInt(pseudoTile[y][x])) {
|
|
||||||
tile.match++;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (tile.secondAnimationFrame) {
|
|
||||||
_.each(tile.secondAnimationFrame, function(row, y) {
|
|
||||||
_.each(row, function(pixel, x) {
|
|
||||||
if (parseInt(pixel) === parseInt(pseudoTile[y][x])) {
|
|
||||||
tile.match++;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
tile.match /= 2;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// what if there are several equally good matches?
|
|
||||||
// find highest match amount and find all of them
|
|
||||||
let bestMatchAmount = _.last(_.sortBy(bitsyData.tiles, ['match'])).match;
|
|
||||||
let bestMatches = _.filter(bitsyData.tiles, {'match': bestMatchAmount});
|
|
||||||
|
|
||||||
// sort by name in ascending order
|
|
||||||
// earlier names are preferable
|
|
||||||
bestMatch = _.first(_.sortBy(bestMatches, 'name'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! bestMatch || bestMatch.match < tileMatchThreshold) {
|
|
||||||
// turn pseudo-tile into a real tile and add it to the tile data
|
|
||||||
|
|
||||||
let name = newTileName();
|
|
||||||
|
|
||||||
bitsyData.tiles.push({
|
|
||||||
name: name,
|
|
||||||
bitmap: pseudoTile,
|
|
||||||
new: true
|
|
||||||
});
|
|
||||||
|
|
||||||
room.push(name);
|
|
||||||
|
|
||||||
// issue with this approach:
|
|
||||||
// what if a tile we add late in the loop is a better match for an earlier "good enough" match?
|
|
||||||
// this would also cause different results if the user were to add the same room several times
|
|
||||||
// we could keep iterating until the room no longer changes
|
|
||||||
} else {
|
|
||||||
room.push(bestMatch.name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
room = _.chunk(room, 16);
|
|
||||||
|
|
||||||
// write room to output
|
|
||||||
|
|
||||||
imageData = document.getElementById("room-output").getContext('2d').getImageData(0, 0, 128, 128);
|
|
||||||
rawData = imageData.data;
|
|
||||||
|
|
||||||
_.each(room, function(row, tileY) {
|
|
||||||
_.each(row, function(tileName, tileX) {
|
|
||||||
let tile = _.find(bitsyData.tiles, {'name' : tileName});
|
|
||||||
|
|
||||||
_.each(tile.bitmap, function(row, y) {
|
|
||||||
_.each(row, function(pixel, x) {
|
|
||||||
let position = (((tileY * 8) + y) * 128) + ((tileX * 8) + x);
|
|
||||||
|
|
||||||
position *= 4; // 4 values (rgba) per pixel
|
|
||||||
|
|
||||||
let pixelColour = {};
|
|
||||||
|
|
||||||
switch(parseInt(pixel)) {
|
|
||||||
case 0: pixelColour = palette.background; break;
|
|
||||||
case 1: pixelColour = palette.tile; break;
|
|
||||||
default: console.log("error");
|
|
||||||
}
|
|
||||||
|
|
||||||
rawData[position ] = pixelColour.red;
|
|
||||||
rawData[position + 1] = pixelColour.green;
|
|
||||||
rawData[position + 2] = pixelColour.blue;
|
|
||||||
rawData[position + 3] = 255;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('room-output').getContext('2d').putImageData(imageData, 0, 0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let renderDebounced = _.debounce(render, 30);
|
|
||||||
let renderThrottled = _.throttle(render, 30);
|
|
||||||
|
|
||||||
$croppie.on('update', renderDebounced);
|
|
||||||
|
|
||||||
let $brightness = $('#brightness');
|
|
||||||
|
|
||||||
$brightness.on('change', renderThrottled);
|
|
||||||
|
|
||||||
$brightness.on('dblclick', function() {
|
|
||||||
$(this).val(0);
|
|
||||||
|
|
||||||
renderDebounced();
|
|
||||||
});
|
|
||||||
|
|
||||||
$('label[for="brightness"]').on('click touchdown', function() {
|
|
||||||
$('#brightness').trigger('dblclick');
|
|
||||||
});
|
|
||||||
|
|
||||||
let $bitsyData = $('#bitsy-data');
|
|
||||||
|
|
||||||
$bitsyData.on('change blur keyup', handleBitsyGameData);
|
|
||||||
|
|
||||||
$bitsyData.on('focus', function() {
|
|
||||||
$(this).select();
|
|
||||||
});
|
|
||||||
|
|
||||||
handleBitsyGameData();
|
|
||||||
|
|
||||||
$('#imageUpload').on('change', function () {
|
|
||||||
readFile(this, function (e) {
|
|
||||||
$croppie.croppie('bind', {
|
|
||||||
url: e.target.result,
|
|
||||||
zoom: 0
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$('input.game-data').on('change', function() {
|
|
||||||
readTextFile(this, function (e) {
|
|
||||||
$bitsyData.val(e.target.result);
|
|
||||||
handleBitsyGameData();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// these inputs get added and removed from the DOM so the event handler needs to be on the document
|
|
||||||
$(document).on('change', '#palette input', function() {
|
|
||||||
let id = parseInt($(this).closest('.palette').find('input[name="id"]').val());
|
|
||||||
|
|
||||||
// if this is a colour input, update the palette
|
|
||||||
if ($(this).attr('type') === 'color') {
|
|
||||||
if (id === palette.id) {
|
|
||||||
palette[$(this).attr('name')] = hexToColour($(this).val());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if this is a radio button, pick this palette
|
|
||||||
if ($(this).attr('type') === 'radio') {
|
|
||||||
palette.id = id;
|
|
||||||
palette.background = hexToColour($(this).closest('.palette').find('input[name="background"]').val());
|
|
||||||
palette.tile = hexToColour($(this).closest('.palette').find('input[name="tile"]' ).val());
|
|
||||||
// sprite colour is not currently used
|
|
||||||
}
|
|
||||||
|
|
||||||
renderDebounced();
|
|
||||||
});
|
|
||||||
|
|
||||||
$(document).on('change', '#threshold', function() {
|
|
||||||
let newValue = parseInt($(this).val());
|
|
||||||
|
|
||||||
if (newValue < tileMatchThreshold) {
|
|
||||||
// set tiles back to default
|
|
||||||
bitsyData.tiles = _.filter(bitsyData.tiles, ['new', false]);
|
|
||||||
}
|
|
||||||
|
|
||||||
tileMatchThreshold = newValue;
|
|
||||||
|
|
||||||
renderThrottled();
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#never').on('click touchend', function() {
|
|
||||||
$('#threshold').val(0).change();
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#always').on('click touchend', function() {
|
|
||||||
$('#threshold').val(64).change();
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#save').on('click touchend', function() {
|
|
||||||
let $textArea = $('textarea');
|
|
||||||
|
|
||||||
let newGameData = $textArea.val();
|
|
||||||
|
|
||||||
// handle rooms
|
|
||||||
|
|
||||||
// need to import IDs so we don't give the new room a conflicting ID
|
|
||||||
let roomIds = newGameData.match(/ROOM \d+\n/g);
|
|
||||||
|
|
||||||
roomIds = _.map(roomIds, function(roomId) {
|
|
||||||
return parseInt(roomId.replace(/[^\d]+/g, ""));
|
|
||||||
});
|
|
||||||
|
|
||||||
let newRoomId = _.max(roomIds) + 1;
|
|
||||||
|
|
||||||
let newRoomName = $('#roomName').val();
|
|
||||||
// remove invalid chars? what's invalid? newlines? are those possible?
|
|
||||||
|
|
||||||
let newRoom = "ROOM " + newRoomId + "\n";
|
|
||||||
|
|
||||||
_.each(room, function(row) {
|
|
||||||
newRoom += _.toString(row) + "\n";
|
|
||||||
});
|
|
||||||
|
|
||||||
if (newRoomName) {
|
|
||||||
newRoom += "NAME " + newRoomName + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
newRoom += "PAL " + palette.id + "\n";
|
|
||||||
|
|
||||||
newGameData = newGameData.replace(/(ROOM .*\n(.*\n)*PAL .*)/g, '$1\n\n' + newRoom);
|
|
||||||
|
|
||||||
// handle tiles
|
|
||||||
|
|
||||||
let newTiles = _.filter(bitsyData.tiles, 'new');
|
|
||||||
let tileText = "";
|
|
||||||
|
|
||||||
_.each(newTiles, function(tile, n) {
|
|
||||||
tileText += "TIL " + tile.name + "\n"; //again, rename tile name to id...
|
|
||||||
|
|
||||||
_.each(tile.bitmap, function(row) {
|
|
||||||
tileText += row.join('') + "\n";
|
|
||||||
});
|
|
||||||
|
|
||||||
tileText += "NAME " + newRoomName + " " + (n + 1) + "\n";
|
|
||||||
|
|
||||||
// don't need to worry about animation right now
|
|
||||||
|
|
||||||
tileText += "\n";
|
|
||||||
});
|
|
||||||
|
|
||||||
newGameData = newGameData.replace(/(TIL.*(.*\n)*)SPR/g, '$1\n\n' + tileText + 'SPR');
|
|
||||||
|
|
||||||
// write
|
|
||||||
$textArea.val(newGameData);
|
|
||||||
|
|
||||||
handleBitsyGameData();
|
|
||||||
|
|
||||||
// todo: give the user some nice "yay! it worked!" kinda feedback?
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,112 +0,0 @@
|
||||||
@font-face {
|
|
||||||
font-family: 'rubikregular';
|
|
||||||
src: url('rubik-regular-webfont.woff2') format('woff2'), url('rubik-regular-webfont.woff') format('woff');
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
font-family: "rubikregular", sans-serif;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
background-color: #594a54;
|
|
||||||
color: #d3cbd0;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
color: #f69f8f;
|
|
||||||
}
|
|
||||||
canvas {
|
|
||||||
image-rendering: -moz-crisp-edges;
|
|
||||||
image-rendering: pixelated;
|
|
||||||
}
|
|
||||||
input[type="color"] {
|
|
||||||
width: 2em;
|
|
||||||
height: 2em;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border: none;
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
input[type="color"][disabled] {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
input[type="file"] {
|
|
||||||
padding: 1em 0;
|
|
||||||
width: 256px;
|
|
||||||
}
|
|
||||||
input[type="text"],
|
|
||||||
button {
|
|
||||||
width: 14em;
|
|
||||||
margin: 1em;
|
|
||||||
padding: 0.25em;
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
table {
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
table td,
|
|
||||||
table th {
|
|
||||||
width: 50%;
|
|
||||||
}
|
|
||||||
table td {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
table th {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
textarea {
|
|
||||||
height: 256px;
|
|
||||||
width: 256px;
|
|
||||||
font-family: monospace;
|
|
||||||
}
|
|
||||||
textarea,
|
|
||||||
input {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
.box256 {
|
|
||||||
height: 256px;
|
|
||||||
width: 256px;
|
|
||||||
}
|
|
||||||
.centre {
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
.croppie-container {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
.flex-container {
|
|
||||||
background-color: #d3cbd0;
|
|
||||||
display: flex;
|
|
||||||
flex-flow: row wrap;
|
|
||||||
}
|
|
||||||
.section {
|
|
||||||
margin: 0 auto;
|
|
||||||
background-color: #d3cbd0;
|
|
||||||
color: #594a54;
|
|
||||||
width: 256px;
|
|
||||||
padding-bottom: 1em;
|
|
||||||
}
|
|
||||||
#brightness {
|
|
||||||
width: 256px;
|
|
||||||
}
|
|
||||||
#threshold {
|
|
||||||
width: 150px;
|
|
||||||
}
|
|
||||||
#brightness + label,
|
|
||||||
#threshold + label {
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
#palettes {
|
|
||||||
height: 256px;
|
|
||||||
width: 256px;
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
|
||||||
#preview,
|
|
||||||
#room-output {
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 256px;
|
|
||||||
}
|
|
||||||
#save {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
|
@ -1,144 +1,133 @@
|
||||||
@font-face {
|
@background: #57506a;
|
||||||
font-family: 'rubikregular';
|
@page-background: #968eb5;
|
||||||
src: url('rubik-regular-webfont.woff2') format('woff2'),
|
@accent: #ec6d7d;
|
||||||
url('rubik-regular-webfont.woff') format('woff');
|
@text: #464256;
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@light: #d3cbd0;
|
|
||||||
@dark: #594a54;
|
|
||||||
@accent: #f69f8f; // pink
|
|
||||||
|
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
font-family: "rubikregular", sans-serif;
|
color: @text;
|
||||||
|
margin: 0 auto 0.5em auto;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
background-color: @dark;
|
background-color: @background;
|
||||||
color: @light;
|
font-size: 3vmin;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
button {
|
||||||
|
padding: 1em;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&.pagination:not(.normal) {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 5vmin;
|
||||||
|
width: auto;
|
||||||
|
|
||||||
|
&.prev {
|
||||||
|
left: 5vmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.next, &.start {
|
||||||
|
right: 5vmin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
header * {
|
||||||
color: @accent;
|
color: @accent;
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas {
|
h1 {
|
||||||
image-rendering: -moz-crisp-edges;
|
|
||||||
image-rendering: pixelated;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="color"] {
|
|
||||||
&[disabled] {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
width: 2em;
|
|
||||||
height: 2em;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
|
||||||
border: none;
|
|
||||||
background: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="file"] {
|
h3 {
|
||||||
padding: 1em 0;
|
font-size: 0.9em;
|
||||||
width: 256px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="text"], button {
|
input {
|
||||||
width: 14em;
|
width: 100%;
|
||||||
margin: 1em;
|
|
||||||
padding: 0.25em;
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
margin: 0 auto;
|
|
||||||
|
|
||||||
td, th {
|
|
||||||
width: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
&[type="checkbox"] {
|
||||||
text-align: right;
|
width: auto;
|
||||||
|
margin-right: 1em;
|
||||||
|
position: relative;
|
||||||
|
top: 0.25em;
|
||||||
|
left: 0.25em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 0.8em;
|
||||||
|
margin: 0 auto 1em auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-size: 0.75em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
.box256;
|
height: 15em;
|
||||||
|
padding: 0.5em;
|
||||||
font-family: monospace;
|
text-align: left;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea, input {
|
.background {
|
||||||
|
background-color: @background;
|
||||||
|
padding: 0.5em;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkboxes label {
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper-tools {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.half {
|
||||||
|
display: inline-block;
|
||||||
|
text-align: left;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-container {
|
||||||
|
height: 46vh;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.box256 {
|
.page {
|
||||||
|
height: 80vmin;
|
||||||
|
width: 80vmin;
|
||||||
|
|
||||||
|
background-color: @page-background;
|
||||||
|
color: @text;
|
||||||
|
border-radius: 5vmin;
|
||||||
|
box-shadow: @accent 1vmin 1vmin;
|
||||||
|
padding: 5vmin;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#preview {
|
||||||
|
width: 256px;
|
||||||
height: 256px;
|
height: 256px;
|
||||||
width: 256px;
|
image-rendering: pixelated;
|
||||||
}
|
image-rendering: crisp-edges;
|
||||||
|
|
||||||
.centre {
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.croppie-container {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-container {
|
|
||||||
background-color: @light;
|
|
||||||
display: flex;
|
|
||||||
flex-flow: row wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make this just for desktop view?
|
|
||||||
// put sections in a single column on mobile/etc?
|
|
||||||
.section {
|
|
||||||
.centre;
|
|
||||||
|
|
||||||
background-color: @light;
|
|
||||||
color: @dark;
|
|
||||||
width: 256px;
|
|
||||||
padding-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#brightness {
|
|
||||||
width: 256px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#threshold {
|
|
||||||
width: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#brightness, #threshold {
|
|
||||||
+ label{
|
|
||||||
.centre;
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo make this match the croppie slider or vice versa
|
|
||||||
}
|
|
||||||
|
|
||||||
#palettes {
|
|
||||||
.box256;
|
|
||||||
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
#preview, #room-output {
|
|
||||||
.centre;
|
|
||||||
|
|
||||||
width: 256px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#save {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
}
|
||||||
|
|
90
index.html
90
index.html
|
@ -1,90 +0,0 @@
|
||||||
<!DOCTYPE html><html><head><meta charset="utf-8"><title>image to bitsy</title><!-- lodash--><script src="includes/lodash.min.js"></script><!-- jquery--><script src="includes/jquery.min.js"></script><!-- croppie--><link rel="stylesheet" href="includes/croppie.css"><script src="includes/croppie.js"></script><!-- main stuff--><link rel="stylesheet" type="text/css" href="includes/style.css"><script src="includes/script.js"></script></head><body><header><h1>image-to-bitsy</h1><p>convert any image to a <a href="https://ledoux.itch.io/bitsy">bitsy</a> room</p><p><a href="https://github.com/synth-ruiner/bitsy-image-to-room">about</a>
|
|
||||||
|
|
|
||||||
please contact me if you have any issues:
|
|
||||||
<a href="https://twitter.com/synth_ruiner">twitter</a>,
|
|
||||||
<a href="mailto:max@tinybird.info">email</a>
|
|
||||||
</p></header><div class="flex-container"><div class="section" id="game-data"><h2>game data</h2><textarea id="bitsy-data" placeholder="Bitsy data or html">Write your game's title here
|
|
||||||
|
|
||||||
# BITSY VERSION 5.3
|
|
||||||
|
|
||||||
! ROOM_FORMAT 1
|
|
||||||
|
|
||||||
PAL 0
|
|
||||||
0,82,204
|
|
||||||
128,159,255
|
|
||||||
255,255,255
|
|
||||||
|
|
||||||
ROOM 0
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
|
||||||
0,a,a,a,a,a,a,a,a,a,a,a,a,a,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
|
||||||
0,a,a,a,a,a,a,a,a,a,a,a,a,a,a,0
|
|
||||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
|
||||||
PAL 0
|
|
||||||
|
|
||||||
TIL a
|
|
||||||
11111111
|
|
||||||
10000001
|
|
||||||
10000001
|
|
||||||
10011001
|
|
||||||
10011001
|
|
||||||
10000001
|
|
||||||
10000001
|
|
||||||
11111111
|
|
||||||
|
|
||||||
SPR A
|
|
||||||
00011000
|
|
||||||
00011000
|
|
||||||
00011000
|
|
||||||
00111100
|
|
||||||
01111110
|
|
||||||
10111101
|
|
||||||
00100100
|
|
||||||
00100100
|
|
||||||
POS 0 4,4
|
|
||||||
|
|
||||||
SPR a
|
|
||||||
00000000
|
|
||||||
00000000
|
|
||||||
01010001
|
|
||||||
01110001
|
|
||||||
01110010
|
|
||||||
01111100
|
|
||||||
00111100
|
|
||||||
00100100
|
|
||||||
DLG SPR_0
|
|
||||||
POS 0 8,12
|
|
||||||
|
|
||||||
ITM 0
|
|
||||||
00000000
|
|
||||||
00000000
|
|
||||||
00000000
|
|
||||||
00111100
|
|
||||||
01100100
|
|
||||||
00100100
|
|
||||||
00011000
|
|
||||||
00000000
|
|
||||||
NAME tea
|
|
||||||
DLG ITM_0
|
|
||||||
|
|
||||||
DLG SPR_0
|
|
||||||
I'm a cat
|
|
||||||
|
|
||||||
DLG ITM_0
|
|
||||||
You found a nice warm cup of tea
|
|
||||||
|
|
||||||
VAR a
|
|
||||||
42
|
|
||||||
|
|
||||||
</textarea><p><input class="game-data" type="file"></p><p>paste or upload your game data (or html) here</p><p>(maybe make a backup first)</p></div><div class="section" id="image"><h2>image</h2><div id="croppie"></div><input id="imageUpload" type="file" accepts="image/*"></div><div class="section" id="palette"><h2>palette</h2><form id="palettes"><table><tbody></tbody></table></form></div><div class="section" id="crop"><h2>preview</h2><canvas id="preview" width="128" height="128"></canvas><input id="brightness" type="range" min="-255" max="255" value="0"><label for="brightness">brightness</label></div><div class="section" id="output"><h2>output</h2><canvas id="room-output" width="128" height="128"></canvas><label id="never">never</label><input id="threshold" type="range" min="0" max="64" value="64"><label id="always"> always</label><br><label for="threshold">create new tiles</label><br><input id="roomName" type="text" placeholder="room name"><button id="save">write to game data</button></div></div></body></html>
|
|
140
index.pug
140
index.pug
|
@ -1,96 +1,96 @@
|
||||||
doctype html
|
doctype html
|
||||||
html
|
html(lang="en-gb")
|
||||||
head
|
head
|
||||||
meta(charset="utf-8")
|
meta(charset="utf-8")
|
||||||
title image to bitsy
|
title pixsy
|
||||||
|
link(rel="stylesheet" href="includes/style.css")
|
||||||
// lodash
|
|
||||||
script(src="includes/lodash.min.js")
|
|
||||||
|
|
||||||
// jquery
|
|
||||||
script(src="includes/jquery.min.js")
|
|
||||||
|
|
||||||
// croppie
|
|
||||||
link(rel="stylesheet" href="includes/croppie.css")
|
link(rel="stylesheet" href="includes/croppie.css")
|
||||||
script(src="includes/croppie.js")
|
script(src="includes/croppie.min.js")
|
||||||
|
|
||||||
// main stuff
|
|
||||||
link(rel="stylesheet" type="text/css" href="includes/style.css")
|
|
||||||
script(src="includes/script.js")
|
|
||||||
body
|
body
|
||||||
header
|
header
|
||||||
h1 image-to-bitsy
|
h1
|
||||||
p convert any image to a #[a(href="https://ledoux.itch.io/bitsy") bitsy] room
|
| pixsy
|
||||||
|
//img(alt="pixsy" src="includes/pixsy.png")
|
||||||
p.
|
p.
|
||||||
#[a(href="https://github.com/synth-ruiner/bitsy-image-to-room") about]
|
convert images to Bitsy rooms
|
||||||
|
|
|
||||||
|
#[a(href="./old/") old version]
|
||||||
|
|
|
|
||||||
please contact me if you have any issues:
|
|
||||||
#[a(href="https://twitter.com/synth_ruiner") twitter],
|
|
||||||
#[a(href="mailto:max@tinybird.info") email]
|
#[a(href="mailto:max@tinybird.info") email]
|
||||||
|
|
|
||||||
.flex-container
|
#[a(href="https://twitter.com/synth_ruiner") twitter]
|
||||||
#game-data.section
|
.pages
|
||||||
|
.page#start
|
||||||
|
button.normal.pagination.next#new create a new bitsy game
|
||||||
|
button.normal.pagination.next#load load an existing bitsy game
|
||||||
|
.page.game-data
|
||||||
h2 game data
|
h2 game data
|
||||||
|
|
||||||
textarea#bitsy-data(placeholder="Bitsy data or html")
|
input#game(type="file" autocomplete="off")
|
||||||
include includes/default.bitsy
|
br
|
||||||
|
|
||||||
p
|
textarea#game-data(
|
||||||
input.game-data(type="file")
|
placeholder="Paste your game data here or use the file chooser button above"
|
||||||
p paste or upload your game data (or html) here
|
autocomplete="off"
|
||||||
p (maybe make a backup first)
|
)
|
||||||
|
|
||||||
#image.section
|
button.pagination.prev previous
|
||||||
|
button.pagination.next#game-data-next(disabled=true) next
|
||||||
|
.page.image#page-image
|
||||||
h2 image
|
h2 image
|
||||||
|
|
||||||
#croppie
|
.image-container
|
||||||
|
input#image(type="file" accept="image/*")
|
||||||
|
#crop(style="display: none;")
|
||||||
|
|
||||||
input#imageUpload(type="file" accepts="image/*")
|
button.pagination.prev previous
|
||||||
|
button.pagination.next#image-next(disabled=true) next
|
||||||
|
.page.room#page-room
|
||||||
|
h2 room
|
||||||
|
|
||||||
#palette.section
|
|
||||||
h2 palette
|
|
||||||
|
|
||||||
form#palettes
|
|
||||||
table
|
table
|
||||||
tbody
|
tbody
|
||||||
|
tr
|
||||||
#crop.section
|
td(style="width: 60%")
|
||||||
h2 preview
|
img#preview(alt="preview")
|
||||||
|
|
||||||
canvas#preview(width=128, height=128)
|
|
||||||
|
|
||||||
input#brightness(type="range" min=-255 max=255 value=0)
|
|
||||||
|
|
||||||
label(for="brightness") brightness
|
|
||||||
|
|
||||||
//- to do
|
|
||||||
input#dithering(type="checkbox")
|
|
||||||
label(for="dithering") dithering
|
|
||||||
|
|
||||||
//- to do
|
|
||||||
input#smoothing(type="checkbox")
|
|
||||||
label(for="smoothing") smoothing
|
|
||||||
|
|
||||||
#output.section
|
|
||||||
h2 output
|
|
||||||
|
|
||||||
canvas#room-output(width=128, height=128)
|
|
||||||
|
|
||||||
label#never never
|
|
||||||
input#threshold(type="range" min=0 max=64 value=64)
|
|
||||||
label#always always
|
|
||||||
br
|
|
||||||
label(for="threshold") create new tiles
|
|
||||||
br
|
br
|
||||||
|
|
||||||
input#roomName(type="text", placeholder="room name")
|
label
|
||||||
|
| brightness
|
||||||
|
input#brightness(type="range" min=-96 max=96 value=0)
|
||||||
|
td(style="vertical-align: top;")
|
||||||
|
label
|
||||||
|
| name (optional)
|
||||||
|
input#room-name(type="text" placeholder="e.g. 'bedroom'" autocomplete="off")
|
||||||
|
|
||||||
button#save write to game data
|
label
|
||||||
|
| palette
|
||||||
|
select#palette
|
||||||
|
|
||||||
//- to do
|
#new-palette(style="display: none;")
|
||||||
|
.half
|
||||||
//-label favour broad strokes | favour details
|
input#colour-background(type="color" value="#000000")
|
||||||
|
.half
|
||||||
|
input#colour-foreground(type="color" value="#ffffff")
|
||||||
|
|
||||||
|
label
|
||||||
|
input#dither(type="checkbox" checked=true)
|
||||||
|
| dither
|
||||||
br
|
br
|
||||||
|
|
||||||
//-button Download
|
button.pagination.prev#back-to-image previous
|
||||||
|
button.pagination.next#room-next add room
|
||||||
|
.page.download
|
||||||
|
p#added
|
||||||
|
|
||||||
|
h2 download
|
||||||
|
|
||||||
|
textarea#output(autocomplete="off")
|
||||||
|
br
|
||||||
|
|
||||||
|
button#download download
|
||||||
|
|
||||||
|
button.pagination.prev#add add another image
|
||||||
|
button.pagination.start#reset start again
|
||||||
|
script(type="module")
|
||||||
|
include script.js
|
||||||
|
|
14
package.json
14
package.json
|
@ -1,14 +0,0 @@
|
||||||
{
|
|
||||||
"name": "bitsy-image-to-room",
|
|
||||||
"description": "Tool to convert images to Bitsy rooms. Can work as an offline web application",
|
|
||||||
"version": "0.0.1",
|
|
||||||
"devDependencies": {
|
|
||||||
"pug": "latest",
|
|
||||||
"pug-cli": "latest",
|
|
||||||
"less": "latest"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"croppie": "^2.5.1",
|
|
||||||
"jquery": "^3.5.0"
|
|
||||||
}
|
|
||||||
}
|
|
87
readme.md
87
readme.md
|
@ -1,87 +0,0 @@
|
||||||
# image to bitsy
|
|
||||||
|
|
||||||
## about
|
|
||||||
|
|
||||||
a tool for Bitsy. upload any image and convert it into a room.
|
|
||||||
the room will be added to the game data automatically and you can paste it back into Bitsy.
|
|
||||||
|
|
||||||
## thanks
|
|
||||||
|
|
||||||
to **Adam Le Doux** for creating the wonderful and inspiring Bitsy
|
|
||||||
|
|
||||||
to **J.P. LeBreton** for creating Playscii which was a huge inspiration for this tool
|
|
||||||
|
|
||||||
to **Mark Wonnacott** for being relentlessly encouraging and making me want to work even an eighth as hard as them
|
|
||||||
|
|
||||||
to **Foliotek** for the **Croppie** image plugin
|
|
||||||
|
|
||||||
## contributing
|
|
||||||
|
|
||||||
Forks and pull requests welcome!
|
|
||||||
|
|
||||||
The stylesheet and html are auto-generated; if you want to alter them please edit the pug template or less stylesheet, then either run the included `build.sh` script or build from the command line as follows:
|
|
||||||
|
|
||||||
`pug index.pug index.html`
|
|
||||||
|
|
||||||
`lessc style.less style.css`
|
|
||||||
|
|
||||||
`pug` and `less` can be installed via `npm` as follows:
|
|
||||||
|
|
||||||
`npm install -g pug-cli`
|
|
||||||
|
|
||||||
`npm install -g less`
|
|
||||||
|
|
||||||
I had to hack the included Croppie plugin to allow the user to upload images from their own computer without falling foul of CORS restrictions. So the version bundled here is non-standard. It's a one-line change:
|
|
||||||
|
|
||||||
```
|
|
||||||
// croppie.js:182 (original)
|
|
||||||
if (src.match(/^(https)?:\/\/|^\/\//)) {
|
|
||||||
// croppie.js:182 (mine)
|
|
||||||
if (src.match(/^(file|https)?:\/\/|^\/\//)) {
|
|
||||||
```
|
|
||||||
|
|
||||||
## bugs
|
|
||||||
|
|
||||||
* does not work on ipad (can't scroll to the right?)
|
|
||||||
* possibly fixed; needs testing
|
|
||||||
* create tiles slider breaks onto 2 lines in some browsers?
|
|
||||||
* sometimes overwrites existing rooms?
|
|
||||||
|
|
||||||
## to do
|
|
||||||
|
|
||||||
* test new room ID handling!!!
|
|
||||||
* don't reuse wall tiles
|
|
||||||
* add 'clear'/'upload' buttons for game data
|
|
||||||
* select all on clicking game data entry field
|
|
||||||
* allow user to save output as image, or tweet it :)
|
|
||||||
* *user can currently right-click -> Save As but the 128x128 size is not great*
|
|
||||||
* animate animated tiles
|
|
||||||
* profile script performance and optimise where most needed
|
|
||||||
* make brightness slider trigger redraw every so often while being dragged, instead of waiting until drag stop
|
|
||||||
* add up/down arrows to the brightness slider for incremental tweaks
|
|
||||||
* add 'all-white' tile by default in case the game data doesn't have it?
|
|
||||||
* handle arbitrary animation frames (editor only supports 2 frames, but game data has no upper limit)
|
|
||||||
* list how many new tiles are being created
|
|
||||||
* combine preview and output
|
|
||||||
* give warning on duplicate room names?
|
|
||||||
* loading spinner on rendering?
|
|
||||||
* make brightness slider exponential
|
|
||||||
* rotation options for image
|
|
||||||
|
|
||||||
## could do
|
|
||||||
|
|
||||||
* add some alternate default tiles - something more useful e.g. dithered tiles, gradients
|
|
||||||
* add dithering options
|
|
||||||
* add camera support so users can take a pic instead of uploading an image
|
|
||||||
* add a 'smoothing' stage to remove errant pixels
|
|
||||||
* allow user to add palettes to game data
|
|
||||||
* allow user to draw to canvas
|
|
||||||
* do a 'branching tree' approach to finding the closest tile? i.e. create a 1x1, 2x2, 4x4 version of each tile, so all the broadly darker tiles will sit under '0' and lighter tiles under '1', then tiles that are lighter at the top will sit under '1100', etc... I'm not sure how much more effective this will be or whatever it will give better/faster results but it's worth a try
|
|
||||||
* give heavier weighting to edge pixels when finding a matching tile? (thanks Mark)
|
|
||||||
* apply grid lines to preview
|
|
||||||
* optionally add inverted versions of existing tiles if they are a better match
|
|
||||||
* make new tiles out of fragments of existing tiles instead of directly copying from bitmap
|
|
||||||
* allow user to zoom out so the image is letterboxed/windowboxed/etc.
|
|
||||||
* add 'invert' function
|
|
||||||
* allow for image colour hack
|
|
||||||
* make a tool for batch importing images?
|
|
|
@ -0,0 +1,273 @@
|
||||||
|
import init, {
|
||||||
|
add_room,
|
||||||
|
get_palettes,
|
||||||
|
get_preview,
|
||||||
|
load_image,
|
||||||
|
load_game,
|
||||||
|
load_default_game,
|
||||||
|
output,
|
||||||
|
set_brightness,
|
||||||
|
set_dither,
|
||||||
|
set_palette,
|
||||||
|
set_room_name,
|
||||||
|
} from './pkg/pixsy.js';
|
||||||
|
|
||||||
|
if (typeof WebAssembly !== "object") {
|
||||||
|
window.location = "./old/"
|
||||||
|
}
|
||||||
|
|
||||||
|
// stolen from https://ourcodeworld.com/articles/read/189/how-to-create-a-file-and-generate-a-download-with-javascript-in-the-browser-without-a-server
|
||||||
|
function download(filename, text) {
|
||||||
|
let element = document.createElement('a');
|
||||||
|
|
||||||
|
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
||||||
|
element.setAttribute('download', filename);
|
||||||
|
element.style.display = 'none';
|
||||||
|
document.body.appendChild(element);
|
||||||
|
element.click();
|
||||||
|
document.body.removeChild(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
function el(id) {
|
||||||
|
return document.getElementById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pagination(e) {
|
||||||
|
const parent = e.target.parentNode;
|
||||||
|
|
||||||
|
parent.style.display = "none";
|
||||||
|
|
||||||
|
if (e.target.classList.contains("next")) {
|
||||||
|
parent.nextSibling.style.display = "block";
|
||||||
|
} else if (e.target.classList.contains("prev")) {
|
||||||
|
parent.previousSibling.style.display = "block";
|
||||||
|
} else if (e.target.classList.contains("start")) {
|
||||||
|
document.getElementById("start").style.display = "block";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readFile(input, callback, type = "text") {
|
||||||
|
if (input.files && input.files[0]) {
|
||||||
|
let reader = new FileReader();
|
||||||
|
reader.onload = callback;
|
||||||
|
|
||||||
|
if (type === "text") {
|
||||||
|
reader.readAsText(input.files[0]);
|
||||||
|
} else {
|
||||||
|
reader.readAsDataURL(input.files[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
await init();
|
||||||
|
|
||||||
|
const buttonAddImage = el("add");
|
||||||
|
const buttonBackToImage = el("back-to-image");
|
||||||
|
const buttonDownload = el("download");
|
||||||
|
const buttonGameDataProceed = el("game-data-next");
|
||||||
|
const buttonImageProceed = el("image-next");
|
||||||
|
const buttonRoomProceed = el("room-next");
|
||||||
|
const buttonLoadGame = el("load");
|
||||||
|
const buttonNewGame = el("new");
|
||||||
|
const buttonReset = el("reset");
|
||||||
|
const checkboxDither = el("dither");
|
||||||
|
const divCroppie = el("crop");
|
||||||
|
const divNewPalette = el("new-palette");
|
||||||
|
const inputBrightness = el("brightness");
|
||||||
|
const inputColourBackground = el("colour-background");
|
||||||
|
const inputColourForeground = el("colour-foreground");
|
||||||
|
const inputRoomName = el("room-name");
|
||||||
|
const selectPalette = el("palette");
|
||||||
|
const textareaGameDataInput = el("game-data");
|
||||||
|
const textareaGameDataOutput = el("output");
|
||||||
|
|
||||||
|
const croppie = new Croppie(divCroppie, {
|
||||||
|
viewport: {width: 128, height: 128, type: 'square'},
|
||||||
|
boundary: {width: 256, height: 256},
|
||||||
|
enableZoom: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// hide all pages except start page
|
||||||
|
for (let page of document.getElementsByClassName('page')) {
|
||||||
|
page.style.display = "none";
|
||||||
|
}
|
||||||
|
el("start").style.display = "block";
|
||||||
|
|
||||||
|
for (let pageButton of document.getElementsByClassName("pagination")) {
|
||||||
|
pageButton.addEventListener('click', pagination);
|
||||||
|
pageButton.addEventListener('touchend', pagination);
|
||||||
|
}
|
||||||
|
|
||||||
|
// croppie needs to be on screen to work;
|
||||||
|
// halt pagination until we're finished gathering the results
|
||||||
|
buttonImageProceed.removeEventListener("click", pagination);
|
||||||
|
|
||||||
|
function new_game() {
|
||||||
|
load_default_game();
|
||||||
|
textareaGameDataInput.value = output();
|
||||||
|
checkGameData();
|
||||||
|
// we don't need to look at the default game data, so skip ahead to the image page
|
||||||
|
buttonGameDataProceed.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear_game() {
|
||||||
|
textareaGameDataInput.value = "";
|
||||||
|
checkGameData();
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonNewGame.addEventListener("click", new_game);
|
||||||
|
buttonNewGame.addEventListener("touchend", new_game);
|
||||||
|
buttonLoadGame.addEventListener("click", clear_game);
|
||||||
|
buttonLoadGame.addEventListener("touchend", clear_game);
|
||||||
|
|
||||||
|
// handle game data and image
|
||||||
|
|
||||||
|
el("game").addEventListener("change", function() {
|
||||||
|
readFile(this, function (e) {
|
||||||
|
textareaGameDataInput.value = e.target.result;
|
||||||
|
console.log(load_game(e.target.result));
|
||||||
|
checkGameData();
|
||||||
|
}, "text");
|
||||||
|
});
|
||||||
|
|
||||||
|
function setPaletteDropdown() {
|
||||||
|
const palettes = JSON.parse(get_palettes());
|
||||||
|
console.debug(palettes);
|
||||||
|
|
||||||
|
selectPalette.innerHTML = "";
|
||||||
|
|
||||||
|
palettes.push({
|
||||||
|
id: "NEW_PALETTE",
|
||||||
|
name: "new palette"
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let palette of palettes) {
|
||||||
|
let option = document.createElement("option");
|
||||||
|
|
||||||
|
option.value = palette.id;
|
||||||
|
option.innerText = palette.name;
|
||||||
|
|
||||||
|
selectPalette.appendChild(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkGameData() {
|
||||||
|
if (textareaGameDataInput.value.length > 0) {
|
||||||
|
buttonGameDataProceed.removeAttribute("disabled");
|
||||||
|
setPaletteDropdown();
|
||||||
|
} else {
|
||||||
|
buttonGameDataProceed.setAttribute("disabled", "disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
textareaGameDataInput.addEventListener("change", checkGameData);
|
||||||
|
textareaGameDataInput.addEventListener("keyup", checkGameData);
|
||||||
|
checkGameData();
|
||||||
|
|
||||||
|
el('image').addEventListener('change', function () {
|
||||||
|
readFile(this, function (e) {
|
||||||
|
croppie.bind({url: e.target.result, zoom: 0});
|
||||||
|
divCroppie.style.display = "block";
|
||||||
|
buttonImageProceed.removeAttribute("disabled");
|
||||||
|
}, "image");
|
||||||
|
});
|
||||||
|
|
||||||
|
function loadPreview() {
|
||||||
|
el("preview").setAttribute("src", get_preview());
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleImage() {
|
||||||
|
croppie.result({
|
||||||
|
type: "base64",
|
||||||
|
size: "viewport",
|
||||||
|
format: "png",
|
||||||
|
}).then((result) => {
|
||||||
|
console.log("Loading image: " + load_image(result));
|
||||||
|
|
||||||
|
el("page-image").style.display = "none";
|
||||||
|
el("page-room" ).style.display = "block";
|
||||||
|
|
||||||
|
loadPreview();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonImageProceed.addEventListener("click", handleImage);
|
||||||
|
buttonImageProceed.addEventListener("touchend", handleImage);
|
||||||
|
|
||||||
|
selectPalette.addEventListener("change", () => {
|
||||||
|
set_palette(selectPalette.value, inputColourBackground.value, inputColourForeground.value);
|
||||||
|
|
||||||
|
if (selectPalette.value === "NEW_PALETTE") {
|
||||||
|
divNewPalette.style.display = "block";
|
||||||
|
} else {
|
||||||
|
divNewPalette.style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
loadPreview();
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateCustomPalette() {
|
||||||
|
set_palette(selectPalette.value, inputColourBackground.value, inputColourForeground.value);
|
||||||
|
loadPreview();
|
||||||
|
}
|
||||||
|
|
||||||
|
inputColourForeground.addEventListener("change", updateCustomPalette);
|
||||||
|
inputColourBackground.addEventListener("change", updateCustomPalette);
|
||||||
|
|
||||||
|
checkboxDither.addEventListener("change", () => {
|
||||||
|
set_dither(checkboxDither.checked);
|
||||||
|
loadPreview();
|
||||||
|
});
|
||||||
|
|
||||||
|
inputRoomName.addEventListener("change", () => {
|
||||||
|
set_room_name(inputRoomName.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
inputBrightness.addEventListener("input", () => {
|
||||||
|
set_brightness(inputBrightness.value);
|
||||||
|
loadPreview();
|
||||||
|
});
|
||||||
|
|
||||||
|
function addRoom() {
|
||||||
|
el("added").innerText = add_room();
|
||||||
|
textareaGameDataOutput.value = output();
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonRoomProceed.addEventListener("click", addRoom);
|
||||||
|
buttonRoomProceed.addEventListener("touchend", addRoom);
|
||||||
|
|
||||||
|
function handleDownload() {
|
||||||
|
download("output.bitsy", textareaGameDataOutput.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonDownload.addEventListener("click", handleDownload);
|
||||||
|
buttonDownload.addEventListener("touchend", handleDownload);
|
||||||
|
|
||||||
|
function addImage() {
|
||||||
|
textareaGameDataInput.value = textareaGameDataOutput.value;
|
||||||
|
textareaGameDataOutput.value = "";
|
||||||
|
buttonBackToImage.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonAddImage.addEventListener("click", addImage);
|
||||||
|
buttonAddImage.addEventListener("touchend", addImage);
|
||||||
|
|
||||||
|
// would it be easier just to reload the page? lol
|
||||||
|
function reset() {
|
||||||
|
clear_game();
|
||||||
|
// todo clear file inputs
|
||||||
|
inputBrightness.value = 0;
|
||||||
|
inputRoomName.value = "";
|
||||||
|
selectPalette.innerHTML = "";
|
||||||
|
divNewPalette.style.display = "none";
|
||||||
|
inputColourBackground.value = "#000000";
|
||||||
|
inputColourForeground.value = "#ffffff";
|
||||||
|
checkboxDither.checked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonReset.addEventListener("click", reset);
|
||||||
|
buttonReset.addEventListener("touchend", reset);
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
|
@ -0,0 +1,74 @@
|
||||||
|
use image::Rgba;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct ColourMap {
|
||||||
|
background: Rgba<u8>,
|
||||||
|
foreground: Rgba<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ColourMap {
|
||||||
|
pub(crate) fn from(palette: &bitsy_parser::Palette) -> ColourMap {
|
||||||
|
let background = Rgba::from([
|
||||||
|
palette.colours[0].red,
|
||||||
|
palette.colours[0].green,
|
||||||
|
palette.colours[0].blue,
|
||||||
|
255,
|
||||||
|
]);
|
||||||
|
|
||||||
|
let foreground = Rgba::from([
|
||||||
|
palette.colours[1].red,
|
||||||
|
palette.colours[1].green,
|
||||||
|
palette.colours[1].blue,
|
||||||
|
255,
|
||||||
|
]);
|
||||||
|
|
||||||
|
ColourMap { background, foreground }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn diff(a: &Rgba<u8>, b:&Rgba<u8>) -> u32 {
|
||||||
|
let diff_red = (a[0] as i16 - b[0] as i16).abs();
|
||||||
|
let diff_green= (a[1] as i16 - b[1] as i16).abs();
|
||||||
|
let diff_blue = (a[2] as i16 - b[2] as i16).abs();
|
||||||
|
|
||||||
|
(diff_red + diff_green + diff_blue) as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl image::imageops::colorops::ColorMap for ColourMap {
|
||||||
|
type Color = Rgba<u8>;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn index_of(&self, color: &Self::Color) -> usize {
|
||||||
|
let diff_background = diff(color, &self.background);
|
||||||
|
let diff_foreground = diff(color, &self.foreground);
|
||||||
|
|
||||||
|
if diff_foreground <= diff_background { 1 } else { 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn lookup(&self, idx: usize) -> Option<Self::Color> {
|
||||||
|
match idx {
|
||||||
|
0 => Some(self.background.into()),
|
||||||
|
1 => Some(self.foreground.into()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Indicate NeuQuant implements `lookup`.
|
||||||
|
fn has_lookup(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn map_color(&self, color: &mut Self::Color) {
|
||||||
|
let closest = match self.index_of(color) {
|
||||||
|
1 => self.foreground,
|
||||||
|
_ => self.background,
|
||||||
|
};
|
||||||
|
|
||||||
|
color[0] = closest[0];
|
||||||
|
color[1] = closest[1];
|
||||||
|
color[2] = closest[2];
|
||||||
|
color[3] = closest[3];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,395 @@
|
||||||
|
#![feature(clamp)]
|
||||||
|
|
||||||
|
use bitsy_parser::game::Game;
|
||||||
|
use bitsy_parser::image::Image;
|
||||||
|
use bitsy_parser::tile::Tile;
|
||||||
|
use image::{GenericImageView, Pixel, DynamicImage};
|
||||||
|
use image::imageops::ColorMap;
|
||||||
|
use image::imageops::FilterType::CatmullRom;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
mod colour_map;
|
||||||
|
|
||||||
|
use colour_map::ColourMap;
|
||||||
|
|
||||||
|
const SD: u32 = 8;
|
||||||
|
|
||||||
|
enum SelectedPalette {
|
||||||
|
None,
|
||||||
|
Existing {
|
||||||
|
id: String,
|
||||||
|
},
|
||||||
|
New {
|
||||||
|
background: bitsy_parser::Colour,
|
||||||
|
foreground: bitsy_parser::Colour,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
game: Option<Game>,
|
||||||
|
image: Option<DynamicImage>,
|
||||||
|
room_name: Option<String>,
|
||||||
|
palette: SelectedPalette,
|
||||||
|
dither: bool,
|
||||||
|
brightness: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref STATE: Mutex<State> = Mutex::new(
|
||||||
|
State {
|
||||||
|
game: None,
|
||||||
|
image: None,
|
||||||
|
room_name: None,
|
||||||
|
palette: SelectedPalette::None,
|
||||||
|
dither: true,
|
||||||
|
brightness: 0,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tile_name(prefix: &Option<String>, x: &u32, y: &u32) -> Option<String> {
|
||||||
|
if let Some(prefix) = prefix {
|
||||||
|
Some(format!("{} ({},{})", prefix, x, y))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn load_default_game() {
|
||||||
|
let mut state = STATE.lock().unwrap();
|
||||||
|
|
||||||
|
state.game = Some(bitsy_parser::mock::game_default());
|
||||||
|
|
||||||
|
// yes, this will probably always just be "0", but to be safe…
|
||||||
|
state.palette = SelectedPalette::Existing {
|
||||||
|
id: bitsy_parser::mock::game_default().palette_ids()[0].clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn load_game(game_data: String) -> String {
|
||||||
|
let mut state = STATE.lock().unwrap();
|
||||||
|
|
||||||
|
let result = Game::from(game_data);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok((game, _errs)) => {
|
||||||
|
let palette_id = game.palette_ids()[0].clone();
|
||||||
|
state.game = Some(game);
|
||||||
|
state.palette = SelectedPalette::Existing { id: palette_id };
|
||||||
|
format!("Loaded game")
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
state.game = None;
|
||||||
|
state.palette = SelectedPalette::None;
|
||||||
|
format!("{}", result.err().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn load_image(image_base64: String) -> String {
|
||||||
|
let mut state = STATE.lock().expect("Couldn't lock application state");
|
||||||
|
|
||||||
|
let image_base64: Vec<&str> = image_base64.split("base64,").collect();
|
||||||
|
|
||||||
|
if image_base64.len() < 2 {
|
||||||
|
return format!("Error: Badly-formatted base64: {}", image_base64.join(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
let image_base64 = image_base64[1];
|
||||||
|
|
||||||
|
match base64::decode(image_base64) {
|
||||||
|
Ok(image) => {
|
||||||
|
match image::load_from_memory(image.as_ref()) {
|
||||||
|
Ok(image) => {
|
||||||
|
let size = format!("{}×{}", image.width(), image.height());
|
||||||
|
// todo get rid of magic numbers! what about Bitsy HD?
|
||||||
|
let image = image.resize(128, 128, CatmullRom);
|
||||||
|
state.image = Some(image);
|
||||||
|
size
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
state.image = None;
|
||||||
|
"Error: Couldn't load image".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
state.image = None;
|
||||||
|
"Error: Couldn't decode image".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn set_dither(dither: bool) {
|
||||||
|
let mut state = STATE.lock().unwrap();
|
||||||
|
state.dither = dither;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn set_palette(palette_id: &str, background: String, foreground: String) {
|
||||||
|
let mut state = STATE.lock().unwrap();
|
||||||
|
|
||||||
|
state.palette = match palette_id {
|
||||||
|
"NEW_PALETTE" => SelectedPalette::New {
|
||||||
|
background: bitsy_parser::Colour::from_hex(&background).unwrap(),
|
||||||
|
foreground: bitsy_parser::Colour::from_hex(&foreground).unwrap(),
|
||||||
|
},
|
||||||
|
"" => SelectedPalette::None,
|
||||||
|
_ => SelectedPalette::Existing { id: palette_id.to_string() },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn set_room_name(room_name: String) {
|
||||||
|
let mut state = STATE.lock().unwrap();
|
||||||
|
|
||||||
|
match room_name.is_empty() {
|
||||||
|
true => { state.room_name = None },
|
||||||
|
false => { state.room_name = Some(room_name) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn set_brightness(brightness: i32) {
|
||||||
|
let mut state = STATE.lock().unwrap();
|
||||||
|
state.brightness = brightness;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn get_palettes() -> String {
|
||||||
|
let state = STATE.lock().unwrap();
|
||||||
|
|
||||||
|
let mut palette_objects = json::JsonValue::new_array();
|
||||||
|
|
||||||
|
for palette in &state.game.as_ref().unwrap().palettes {
|
||||||
|
let mut object = json::JsonValue::new_object();
|
||||||
|
|
||||||
|
object.insert("id", palette.id.clone()).unwrap();
|
||||||
|
|
||||||
|
object.insert(
|
||||||
|
"name",
|
||||||
|
palette.name.clone().unwrap_or(
|
||||||
|
format!("Palette {}", palette.id))
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
palette_objects.push(object).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
json::stringify(palette_objects)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn image_to_base64(image: &DynamicImage) -> String {
|
||||||
|
let mut bytes: Vec<u8> = Vec::new();
|
||||||
|
image.write_to(&mut bytes, image::ImageOutputFormat::Png).unwrap();
|
||||||
|
format!("data:image/png;base64,{}", base64::encode(&bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn palette_from(bg: &bitsy_parser::Colour, fg: &bitsy_parser::Colour) -> bitsy_parser::Palette {
|
||||||
|
bitsy_parser::Palette {
|
||||||
|
id: "0".to_string(),
|
||||||
|
name: None,
|
||||||
|
colours: vec![
|
||||||
|
bg.clone(), fg.clone(), bitsy_parser::Colour { red: 0, green: 0, blue: 0 }
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_preview(state: &State) -> DynamicImage {
|
||||||
|
let mut buffer = state.image.as_ref().unwrap().clone().into_rgba();
|
||||||
|
|
||||||
|
let palette = match &state.palette {
|
||||||
|
SelectedPalette::None => bitsy_parser::mock::game_default().palettes[0].clone(),
|
||||||
|
SelectedPalette::Existing { id } => state.game.as_ref().unwrap().get_palette(id).unwrap().clone(),
|
||||||
|
SelectedPalette::New { background, foreground } => palette_from(background, foreground),
|
||||||
|
};
|
||||||
|
|
||||||
|
let colour_map = crate::ColourMap::from(&palette);
|
||||||
|
|
||||||
|
// adjust brightness
|
||||||
|
let mut buffer = image::imageops::brighten(&mut buffer, state.brightness);
|
||||||
|
|
||||||
|
if state.dither {
|
||||||
|
image::imageops::dither(&mut buffer, &colour_map);
|
||||||
|
} else {
|
||||||
|
// just do colour indexing
|
||||||
|
let indices = image::imageops::colorops::index_colors(&mut buffer, &colour_map);
|
||||||
|
|
||||||
|
// todo get rid of magic numbers! what about Bitsy HD?
|
||||||
|
buffer = image::ImageBuffer::from_fn(128, 128, |x, y| -> image::Rgba<u8> {
|
||||||
|
let p = indices.get_pixel(x, y);
|
||||||
|
|
||||||
|
colour_map
|
||||||
|
.lookup(p.0[0] as usize)
|
||||||
|
.expect("indexed colour out-of-range")
|
||||||
|
.into()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
image::DynamicImage::ImageRgba8(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn get_preview() -> String {
|
||||||
|
let state = STATE.lock().unwrap();
|
||||||
|
|
||||||
|
match &state.image.is_some() {
|
||||||
|
true => image_to_base64(&render_preview(&state)),
|
||||||
|
false => "".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn add_room() -> String {
|
||||||
|
let mut state = STATE.lock().expect("Couldn't lock application state");
|
||||||
|
|
||||||
|
if state.game.is_none() {
|
||||||
|
return "No game data loaded".to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
match &state.palette {
|
||||||
|
SelectedPalette::None => { return "No palette selected".to_string(); },
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut game = state.game.clone().unwrap();
|
||||||
|
|
||||||
|
if state.image.is_none() {
|
||||||
|
return "No image loaded".to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
let palette_id = Some(match &state.palette {
|
||||||
|
SelectedPalette::None => bitsy_parser::mock::game_default().palettes[0].id.clone(),
|
||||||
|
SelectedPalette::Existing { id } => id.clone(),
|
||||||
|
SelectedPalette::New { background, foreground } => {
|
||||||
|
game.add_palette(palette_from(background, foreground))
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let foreground = &game.palettes
|
||||||
|
.iter()
|
||||||
|
.find(|&palette| &palette.id == palette_id.as_ref().unwrap())
|
||||||
|
.unwrap().colours[1].clone();
|
||||||
|
|
||||||
|
let preview = render_preview(&state);
|
||||||
|
|
||||||
|
let width = 128;
|
||||||
|
let height = 128;
|
||||||
|
let columns = (width as f64 / SD as f64).floor() as u32;
|
||||||
|
let rows = (height as f64 / SD as f64).floor() as u32;
|
||||||
|
|
||||||
|
let mut tile_ids = Vec::new();
|
||||||
|
let initial_tile_count = game.tiles.len();
|
||||||
|
|
||||||
|
for row in 0..rows {
|
||||||
|
for column in 0..columns {
|
||||||
|
let mut pixels = Vec::with_capacity(64);
|
||||||
|
|
||||||
|
fn colour_match(a: &image::Rgb<u8>, b: &bitsy_parser::Colour) -> u8 {
|
||||||
|
if a[0] == b.red && a[1] == b.green && a[2] == b.blue { 1 } else { 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
for y in (row * SD)..((row + 1) * SD) {
|
||||||
|
for x in (column * SD)..((column + 1) * SD) {
|
||||||
|
let pixel = preview.get_pixel(x, y).to_rgb();
|
||||||
|
pixels.push(colour_match(&pixel, foreground));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let tile = Tile {
|
||||||
|
// "0" will get overwritten to a new, safe tile ID
|
||||||
|
id: "0".to_string(),
|
||||||
|
name: tile_name(&state.room_name, &column, &row),
|
||||||
|
wall: None,
|
||||||
|
animation_frames: vec![Image { pixels }],
|
||||||
|
colour_id: None
|
||||||
|
};
|
||||||
|
|
||||||
|
let tile_id = if game.tiles.contains(&tile) {
|
||||||
|
game.tiles.iter().find(|&t| t == &tile).unwrap().id.clone()
|
||||||
|
} else {
|
||||||
|
game.add_tile(tile)
|
||||||
|
};
|
||||||
|
|
||||||
|
tile_ids.push(tile_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
game.add_room(bitsy_parser::Room {
|
||||||
|
id: "0".to_string(),
|
||||||
|
palette_id,
|
||||||
|
name: state.room_name.clone(),
|
||||||
|
tiles: tile_ids,
|
||||||
|
items: vec![],
|
||||||
|
exits: vec![],
|
||||||
|
endings: vec![],
|
||||||
|
walls: None
|
||||||
|
});
|
||||||
|
|
||||||
|
game.dedupe_tiles();
|
||||||
|
|
||||||
|
let new_tile_count = game.tiles.len();
|
||||||
|
|
||||||
|
state.game = Some(game.to_owned());
|
||||||
|
|
||||||
|
format!(
|
||||||
|
"Added room \"{}\" with {} new tiles",
|
||||||
|
&state.room_name.as_ref().unwrap_or(&"untitled".to_string()),
|
||||||
|
new_tile_count - initial_tile_count
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn output() -> String {
|
||||||
|
let state = STATE.lock().unwrap();
|
||||||
|
|
||||||
|
match &state.game {
|
||||||
|
Some(game) => game.to_string(),
|
||||||
|
None => "No game loaded".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::{add_room, load_image, load_default_game, output, get_preview, set_room_name};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn image_to_base64() {
|
||||||
|
let image = image::load_from_memory(include_bytes!("test-resources/test.png")).unwrap();
|
||||||
|
let output = crate::image_to_base64(&image);
|
||||||
|
let expected = include_str!("test-resources/test.png.base64").trim();
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_palettes() {
|
||||||
|
load_default_game();
|
||||||
|
let output = crate::get_palettes();
|
||||||
|
let expected = "[{\"id\":\"0\",\"name\":\"blueprint\"}]";
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn render_preview() {
|
||||||
|
load_default_game();
|
||||||
|
load_image(include_str!("test-resources/colour_input.png.base64").trim().to_string());
|
||||||
|
let output = get_preview();
|
||||||
|
let expected = include_str!("test-resources/colour_input.png.base64.greyscale").trim();
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn example() {
|
||||||
|
load_default_game();
|
||||||
|
load_image(include_str!("test-resources/test.png.base64").trim().to_string());
|
||||||
|
set_room_name("test".to_string());
|
||||||
|
println!("add_room(): {}", add_room());
|
||||||
|
// todo what? why are extraneous pixels appearing in the output tiles?
|
||||||
|
assert_eq!(output(), include_str!("test-resources/expected.bitsy"));
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,159 @@
|
||||||
|
Write your game's title here
|
||||||
|
|
||||||
|
# BITSY VERSION 7.2
|
||||||
|
|
||||||
|
! ROOM_FORMAT 1
|
||||||
|
|
||||||
|
PAL 0
|
||||||
|
NAME blueprint
|
||||||
|
0,82,204
|
||||||
|
128,159,255
|
||||||
|
255,255,255
|
||||||
|
|
||||||
|
ROOM 0
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
0,a,a,a,a,a,a,a,a,a,a,a,a,a,a,0
|
||||||
|
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
||||||
|
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
||||||
|
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
||||||
|
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
||||||
|
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
||||||
|
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
||||||
|
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
||||||
|
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
||||||
|
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
||||||
|
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
||||||
|
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
||||||
|
0,a,0,0,0,0,0,0,0,0,0,0,0,0,a,0
|
||||||
|
0,a,a,a,a,a,a,a,a,a,a,a,a,a,a,0
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
NAME example room
|
||||||
|
PAL 0
|
||||||
|
|
||||||
|
ROOM 1
|
||||||
|
a,a,1,1,2,2,3,0,0,0,0,0,0,0,0,0
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
NAME test
|
||||||
|
PAL 0
|
||||||
|
|
||||||
|
TIL a
|
||||||
|
11111111
|
||||||
|
10000001
|
||||||
|
10000001
|
||||||
|
10011001
|
||||||
|
10011001
|
||||||
|
10000001
|
||||||
|
10000001
|
||||||
|
11111111
|
||||||
|
NAME block
|
||||||
|
|
||||||
|
TIL 1
|
||||||
|
00011000
|
||||||
|
00111000
|
||||||
|
00011000
|
||||||
|
00011000
|
||||||
|
00011000
|
||||||
|
00011000
|
||||||
|
00011000
|
||||||
|
00111100
|
||||||
|
NAME test (2,0)
|
||||||
|
|
||||||
|
TIL 2
|
||||||
|
00111100
|
||||||
|
01100110
|
||||||
|
01100110
|
||||||
|
00001100
|
||||||
|
00011000
|
||||||
|
00110000
|
||||||
|
01100000
|
||||||
|
01111110
|
||||||
|
NAME test (4,0)
|
||||||
|
|
||||||
|
TIL 3
|
||||||
|
00111100
|
||||||
|
01100110
|
||||||
|
01100110
|
||||||
|
00001100
|
||||||
|
00001100
|
||||||
|
01100110
|
||||||
|
01100110
|
||||||
|
00111100
|
||||||
|
NAME test (6,0)
|
||||||
|
|
||||||
|
SPR A
|
||||||
|
00011000
|
||||||
|
00011000
|
||||||
|
00011000
|
||||||
|
00111100
|
||||||
|
01111110
|
||||||
|
10111101
|
||||||
|
00100100
|
||||||
|
00100100
|
||||||
|
POS 0 4,4
|
||||||
|
|
||||||
|
SPR a
|
||||||
|
00000000
|
||||||
|
00000000
|
||||||
|
01010001
|
||||||
|
01110001
|
||||||
|
01110010
|
||||||
|
01111100
|
||||||
|
00111100
|
||||||
|
00100100
|
||||||
|
NAME cat
|
||||||
|
DLG 0
|
||||||
|
POS 0 8,12
|
||||||
|
|
||||||
|
ITM 0
|
||||||
|
00000000
|
||||||
|
00000000
|
||||||
|
00000000
|
||||||
|
00111100
|
||||||
|
01100100
|
||||||
|
00100100
|
||||||
|
00011000
|
||||||
|
00000000
|
||||||
|
NAME tea
|
||||||
|
DLG 1
|
||||||
|
|
||||||
|
ITM 1
|
||||||
|
00000000
|
||||||
|
00111100
|
||||||
|
00100100
|
||||||
|
00111100
|
||||||
|
00010000
|
||||||
|
00011000
|
||||||
|
00010000
|
||||||
|
00011000
|
||||||
|
NAME key
|
||||||
|
DLG 2
|
||||||
|
|
||||||
|
DLG 0
|
||||||
|
I'm a cat
|
||||||
|
NAME cat dialog
|
||||||
|
|
||||||
|
DLG 1
|
||||||
|
You found a nice warm cup of tea
|
||||||
|
NAME tea dialog
|
||||||
|
|
||||||
|
DLG 2
|
||||||
|
A key! {wvy}What does it open?{wvy}
|
||||||
|
NAME key dialog
|
||||||
|
|
||||||
|
VAR a
|
||||||
|
42
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 523 B |
|
@ -0,0 +1 @@
|
||||||
|
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAABHNCSVQICAgIfAhkiAAAAcJJREFUeJzt19FqgzAAQFEz+v+/nD1t2NLWsQgW7jlP2ogVvUYdc865LRhj/C7/7Gr/29678cfDeNxmdZznbtv2vwu2H39cPtr26H/mnNuc8259ZZzXvs7a0dHJdjE+022/sjKFrzh6jKyO89ppM8AZrgqw7C6AMcbbk3s0vmL1BfLZewDHPmIGcOdfZ5z1GbjymfbqEI7u5nf7EMvfjG3bzJVhH/EI4DoCiBNAnADiBBAngDgBxAkgTgBxAogTQJwA4gQQJ4A4AcQJIE4AcQKIE0CcAOIEECeAOAHECSBOAHECiBNAnADiBBAngDgBxAkgTgBxAogTQJwA4gQQJ4A4AcQJIE4AcQKIE0CcAOIEECeAOAHECSBOAHECiBNAnADiBBAngDgBxAkgTgBxAogTQJwA4gQQJ4A4AcQJIE4AcQKIE0CcAOIEECeAOAHECSBOAHECiBNAnADiBBAngDgBxAkgTgBxAogTQJwA4gQQJ4A4AcQJIE4AcQKIE0CcAOIEECeAOAHECSBOAHECiBNAnADiBBAngDgBxAkgTgBxAogTQJwA4gQQJ4A4AcQJIE4AcQKIE0CcAOIEECeAOAHEfQM+SHkFb+/YEwAAAABJRU5ErkJggg==
|
Loading…
Reference in New Issue