0.5.1 • Published 7 years ago

vrdom v0.5.1

Weekly downloads
5
License
WTFPL
Repository
github
Last release
7 years ago

vrdom

An alternative to react production build for browser side.

What works and documented on react in production should work with vrdom.

Usage with transpilers

babel inline configuration

/** @jsx vrdom.createElement */

var vrdom = require("vrdom");

babel6 .babelrc configuration

{
  "plugins": [
    ["transform-react-jsx", { "pragma": "vrdom.createElement" }]
  ]
}

Example

jsfiddle

/** @jsx vrdom.createElement */

let container = document.createElement("div");
document.body.appendChild(container);

class Component extends vrdom.Component {
  render() {
    return <div>COMPONENT</div>;
  }
}

let ComponentClass = vrdom.createClass({
  render() {
    return <div>COMPONENT CLASS</div>;
  }
});

function Stateless() {
  return <div>STATELESS COMPONENT</div>;
}

vrdom.render(
  <div>
    <div>DOM</div>
    <Component />
    <ComponentClass />
    <Stateless />
  </div>
, container);

What is not in vrdom

  • Proptypes: Although it may help for development,
    there are not used in production build of neither React nor Preact. However, empty proptypes exists to keep compatibility with existing react plugins.
  • Warnings: missing almost all React warings. ex: on aria-* and others. Again not used in production build
  • Developper Tool
  • Performance Tool
  • Addons
  • Undocumented react api unstable_*

Hooks

Third party libraries can sometimes be painful to integrate with react.
Hooks were created for that purpose.

For example, to integrate material design lite(MDL), some libraries specific to react have been created.
To use MDL, reading MDL documetion is not enough, you also need to read those libraries specific to react.

With hooks, to integrate MDL, you can do

jsfiddle

class MDLComponent extends vrdom.Component {
  componentDidMount() {
    this.el = vrdom.findDOMNode(this);
    componentHandler.upgradeElement(this.el);
  }

  componentWillUnmount() {
    componentHandler.downgradeElements([this.el]);
    delete this.el;
  }

  render() {
    var tagName = this.props.tagName || "span";
    var args = [tagName, this.props.config];

    // add children
    var children = this.props.children;
    if (Array.isArray(children)) {
      args.push.apply(args, children);
    } else if (children != null) {
      args.push(children);
    }

    // create the node,
    // upgrade on mount,
    // downgrage on unmount
    return vrdom.createElement.apply(vrdom, args);
  }
}

function MDLMiddleware(args) {
  var type = args[0];
  var config = args[1];

  if (config && !config.mdlIgnore && "string" === typeof type && /(?:^|\s)mdl-/.test(config.className || config.class)) {
    args[0] = MDLComponent; // replace element type with MDLComponent

    args[1] = {
      key: config.key, // preserve key
      ref: config.ref, // preserve ref
      tagName: type,
      config: vrdom.functions.assign({}, config) // clone because we will modify config
    };

    // ignore MDLMiddleware when creating element in MDLComponent
    // and thus avoiding a stack overflow
    args[1].config.mdlIgnore = true;

    delete args[1].config.key; // key has been used
    delete args[1].config.ref; // ref has been used
  }

  return args;
}

/* Tell vrdom to call MDLMiddleware before creating any element */
vrdom.hooks.appendHook("beforeCreateElement", MDLMiddleware);

/* From this point, any DOM element created with a className starting with mdl-, will be an MDLComponent */

/* use createClass to get autobindings */
var MDLElement = vrdom.createClass({
  handleClick(evt) {
    evt.preventDefault();
    var button = vrdom.findDOMNode(this.refs.button);
    alert(button.type + " click");
  },

  render() {
    return (
      <div className="container material-design-lite-components">
        {/* Badges */}
        <div className="container">
          {/* Number badge on icon */}
          <div className="material-icons mdl-badge mdl-badge--overlap" data-badge={1}>account_box</div>
          {/* Icon badge on icon */}
          <div className="material-icons mdl-badge mdl-badge--overlap" data-badge="♥">account_box</div>
        </div>

        {/* Buttons */}
        <button
          type="button" ref="button" onClick={ this.handleClick }
          className="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--accent"
        >
          Button
        </button>
      </div>
    );
  }
});

