Comparing version 1.0.0 to 1.1.0
135
lib/html.js
@@ -83,3 +83,106 @@ (function() { | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.datom_as_html = (d) => { | ||
this.parse_compact_tagname = function(compact_tagname) { | ||
var R, attribute, attributes, avalue, i, len, ref, tagname; | ||
({tagname, attributes} = (compact_tagname.match(/^(?<tagname>[^#.]*)(?<attributes>.*)$/)).groups); | ||
R = {}; | ||
if (tagname !== '') { | ||
R.tagname = tagname; | ||
} | ||
if (attributes === '') { | ||
return R; | ||
} | ||
ref = attributes.split(/([#.][^#.]*)/); | ||
for (i = 0, len = ref.length; i < len; i++) { | ||
attribute = ref[i]; | ||
if (attribute === '') { | ||
continue; | ||
} | ||
avalue = attribute.slice(1); | ||
if (!(avalue.length > 0)) { | ||
throw new Error(`^intertext/parse_compact_tagname@4422^ illegal compact tag syntax in ${rpr(compact_tagname)}`); | ||
} | ||
if (attribute[0] === '#') { | ||
R.id = avalue; | ||
} else { | ||
(R.class != null ? R.class : R.class = []).push(avalue); | ||
} | ||
} | ||
if (R.class != null) { | ||
R.class = R.class.join(' '); | ||
} | ||
return R; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.h = function(compact_tagname, attributes, ...content) { | ||
var R, clasz, end_tag, i, id, idx, len, part, sigil, start_tag, tagname, use_attributes; | ||
validate.nonempty_text(compact_tagname); | ||
({ | ||
tagname, | ||
id, | ||
class: clasz | ||
} = this.parse_compact_tagname(compact_tagname)); | ||
validate.intertext_html_tagname(tagname); | ||
use_attributes = false; | ||
if (attributes != null) { | ||
if (isa.object(attributes)) { | ||
use_attributes = true; | ||
} else { | ||
content.unshift(attributes); | ||
} | ||
} | ||
if (content.length === 0) { | ||
sigil = '^'; | ||
end_tag = null; | ||
} else { | ||
sigil = '<'; | ||
end_tag = { | ||
$key: `>${tagname}` | ||
}; | ||
for (idx = i = 0, len = content.length; i < len; idx = ++i) { | ||
part = content[idx]; | ||
if (isa.text(part)) { | ||
content[idx] = { | ||
$key: '^text', | ||
text: this._escape_text(part) | ||
}; | ||
} | ||
} | ||
} | ||
start_tag = { | ||
$key: `${sigil}${tagname}` | ||
}; | ||
if (id != null) { | ||
start_tag.id = id; | ||
} | ||
if (clasz != null) { | ||
start_tag.class = clasz; | ||
} | ||
if (use_attributes) { | ||
assign(start_tag, attributes); | ||
} | ||
R = [start_tag, ...content]; | ||
if (end_tag != null) { | ||
R.push(end_tag); | ||
} | ||
return R.flat(2e308); | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.datoms_as_html = function(ds) { | ||
var d; | ||
validate.list(ds); | ||
return ((function() { | ||
var i, len, results; | ||
results = []; | ||
for (i = 0, len = ds.length; i < len; i++) { | ||
d = ds[i]; | ||
results.push(this.datom_as_html(d)); | ||
} | ||
return results; | ||
}).call(this)).join(''); | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.datom_as_html = function(d) { | ||
var atxt, i, key, len, ref, ref1, ref2, ref3, sigil, slash, src, tagname, value, x_key, x_sys_key; | ||
@@ -152,3 +255,3 @@ DATOM.types.validate.datom_datom(d); | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.$datom_as_html = () => { | ||
this.$datom_as_html = function() { | ||
var $; | ||
@@ -249,2 +352,30 @@ ({$} = (require('steampipes')).export()); | ||
-------------------------------------------------------------------------------- | ||
from https://github.com/goodeggs/teacup/blob/master/src/teacup.coffee | ||
elements = | ||
* Valid HTML 5 elements requiring a closing tag. | ||
* Note: the `var` element is out for obvious reasons, please use `tag 'var'`. | ||
regular: 'a abbr address article aside audio b bdi bdo blockquote body button | ||
canvas caption cite code colgroup datalist dd del details dfn div dl dt em | ||
fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 head header hgroup | ||
html i iframe ins kbd label legend li map mark menu meter nav noscript object | ||
ol optgroup option output p pre progress q rp rt ruby s samp section | ||
select small span strong sub summary sup table tbody td textarea tfoot | ||
th thead time title tr u ul video' | ||
raw: 'style' | ||
script: 'script' | ||
* Valid self-closing HTML 5 elements. | ||
void: 'area base br col command embed hr img input keygen link meta param | ||
source track wbr' | ||
obsolete: 'applet acronym bgsound dir frameset noframes isindex listing | ||
nextid noembed plaintext rb strike xmp big blink center font marquee multicol | ||
nobr spacer tt' | ||
obsolete_void: 'basefont frame' | ||
-------------------------------------------------------------------------------- | ||
* #----------------------------------------------------------------------------------------------------------- | ||
@@ -251,0 +382,0 @@ * @html5_block_level_tagnames = new Set """address article aside blockquote dd details dialog div dl dt |
(function() { | ||
'use strict'; | ||
var CND, FS, INTERTEXT, Intertext, MAIN, Multimix, PATH, alert, assign, badge, cast, debug, echo, help, info, isa, jr, log, rpr, type_of, urge, validate, warn, whisper; | ||
var CND, FS, Html, Hyph, INTERTEXT, Intertext, MAIN, Mkts, Multimix, PATH, Slabs, alert, assign, badge, cast, debug, echo, help, info, isa, jr, log, rpr, type_of, urge, validate, warn, whisper; | ||
@@ -45,12 +45,51 @@ //########################################################################################################### | ||
/* | ||
#........................................................................................................... | ||
_format = require 'number-format.js' | ||
format_float = ( x ) -> _format '#,##0.000', x | ||
format_integer = ( x ) -> _format '#,##0.', x | ||
format_as_percentage = ( x ) -> _format '#,##0.00', x * 100 | ||
*/ | ||
Html = (function() { | ||
/* | ||
#........................................................................................................... | ||
_format = require 'number-format.js' | ||
format_float = ( x ) -> _format '#,##0.000', x | ||
format_integer = ( x ) -> _format '#,##0.', x | ||
format_as_percentage = ( x ) -> _format '#,##0.00', x * 100 | ||
*/ | ||
//----------------------------------------------------------------------------------------------------------- | ||
class Html extends Multimix {}; | ||
Html.include(require('./html')); | ||
return Html; | ||
}).call(this); | ||
Mkts = (function() { | ||
//----------------------------------------------------------------------------------------------------------- | ||
class Mkts extends Multimix {}; | ||
Mkts.include(require('./mkts')); | ||
return Mkts; | ||
}).call(this); | ||
Hyph = (function() { | ||
//----------------------------------------------------------------------------------------------------------- | ||
class Hyph extends Multimix {}; | ||
Hyph.include(require('./hyphenation')); | ||
return Hyph; | ||
}).call(this); | ||
Slabs = (function() { | ||
//----------------------------------------------------------------------------------------------------------- | ||
class Slabs extends Multimix {}; | ||
Slabs.include(require('./slabs')); | ||
return Slabs; | ||
}).call(this); | ||
//=========================================================================================================== | ||
//----------------------------------------------------------------------------------------------------------- | ||
MAIN = this; | ||
@@ -65,6 +104,6 @@ | ||
super(); | ||
this.HTML = require('./html'); | ||
this.MKTS = require('./mkts'); | ||
this.HYPH = require('./hyphenation'); | ||
this.SLABS = require('./slabs'); | ||
this.HTML = new Html(); | ||
this.MKTS = new Mkts(); | ||
this.HYPH = new Hyph(); | ||
this.SLABS = new Slabs(); | ||
if (target != null) { | ||
@@ -71,0 +110,0 @@ this.export(target); |
@@ -96,3 +96,3 @@ (function() { | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["isa.intertext_html_tagname"] = async function(T, done) { | ||
this["isa.intertext_html_tagname (1)"] = async function(T, done) { | ||
var error, i, len, matcher, probe, probes_and_matchers; | ||
@@ -114,2 +114,27 @@ probes_and_matchers = [["", false, null], ["\"", false, null], ["'", false, null], ["<", false, null], ["<>", false, null], ["foo bar", false, null], ["foo\nbar", false, null], ["foo", true, null], ["此は何ですか", true, null]]; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["isa.intertext_html_tagname (2)"] = async function(T, done) { | ||
var i, len, probe, probes; | ||
probes = `a abbr acronym address applet area article aside audio b base basefont bdi bdo bgsound big | ||
blink blockquote body br button canvas caption center cite code col colgroup command datalist dd del | ||
details dfn dialog dir div dl dt em embed fieldset figcaption figure font footer form frame frameset h1 h2 | ||
h3 h4 h5 h6 head header hgroup hr html i iframe img input ins isindex kbd keygen label legend li link | ||
listing main map mark marquee menu meta meter multicol nav nextid nobr noembed noframes noscript object ol | ||
optgroup option output p param plaintext pre progress q rb rp rt ruby s samp script section select small | ||
source spacer span strike strong sub summary sup table tbody td textarea tfoot th thead time title tr | ||
track tt u ul video wbr xmp | ||
foo:bar foo-bar Foo-bar`.split(/\s+/); | ||
for (i = 0, len = probes.length; i < len; i++) { | ||
probe = probes[i]; | ||
await T.perform(probe, true, null, function() { | ||
return new Promise(function(resolve, reject) { | ||
return resolve(isa.intertext_html_tagname(probe)); | ||
}); | ||
}); | ||
} | ||
//......................................................................................................... | ||
done(); | ||
return null; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["HTML.datom_as_html (singular tags)"] = async function(T, done) { | ||
@@ -1186,2 +1211,399 @@ var error, i, len, matcher, probe, probes_and_matchers; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["HTML.parse_compact_tagname"] = async function(T, done) { | ||
var error, h, i, len, matcher, parse_compact_tagname, probe, probes_and_matchers; | ||
INTERTEXT = require('../..'); | ||
({parse_compact_tagname, h} = INTERTEXT.HTML.export()); | ||
//......................................................................................................... | ||
probes_and_matchers = [ | ||
[ | ||
"foo-bar", | ||
{ | ||
"tagname": "foo-bar" | ||
}, | ||
null | ||
], | ||
[ | ||
"foo-bar#c55", | ||
{ | ||
"tagname": "foo-bar", | ||
"id": "c55" | ||
}, | ||
null | ||
], | ||
[ | ||
"foo-bar.blah.beep", | ||
{ | ||
"tagname": "foo-bar", | ||
"class": "blah beep" | ||
}, | ||
null | ||
], | ||
[ | ||
"foo-bar#c55.blah.beep", | ||
{ | ||
"tagname": "foo-bar", | ||
"id": "c55", | ||
"class": "blah beep" | ||
}, | ||
null | ||
], | ||
[ | ||
"#c55", | ||
{ | ||
id: "c55" | ||
} | ||
], | ||
[ | ||
".blah.beep", | ||
{ | ||
"class": "blah beep" | ||
} | ||
], | ||
["...#", | ||
null, | ||
"illegal compact tag syntax"] | ||
]; | ||
for (i = 0, len = probes_and_matchers.length; i < len; i++) { | ||
[probe, matcher, error] = probes_and_matchers[i]; | ||
await T.perform(probe, matcher, error, function() { | ||
return new Promise(function(resolve, reject) { | ||
return resolve(parse_compact_tagname(probe)); | ||
}); | ||
}); | ||
} | ||
//......................................................................................................... | ||
done(); | ||
return null; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["HTML.h"] = async function(T, done) { | ||
var error, h, i, len, matcher, parse_compact_tagname, probe, probes_and_matchers; | ||
INTERTEXT = require('../..'); | ||
({parse_compact_tagname, h} = INTERTEXT.HTML.export()); | ||
//......................................................................................................... | ||
probes_and_matchers = [ | ||
[ | ||
["div"], | ||
[ | ||
{ | ||
"$key": "^div" | ||
} | ||
], | ||
null | ||
], | ||
[ | ||
["div#x32"], | ||
[ | ||
{ | ||
"$key": "^div", | ||
"id": "x32" | ||
} | ||
], | ||
null | ||
], | ||
[ | ||
["div.foo"], | ||
[ | ||
{ | ||
"$key": "^div", | ||
"class": "foo" | ||
} | ||
], | ||
null | ||
], | ||
[ | ||
["div#x32.foo"], | ||
[ | ||
{ | ||
"$key": "^div", | ||
"id": "x32", | ||
"class": "foo" | ||
} | ||
], | ||
null | ||
], | ||
[ | ||
[ | ||
"div#x32", | ||
{ | ||
"alt": "nice guy" | ||
} | ||
], | ||
[ | ||
{ | ||
"$key": "^div", | ||
"id": "x32", | ||
"alt": "nice guy" | ||
} | ||
], | ||
null | ||
], | ||
[ | ||
[ | ||
"div#x32", | ||
{ | ||
"alt": "nice guy" | ||
}, | ||
" a > b & b > c => a > c" | ||
], | ||
[ | ||
{ | ||
"$key": "<div", | ||
"id": "x32", | ||
"alt": "nice guy" | ||
}, | ||
{ | ||
"$key": "^text", | ||
"text": " a > b & b > c => a > c" | ||
}, | ||
{ | ||
"$key": ">div" | ||
} | ||
], | ||
null | ||
], | ||
[ | ||
["foo-bar"], | ||
[ | ||
{ | ||
"$key": "^foo-bar" | ||
} | ||
], | ||
null | ||
], | ||
[ | ||
["foo-bar#c55"], | ||
[ | ||
{ | ||
"$key": "^foo-bar", | ||
"id": "c55" | ||
} | ||
], | ||
null | ||
], | ||
[ | ||
["foo-bar.blah.beep"], | ||
[ | ||
{ | ||
"$key": "^foo-bar", | ||
"class": "blah beep" | ||
} | ||
], | ||
null | ||
], | ||
[ | ||
["foo-bar#c55.blah.beep"], | ||
[ | ||
{ | ||
"$key": "^foo-bar", | ||
"id": "c55", | ||
"class": "blah beep" | ||
} | ||
], | ||
null | ||
], | ||
[["#c55"], | ||
null, | ||
"not a valid intertext_html_tagname"], | ||
[[".blah.beep"], | ||
null, | ||
"not a valid intertext_html_tagname"], | ||
[["...#"], | ||
null, | ||
"illegal compact tag syntax"] | ||
]; | ||
for (i = 0, len = probes_and_matchers.length; i < len; i++) { | ||
[probe, matcher, error] = probes_and_matchers[i]; | ||
await T.perform(probe, matcher, error, function() { | ||
return new Promise(function(resolve, reject) { | ||
// urge h probe... | ||
return resolve(h(...probe)); | ||
}); | ||
}); | ||
} | ||
//......................................................................................................... | ||
done(); | ||
return null; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["HTML.datoms_as_html (1)"] = async function(T, done) { | ||
var datoms_as_html, error, h, i, len, matcher, probe, probes_and_matchers; | ||
INTERTEXT = require('../..'); | ||
({datoms_as_html, h} = INTERTEXT.HTML.export()); | ||
//......................................................................................................... | ||
probes_and_matchers = [ | ||
[["div"], | ||
"<div></div>", | ||
null], | ||
[["div#x32"], | ||
"<div id=x32></div>", | ||
null], | ||
[["div.foo"], | ||
"<div class=foo></div>", | ||
null], | ||
[["div#x32.foo"], | ||
"<div class=foo id=x32></div>", | ||
null], | ||
[ | ||
[ | ||
"div#x32", | ||
{ | ||
"alt": "nice guy" | ||
} | ||
], | ||
"<div alt='nice guy' id=x32></div>", | ||
null | ||
], | ||
[ | ||
[ | ||
"div#x32", | ||
{ | ||
"alt": "nice guy" | ||
}, | ||
" a > b & b > c => a > c" | ||
], | ||
"<div alt='nice guy' id=x32> a &gt; b &amp; b &gt; c =&gt; a &gt; c</div>", | ||
null | ||
], | ||
[["foo-bar"], | ||
"<foo-bar></foo-bar>", | ||
null], | ||
[["foo-bar#c55"], | ||
"<foo-bar id=c55></foo-bar>", | ||
null], | ||
[["foo-bar.blah.beep"], | ||
"<foo-bar class='blah beep'></foo-bar>", | ||
null], | ||
[["foo-bar#c55.blah.beep"], | ||
"<foo-bar class='blah beep' id=c55></foo-bar>", | ||
null], | ||
[["#c55"], | ||
null, | ||
"not a valid intertext_html_tagname"], | ||
[[".blah.beep"], | ||
null, | ||
"not a valid intertext_html_tagname"], | ||
[["...#"], | ||
null, | ||
"illegal compact tag syntax"] | ||
]; | ||
for (i = 0, len = probes_and_matchers.length; i < len; i++) { | ||
[probe, matcher, error] = probes_and_matchers[i]; | ||
await T.perform(probe, matcher, error, function() { | ||
return new Promise(function(resolve, reject) { | ||
// urge datoms_as_html h probe... | ||
return resolve(datoms_as_html(h(...probe))); | ||
}); | ||
}); | ||
} | ||
//......................................................................................................... | ||
done(); | ||
return null; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["HTML.datoms_as_html (2)"] = function(T, done) { | ||
var datoms_as_html, dhtml, h; | ||
INTERTEXT = require('../..'); | ||
({datoms_as_html, h} = INTERTEXT.HTML.export()); | ||
//......................................................................................................... | ||
urge(dhtml = h('article#c2', { | ||
editable: true | ||
}, h('h1', "A truly curious Coincidence"))); | ||
T.eq(dhtml, [ | ||
{ | ||
'$key': '<article', | ||
id: 'c2', | ||
editable: true | ||
}, | ||
{ | ||
'$key': '<h1' | ||
}, | ||
{ | ||
'$key': '^text', | ||
text: 'A truly curious Coincidence' | ||
}, | ||
{ | ||
'$key': '>h1' | ||
}, | ||
{ | ||
'$key': '>article' | ||
} | ||
]); | ||
//......................................................................................................... | ||
done(); | ||
return null; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["HTML.datoms_as_html (3)"] = function(T, done) { | ||
var datoms_as_html, dhtml, h; | ||
INTERTEXT = require('../..'); | ||
({datoms_as_html, h} = INTERTEXT.HTML.export()); | ||
//......................................................................................................... | ||
urge(dhtml = h('article#c2', { | ||
editable: true | ||
}, h('h1', "A truly curious Coincidence"), h('p.noindent', h('em', "Seriously,"), " he said, ", h('em', "we'd better start cooking now.")))); | ||
//......................................................................................................... | ||
whisper(jr(datoms_as_html(dhtml))); | ||
T.eq(datoms_as_html(dhtml), "<article editable id=c2><h1>A truly curious Coincidence</h1><p class=noindent><em>Seriously,</em> he said, <em>we'd better start cooking now.</em></p></article>"); | ||
T.eq(dhtml, [ | ||
{ | ||
'$key': '<article', | ||
id: 'c2', | ||
editable: true | ||
}, | ||
{ | ||
'$key': '<h1' | ||
}, | ||
{ | ||
'$key': '^text', | ||
text: 'A truly curious Coincidence' | ||
}, | ||
{ | ||
'$key': '>h1' | ||
}, | ||
{ | ||
'$key': '<p', | ||
class: 'noindent' | ||
}, | ||
{ | ||
'$key': '<em' | ||
}, | ||
{ | ||
'$key': '^text', | ||
text: 'Seriously,' | ||
}, | ||
{ | ||
'$key': '>em' | ||
}, | ||
{ | ||
'$key': '^text', | ||
text: ' he said, ' | ||
}, | ||
{ | ||
'$key': '<em' | ||
}, | ||
{ | ||
'$key': '^text', | ||
text: "we'd better start cooking now." | ||
}, | ||
{ | ||
'$key': '>em' | ||
}, | ||
{ | ||
'$key': '>p' | ||
}, | ||
{ | ||
'$key': '>article' | ||
} | ||
]); | ||
//......................................................................................................... | ||
done(); | ||
return null; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["HTML demo"] = function(T, done) { | ||
@@ -1251,3 +1673,7 @@ var d, datoms, i, len, ref, text; | ||
// await @_demo() | ||
test(this); | ||
// test @ | ||
// test @[ "HTML.parse_compact_tagname" ] | ||
// test @[ "HTML.h" ] | ||
// test @[ "isa.intertext_html_tagname (2)" ] | ||
test(this["HTML.datoms_as_html (3)"]); | ||
return help('ok'); | ||
@@ -1257,4 +1683,2 @@ })(); | ||
// test @[ "demo" ] | ||
}).call(this); |
@@ -1,2 +0,1 @@ | ||
// Generated by CoffeeScript 2.5.0 | ||
(function() { | ||
@@ -228,3 +227,3 @@ 'use strict'; | ||
tagname_tail_pattern = /\.-0-9\xb7\u0300-\u036f\u203f-\u2040/u; | ||
tagname_tail_pattern = /0-9\.\x2d\xb7\u0300-\u036f\u203f-\u2040/u; | ||
@@ -278,3 +277,1 @@ tagname_pattern = RegExp(`^[${tagname_head_pattern.source}][${tagname_head_pattern.source}${tagname_tail_pattern.source}]*$`, "u"); | ||
}).call(this); | ||
//# sourceMappingURL=types.js.map |
{ | ||
"name": "intertext", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "Services for Recurrent Text-related Tasks", | ||
@@ -38,3 +38,3 @@ "main": "lib/main.js", | ||
"linebreak": "^1.0.2", | ||
"multimix": "^2.1.3", | ||
"multimix": "^2.1.4", | ||
"steampipes": "^5.0.0" | ||
@@ -41,0 +41,0 @@ }, |
@@ -18,2 +18,4 @@ | ||
- [HTML Generation](#html-generation) | ||
- [HTML Generation from Datoms](#html-generation-from-datoms) | ||
- [HTML Generation from Method Calls](#html-generation-from-method-calls) | ||
- [Example: HTML Parsing and HTML Generation](#example-html-parsing-and-html-generation) | ||
@@ -280,3 +282,3 @@ - [Benchmarks](#benchmarks) | ||
<!-- Successor to `coffeenode-teacup`? --> | ||
#### HTML Generation from Datoms | ||
@@ -312,2 +314,19 @@ `{ HTML, } = require 'intertext'` | ||
#### HTML Generation from Method Calls | ||
compact syntax for HTML tags: | ||
* `HTML.parse_compact_tagname = ( compact_tagname ) ->`: Given a string with tagname followed by using CSS | ||
selector syntax, return an obkject with `tagname`, `id`, `class` | ||
* `HTML.datoms_as_html = ( ds ) ->` | ||
* `HTML.h = ( compact_tagname, attributes, content... ) ->` | ||
`<div#c432.foo.bar>...</div>` => `<div id=c432 class='foo bar'>...</div>` | ||
`<p.noindent>...</p>` => `<p class=noindent>...</p>` | ||
### Example: HTML Parsing and HTML Generation | ||
@@ -314,0 +333,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
301082
3806
587
Updatedmultimix@^2.1.4