{"action":"created","comment":{"url":"https://api.github.com/repos/reactjs/react-art/pulls/comments/90308645","pull_request_review_id":10829875,"id":90308645,"diff_hunk":"@@ -329,315 +88,446 @@ const NodeMixin = {\n       pooledTransform.transform(props.transform);\n     }\n \n-    if (node.xx !== pooledTransform.xx || node.yx !== pooledTransform.yx ||\n-        node.xy !== pooledTransform.xy || node.yy !== pooledTransform.yy ||\n-        node.x  !== pooledTransform.x  || node.y  !== pooledTransform.y) {\n+    if (\n+      node.xx !== pooledTransform.xx || node.yx !== pooledTransform.yx ||\n+      node.xy !== pooledTransform.xy || node.yy !== pooledTransform.yy ||\n+      node.x  !== pooledTransform.x  || node.y  !== pooledTransform.y\n+    ) {\n       node.transformTo(pooledTransform);\n     }\n \n-    if (props.cursor !== oldProps.cursor || props.title !== oldProps.title) {\n+    if (\n+      props.cursor !== prevProps.cursor ||\n+      props.title !== prevProps.title\n+    ) {\n       node.indicate(props.cursor, props.title);\n     }\n \n-    if (node.blend && props.opacity !== oldProps.opacity) {\n+    if (\n+      node.blend &&\n+      props.opacity !== prevProps.opacity\n+    ) {\n       node.blend(props.opacity == null ? 1 : props.opacity);\n     }\n \n-    if (props.visible !== oldProps.visible) {\n+    if (props.visible !== prevProps.visible) {\n       if (props.visible == null || props.visible) {\n         node.show();\n       } else {\n         node.hide();\n       }\n     }\n \n-    for (let type in EventTypes) {\n-      this.putEventListener(EventTypes[type], props[type]);\n+    for (let type in EVENT_TYPES) {\n+      this._addEventListeners(EVENT_TYPES[type], props[type]);\n     }\n-  },\n-\n-  mountComponentIntoNode: function(rootID, container) {\n-    throw new Error(\n-      'You cannot render an ART component standalone. ' +\n-      'You need to wrap it in a Surface.'\n-    );\n   }\n \n-};\n-\n-// Group\n-\n-const Group = createComponent('Group', NodeMixin, ContainerMixin, {\n-\n-  mountComponent: function(\n-    transaction,\n-    nativeParent,\n-    nativeContainerInfo,\n-    context\n-  ) {\n-    this.node = Mode.Group();\n-    const props = this._currentElement.props;\n-    this.applyGroupProps(emptyObject, props);\n-    this.mountAndInjectChildren(props.children, transaction, context);\n-    return this.node;\n-  },\n-\n-  receiveComponent: function(nextComponent, transaction, context) {\n-    const props = nextComponent.props;\n-    const oldProps = this._currentElement.props;\n-    this.applyGroupProps(oldProps, props);\n-    this.updateChildren(props.children, transaction, context);\n-    this._currentElement = nextComponent;\n-  },\n-\n-  applyGroupProps: function(oldProps, props) {\n-    this.node.width = props.width;\n-    this.node.height = props.height;\n-    this.applyNodeProps(oldProps, props);\n-  },\n-\n-  unmountComponent: function() {\n-    this.destroyEventListeners();\n-    this.unmountChildren();\n+  handleEvent(event) {\n+    const listener = this._listeners[event.type];\n+    if (!listener) {\n+      return;\n+    }\n+    if (typeof listener === 'function') {\n+      listener.call(this, event);\n+    } else if (listener.handleEvent) {\n+      listener.handleEvent(event);\n+    }\n   }\n \n-});\n-\n-// ClippingRectangle\n-const ClippingRectangle = createComponent(\n-    'ClippingRectangle', NodeMixin, ContainerMixin, {\n-\n-  mountComponent: function(\n-    transaction,\n-    nativeParent,\n-    nativeContainerInfo,\n-    context\n-  ) {\n-    this.node = Mode.ClippingRectangle();\n-    const props = this._currentElement.props;\n-    this.applyClippingProps(emptyObject, props);\n-    this.mountAndInjectChildren(props.children, transaction, context);\n-    return this.node;\n-  },\n-\n-  receiveComponent: function(nextComponent, transaction, context) {\n-    const props = nextComponent.props;\n-    const oldProps = this._currentElement.props;\n-    this.applyClippingProps(oldProps, props);\n-    this.updateChildren(props.children, transaction, context);\n-    this._currentElement = nextComponent;\n-  },\n-\n-  applyClippingProps: function(oldProps, props) {\n-    this.node.width = props.width;\n-    this.node.height = props.height;\n-    this.node.x = props.x;\n-    this.node.y = props.y;\n-    this.applyNodeProps(oldProps, props);\n-  },\n+  _addEventListeners(type, listener) {\n+    this._listeners[type] = listener;\n+    if (listener) {\n+      if (!this._subscriptions[type]) {\n+        this._subscriptions[type] =\n+          this.instance.subscribe(type, listener, this);\n+      }\n+    } else {\n+      if (this._subscriptions[type]) {\n+        this._subscriptions[type]();\n+        delete this._subscriptions[type];\n+      }\n+    }\n+  }\n \n-  unmountComponent: function() {\n-    this.destroyEventListeners();\n-    this.unmountChildren();\n+  _removeEventListeners() {\n+    if (this._subscriptions) {\n+      for (let type in this._subscriptions) {\n+        this._subscriptions[type]();\n+      }\n+    }\n+    this._subscriptions = null;\n+    this._listeners = null;\n   }\n \n-});\n+  _getScaleX(props) {\n+    if (props.scaleX != null) {\n+      return props.scaleX;\n+    } else if (props.scale != null) {\n+      return props.scale;\n+    } else {\n+      return 1;\n+    }\n+  }\n \n+  _getScaleY(props) {\n+    if (props.scaleY != null) {\n+      return props.scaleY;\n+    } else if (props.scale != null) {\n+      return props.scale;\n+    } else {\n+      return 1;\n+    }\n+  }\n+}\n \n-// Renderables\n+class RenderableNode extends Node {\n+  applyProps(\n+    props,\n+    prevProps = {},\n+  ) {\n+    super.applyProps(props, prevProps);\n \n-const RenderableMixin = assign({}, NodeMixin, {\n+    const node = this.instance;\n \n-  applyRenderableProps: function(oldProps, props) {\n-    if (oldProps.fill !== props.fill) {\n+    if (prevProps.fill !== props.fill) {\n       if (props.fill && props.fill.applyFill) {\n-        props.fill.applyFill(this.node);\n+        props.fill.applyFill(node);\n       } else {\n-        this.node.fill(props.fill);\n+        node.fill(props.fill);\n       }\n     }\n     if (\n-      oldProps.stroke !== props.stroke ||\n-      oldProps.strokeWidth !== props.strokeWidth ||\n-      oldProps.strokeCap !== props.strokeCap ||\n-      oldProps.strokeJoin !== props.strokeJoin ||\n-      // TODO: Consider a deep check of stokeDash.\n-      // This may benefit the VML version in IE.\n-      oldProps.strokeDash !== props.strokeDash\n+      prevProps.stroke !== props.stroke ||\n+      prevProps.strokeWidth !== props.strokeWidth ||\n+      prevProps.strokeCap !== props.strokeCap ||\n+      prevProps.strokeJoin !== props.strokeJoin ||\n+      // TODO: Consider deep check of stokeDash; may benefit VML in IE.\n+      prevProps.strokeDash !== props.strokeDash\n     ) {\n-      this.node.stroke(\n+      node.stroke(\n         props.stroke,\n         props.strokeWidth,\n         props.strokeCap,\n         props.strokeJoin,\n-        props.strokeDash\n+        props.strokeDash,\n       );\n     }\n-    this.applyNodeProps(oldProps, props);\n-  },\n-\n-  unmountComponent: function() {\n-    this.destroyEventListeners();\n   }\n+}\n \n-});\n+// TODO: This component doesn't work for <svg> mode.\n+// It doesn't generate the <defs><clipPath><rect> only a <g>\n+// It also doesn't add the expected 'clip-path' attribute to the <g>\n+// It's also unclear if it should be applying the 'x'/'y' properties to the <g>\n+class ClippingRectangle extends Node {\n+  constructor(props) {\n+    super(TYPES.CLIPPING_RECTANGLE, Mode.ClippingRectangle(), props);\n+  }\n \n-// Shape\n+  applyProps(\n+    props,\n+    prevProps = {},\n+  ) {\n+    super.applyProps(props, prevProps);\n \n-const Shape = createComponent('Shape', RenderableMixin, {\n+    this.instance.width = props.width;\n+    this.instance.height = props.height;\n+  }\n+}\n \n-  construct: function(element) {\n-    this._currentElement = element;\n-    this._oldDelta = null;\n-    this._oldPath = null;\n-  },\n+class Group extends Node {\n+  constructor(props) {\n+    super(TYPES.GROUP, Mode.Group(), props);\n+  }\n \n-  mountComponent: function(\n-    transaction,\n-    nativeParent,\n-    nativeContainerInfo,\n-    context\n+  applyProps(\n+    props,\n+    prevProps = {},\n   ) {\n-    this.node = Mode.Shape();\n-    const props = this._currentElement.props;\n-    this.applyShapeProps(emptyObject, props);\n-    return this.node;\n-  },\n+    super.applyProps(props, prevProps);\n \n-  receiveComponent: function(nextComponent, transaction, context) {\n-    const props = nextComponent.props;\n-    const oldProps = this._currentElement.props;\n-    this.applyShapeProps(oldProps, props);\n-    this._currentElement = nextComponent;\n-  },\n+    this.instance.width = props.width;\n+    this.instance.height = props.height;\n+  }\n+}\n \n-  applyShapeProps: function(oldProps, props) {\n-    const oldDelta = this._oldDelta;\n-    const oldPath = this._oldPath;\n-    const path = props.d || childrenAsString(props.children);\n+class Shape extends RenderableNode {\n+  constructor(props) {\n+    super(TYPES.SHAPE, Mode.Shape(), props);\n+  }\n+\n+  applyProps(\n+    props,\n+    prevProps = {},\n+  ) {\n+    super.applyProps(props, prevProps);\n \n-    if (path.delta !== oldDelta ||\n-        path !== oldPath ||\n-        oldProps.width !== props.width ||\n-        oldProps.height !== props.height) {\n+    const path = props.d || childrenAsString(props.children);\n+    const prevPath = this._prevPath;\n+    const prevDelta = this._prevDelta;\n \n-      this.node.draw(\n+    if (\n+      path !== prevPath ||\n+      path.delta !== prevDelta ||\n+      prevProps.height !== props.height ||\n+      prevProps.width !== props.width\n+    ) {\n+      this.instance.draw(\n         path,\n         props.width,\n-        props.height\n+        props.height,\n       );\n \n-      this._oldPath = path;\n-      this._oldDelta = path.delta;\n+      this._prevPath = path;\n+      this.prevDelta = path.delta;\n     }\n-\n-    this.applyRenderableProps(oldProps, props);\n   }\n+}\n \n-});\n-\n-// Text\n+class Text extends RenderableNode {\n+  constructor(props) {\n+    const string = childrenAsString(props.children);\n+    const instance = Mode.Text(\n+      string,\n+      props.font,\n+      props.alignment,\n+      props.path,\n+    );\n \n-const Text = createComponent('Text', RenderableMixin, {\n+    super(TYPES.TEXT, instance, props);\n \n-  construct: function(element) {\n-    this._currentElement = element;\n-    this._oldString = null;\n-  },\n+    this._currentString = string;\n+  }\n \n-  mountComponent: function(\n-    transaction,\n-    nativeParent,\n-    nativeContainerInfo,\n-    context\n+  applyProps(\n+    props,\n+    prevProps = {},\n   ) {\n-    const props = this._currentElement.props;\n-    const newString = childrenAsString(props.children);\n-    this.node = Mode.Text(newString, props.font, props.alignment, props.path);\n-    this._oldString = newString;\n-    this.applyRenderableProps(emptyObject, props);\n-    return this.node;\n-  },\n+    super.applyProps(props, prevProps);\n+\n+    const string = childrenAsString(props.children);\n+\n+    if (\n+      this._currentString != string ||\n+      !this._isSameFont(props.font, prevProps.font) ||\n+      props.alignment !== prevProps.alignment ||\n+      props.path !== prevProps.path\n+    ) {\n+      this.instance.draw(\n+        string,\n+        props.font,\n+        props.alignment,\n+        props.path,\n+      );\n \n-  isSameFont: function(oldFont, newFont) {\n+      this._currentString = string;\n+    }\n+  }\n+\n+  _isSameFont(oldFont, newFont) {\n     if (oldFont === newFont) {\n       return true;\n-    }\n-    if (typeof newFont === 'string' || typeof oldFont === 'string') {\n+    } else if (\n+      typeof newFont === 'string' ||\n+      typeof oldFont === 'string'\n+    ) {\n       return false;\n+    } else {\n+      return (\n+        newFont.fontSize === oldFont.fontSize &&\n+        newFont.fontStyle === oldFont.fontStyle &&\n+        newFont.fontVariant === oldFont.fontVariant &&\n+        newFont.fontWeight === oldFont.fontWeight &&\n+        newFont.fontFamily === oldFont.fontFamily\n+      );\n     }\n-    return (\n-      newFont.fontSize === oldFont.fontSize &&\n-      newFont.fontStyle === oldFont.fontStyle &&\n-      newFont.fontVariant === oldFont.fontVariant &&\n-      newFont.fontWeight === oldFont.fontWeight &&\n-      newFont.fontFamily === oldFont.fontFamily\n+  }\n+}\n+\n+class Surface extends Component {\n+  componentDidMount() {\n+    const { height, width } = this.props;\n+\n+    this._surface = Mode.Surface(+width, +height, this._tagRef);\n+\n+    // HACK Simplify appendChild-type methods by mirroring Art instance wrappers\n+    const container = {\n+      instance: this._surface,\n+    };\n+\n+    this._mountNode = ARTRenderer.mountContainer(\n+      this.props.children,\n+      container,\n     );\n-  },\n+  }\n \n-  receiveComponent: function(nextComponent, transaction, context) {\n-    const props = nextComponent.props;\n-    const oldProps = this._currentElement.props;\n+  componentDidUpdate(prevProps, prevState) {\n+    const props = this.props;\n \n-    const oldString = this._oldString;\n-    const newString = childrenAsString(props.children);\n+    if (\n+      props.height !== prevProps.height ||\n+      props.width !== prevProps.width\n+    ) {\n+      this._surface.resize(+props.width, +props.height);\n+    }\n \n-    if (oldString !== newString ||\n-        !this.isSameFont(oldProps.font, props.font) ||\n-        oldProps.alignment !== props.alignment ||\n-        oldProps.path !== props.path) {\n-      this.node.draw(\n-        newString,\n-        props.font,\n-        props.alignment,\n-        props.path\n-      );\n-      this._oldString = newString;\n+    ARTRenderer.updateContainer(this.props.children, this._mountNode);\n+\n+    if (this._surface.render) {\n+      this._surface.render();\n     }\n+  }\n \n-    this.applyRenderableProps(oldProps, props);\n-    this._currentElement = nextComponent;\n+  componentWillUnmount() {\n+    ARTRenderer.unmountContainer(this._mountNode);\n   }\n \n-});\n+  render() {\n+    // This is going to be a placeholder because we don't know what it will\n+    // actually resolve to because ART may render canvas, vml or svg tags here.\n+    // We only allow a subset of properties since others might conflict with\n+    // ART's properties.\n+    const props = this.props;\n+\n+    // TODO: ART's Canvas Mode overrides surface title and cursor\n+    const Tag = Mode.Surface.tagName;\n \n-// Declarative fill type objects - API design not finalized\n+    return (\n+      <Tag\n+        ref={ref => this._tagRef = ref}\n+        accessKey={props.accessKey}\n+        className={props.className}\n+        draggable={props.draggable}\n+        role={props.role}\n+        style={props.style}\n+        tabIndex={props.tabIndex}\n+        title={props.title}\n+      />\n+    );\n+  }\n+}\n+\n+/** Declarative fill-type objects; API design not finalized */\n \n const slice = Array.prototype.slice;\n \n-function LinearGradient(stops, x1, y1, x2, y2) {\n-  this.args = slice.call(arguments);\n+class LinearGradient {\n+  constructor(stops, x1, y1, x2, y2) {\n+    this._args = slice.call(arguments);\n+  }\n+\n+  applyFill(node) {\n+    node.fillLinear.apply(node, this._args);\n+  }\n }\n \n-LinearGradient.prototype.applyFill = function(node) {\n-  node.fillLinear.apply(node, this.args);\n-};\n+class RadialGradient {\n+  constructor(stops, fx, fy, rx, ry, cx, cy) {\n+    this._args = slice.call(arguments);\n+  }\n \n-function RadialGradient(stops, fx, fy, rx, ry, cx, cy) {\n-  this.args = slice.call(arguments);\n+  applyFill(node) {\n+    node.fillRadial.apply(node, this.args);\n+  }\n }\n \n-RadialGradient.prototype.applyFill = function(node) {\n-  node.fillRadial.apply(node, this.args);\n-};\n+class Pattern {\n+  constructor(url, width, height, left, top) {\n+    this._args = slice.call(arguments);\n+  }\n \n-function Pattern(url, width, height, left, top) {\n-  this.args = slice.call(arguments);\n+  applyFill(node) {\n+    node.fillImage.apply(node, this.args);\n+  }\n }\n \n-Pattern.prototype.applyFill = function(node) {\n-  node.fillImage.apply(node, this.args);\n-};\n+/** RENDERER */\n+\n+const ARTRenderer = ReactFiberReconciler({\n+  appendChild(parentInstance, child) {\n+    child.instance.inject(parentInstance.instance);\n+  },\n+\n+  appendInitialChild(parentInstance, child) {\n+    child.instance.inject(parentInstance.instance);\n+  },\n+\n+  commitTextUpdate(textInstance, oldText, newText) {\n+    invariant(false, 'ReactART does not support text children');\n+  },\n+\n+  commitUpdate(instance, oldProps, newProps) {\n+    instance.applyProps(newProps, oldProps);\n+  },\n+\n+  createInstance(type, props, internalInstanceHandle) {\n+    let instance;\n+\n+    switch (type) {\n+      case TYPES.CLIPPING_RECTANGLE:\n+        instance = new ClippingRectangle(props);\n+        break;\n+      case TYPES.GROUP:\n+        instance = new Group(props);\n+        break;\n+      case TYPES.SHAPE:\n+        instance = new Shape(props);\n+        break;\n+      case TYPES.TEXT:\n+        instance = new Text(props);\n+        break;\n+    }\n+\n+    return instance;\n+  },\n+\n+  createTextInstance(text, internalInstanceHandle) {","path":"src/ReactART.js","position":null,"original_position":964,"commit_id":"7122c8522c4088e8ee5cabd8cd66336e01dacb9c","original_commit_id":"a3aa3722739a5414f43e85ce50738d96389ba6eb","user":{"login":"bvaughn","id":29597,"avatar_url":"https://avatars.githubusercontent.com/u/29597?v=3","gravatar_id":"","url":"https://api.github.com/users/bvaughn","html_url":"https://github.com/bvaughn","followers_url":"https://api.github.com/users/bvaughn/followers","following_url":"https://api.github.com/users/bvaughn/following{/other_user}","gists_url":"https://api.github.com/users/bvaughn/gists{/gist_id}","starred_url":"https://api.github.com/users/bvaughn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bvaughn/subscriptions","organizations_url":"https://api.github.com/users/bvaughn/orgs","repos_url":"https://api.github.com/users/bvaughn/repos","events_url":"https://api.github.com/users/bvaughn/events{/privacy}","received_events_url":"https://api.github.com/users/bvaughn/received_events","type":"User","site_admin":false},"body":"I think I may punt on supporting custom components that return text for this initial iteration. We can always add support for that in a follow-up.\r\n\r\nThe current API makes it difficult to associate a text string with its parent instance. I initially tried:\r\n\r\n1. `createTextInstance` returns `text` (string).\r\n1. `appendInitialChild` handles special case where `child` is a string by appending to an array stored on the ART text `instance` (for lack of a better place).\r\n1. When applying props for text, use the aforementioned array whenever `props.children` is not a string.\r\n\r\nUnfortunately `commitTextUpdate` only gets the updated text string and has no reference to the ART instance, so no way to update the text-array.\r\n\r\nAlso, `createTextInstance` is called _before_ the ART instance is created and so the only thing I have access to at that point is the `internalInstanceHandle` which I shouldn't be crawling in the renderer.  This also complicates the _initial_ display because- without using `internalInstanceHandle`- there's no way to gather up text-children and pass them along to the eventual ART text instance.","created_at":"2016-11-30T19:28:53Z","updated_at":"2016-11-30T19:28:53Z","html_url":"https://github.com/reactjs/react-art/pull/105#discussion_r90308645","pull_request_url":"https://api.github.com/repos/reactjs/react-art/pulls/105","_links":{"self":{"href":"https://api.github.com/repos/reactjs/react-art/pulls/comments/90308645"},"html":{"href":"https://github.com/reactjs/react-art/pull/105#discussion_r90308645"},"pull_request":{"href":"https://api.github.com/repos/reactjs/react-art/pulls/105"}}},"pull_request":{"url":"https://api.github.com/repos/reactjs/react-art/pulls/105","id":95798145,"html_url":"https://github.com/reactjs/react-art/pull/105","diff_url":"https://github.com/reactjs/react-art/pull/105.diff","patch_url":"https://github.com/reactjs/react-art/pull/105.patch","issue_url":"https://api.github.com/repos/reactjs/react-art/issues/105","number":105,"state":"open","locked":false,"title":"ReactART components based on ReactFiberReconciler","user":{"login":"bvaughn","id":29597,"avatar_url":"https://avatars.githubusercontent.com/u/29597?v=3","gravatar_id":"","url":"https://api.github.com/users/bvaughn","html_url":"https://github.com/bvaughn","followers_url":"https://api.github.com/users/bvaughn/followers","following_url":"https://api.github.com/users/bvaughn/following{/other_user}","gists_url":"https://api.github.com/users/bvaughn/gists{/gist_id}","starred_url":"https://api.github.com/users/bvaughn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bvaughn/subscriptions","organizations_url":"https://api.github.com/users/bvaughn/orgs","repos_url":"https://api.github.com/users/bvaughn/repos","events_url":"https://api.github.com/users/bvaughn/events{/privacy}","received_events_url":"https://api.github.com/users/bvaughn/received_events","type":"User","site_admin":false},"body":"This change set encompasses the following:\r\n* Top-level `Surface` component extends `React.Component` and uses user-specified renderer (eg `ReactDOM`).\r\n* All other react-art components use new `ReactFiberReconciler` based renderer.\r\n* `VectorWidget` updated to add a bit more coverage of components (eg gradient, text).\r\n\r\nPushing for discussion purposes. Particularly interested in feedback regarding the class/inheritance design. I could change this to use wrapper objects and pure apply-props functions if desired.\r\n\r\nWhile testing, I noticed that the `ClippingRectangle` target doesn't work quite right for SVG mode. I've also added an inline _TODO_ comment to call this out (in case we care to fix it in the underlying Art library).","created_at":"2016-11-29T23:31:16Z","updated_at":"2016-11-30T19:28:53Z","closed_at":null,"merged_at":null,"merge_commit_sha":"5d289a4732ae06e1a5699f3fbb2cbf6218d776ff","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/reactjs/react-art/pulls/105/commits","review_comments_url":"https://api.github.com/repos/reactjs/react-art/pulls/105/comments","review_comment_url":"https://api.github.com/repos/reactjs/react-art/pulls/comments{/number}","comments_url":"https://api.github.com/repos/reactjs/react-art/issues/105/comments","statuses_url":"https://api.github.com/repos/reactjs/react-art/statuses/7122c8522c4088e8ee5cabd8cd66336e01dacb9c","head":{"label":"bvaughn:fiber","ref":"fiber","sha":"7122c8522c4088e8ee5cabd8cd66336e01dacb9c","user":{"login":"bvaughn","id":29597,"avatar_url":"https://avatars.githubusercontent.com/u/29597?v=3","gravatar_id":"","url":"https://api.github.com/users/bvaughn","html_url":"https://github.com/bvaughn","followers_url":"https://api.github.com/users/bvaughn/followers","following_url":"https://api.github.com/users/bvaughn/following{/other_user}","gists_url":"https://api.github.com/users/bvaughn/gists{/gist_id}","starred_url":"https://api.github.com/users/bvaughn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bvaughn/subscriptions","organizations_url":"https://api.github.com/users/bvaughn/orgs","repos_url":"https://api.github.com/users/bvaughn/repos","events_url":"https://api.github.com/users/bvaughn/events{/privacy}","received_events_url":"https://api.github.com/users/bvaughn/received_events","type":"User","site_admin":false},"repo":{"id":74410862,"name":"react-art","full_name":"bvaughn/react-art","owner":{"login":"bvaughn","id":29597,"avatar_url":"https://avatars.githubusercontent.com/u/29597?v=3","gravatar_id":"","url":"https://api.github.com/users/bvaughn","html_url":"https://github.com/bvaughn","followers_url":"https://api.github.com/users/bvaughn/followers","following_url":"https://api.github.com/users/bvaughn/following{/other_user}","gists_url":"https://api.github.com/users/bvaughn/gists{/gist_id}","starred_url":"https://api.github.com/users/bvaughn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bvaughn/subscriptions","organizations_url":"https://api.github.com/users/bvaughn/orgs","repos_url":"https://api.github.com/users/bvaughn/repos","events_url":"https://api.github.com/users/bvaughn/events{/privacy}","received_events_url":"https://api.github.com/users/bvaughn/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/bvaughn/react-art","description":"React Bridge to the ART Drawing Library","fork":true,"url":"https://api.github.com/repos/bvaughn/react-art","forks_url":"https://api.github.com/repos/bvaughn/react-art/forks","keys_url":"https://api.github.com/repos/bvaughn/react-art/keys{/key_id}","collaborators_url":"https://api.github.com/repos/bvaughn/react-art/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/bvaughn/react-art/teams","hooks_url":"https://api.github.com/repos/bvaughn/react-art/hooks","issue_events_url":"https://api.github.com/repos/bvaughn/react-art/issues/events{/number}","events_url":"https://api.github.com/repos/bvaughn/react-art/events","assignees_url":"https://api.github.com/repos/bvaughn/react-art/assignees{/user}","branches_url":"https://api.github.com/repos/bvaughn/react-art/branches{/branch}","tags_url":"https://api.github.com/repos/bvaughn/react-art/tags","blobs_url":"https://api.github.com/repos/bvaughn/react-art/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/bvaughn/react-art/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/bvaughn/react-art/git/refs{/sha}","trees_url":"https://api.github.com/repos/bvaughn/react-art/git/trees{/sha}","statuses_url":"https://api.github.com/repos/bvaughn/react-art/statuses/{sha}","languages_url":"https://api.github.com/repos/bvaughn/react-art/languages","stargazers_url":"https://api.github.com/repos/bvaughn/react-art/stargazers","contributors_url":"https://api.github.com/repos/bvaughn/react-art/contributors","subscribers_url":"https://api.github.com/repos/bvaughn/react-art/subscribers","subscription_url":"https://api.github.com/repos/bvaughn/react-art/subscription","commits_url":"https://api.github.com/repos/bvaughn/react-art/commits{/sha}","git_commits_url":"https://api.github.com/repos/bvaughn/react-art/git/commits{/sha}","comments_url":"https://api.github.com/repos/bvaughn/react-art/comments{/number}","issue_comment_url":"https://api.github.com/repos/bvaughn/react-art/issues/comments{/number}","contents_url":"https://api.github.com/repos/bvaughn/react-art/contents/{+path}","compare_url":"https://api.github.com/repos/bvaughn/react-art/compare/{base}...{head}","merges_url":"https://api.github.com/repos/bvaughn/react-art/merges","archive_url":"https://api.github.com/repos/bvaughn/react-art/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/bvaughn/react-art/downloads","issues_url":"https://api.github.com/repos/bvaughn/react-art/issues{/number}","pulls_url":"https://api.github.com/repos/bvaughn/react-art/pulls{/number}","milestones_url":"https://api.github.com/repos/bvaughn/react-art/milestones{/number}","notifications_url":"https://api.github.com/repos/bvaughn/react-art/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/bvaughn/react-art/labels{/name}","releases_url":"https://api.github.com/repos/bvaughn/react-art/releases{/id}","deployments_url":"https://api.github.com/repos/bvaughn/react-art/deployments","created_at":"2016-11-21T22:18:42Z","updated_at":"2016-11-21T22:18:43Z","pushed_at":"2016-11-30T18:15:50Z","git_url":"git://github.com/bvaughn/react-art.git","ssh_url":"git@github.com:bvaughn/react-art.git","clone_url":"https://github.com/bvaughn/react-art.git","svn_url":"https://github.com/bvaughn/react-art","homepage":null,"size":299,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"reactjs:master","ref":"master","sha":"db4dcef9532cc9e3e1235bc62e917efcb3fb5b24","user":{"login":"reactjs","id":6412038,"avatar_url":"https://avatars.githubusercontent.com/u/6412038?v=3","gravatar_id":"","url":"https://api.github.com/users/reactjs","html_url":"https://github.com/reactjs","followers_url":"https://api.github.com/users/reactjs/followers","following_url":"https://api.github.com/users/reactjs/following{/other_user}","gists_url":"https://api.github.com/users/reactjs/gists{/gist_id}","starred_url":"https://api.github.com/users/reactjs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/reactjs/subscriptions","organizations_url":"https://api.github.com/users/reactjs/orgs","repos_url":"https://api.github.com/users/reactjs/repos","events_url":"https://api.github.com/users/reactjs/events{/privacy}","received_events_url":"https://api.github.com/users/reactjs/received_events","type":"Organization","site_admin":false},"repo":{"id":12601393,"name":"react-art","full_name":"reactjs/react-art","owner":{"login":"reactjs","id":6412038,"avatar_url":"https://avatars.githubusercontent.com/u/6412038?v=3","gravatar_id":"","url":"https://api.github.com/users/reactjs","html_url":"https://github.com/reactjs","followers_url":"https://api.github.com/users/reactjs/followers","following_url":"https://api.github.com/users/reactjs/following{/other_user}","gists_url":"https://api.github.com/users/reactjs/gists{/gist_id}","starred_url":"https://api.github.com/users/reactjs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/reactjs/subscriptions","organizations_url":"https://api.github.com/users/reactjs/orgs","repos_url":"https://api.github.com/users/reactjs/repos","events_url":"https://api.github.com/users/reactjs/events{/privacy}","received_events_url":"https://api.github.com/users/reactjs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/reactjs/react-art","description":"React Bridge to the ART Drawing Library","fork":false,"url":"https://api.github.com/repos/reactjs/react-art","forks_url":"https://api.github.com/repos/reactjs/react-art/forks","keys_url":"https://api.github.com/repos/reactjs/react-art/keys{/key_id}","collaborators_url":"https://api.github.com/repos/reactjs/react-art/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/reactjs/react-art/teams","hooks_url":"https://api.github.com/repos/reactjs/react-art/hooks","issue_events_url":"https://api.github.com/repos/reactjs/react-art/issues/events{/number}","events_url":"https://api.github.com/repos/reactjs/react-art/events","assignees_url":"https://api.github.com/repos/reactjs/react-art/assignees{/user}","branches_url":"https://api.github.com/repos/reactjs/react-art/branches{/branch}","tags_url":"https://api.github.com/repos/reactjs/react-art/tags","blobs_url":"https://api.github.com/repos/reactjs/react-art/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/reactjs/react-art/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/reactjs/react-art/git/refs{/sha}","trees_url":"https://api.github.com/repos/reactjs/react-art/git/trees{/sha}","statuses_url":"https://api.github.com/repos/reactjs/react-art/statuses/{sha}","languages_url":"https://api.github.com/repos/reactjs/react-art/languages","stargazers_url":"https://api.github.com/repos/reactjs/react-art/stargazers","contributors_url":"https://api.github.com/repos/reactjs/react-art/contributors","subscribers_url":"https://api.github.com/repos/reactjs/react-art/subscribers","subscription_url":"https://api.github.com/repos/reactjs/react-art/subscription","commits_url":"https://api.github.com/repos/reactjs/react-art/commits{/sha}","git_commits_url":"https://api.github.com/repos/reactjs/react-art/git/commits{/sha}","comments_url":"https://api.github.com/repos/reactjs/react-art/comments{/number}","issue_comment_url":"https://api.github.com/repos/reactjs/react-art/issues/comments{/number}","contents_url":"https://api.github.com/repos/reactjs/react-art/contents/{+path}","compare_url":"https://api.github.com/repos/reactjs/react-art/compare/{base}...{head}","merges_url":"https://api.github.com/repos/reactjs/react-art/merges","archive_url":"https://api.github.com/repos/reactjs/react-art/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/reactjs/react-art/downloads","issues_url":"https://api.github.com/repos/reactjs/react-art/issues{/number}","pulls_url":"https://api.github.com/repos/reactjs/react-art/pulls{/number}","milestones_url":"https://api.github.com/repos/reactjs/react-art/milestones{/number}","notifications_url":"https://api.github.com/repos/reactjs/react-art/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/reactjs/react-art/labels{/name}","releases_url":"https://api.github.com/repos/reactjs/react-art/releases{/id}","deployments_url":"https://api.github.com/repos/reactjs/react-art/deployments","created_at":"2013-09-04T20:29:33Z","updated_at":"2016-11-29T14:58:14Z","pushed_at":"2016-11-30T18:15:50Z","git_url":"git://github.com/reactjs/react-art.git","ssh_url":"git@github.com:reactjs/react-art.git","clone_url":"https://github.com/reactjs/react-art.git","svn_url":"https://github.com/reactjs/react-art","homepage":null,"size":323,"stargazers_count":1233,"watchers_count":1233,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":109,"mirror_url":null,"open_issues_count":28,"forks":109,"open_issues":28,"watchers":1233,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/reactjs/react-art/pulls/105"},"html":{"href":"https://github.com/reactjs/react-art/pull/105"},"issue":{"href":"https://api.github.com/repos/reactjs/react-art/issues/105"},"comments":{"href":"https://api.github.com/repos/reactjs/react-art/issues/105/comments"},"review_comments":{"href":"https://api.github.com/repos/reactjs/react-art/pulls/105/comments"},"review_comment":{"href":"https://api.github.com/repos/reactjs/react-art/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/reactjs/react-art/pulls/105/commits"},"statuses":{"href":"https://api.github.com/repos/reactjs/react-art/statuses/7122c8522c4088e8ee5cabd8cd66336e01dacb9c"}}}}
{"actor":{"display_login":"bvaughn"}}