Giter VIP home page Giter VIP logo

mage2-ordered-assets's Introduction

mage2-ordered-assets

Order assets (read: css tags) explicitly with an order attribute

Magento2 has no way to order assets out of the box. This extension allows you to specify an order attribute in css tags in layout XML files and layout updates in the admin UI.

Installation

Composer

composer require quickshiftin/assetorderer

Manual

Download the repository and add it in your Magento2 installation under app/code/Quickshiftin/Assetorderer

Magento commands

Once you've installed the code via composer or download, you need to run some Magento commands:

  • bin/magento module:enable Quickshiftin_Assetorderer
  • bin/magento setup:upgrade
  • rm -rf var/cache var/di var/generation var/page_cache && bin/magento setup:di:compile

Usage

Suppose you want to add a custom CSS file, css/home.css, on your homepage. Ordinarilly you would enter this in the layout update editor

<head>
<css src="css/home.css"/>
</head>

However, Magento most likely will place the generated link tag before the base CSS file, thus not honoring the cascade. With the extension installed you can enter the css tag with an arbitrary order attribute like so

<head>
<css src="css/home.css" order="100" />
</head>

Any tags without an explicit order will come as they appear normally (effectively treated like they have an order of 1).

Unit Tests

To run the unit tests, in a working installation of Magento2, with the extension enabled

  • cp vendor/quickshiftin/assetorderer/phpunit.xml dev/tests/unit
  • cd dev/tests/unit
  • php ../../../vendor/phpunit/phpunit/phpunit

mage2-ordered-assets's People

Contributors

quickshiftin avatar rakibabu avatar redenzian avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

mage2-ordered-assets's Issues

Order "0" is seen as "1"

You wrote Any tags without an explicit order will come as they appear normally (effectively treated like they have an order of 1).

So I added a script with order 0, so that it gets ordered to the very top:

<css src="css/bootstrap.min.css" order="0"/>

But it is not.

I also tried 10 but then it gets ordererd at the bottom.

Still necessary?

I just installed your module and found out (by accident) that the order of my CSS files was influenced by an "order" attribute just like stated in your readme.md even before your module was activated.
I'm not sure though, because I couldn't find anything related CSS ordering in the official magento documentation and when this happened I already had your module files in my installation. But without running magento setup:upgrade and magento setup:di:compile. I'm still new to Magento 2 so I have no idea if this means your module was totally ineffective at that point or not.

So as you wrote this and have deeper insights, is this module still necessary if we want to change the CSS order by specifying an order attribute in layout files?

Magento 2.2.5 issue with interface

Cannot get extension to work with new Magento 2.2.5

Error in log:

[02-Aug-2018 17:58:50 UTC] PHP Fatal error:  Uncaught TypeError: Argument 1 passed to Magento\Framework\View\Page\Config\Renderer::getAssetContentType() must implement interface Magento\Framework\View\Asset\AssetInterface, instance of Quickshiftin\Assetorderer\View\Asset\File given, called in /home/dev2magicmurals/public_html/vendor/magento/framework/View/Page/Config/Renderer.php on line 351 and defined in /home/dev2magicmurals/public_html/vendor/magento/framework/View/Page/Config/Renderer.php:368
Stack trace:
#0 /home/dev2magicmurals/public_html/vendor/magento/framework/View/Page/Config/Renderer.php(351): Magento\Framework\View\Page\Config\Renderer->getAssetContentType(Object(Quickshiftin\Assetorderer\View\Asset\File))
#1 /home/dev2magicmurals/public_html/vendor/magento/framework/View/Page/Config/Renderer.php(239): Magento\Framework\View\Page\Config\Renderer->renderAssetHtml(Object(Magento\Framework\View\Asset\PropertyGroup\Interceptor))
#2 /home/dev2magicmurals/public_html/vendor/magento/framework/View/Page/Config/Renderer.php(226): Magento\Framework\ in /home/dev2magicmurals/public_html/vendor/magento/framework/View/Page/Config/Renderer.php on line 368

PHP Error when using Remote CSS Files

Hello,

thx for this extension, it helped me a lot.
There is an problem if you use remote files (like google fonts). There is an PHP Error since Remote files are of type "\Magento\Framework\View\Asses\Remote".

I will add a pull request for my changed version which handles Files and Remotes.

best regards

Error on install

[InvalidArgumentException]
Plugin class Quickshiftin\Assetorderer\Config\Dom\UrnResolver doesn't exist

magento 2.2.7

Invalid Document: Title is Required but missing

On Magento 2.2.0 after downloading the source code with composer, trying to run

php bin/magento setup:upgrade

returns the following error:

Running schema recurring...Invalid Document 
Element 'resource': The attribute 'title' is required but missing.
Line: 5

after compiling magento marks an error asking run setup:upgrade

Exception #0 (Magento\Framework\Config\Dom\ValidationException): Element 'css', attribute 'order': The attribute 'order' is not allowed.

I've overridden the default_head_blocks.xml file.

Trying to add:

<head>
    <css src="css/prakashan/custom.css" order="100"/>
</head>

Getting error:

1 exception(s):
Exception #0 (Magento\Framework\Config\Dom\ValidationException): Element 'css', attribute 'order': The attribute 'order' is not allowed.
Line: 33

Exception #0 (Magento\Framework\Config\Dom\ValidationException): Element 'css', attribute 'order': The attribute 'order' is not allowed.
Line: 33

#0 /home/sajal/web/magento2prk/vendor/magento/framework/Config/Dom.php(115): Magento\Framework\Config\Dom->_initDom('<layout xmlns:x...')
#1 /home/sajal/web/magento2prk/vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php(111): Magento\Framework\Config\Dom->__construct('<layout xmlns:x...', Object(Magento\Framework\App\Arguments\ValidationState), Array, NULL, '/home/sajal/web...', '%message%\nLine:...')
#2 /home/sajal/web/magento2prk/vendor/magento/framework/ObjectManager/Factory/Compiled.php(108): Magento\Framework\ObjectManager\Factory\AbstractFactory->createObject('Magento\Framewo...', Array)
#3 /home/sajal/web/magento2prk/vendor/magento/framework/ObjectManager/ObjectManager.php(56): Magento\Framework\ObjectManager\Factory\Compiled->create('Magento\Framewo...', Array)
#4 /home/sajal/web/magento2prk/vendor/magento/framework/Config/DomFactory.php(42): Magento\Framework\ObjectManager\ObjectManager->create('Magento\Framewo...', Array)
#5 /home/sajal/web/magento2prk/vendor/magento/framework/View/Model/Layout/Update/Validator.php(141): Magento\Framework\Config\DomFactory->createDom(Array)

After installing, magento throws exception: Asset has to implement \Magento\Framework\View\Asset\MergeableInterface.

1 exception(s):
Exception #0 (InvalidArgumentException): Asset has to implement \Magento\Framework\View\Asset\MergeableInterface.

Exception #0 (InvalidArgumentException): Asset has to implement \Magento\Framework\View\Asset\MergeableInterface.

