Giter Club home page Giter Club logo

fields's People

Contributors

radianttap 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  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  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  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

fields's Issues

Crashing issue when toggling "postal address" to ON

Scenario:

  1. Go to Sign up
  2. Toggle "add postal address" OFF
  3. Toggle it back ON
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndexedSubscript:]: index 4 beyond bounds [0 .. 3]'
*** First throw call stack:
Thread 1 Queue : com.apple.main-thread (serial)
#0	0x00007fff513fbaf0 in objc_exception_throw ()
#1	0x00007fff23d03ab1 in _CFThrowFormattedException ()
#2	0x00007fff23b85749 in -[__NSArrayM objectAtIndexedSubscript:] ()
#3	0x00007fff47889c8c in -[UICollectionView _viewAnimationsForCurrentUpdate] ()
#4	0x00007fff4788f1a6 in __71-[UICollectionView _updateWithItems:tentativelyForReordering:animator:]_block_invoke.1877 ()
#5	0x00007fff4856a626 in +[UIView(Animation) performWithoutAnimation:] ()
#6	0x00007fff4788dfdb in -[UICollectionView _updateWithItems:tentativelyForReordering:animator:] ()
#7	0x00007fff47886a8e in -[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:animator:] ()
#8	0x00007fff478905ae in -[UICollectionView _endUpdatesWithInvalidationContext:tentativelyForReordering:animator:] ()
#9	0x00007fff47890906 in -[UICollectionView _performBatchUpdates:completion:invalidationContext:tentativelyForReordering:animator:] ()
#10	0x00007fff4789071c in -[UICollectionView _performBatchUpdates:completion:invalidationContext:tentativelyForReordering:] ()
#11	0x00007fff4789069f in -[UICollectionView _performBatchUpdates:completion:invalidationContext:] ()
#12	0x00007fff478905f4 in -[UICollectionView performBatchUpdates:completion:] ()
#13	0x00000001057df883 in $defer #1 () in RegisterDataSource.processAddressToggle() at /Users/aleck/dev/codeaplus/github/Fields/demo-app/RegisterDataSource.swift:147
#14	0x00000001057d965c in RegisterDataSource.processAddressToggle() at /Users/aleck/dev/codeaplus/github/Fields/demo-app/RegisterDataSource.swift:143
#15	0x00000001057d9365 in RegisterDataSource.shouldAddAddress.didset at /Users/aleck/dev/codeaplus/github/Fields/demo-app/RegisterDataSource.swift:24
#16	0x00000001057d9769 in RegisterDataSource.shouldAddAddress.setter ()
#17	0x00000001057e2a38 in closure #1 in closure #3 in RegisterDataSource.buildAccountSection() at /Users/aleck/dev/codeaplus/github/Fields/demo-app/RegisterDataSource.swift:259
#18	0x000000010580973e in ToggleCell.toggled(_:) at /Users/aleck/dev/codeaplus/github/Fields/Fields/Cells/ToggleCell.swift:56
#19	0x0000000105809794 in @objc ToggleCell.toggled(_:) ()
#20	0x00007fff48093fff in -[UIApplication sendAction:to:from:forEvent:] ()
#21	0x00007fff47a6c00e in -[UIControl sendAction:to:forEvent:] ()
#22	0x00007fff47a6c358 in -[UIControl _sendActionsForEvents:withEvent:] ()
#23	0x00007fff47a9c91b in -[UISwitchModernVisualElement sendStateChangeActions] ()
#24	0x00007fff47a9bbfd in -[UISwitchMVEGestureTrackingSession _sendStateChangeActionsIfNecessary] ()
#25	0x00007fff47a9d207 in __88-[UISwitchModernVisualElement _handleLongPressWithGestureLocationInBounds:gestureState:]_block_invoke ()
#26	0x00007fff4809be5b in _runAfterCACommitDeferredBlocks ()
#27	0x00007fff4808c7b4 in _cleanUpAfterCAFlushAndRunDeferredBlocks ()
#28	0x00007fff480bc3a9 in _afterCACommitHandler ()
#29	0x00007fff23bd3867 in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ ()
#30	0x00007fff23bce2fe in __CFRunLoopDoObservers ()
#31	0x00007fff23bce97a in __CFRunLoopRun ()
#32	0x00007fff23bce066 in CFRunLoopRunSpecific ()
#33	0x00007fff384c0bb0 in GSEventRunModal ()
#34	0x00007fff48092d4d in UIApplicationMain ()
#35	0x000000010581cadb in main at /Users/aleck/dev/codeaplus/github/Fields/demo-app/AppDelegate.swift:8
#36	0x00007fff5227ec25 in start ()