var container = document.createElement("div");
document.body.appendChild(container);
vrdom.render(<MDLElement />, container);

HTML Attribtes

IDL Attributes and their HTML Attributescounter parts can be used.

Most attributes are case insensitive like in HTML.

data-*, aria-*, on* attributes are case insensitive.

Here is the list of all supported attributes:

IDL AttributeHTML AttributeComment
aLinkalinkAttribute case insensitive
abbrabbrAttribute case insensitive
acceptacceptAttribute case insensitive
acceptCharsetaccept-charsetAttribute case insensitive
accessKeyaccesskeyAttribute case insensitive
actionactionAttribute case insensitive
alignalignAttribute case insensitive
allowFullscreenallowfullscreenAttribute case insensitive
allowTransparencyallowtransparencyAttribute case insensitive
altaltAttribute case insensitive
archivearchiveAttribute case insensitive
asyncasyncAttribute case insensitive
autocompleteautocompleteAttribute case insensitive
autofocusautofocusAttribute case insensitive
autoplayautoplayAttribute case insensitive
axisaxisAttribute case insensitive
backgroundbackgroundAttribute case insensitive
behaviorbehaviorAttribute case insensitive
bgColorbgcolorAttribute case insensitive
borderborderAttribute case insensitive
borderColorbordercolorAttribute case insensitive
bottomMarginbottommarginAttribute case insensitive
capturecaptureAttribute case insensitive
cellPaddingcellpaddingAttribute case insensitive
cellSpacingcellspacingAttribute case insensitive
chcharAttribute case insensitive
chOffcharoffAttribute case insensitive
challengechallengeAttribute case insensitive
charsetcharsetAttribute case insensitive
checkedcheckedAttribute case insensitive
citeciteAttribute case insensitive
classIdclassidAttribute case insensitive
classNameclassAttribute case insensitive
clearclearAttribute case insensitive
codecodeAttribute case insensitive
codeBasecodebaseAttribute case insensitive
codeTypecodetypeAttribute case insensitive
colSpancolspanAttribute case insensitive
colorcolorAttribute case insensitive
colscolsAttribute case insensitive
compactcompactAttribute case insensitive
contentcontentAttribute case insensitive
contentEditablecontenteditableAttribute case insensitive
contextMenucontextmenuAttribute case insensitive
controlscontrolsAttribute case insensitive
coordscoordsAttribute case insensitive
crossOrigincrossoriginAttribute case insensitive
datadataAttribute case insensitive
dataFlddatafldAttribute case insensitive
dataFormatasdataformatasAttribute case insensitive
dataPageSizedatapagesizeAttribute case insensitive
dataSrcdatasrcAttribute case insensitive
dateTimedatetimeAttribute case insensitive
declaredeclareAttribute case insensitive
defaultdefaultAttribute case insensitive
deferdeferAttribute case insensitive
dirdirAttribute case insensitive
dirNamedirnameAttribute case insensitive
directiondirectionAttribute case insensitive
disableddisabledAttribute case insensitive
downloaddownloadAttribute case insensitive
draggabledraggableAttribute case insensitive
enctypeenctypeAttribute case insensitive
eventeventAttribute case insensitive
facefaceAttribute case insensitive
formActionformactionAttribute case insensitive
formEnctypeformenctypeAttribute case insensitive
formMethodformmethodAttribute case insensitive
formNoValidateformnovalidateAttribute case insensitive
formTargetformtargetAttribute case insensitive
frameframeAttribute case insensitive
frameBorderframeborderAttribute case insensitive
frameSpacingframespacingAttribute case insensitive
heightheightAttribute case insensitive
hiddenhiddenAttribute case insensitive
highhighAttribute case insensitive
hrefhrefAttribute case insensitive
hreflanghreflangAttribute case insensitive
hspacehspaceAttribute case insensitive
htmlForforAttribute case insensitive
httpEquivhttp-equivAttribute case insensitive
iconiconAttribute case insensitive
ididAttribute case insensitive
inputModeinputmodeAttribute case insensitive
isMapismapAttribute case insensitive
keytypekeytypeAttribute case insensitive
kindkindAttribute case insensitive
labellabelAttribute case insensitive
langlangAttribute case insensitive
languagelanguageAttribute case insensitive
leftMarginleftmarginAttribute case insensitive
linklinkAttribute case insensitive
looploopAttribute case insensitive
lowlowAttribute case insensitive
lowsrclowsrcAttribute case insensitive
manifestmanifestAttribute case insensitive
marginHeightmarginheightAttribute case insensitive
marginTopmargintopAttribute case insensitive
marginWidthmarginwidthAttribute case insensitive
maxmaxAttribute case insensitive
maxLengthmaxlengthAttribute case insensitive
mediamediaAttribute case insensitive
menumenuAttribute case insensitive
methodmethodAttribute case insensitive
methodsmethodsAttribute case insensitive
minminAttribute case insensitive
minLengthminlengthAttribute case insensitive
multiplemultipleAttribute case insensitive
mutedmutedAttribute case insensitive
namenameAttribute case insensitive
noHrefnohrefAttribute case insensitive
noResizenoresizeAttribute case insensitive
noShadenoshadeAttribute case insensitive
noValidatenovalidateAttribute case insensitive
noWrapnowrapAttribute case insensitive
noncenonceAttribute case insensitive
objectobjectAttribute case insensitive
openopenAttribute case insensitive
optimumoptimumAttribute case insensitive
patternpatternAttribute case insensitive
placeholderplaceholderAttribute case insensitive
posterposterAttribute case insensitive
preloadpreloadAttribute case insensitive
profileprofileAttribute case insensitive
radiogroupradiogroupAttribute case insensitive
readOnlyreadonlyAttribute case insensitive
relrelAttribute case insensitive
requiredrequiredAttribute case insensitive
revrevAttribute case insensitive
reversedreversedAttribute case insensitive
rightMarginrightmarginAttribute case insensitive
rowSpanrowspanAttribute case insensitive
rowsrowsAttribute case insensitive
rulesrulesAttribute case insensitive
sandboxsandboxAttribute case insensitive
schemeschemeAttribute case insensitive
scopescopeAttribute case insensitive
scrollAmountscrollamountAttribute case insensitive
scrollDelayscrolldelayAttribute case insensitive
scrollingscrollingAttribute case insensitive
selectedselectedAttribute case insensitive
shapeshapeAttribute case insensitive
sizesizeAttribute case insensitive
sizessizesAttribute case insensitive
slotslotAttribute case insensitive
spanspanAttribute case insensitive
spellcheckspellcheckAttribute case insensitive
srcsrcAttribute case insensitive
srcdocsrcdocAttribute case insensitive
srclangsrclangAttribute case insensitive
srcsetsrcsetAttribute case insensitive
standbystandbyAttribute case insensitive
startstartAttribute case insensitive
stepstepAttribute case insensitive
stylestyleAttribute case insensitive
summarysummaryAttribute case insensitive
tabIndextabindexAttribute case insensitive
targettargetAttribute case insensitive
texttextAttribute case insensitive
titletitleAttribute case insensitive
translatetranslateAttribute case insensitive
trueSpeedtruespeedAttribute case insensitive
typetypeAttribute case insensitive
typeMustMatchtypemustmatchAttribute case insensitive
urnurnAttribute case insensitive
useMapusemapAttribute case insensitive
vAlignvalignAttribute case insensitive
vLinkvlinkAttribute case insensitive
valuevalueAttribute case insensitive
valueTypevaluetypeAttribute case insensitive
versionversionAttribute case insensitive
vspacevspaceAttribute case insensitive
widthwidthAttribute case insensitive
wrapwrapAttribute case insensitive
accentHeightaccent-heightAttribute case insensitive
accumulateaccumulateAttribute case insensitive
additiveadditiveAttribute case insensitive
alignmentBaselinealignment-baselineAttribute case insensitive
alphabeticalphabeticAttribute case insensitive
amplitudeamplitudeAttribute case insensitive
arabicFormarabic-formAttribute case insensitive
ascentascentAttribute case insensitive
attributeNameattributeName
attributeTypeattributeType
azimuthazimuthAttribute case insensitive
baseFrequencybaseFrequency
baseProfilebaseProfile
baselineShiftbaseline-shiftAttribute case insensitive
bboxbboxAttribute case insensitive
beginbeginAttribute case insensitive
biasbiasAttribute case insensitive
bufferedRenderingbuffered-renderingAttribute case insensitive
bybyAttribute case insensitive
calcModecalcMode
capHeightcap-heightAttribute case insensitive
clipclipAttribute case insensitive
clipPathclip-pathAttribute case insensitive
clipRuleclip-ruleAttribute case insensitive
clipPathUnitsclipPathUnits
colorInterpolationcolor-interpolationAttribute case insensitive
colorInterpolationFilterscolor-interpolation-filtersAttribute case insensitive
colorProfilecolor-profileAttribute case insensitive
colorRenderingcolor-renderingAttribute case insensitive
contentScriptTypecontentScriptType
contentStyleTypecontentStyleType
cursorcursorAttribute case insensitive
cxcxAttribute case insensitive
cycyAttribute case insensitive
ddAttribute case insensitive
descentdescentAttribute case insensitive
diffuseConstantdiffuseConstant
displaydisplayAttribute case insensitive
divisordivisorAttribute case insensitive
dominantBaselinedominant-baselineAttribute case insensitive
durdurAttribute case insensitive
dxdxAttribute case insensitive
dydyAttribute case insensitive
edgeModeedgeMode
elevationelevationAttribute case insensitive
enableBackgroundenable-backgroundAttribute case insensitive
endendAttribute case insensitive
exponentexponentAttribute case insensitive
externalResourcesRequiredexternalResourcesRequired
fillfillAttribute case insensitive
fillOpacityfill-opacityAttribute case insensitive
fillRulefill-ruleAttribute case insensitive
filterfilterAttribute case insensitive
filterResfilterRes
filterUnitsfilterUnits
floodColorflood-colorAttribute case insensitive
floodOpacityflood-opacityAttribute case insensitive
fontFamilyfont-familyAttribute case insensitive
fontSizefont-sizeAttribute case insensitive
fontSizeAdjustfont-size-adjustAttribute case insensitive
fontStretchfont-stretchAttribute case insensitive
fontStylefont-styleAttribute case insensitive
fontVariantfont-variantAttribute case insensitive
fontWeightfont-weightAttribute case insensitive
formatformatAttribute case insensitive
frfrAttribute case insensitive
fromfromAttribute case insensitive
fxfxAttribute case insensitive
fyfyAttribute case insensitive
g1g1Attribute case insensitive
g2g2Attribute case insensitive
glyphNameglyph-nameAttribute case insensitive
glyphOrientationHorizontalglyph-orientation-horizontalAttribute case insensitive
glyphOrientationVerticalglyph-orientation-verticalAttribute case insensitive
glyphRefglyphRef
gradientTransformgradientTransform
gradientUnitsgradientUnits
hanginghangingAttribute case insensitive
hatchContentUnitshatchContentUnits
hatchUnitshatchUnits
horizAdvXhoriz-adv-xAttribute case insensitive
horizOriginXhoriz-origin-xAttribute case insensitive
horizOriginYhoriz-origin-yAttribute case insensitive
ideographicideographicAttribute case insensitive
imageRenderingimage-renderingAttribute case insensitive
ininAttribute case insensitive
in2in2Attribute case insensitive
inlineSizeinline-sizeAttribute case insensitive
interceptinterceptAttribute case insensitive
kkAttribute case insensitive
k1k1Attribute case insensitive
k2k2Attribute case insensitive
k3k3Attribute case insensitive
k4k4Attribute case insensitive
kernelMatrixkernelMatrix
kernelUnitLengthkernelUnitLength
kerningkerningAttribute case insensitive
keyPointskeyPoints
keySplineskeySplines
keyTimeskeyTimes
lengthAdjustlengthAdjust
letterSpacingletter-spacingAttribute case insensitive
lightingColorlighting-colorAttribute case insensitive
limitingConeAnglelimitingConeAngle
locallocalAttribute case insensitive
markerEndmarker-endAttribute case insensitive
markerMidmarker-midAttribute case insensitive
markerStartmarker-startAttribute case insensitive
markerHeightmarkerHeight
markerUnitsmarkerUnits
markerWidthmarkerWidth
maskmaskAttribute case insensitive
maskContentUnitsmaskContentUnits
maskUnitsmaskUnits
mathematicalmathematicalAttribute case insensitive
modemodeAttribute case insensitive
numOctavesnumOctaves
offsetoffsetAttribute case insensitive
opacityopacityAttribute case insensitive
operatoroperatorAttribute case insensitive
orderorderAttribute case insensitive
orientorientAttribute case insensitive
orientationorientationAttribute case insensitive
originoriginAttribute case insensitive
overflowoverflowAttribute case insensitive
overlinePositionoverline-positionAttribute case insensitive
overlineThicknessoverline-thicknessAttribute case insensitive
paintOrderpaint-orderAttribute case insensitive
panose1panose-1Attribute case insensitive
pathpathAttribute case insensitive
pathLengthpathLength
patternContentUnitspatternContentUnits
patternTransformpatternTransform
patternUnitspatternUnits
pitchpitchAttribute case insensitive
playbackorderplaybackorderAttribute case insensitive
pointerEventspointer-eventsAttribute case insensitive
pointspointsAttribute case insensitive
pointsAtXpointsAtX
pointsAtYpointsAtY
pointsAtZpointsAtZ
preserveAlphapreserveAlpha
preserveAspectRatiopreserveAspectRatio
primitiveUnitsprimitiveUnits
rrAttribute case insensitive
radiusradiusAttribute case insensitive
refXrefX
refYrefY
renderingIntentrendering-intentAttribute case insensitive
repeatCountrepeatCount
repeatDurrepeatDur
requiredExtensionsrequiredExtensions
requiredFeaturesrequiredFeatures
restartrestartAttribute case insensitive
resultresultAttribute case insensitive
roleroleAttribute case insensitive
rotaterotateAttribute case insensitive
rxrxAttribute case insensitive
ryryAttribute case insensitive
scalescaleAttribute case insensitive
seedseedAttribute case insensitive
shapeInsideshape-insideAttribute case insensitive
shapeMarginshape-marginAttribute case insensitive
shapeOutsideshape-outsideAttribute case insensitive
shapePaddingshape-paddingAttribute case insensitive
shapeRenderingshape-renderingAttribute case insensitive
sidesideAttribute case insensitive
slopeslopeAttribute case insensitive
solidColorsolid-colorAttribute case insensitive
solidOpacitysolid-opacityAttribute case insensitive
spacingspacingAttribute case insensitive
specularConstantspecularConstant
specularExponentspecularExponent
spreadMethodspreadMethod
startOffsetstartOffset
stdDeviationstdDeviation
stemhstemhAttribute case insensitive
stemvstemvAttribute case insensitive
stitchTilesstitchTiles
stopColorstop-colorAttribute case insensitive
stopOpacitystop-opacityAttribute case insensitive
strikethroughPositionstrikethrough-positionAttribute case insensitive
strikethroughThicknessstrikethrough-thicknessAttribute case insensitive
stringstringAttribute case insensitive
strokestrokeAttribute case insensitive
strokeDasharraystroke-dasharrayAttribute case insensitive
strokeDashoffsetstroke-dashoffsetAttribute case insensitive
strokeLinecapstroke-linecapAttribute case insensitive
strokeLinejoinstroke-linejoinAttribute case insensitive
strokeMiterlimitstroke-miterlimitAttribute case insensitive
strokeOpacitystroke-opacityAttribute case insensitive
strokeWidthstroke-widthAttribute case insensitive
surfaceScalesurfaceScale
systemLanguagesystemLanguage
tableValuestableValues
targetXtargetX
targetYtargetY
textAnchortext-anchorAttribute case insensitive
textDecorationtext-decorationAttribute case insensitive
textOverflowtext-overflowAttribute case insensitive
textRenderingtext-renderingAttribute case insensitive
textLengthtextLength
timelinebegintimelinebeginAttribute case insensitive
totoAttribute case insensitive
transformtransformAttribute case insensitive
u1u1Attribute case insensitive
u2u2Attribute case insensitive
underlinePositionunderline-positionAttribute case insensitive
underlineThicknessunderline-thicknessAttribute case insensitive
unicodeunicodeAttribute case insensitive
unicodeBidiunicode-bidiAttribute case insensitive
unicodeRangeunicode-rangeAttribute case insensitive
unitsPerEmunits-per-emAttribute case insensitive
vAlphabeticv-alphabeticAttribute case insensitive
vHangingv-hangingAttribute case insensitive
vIdeographicv-ideographicAttribute case insensitive
vMathematicalv-mathematicalAttribute case insensitive
valuesvaluesAttribute case insensitive
vectorEffectvector-effectAttribute case insensitive
vertAdvYvert-adv-yAttribute case insensitive
vertOriginXvert-origin-xAttribute case insensitive
vertOriginYvert-origin-yAttribute case insensitive
viewBoxviewBox
viewTargetviewTarget
visibilityvisibilityAttribute case insensitive
whiteSpacewhite-spaceAttribute case insensitive
widthswidthsAttribute case insensitive
wordSpacingword-spacingAttribute case insensitive
writingModewriting-modeAttribute case insensitive
xxAttribute case insensitive
xHeightx-heightAttribute case insensitive
x1x1Attribute case insensitive
x2x2Attribute case insensitive
xChannelSelectorxChannelSelector
xlinkActuatexlink:actuate
xlinkArcrolexlink:arcrole
xlinkHrefxlink:href
xlinkRolexlink:role
xlinkShowxlink:show
xlinkTitlexlink:title
xlinkTypexlink:type
xmlBasexml:base
xmlLangxml:lang
xmlSpacexml:space
yyAttribute case insensitive
y1y1Attribute case insensitive
y2y2Attribute case insensitive
yChannelSelectoryChannelSelector
zzAttribute case insensitive
zoomAndPanzoomAndPan