#1 Magento\Framework\ObjectManager\Factory\AbstractFactory->createObject('Magento\Framewor...', array(&Magento\Framework\Logger\Monolog#0000000000d58962000000000be59658#, &Magento\Framework\View\Asset\MergeStrategy\Checksum#0000000000d58f49000000000be59658#, &Magento\Framework\View\Asset\Repository#0000000000d58860000000000be59658#, array('mage/calendar.cs...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1e000000000be59658#, 'MGS_Mmegamenu::c...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f0a000000000be59658#, 'MGS_Promobanners...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f0b000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1d000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f10000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f15000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f12000000000be59658#, 'Magento_Swatches...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f17000000000be59658#, 'css/bootstrap.mi...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4f000000000be59658#, 'css/font-awesome...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f11000000000be59658#, 'css/pe-icon-7-st...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f56000000000be59658#, 'css/menu.css' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1c000000000be59658#, 'css/theme_defaul...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1f000000000be59658#, 'css/theme.css' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58e62000000000be59658#, 'css/responsive.c...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4b000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f18000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4d000000000be59658#, 'MGS_InstantSearc...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4e000000000be59658#), NULL)) called at [vendor/magento/framework/ObjectManager/Factory/Compiled.php:108]
#2 Magento\Framework\ObjectManager\Factory\Compiled->create('Magento\Framewor...', array('assets' => array('mage/calendar.cs...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1e000000000be59658#, 'MGS_Mmegamenu::c...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f0a000000000be59658#, 'MGS_Promobanners...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f0b000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1d000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f10000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f15000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f12000000000be59658#, 'Magento_Swatches...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f17000000000be59658#, 'css/bootstrap.mi...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4f000000000be59658#, 'css/font-awesome...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f11000000000be59658#, 'css/pe-icon-7-st...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f56000000000be59658#, 'css/menu.css' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1c000000000be59658#, 'css/theme_defaul...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1f000000000be59658#, 'css/theme.css' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58e62000000000be59658#, 'css/responsive.c...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4b000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f18000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4d000000000be59658#, 'MGS_InstantSearc...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4e000000000be59658#), 'mergeStrategy' => &Magento\Framework\View\Asset\MergeStrategy\Checksum#0000000000d58f49000000000be59658#)) called at [vendor/magento/framework/ObjectManager/ObjectManager.php:56]
#3 Magento\Framework\ObjectManager\ObjectManager->create('Magento\Framewor...', array('assets' => array('mage/calendar.cs...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1e000000000be59658#, 'MGS_Mmegamenu::c...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f0a000000000be59658#, 'MGS_Promobanners...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f0b000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1d000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f10000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f15000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f12000000000be59658#, 'Magento_Swatches...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f17000000000be59658#, 'css/bootstrap.mi...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4f000000000be59658#, 'css/font-awesome...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f11000000000be59658#, 'css/pe-icon-7-st...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f56000000000be59658#, 'css/menu.css' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1c000000000be59658#, 'css/theme_defaul...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1f000000000be59658#, 'css/theme.css' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58e62000000000be59658#, 'css/responsive.c...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4b000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f18000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4d000000000be59658#, 'MGS_InstantSearc...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4e000000000be59658#), 'mergeStrategy' => &Magento\Framework\View\Asset\MergeStrategy\Checksum#0000000000d58f49000000000be59658#)) called at [vendor/magento/framework/View/Asset/MergeService.php:92]
#4 Magento\Framework\View\Asset\MergeService->getMergedAssets(array('mage/calendar.cs...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1e000000000be59658#, 'MGS_Mmegamenu::c...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f0a000000000be59658#, 'MGS_Promobanners...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f0b000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1d000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f10000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f15000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f12000000000be59658#, 'Magento_Swatches...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f17000000000be59658#, 'css/bootstrap.mi...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4f000000000be59658#, 'css/font-awesome...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f11000000000be59658#, 'css/pe-icon-7-st...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f56000000000be59658#, 'css/menu.css' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1c000000000be59658#, 'css/theme_defaul...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1f000000000be59658#, 'css/theme.css' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58e62000000000be59658#, 'css/responsive.c...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4b000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f18000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4d000000000be59658#, 'MGS_InstantSearc...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4e000000000be59658#), 'css') called at [vendor/magento/framework/View/Page/Config/Renderer.php:276]
#5 Magento\Framework\View\Page\Config\Renderer->processMerge(array('mage/calendar.cs...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1e000000000be59658#, 'MGS_Mmegamenu::c...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f0a000000000be59658#, 'MGS_Promobanners...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f0b000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1d000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f10000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f15000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f12000000000be59658#, 'Magento_Swatches...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f17000000000be59658#, 'css/bootstrap.mi...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4f000000000be59658#, 'css/font-awesome...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f11000000000be59658#, 'css/pe-icon-7-st...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f56000000000be59658#, 'css/menu.css' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1c000000000be59658#, 'css/theme_defaul...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f1f000000000be59658#, 'css/theme.css' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58e62000000000be59658#, 'css/responsive.c...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4b000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f18000000000be59658#, 'MGS_Mpanel::css/...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4d000000000be59658#, 'MGS_InstantSearc...' => &Quickshiftin\Assetorderer\View\Asset\File#0000000000d58f4e000000000be59658#), &Magento\Framework\View\Asset\PropertyGroup\Interceptor#0000000000d58e5b000000000be59658#) called at [vendor/quickshiftin/assetorderer/View/Page/Config/Renderer.php:40]
#6 Quickshiftin\Assetorderer\View\Page\Config\Renderer->renderAssetHtml(&Magento\Framework\View\Asset\PropertyGroup\Interceptor#0000000000d58e5b000000000be59658#) called at [vendor/magento/framework/View/Page/Config/Renderer.php:261]
#7 Magento\Framework\View\Page\Config\Renderer->renderAssetGroup(&Magento\Framework\View\Asset\PropertyGroup\Interceptor#0000000000d58e5b000000000be59658#) called at [vendor/quickshiftin/assetorderer/View/Page/Config/Renderer.php:28]
#8 Quickshiftin\Assetorderer\View\Page\Config\Renderer->renderAssets(array('css' => '', 'ico' => '', 'js' => '')) called at [vendor/magento/framework/View/Page/Config/Renderer.php:101]
#9 Magento\Framework\View\Page\Config\Renderer->renderHeadContent() called at [vendor/magento/framework/View/Result/Page.php:249]
#10 Magento\Framework\View\Result\Page->render(&Magento\Framework\App\Response\Http\Interceptor#0000000000d58942000000000be59658#) called at [vendor/magento/framework/View/Result/Layout.php:170]
#11 Magento\Framework\View\Result\Layout->renderResult(&Magento\Framework\App\Response\Http\Interceptor#0000000000d58942000000000be59658#) called at [vendor/magento/framework/Interception/Interceptor.php:58]
#12 MGS\Mpanel\Block\Framework\Page\Interceptor->___callParent('renderResult', array(&Magento\Framework\App\Response\Http\Interceptor#0000000000d58942000000000be59658#)) called at [vendor/magento/framework/Interception/Interceptor.php:138]
#13 MGS\Mpanel\Block\Framework\Page\Interceptor->Magento\Framework\Interception\{closure}(&Magento\Framework\App\Response\Http\Interceptor#0000000000d58942000000000be59658#) called at [vendor/magento/framework/Interception/Interceptor.php:153]
#14 MGS\Mpanel\Block\Framework\Page\Interceptor->___callPlugins('renderResult', array(&Magento\Framework\App\Response\Http\Interceptor#0000000000d58942000000000be59658#), array(array('result-messages', 'result-builtin-c...', 'result-varnish-c...'))) called at [generated/code/MGS/Mpanel/Block/Framework/Page/Interceptor.php:39]
#15 MGS\Mpanel\Block\Framework\Page\Interceptor->renderResult(&Magento\Framework\App\Response\Http\Interceptor#0000000000d58942000000000be59658#) called at [vendor/magento/framework/App/Http.php:140]
#16 Magento\Framework\App\Http->launch() called at [vendor/magento/framework/App/Bootstrap.php:257]
#17 Magento\Framework\App\Bootstrap->run(&Magento\Framework\App\Http\Interceptor#0000000000d5894c000000000be59658#) called at [index.php:39]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.