Rotation bug, layout not drawn properly

While testing on iPad, I noticed that shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool is not called every time and thus layout is not re-built for new bounds size.

It's really inconclusive what might be the issue, but I managed to get some suspicious stack traces. Here's how stack trace looks like when the method is called on rotation and is breakpointed in invalidateLayout(with:):

#0	0x00000001073a0e9a in FieldHeightSizingLayout.invalidateLayout(with:)
#1	0x00000001073a33a4 in @objc FieldHeightSizingLayout.invalidateLayout(with:) ()
#2	0x000000010f4ab48c in -[UICollectionViewLayout _invalidateLayoutUsingContext:] ()
#3	0x000000010f4554aa in -[UICollectionView setBounds:] ()
#4	0x0000000110091fb0 in -[UIView(Geometry) _applyISEngineLayoutValuesToBoundsOnly:] ()
#5	0x00000001100922a7 in -[UIView(Geometry) _resizeWithOldSuperviewSize:] ()
#6	0x000000010ffd3dd8 in -[UIScrollView(_UIOldConstraintBasedLayoutSupport) _resizeWithOldSuperviewSize:] ()
#7	0x0000000109dfc013 in -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] ()
#8	0x0000000110090d6b in -[UIView(Geometry) resizeSubviewsWithOldSize:] ()
#9	0x000000010ffe2459 in -[UIView(AdditionalLayoutSupport) _is_layout] ()
#10	0x00000001100997c0 in -[UIView(Hierarchy) _updateConstraintsAsNecessaryAndApplyLayoutFromEngine] ()
#11	0x00000001100ad9c1 in -[UIView(CALayerDelegate) layoutSublayersOfLayer:] ()
#12	0x000000010d314eae in -[CALayer layoutSublayers] ()
#13	0x000000010d319b88 in CA::Layer::layout_if_needed(CA::Transaction*) ()
#14	0x000000010d314dd7 in -[CALayer layoutIfNeeded] ()
#15	0x000000010f5fdf45 in -[UIViewController window:willAnimateRotationToInterfaceOrientation:duration:newSize:] ()
#16	0x000000010f6053a2 in __95-[UIViewController(AdaptiveSizing) _window:viewWillTransitionToSize:withTransitionCoordinator:]_block_invoke.3392 ()
#17	0x000000010f60ced8 in -[_UIViewControllerTransitionCoordinator _applyBlocks:releaseBlocks:] ()
#18	0x000000010f608efc in -[_UIViewControllerTransitionContext __runAlongsideAnimations] ()
#19	0x00000001100a13e5 in +[UIView(UIViewAnimationWithBlocks) _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] ()
#20	0x00000001100a18c2 in +[UIView(UIViewAnimationWithBlocks) animateWithDuration:delay:options:animations:completion:] ()
#21	0x000000010f621c9d in __58-[_UIWindowRotationAnimationController animateTransition:]_block_invoke_2 ()
#22	0x00000001100a5b58 in +[UIView(Internal) _performBlockDelayingTriggeringResponderEvents:] ()
#23	0x000000010f621a56 in __58-[_UIWindowRotationAnimationController animateTransition:]_block_invoke ()
#24	0x00000001100a13e5 in +[UIView(UIViewAnimationWithBlocks) _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] ()
#25	0x00000001100a18c2 in +[UIView(UIViewAnimationWithBlocks) animateWithDuration:delay:options:animations:completion:] ()
#26	0x000000010f621952 in -[_UIWindowRotationAnimationController animateTransition:] ()
#27	0x000000010fc1eb47 in -[UIWindow _rotateToBounds:withAnimator:transitionContext:] ()
#28	0x000000010fc21575 in -[UIWindow _rotateWindowToOrientation:updateStatusBar:duration:skipCallbacks:] ()
#29	0x000000010fc21e7d in -[UIWindow _setRotatableClient:toOrientation:updateStatusBar:duration:force:isRotating:] ()
#30	0x000000010fc20de3 in -[UIWindow _setRotatableViewOrientation:updateStatusBar:duration:force:] ()
#31	0x000000010fc1f9b1 in __57-[UIWindow _updateToInterfaceOrientation:duration:force:]_block_invoke ()
#32	0x000000010fc1f8da in -[UIWindow _updateToInterfaceOrientation:duration:force:] ()
#33	0x000000010f428663 in -[_UICanvasMetricsCalculator updateMetricsOnWindows:animated:] ()
#34	0x000000010f42d16f in -[_UICanvas _computeMetrics:] ()
#35	0x00000001100a13e5 in +[UIView(UIViewAnimationWithBlocks) _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] ()
#36	0x00000001100a1685 in +[UIView(UIViewAnimationWithBlocks) _animateWithDuration:delay:options:factory:animations:completion:] ()
#37	0x000000010f4278f9 in _performChangesWithTransitionContext ()
#38	0x000000010f4263b5 in -[_UICanvasGeometrySettingsDiffAction _updateSceneGeometryWithSettingObserverContext:canvas:transitionContext:] ()
#39	0x000000010f42632a in __124-[_UICanvasGeometrySettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:]_block_invoke ()
#40	0x000000010f427610 in _performActionsWithDelayForTransitionContext ()
#41	0x000000010f42627d in -[_UICanvasGeometrySettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:] ()
#42	0x000000010f42b6d0 in -[_UICanvas scene:didUpdateWithDiff:transitionContext:completion:] ()
#43	0x000000010f7942a0 in -[UIApplicationSceneClientAgent scene:handleEvent:withCompletion:] ()
#44	0x00000001148a2d11 in __80-[FBSSceneImpl updater:didUpdateSettings:withDiff:transitionContext:completion:]_block_invoke_3 ()
#45	0x000000010b262db5 in _dispatch_client_callout ()
#46	0x000000010b2662ba in _dispatch_block_invoke_direct ()
#47	0x00000001148dd146 in __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ ()
#48	0x00000001148dcdfe in -[FBSSerialQueue _performNext] ()
#49	0x00000001148dd393 in -[FBSSerialQueue _performNextFromRunLoopSource] ()
#50	0x0000000109e37be1 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ ()
#51	0x0000000109e37463 in __CFRunLoopDoSources0 ()
#52	0x0000000109e31b1f in __CFRunLoopRun ()
#53	0x0000000109e31302 in CFRunLoopRunSpecific ()
#54	0x000000010eec72fe in GSEventRunModal ()
#55	0x000000010fbdfba2 in UIApplicationMain ()
#56	0x00000001073f0f4b in main at /Users/aleck/dev/codeaplus/github/Fields/demo-app/AppDelegate.swift:8
#57	0x000000010b2d7541 in start ()