History

React uses a concept (interactions and UI at the same place) that I started to develop with Backbone 3 years ago and happily dropped when I discover React.
However a friend talked to me about the react license.

I don't understand a thing about the license implications and I don't want to be bound to things I do not understand.

That friend wasn't a good fan of React at the time and uses the license as an argument.
I told him:

Ok, I will create my own "React".

I didn't wanted to recreate a React from scratch.
I looked for alternatives. Preact + Preact-compat seem promising.
Then I replaced React with Preact@6.4.0 in one project.

I launched my project tests and ... many failed (more than 50%):

  • The asynchonous update of the view after set state was not appropriate with my tests (partially fixed with preact.options.syncComponentUpdates = true)
  • Events were not unregistered after unmount
  • Did not worked with my dialogs
  • Did not work with my integration of material-design-lite because node is already removed in componentWillUnmount

Preact messes up with my component properties

That is the most annoying issue for me.
All my components have a destroyed method called on componentWillUnmount, which contains

for (prop in this) {
  if (!hasProp.call(this, prop)) continue;
  if (!/^(?:id|props|refs|_reactInternalInstance)$/.test(prop)) {
    delete this[prop];
  }
}

To prevent any potential memory leak, I delete every thing that was created by my components:

  • props, refs and _reactInternalInstance was created by React.
  • id is for debugging purpose.
  • any other owned properties must have been created by my components.