Here's how it looks like when the shouldInvalidateLayout(forBoundsChange:) is not called:

#0	0x00000001073a0e9a in FieldHeightSizingLayout.invalidateLayout(with:) at /Users/aleck/dev/codeaplus/github/Fields/Fields/Layouts/FieldHeightSizingLayout.swift:156
#1	0x00000001073a33a4 in @objc FieldHeightSizingLayout.invalidateLayout(with:) ()
#2	0x000000010f456025 in -[UICollectionView _invalidateLayoutForUpdatedLayoutMarginsIfNeeded] ()
#3	0x000000010f455ec5 in -[UICollectionView layoutMarginsDidChange] ()
#4	0x0000000110080442 in -[UIView _layoutMarginsDidChangeFromOldMargins:] ()
#5	0x0000000110080d94 in -[UIView _updateInferredLayoutMarginsFromSuperview:] ()
#6	0x0000000110089179 in -[UIView _updateCombinedInsetsIfNecessary] ()
#7	0x0000000110092845 in -[UIView(Geometry) setBounds:] ()
#8	0x00000001100250c3 in -[UIScrollView setBounds:] ()
#9	0x000000010f455482 in -[UICollectionView setBounds:] ()
#10	0x0000000110091fb0 in -[UIView(Geometry) _applyISEngineLayoutValuesToBoundsOnly:] ()
#11	0x00000001100922a7 in -[UIView(Geometry) _resizeWithOldSuperviewSize:] ()
#12	0x000000010ffd3dd8 in -[UIScrollView(_UIOldConstraintBasedLayoutSupport) _resizeWithOldSuperviewSize:] ()
#13	0x0000000109dfc013 in -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] ()
#14	0x0000000110090d6b in -[UIView(Geometry) resizeSubviewsWithOldSize:] ()
#15	0x000000010ffe2459 in -[UIView(AdditionalLayoutSupport) _is_layout] ()
#16	0x00000001100997c0 in -[UIView(Hierarchy) _updateConstraintsAsNecessaryAndApplyLayoutFromEngine] ()
#17	0x00000001100ad9c1 in -[UIView(CALayerDelegate) layoutSublayersOfLayer:] ()
#18	0x000000010d314eae in -[CALayer layoutSublayers] ()
#19	0x000000010d319b88 in CA::Layer::layout_if_needed(CA::Transaction*) ()
#20	0x000000010d314dd7 in -[CALayer layoutIfNeeded] ()
#21	0x000000010f5fdf45 in -[UIViewController window:willAnimateRotationToInterfaceOrientation:duration:newSize:] ()
#22	0x000000010f6053a2 in __95-[UIViewController(AdaptiveSizing) _window:viewWillTransitionToSize:withTransitionCoordinator:]_block_invoke.3392 ()
#23	0x000000010f60ced8 in -[_UIViewControllerTransitionCoordinator _applyBlocks:releaseBlocks:] ()
#24	0x000000010f608efc in -[_UIViewControllerTransitionContext __runAlongsideAnimations] ()
#25	0x00000001100a13e5 in +[UIView(UIViewAnimationWithBlocks) _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] ()
#26	0x00000001100a18c2 in +[UIView(UIViewAnimationWithBlocks) animateWithDuration:delay:options:animations:completion:] ()
#27	0x000000010f621c9d in __58-[_UIWindowRotationAnimationController animateTransition:]_block_invoke_2 ()
#28	0x00000001100a5b58 in +[UIView(Internal) _performBlockDelayingTriggeringResponderEvents:] ()
#29	0x000000010f621a56 in __58-[_UIWindowRotationAnimationController animateTransition:]_block_invoke ()
#30	0x00000001100a13e5 in +[UIView(UIViewAnimationWithBlocks) _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] ()
#31	0x00000001100a18c2 in +[UIView(UIViewAnimationWithBlocks) animateWithDuration:delay:options:animations:completion:] ()
#32	0x000000010f621952 in -[_UIWindowRotationAnimationController animateTransition:] ()
#33	0x000000010fc1eb47 in -[UIWindow _rotateToBounds:withAnimator:transitionContext:] ()
#34	0x000000010fc21575 in -[UIWindow _rotateWindowToOrientation:updateStatusBar:duration:skipCallbacks:] ()
#35	0x000000010fc21e7d in -[UIWindow _setRotatableClient:toOrientation:updateStatusBar:duration:force:isRotating:] ()
#36	0x000000010fc20de3 in -[UIWindow _setRotatableViewOrientation:updateStatusBar:duration:force:] ()
#37	0x000000010fc1f9b1 in __57-[UIWindow _updateToInterfaceOrientation:duration:force:]_block_invoke ()
#38	0x000000010fc1f8da in -[UIWindow _updateToInterfaceOrientation:duration:force:] ()
#39	0x000000010f428663 in -[_UICanvasMetricsCalculator updateMetricsOnWindows:animated:] ()
#40	0x000000010f42d16f in -[_UICanvas _computeMetrics:] ()
#41	0x00000001100a13e5 in +[UIView(UIViewAnimationWithBlocks) _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] ()
#42	0x00000001100a1685 in +[UIView(UIViewAnimationWithBlocks) _animateWithDuration:delay:options:factory:animations:completion:] ()
#43	0x000000010f4278f9 in _performChangesWithTransitionContext ()
#44	0x000000010f4263b5 in -[_UICanvasGeometrySettingsDiffAction _updateSceneGeometryWithSettingObserverContext:canvas:transitionContext:] ()
#45	0x000000010f42632a in __124-[_UICanvasGeometrySettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:]_block_invoke ()
#46	0x000000010f427610 in _performActionsWithDelayForTransitionContext ()
#47	0x000000010f42627d in -[_UICanvasGeometrySettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:] ()
#48	0x000000010f42b6d0 in -[_UICanvas scene:didUpdateWithDiff:transitionContext:completion:] ()
#49	0x000000010f7942a0 in -[UIApplicationSceneClientAgent scene:handleEvent:withCompletion:] ()
#50	0x00000001148a2d11 in __80-[FBSSceneImpl updater:didUpdateSettings:withDiff:transitionContext:completion:]_block_invoke_3 ()
#51	0x000000010b262db5 in _dispatch_client_callout ()
#52	0x000000010b2662ba in _dispatch_block_invoke_direct ()
#53	0x00000001148dd146 in __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ ()
#54	0x00000001148dcdfe in -[FBSSerialQueue _performNext] ()
#55	0x00000001148dd393 in -[FBSSerialQueue _performNextFromRunLoopSource] ()
#56	0x0000000109e37be1 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ ()
#57	0x0000000109e37463 in __CFRunLoopDoSources0 ()
#58	0x0000000109e31b1f in __CFRunLoopRun ()
#59	0x0000000109e31302 in CFRunLoopRunSpecific ()
#60	0x000000010eec72fe in GSEventRunModal ()
#61	0x000000010fbdfba2 in UIApplicationMain ()
#62	0x00000001073f0f4b in main at /Users/aleck/dev/codeaplus/github/Fields/demo-app/AppDelegate.swift:8
#63	0x000000010b2d7541 in start ()

FlowLayout behavior on rotation

While looking into solution for #2 I tested how the actual FlowLayout handles rotation and boundsChange. And it seems it's similarly crazy.

Take this scenario in the demo app

  1. Tap on Forgot password
  2. Tap on Options in the nav bar
  3. Rotate iPhone simulator to landscape
  4. Rotate back to portrait

At this point you will get this console output:

The behavior of the UICollectionViewFlowLayout is not defined because:
the item width must be less than the width of the UICollectionView minus the section insets left and right values, minus the content insets left and right values.
The relevant UICollectionViewFlowLayout instance is <Fields_demo.FullWidthLayout: 0x7fe9d2810b40>, and it is attached to <UICollectionView: 0x7fe9d387a200; frame = (0 0; 375 812); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x600000f82e50>; animations = { position=<CABasicAnimation: 0x6000001b4ce0>; bounds.origin=<CABasicAnimation: 0x6000001b4e80>; bounds.size=<CABasicAnimation: 0x6000001b4e40>; }; layer = <CALayer: 0x600000137d20>; contentOffset: {0, -32}; contentSize: {812, 224}; adjustedContentInset: {32, 44, 21, 44}; layout: <Fields_demo.FullWidthLayout: 0x7fe9d2810b40>; dataSource: <Fields_demo.OptionsController: 0x7fe9d2845df0>>.
Make a symbolic breakpoint at UICollectionViewFlowLayoutBreakForInvalidSizes to catch this in the debugger.