Because preact add multiple enumarable properties to any component, deleting them put preact in an unexpected state.

Javascript has no "private" properties nor methods.
The best you can do is to define a generated random property, non enumerable and put all your stuff in that property.
Something similar is done in jQuery and React.

I was unable to fully understand preact code to fix all of those problems. I gave up.

The good attitude should have been to open issues on preact.
However, the idea that a future problem may rise, a problem that I won't be able to solve because I was unable to make preact code myself pissed me off.

I was so pissed off that I started to create my own React.

In conclusion, this library is an act of anger.

Here is the jsfiddle with some bugs identified with preact.

License

            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
                    Version 2, December 2004

 Copyright (c) 2017 Stéphane MBAPE (http://smbape.com)

 Everyone is permitted to copy and distribute verbatim or modified
 copies of this license document, and changing it is allowed as long
 as the name is changed.

            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. You just DO WHAT THE FUCK YOU WANT TO.
0.5.1

7 years ago

0.5.0

7 years ago

0.4.1

7 years ago

0.4.0

7 years ago

0.3.0

7 years ago

0.2.3

7 years ago

0.2.2

7 years ago

0.2.1

8 years ago

0.1.7

8 years ago

0.1.5

8 years ago

0.1.4

8 years ago

0.1.2

8 years ago

0.1.1

8 years ago

0.1.0

8 years ago

0.0.3

8 years ago

0.0.2

8 years ago