The relevant layouts are FullWidthLayout and BaseGridLayout.

This code in BaseGridLayout should be enough:

override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
	switch scrollDirection {
	case .horizontal:
		return newBounds.height != collectionView?.bounds.height
	case .vertical:
		return newBounds.width != collectionView?.bounds.width
	@unknown default:
		return super.shouldInvalidateLayout(forBoundsChange: newBounds)
	}
}

to trigger layout re-calculation. However, it seems that UIKit is first using older layout attributes then recalculates into new ones, for new bounds.

I can't recall this working like that previously...

EXC_BAD_ACCESS in FieldHeightSizingLayout.relayout()

This seems really cool. Thanks for publishing and the article you wrote with it.

I'm trying out the demo app (under iOS 13 on an iPhone XR simulator - not sure if that's an issue) and getting repeated crashes when it is trying to call relayout() in FieldHeightSizingLayout

The line in particular is 195:
let sectionCount = cv.numberOfSections

If I try to scroll down past the category icons on the Signup form, it crashes every time, but I also have gotten the same crash when moving around generally.

Any ideas? Let me know if I can provide additional info

Double rendering for the footer during animated changes

There's a very annoying visual glitch during insertItems animation:

animated-cv-changes

There are two copies of the footer which slide down to different positions, then the top one disappears and bottom one (with correct position stays on).

I suspect the "copy" is somehow using non-self-sized position of the footer, but I have no idea (for now) how to prevent / correct this.

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.