Skip to content
Browse files

No more isa-swizzling.

  • Loading branch information...
1 parent 262443b commit 20a5afbdf80095af0f63f1f4fab49a59553dbdf2 @robbiehanson committed Jan 8, 2010
Showing with 148 additions and 214 deletions.
  1. +20 −33 DDXMLDocument.m
  2. +34 −47 DDXMLElement.m
  3. +84 −122 DDXMLNode.m
  4. +10 −12 DDXMLPrivate.h
View
53 DDXMLDocument.m
@@ -5,46 +5,33 @@
@implementation DDXMLDocument
-+ (id)nodeWithPrimitive:(xmlKindPtr)nodePtr
+/**
+ * Returns a DDXML wrapper object for the given primitive node.
+ * The given node MUST be non-NULL and of the proper type.
+ *
+ * If the wrapper object already exists, it is retained/autoreleased and returned.
+ * Otherwise a new wrapper object is alloc/init/autoreleased and returned.
+**/
++ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr
{
- // Note: We don't simply call the init methods blindly.
- // Doing so might cause an unnecessary alloc followed by an immediate release.
-
- if(nodePtr == NULL || nodePtr->type != XML_DOCUMENT_NODE)
- {
- return nil;
- }
+ // If a wrapper object already exists, the _private variable is pointing to it.
- xmlDocPtr doc = (xmlDocPtr)nodePtr;
+ xmlDocPtr doc = (xmlDocPtr)kindPtr;
if(doc->_private == NULL)
- return [[[DDXMLDocument alloc] initWithCheckedPrimitive:nodePtr] autorelease];
+ return [[[DDXMLDocument alloc] initWithCheckedPrimitive:kindPtr] autorelease];
else
return [[((DDXMLDocument *)(doc->_private)) retain] autorelease];
}
-- (id)initWithUncheckedPrimitive:(xmlKindPtr)nodePtr
-{
- if(nodePtr == NULL || nodePtr->type != XML_DOCUMENT_NODE)
- {
- [self release];
- return nil;
- }
-
- xmlDocPtr doc = (xmlDocPtr)nodePtr;
- if(doc->_private == NULL)
- {
- return [self initWithCheckedPrimitive:nodePtr];
- }
- else
- {
- [self release];
- return [((DDXMLDocument *)(doc->_private)) retain];
- }
-}
-
-- (id)initWithCheckedPrimitive:(xmlKindPtr)nodePtr
+/**
+ * Returns a DDXML wrapper object for the given primitive node.
+ * The given node MUST be non-NULL and of the proper type.
+ *
+ * The given node is checked, meaning a wrapper object for it does not already exist.
+**/
+- (id)initWithCheckedPrimitive:(xmlKindPtr)kindPtr
{
- self = [super initWithCheckedPrimitive:nodePtr];
+ self = [super initWithCheckedPrimitive:kindPtr];
return self;
}
@@ -106,7 +93,7 @@ - (DDXMLElement *)rootElement
xmlNodePtr rootNode = xmlDocGetRootElement(doc);
if(rootNode != NULL)
- return [DDXMLElement nodeWithPrimitive:(xmlKindPtr)(rootNode)];
+ return [DDXMLElement nodeWithPrimitive:(xmlKindPtr)rootNode];
else
return nil;
}
View
81 DDXMLElement.m
@@ -5,6 +5,36 @@
@implementation DDXMLElement
+/**
+ * Returns a DDXML wrapper object for the given primitive node.
+ * The given node MUST be non-NULL and of the proper type.
+ *
+ * If the wrapper object already exists, it is retained/autoreleased and returned.
+ * Otherwise a new wrapper object is alloc/init/autoreleased and returned.
+**/
++ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr
+{
+ // If a wrapper object already exists, the _private variable is pointing to it.
+
+ xmlNodePtr node = (xmlNodePtr)kindPtr;
+ if(node->_private == NULL)
+ return [[[DDXMLElement alloc] initWithCheckedPrimitive:kindPtr] autorelease];
+ else
+ return [[((DDXMLElement *)(node->_private)) retain] autorelease];
+}
+
+/**
+ * Returns a DDXML wrapper object for the given primitive node.
+ * The given node MUST be non-NULL and of the proper type.
+ *
+ * The given node is checked, meaning a wrapper object for it does not already exist.
+**/
+- (id)initWithCheckedPrimitive:(xmlKindPtr)kindPtr
+{
+ self = [super initWithCheckedPrimitive:kindPtr];
+ return self;
+}
+
- (id)initWithName:(NSString *)name
{
// Note: Make every guarantee that genericPtr is not null
@@ -70,49 +100,6 @@ - (id)initWithXMLString:(NSString *)string error:(NSError **)error
return [result retain];
}
-+ (id)nodeWithPrimitive:(xmlKindPtr)nodePtr
-{
- // Note: We don't simply call the init methods blindly.
- // Doing so might cause an unnecessary alloc followed by an immediate release.
-
- if(nodePtr == NULL || nodePtr->type != XML_ELEMENT_NODE)
- {
- return nil;
- }
-
- xmlNodePtr node = (xmlNodePtr)nodePtr;
- if(node->_private == NULL)
- return [[[DDXMLElement alloc] initWithCheckedPrimitive:nodePtr] autorelease];
- else
- return [[((DDXMLElement *)(node->_private)) retain] autorelease];
-}
-
-- (id)initWithUncheckedPrimitive:(xmlKindPtr)nodePtr
-{
- if(nodePtr == NULL || nodePtr->type != XML_ELEMENT_NODE)
- {
- [self release];
- return nil;
- }
-
- xmlNodePtr node = (xmlNodePtr)nodePtr;
- if(node->_private == NULL)
- {
- return [self initWithCheckedPrimitive:nodePtr];
- }
- else
- {
- [self release];
- return [((DDXMLElement *)(node->_private)) retain];
- }
-}
-
-- (id)initWithCheckedPrimitive:(xmlKindPtr)nodePtr
-{
- self = [super initWithCheckedPrimitive:nodePtr];
- return self;
-}
-
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Elements by name
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -398,7 +385,7 @@ - (NSArray *)namespaces
xmlNsPtr ns = ((xmlNodePtr)genericPtr)->nsDef;
while(ns != NULL)
{
- [result addObject:[DDXMLNode nodeWithPrimitive:(xmlKindPtr)ns nsParent:(xmlNodePtr)genericPtr]];
+ [result addObject:[DDXMLNode nodeWithPrimitive:ns nsParent:(xmlNodePtr)genericPtr]];
ns = ns->next;
}
@@ -416,7 +403,7 @@ - (DDXMLNode *)namespaceForPrefix:(NSString *)prefix
xmlNsPtr ns = ((xmlNodePtr)genericPtr)->ns;
if(ns != NULL)
{
- return [DDXMLNode nodeWithPrimitive:(xmlKindPtr)ns nsParent:(xmlNodePtr)genericPtr];
+ return [DDXMLNode nodeWithPrimitive:ns nsParent:(xmlNodePtr)genericPtr];
}
}
else
@@ -426,7 +413,7 @@ - (DDXMLNode *)namespaceForPrefix:(NSString *)prefix
{
if(xmlStrEqual(ns->prefix, [prefix xmlChar]))
{
- return [DDXMLNode nodeWithPrimitive:(xmlKindPtr)ns nsParent:(xmlNodePtr)genericPtr];
+ return [DDXMLNode nodeWithPrimitive:ns nsParent:(xmlNodePtr)genericPtr];
}
ns = ns->next;
}
@@ -459,7 +446,7 @@ + (DDXMLNode *)resolveNamespaceForPrefix:(NSString *)prefix atNode:(xmlNodePtr)n
{
if(xmlStrEqual(ns->prefix, [prefix xmlChar]))
{
- return [DDXMLNode nodeWithPrimitive:(xmlKindPtr)ns nsParent:nodePtr];
+ return [DDXMLNode nodeWithPrimitive:ns nsParent:nodePtr];
}
ns = ns->next;
}
View
206 DDXMLNode.m
@@ -118,155 +118,102 @@ + (id)textWithStringValue:(NSString *)stringValue
#pragma mark Init, Dealloc
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Returns a DDXML wrapper object for the given primitive node.
- * If the wrapper object already exists, it is retained/autoreleased and returned.
- * Otherwise a new object is alloc/init/autoreleased and returned.
-**/
-+ (id)nodeWithPrimitive:(xmlKindPtr)nodePtr
++ (id)nodeWithUnknownPrimitive:(xmlKindPtr)kindPtr
{
- if(nodePtr == NULL)
+ if(kindPtr->type == XML_DOCUMENT_NODE)
{
- return nil;
+ return [DDXMLDocument nodeWithPrimitive:kindPtr];
}
-
- // Warning: The _private variable is in a different location in the xmlNsPtr
-
- if([[self class] isXmlNsPtr:nodePtr])
+ else if(kindPtr->type == XML_ELEMENT_NODE)
{
- xmlNsPtr ns = (xmlNsPtr)nodePtr;
- if(ns->_private != NULL)
- {
- return [[((DDXMLNode *)(ns->_private)) retain] autorelease];
- }
+ return [DDXMLElement nodeWithPrimitive:kindPtr];
}
else
{
- xmlStdPtr node = (xmlStdPtr)nodePtr;
- if(node->_private != NULL)
- {
- return [[((DDXMLNode *)(node->_private)) retain] autorelease];
- }
+ return [DDXMLNode nodeWithPrimitive:kindPtr];
}
-
- return [[[DDXMLNode alloc] initWithCheckedPrimitive:nodePtr] autorelease];
}
-- (id)initWithUncheckedPrimitive:(xmlKindPtr)nodePtr
+/**
+ * Returns a DDXML wrapper object for the given primitive node.
+ * The given node MUST be non-NULL and of the proper type.
+ *
+ * If the wrapper object already exists, it is retained/autoreleased and returned.
+ * Otherwise a new wrapper object is alloc/init/autoreleased and returned.
+**/
++ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr
{
- if(nodePtr == NULL)
- {
- [self release];
- return nil;
- }
-
+ // If a wrapper object already exists, the _private variable is pointing to it.
// Warning: The _private variable is in a different location in the xmlNsPtr
- if([[self class] isXmlNsPtr:nodePtr])
+ if([self isXmlNsPtr:kindPtr])
{
- xmlNsPtr ns = (xmlNsPtr)nodePtr;
+ xmlNsPtr ns = (xmlNsPtr)kindPtr;
if(ns->_private != NULL)
{
- [self release];
- return [((DDXMLNode *)(ns->_private)) retain];
+ return [[((DDXMLNode *)(ns->_private)) retain] autorelease];
}
}
else
{
- xmlStdPtr node = (xmlStdPtr)nodePtr;
+ xmlStdPtr node = (xmlStdPtr)kindPtr;
if(node->_private != NULL)
{
- [self release];
- return [((DDXMLNode *)(node->_private)) retain];
+ return [[((DDXMLNode *)(node->_private)) retain] autorelease];
}
}
- return [self initWithCheckedPrimitive:nodePtr];
+ return [[[DDXMLNode alloc] initWithCheckedPrimitive:kindPtr] autorelease];
}
-- (id)initWithCheckedPrimitive:(xmlKindPtr)nodePtr
+/**
+ * Returns a DDXML wrapper object for the given primitive node.
+ * The given node MUST be non-NULL and of the proper type.
+ *
+ * The given node is checked, meaning a wrapper object for it does not already exist.
+**/
+- (id)initWithCheckedPrimitive:(xmlKindPtr)kindPtr
{
- BOOL maybeIsaSwizzle = [self isMemberOfClass:[DDXMLNode class]];
-
if((self = [super init]))
{
- genericPtr = nodePtr;
+ genericPtr = kindPtr;
nsParentPtr = NULL;
[self nodeRetain];
}
-
- if(self && maybeIsaSwizzle)
- {
- if(nodePtr->type == XML_ELEMENT_NODE)
- {
- self->isa = [DDXMLElement class];
- }
- else if(nodePtr->type == XML_DOCUMENT_NODE)
- {
- self->isa = [DDXMLDocument class];
- }
- }
-
return self;
}
-+ (id)nodeWithPrimitive:(xmlKindPtr)nodePtr nsParent:(xmlNodePtr)parentPtr
+/**
+ * Returns a DDXML wrapper object for the given primitive node.
+ * The given node MUST be non-NULL and of the proper type.
+ *
+ * If the wrapper object already exists, it is retained/autoreleased and returned.
+ * Otherwise a new wrapper object is alloc/init/autoreleased and returned.
+**/
++ (id)nodeWithPrimitive:(xmlNsPtr)ns nsParent:(xmlNodePtr)parent
{
- if(nodePtr == NULL || nodePtr->type != XML_NAMESPACE_DECL)
- {
- return nil;
- }
+ // If a wrapper object already exists, the _private variable is pointing to it.
- xmlNsPtr ns = (xmlNsPtr)nodePtr;
if(ns->_private == NULL)
- return [[[DDXMLNode alloc] initWithCheckedPrimitive:nodePtr nsParent:parentPtr] autorelease];
+ return [[[DDXMLNode alloc] initWithCheckedPrimitive:ns nsParent:parent] autorelease];
else
return [[((DDXMLNode *)(ns->_private)) retain] autorelease];
}
-- (id)initWithUncheckedPrimitive:(xmlKindPtr)nodePtr nsParent:(xmlNodePtr)parentPtr
-{
- if(nodePtr == NULL || nodePtr->type != XML_NAMESPACE_DECL)
- {
- [self release];
- return nil;
- }
-
- xmlNsPtr ns = (xmlNsPtr)nodePtr;
- if(ns->_private == NULL)
- {
- return [self initWithCheckedPrimitive:nodePtr nsParent:parentPtr];
- }
- else
- {
- [self release];
- return [((DDXMLNode *)(ns->_private)) retain];
- }
-}
-
-- (id)initWithCheckedPrimitive:(xmlKindPtr)nodePtr nsParent:(xmlNodePtr)parentPtr
+/**
+ * Returns a DDXML wrapper object for the given primitive node.
+ * The given node MUST be non-NULL and of the proper type.
+ *
+ * The given node is checked, meaning a wrapper object for it does not already exist.
+**/
+- (id)initWithCheckedPrimitive:(xmlNsPtr)ns nsParent:(xmlNodePtr)parent
{
- BOOL maybeIsaSwizzle = [self isMemberOfClass:[DDXMLNode class]];
-
if((self = [super init]))
{
- genericPtr = nodePtr;
- nsParentPtr = parentPtr;
+ genericPtr = (xmlKindPtr)ns;
+ nsParentPtr = parent;
[self nodeRetain];
}
-
- if(maybeIsaSwizzle)
- {
- if(nodePtr->type == XML_ELEMENT_NODE)
- {
- self->isa = [DDXMLElement class];
- }
- else if(nodePtr->type == XML_DOCUMENT_NODE)
- {
- self->isa = [DDXMLDocument class];
- }
- }
-
return self;
}
@@ -287,45 +234,52 @@ - (void)dealloc
- (id)copyWithZone:(NSZone *)zone
{
- // Todo: Do these copied object have the same _private ptr?
- // If so, the pointer needs to be reset.
-
if([self isXmlDocPtr])
{
xmlDocPtr copyDocPtr = xmlCopyDoc((xmlDocPtr)genericPtr, 1);
- return [[DDXMLDocument alloc] initWithUncheckedPrimitive:(xmlKindPtr)copyDocPtr];
+ if(copyDocPtr == NULL) return nil;
+
+ return [[DDXMLDocument alloc] initWithCheckedPrimitive:(xmlKindPtr)copyDocPtr];
}
if([self isXmlNodePtr])
{
xmlNodePtr copyNodePtr = xmlCopyNode((xmlNodePtr)genericPtr, 1);
+ if(copyNodePtr == NULL) return nil;
+
if([self isKindOfClass:[DDXMLElement class]])
- return [[DDXMLElement alloc] initWithUncheckedPrimitive:(xmlKindPtr)copyNodePtr];
+ return [[DDXMLElement alloc] initWithCheckedPrimitive:(xmlKindPtr)copyNodePtr];
else
- return [[DDXMLNode alloc] initWithUncheckedPrimitive:(xmlKindPtr)copyNodePtr];
+ return [[DDXMLNode alloc] initWithCheckedPrimitive:(xmlKindPtr)copyNodePtr];
}
if([self isXmlAttrPtr])
{
xmlAttrPtr copyAttrPtr = xmlCopyProp(NULL, (xmlAttrPtr)genericPtr);
- return [[DDXMLNode alloc] initWithUncheckedPrimitive:(xmlKindPtr)copyAttrPtr];
+ if(copyAttrPtr == NULL) return nil;
+
+ return [[DDXMLNode alloc] initWithCheckedPrimitive:(xmlKindPtr)copyAttrPtr];
}
if([self isXmlNsPtr])
{
xmlNsPtr copyNsPtr = xmlCopyNamespace((xmlNsPtr)genericPtr);
- return [[DDXMLNode alloc] initWithUncheckedPrimitive:(xmlKindPtr)copyNsPtr nsParent:NULL];
+ if(copyNsPtr == NULL) return nil;
+
+ return [[DDXMLNode alloc] initWithCheckedPrimitive:copyNsPtr nsParent:NULL];
}
if([self isXmlDtdPtr])
{
xmlDtdPtr copyDtdPtr = xmlCopyDtd((xmlDtdPtr)genericPtr);
- return [[DDXMLNode alloc] initWithUncheckedPrimitive:(xmlKindPtr)copyDtdPtr];
+ if(copyDtdPtr == NULL) return nil;
+
+ return [[DDXMLNode alloc] initWithCheckedPrimitive:(xmlKindPtr)copyDtdPtr];
}
return nil;
@@ -535,7 +489,7 @@ - (DDXMLDocument *)rootDocument
else
node = (xmlStdPtr)genericPtr;
- if(node == NULL)
+ if(node == NULL || node->doc == NULL)
return nil;
else
return [DDXMLDocument nodeWithPrimitive:(xmlKindPtr)node->doc];
@@ -552,12 +506,16 @@ - (DDXMLNode *)parent
{
if([self isXmlNsPtr])
{
- return [DDXMLNode nodeWithPrimitive:(xmlKindPtr)nsParentPtr];
+ if(nsParentPtr == NULL) return nil;
+
+ return [DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)nsParentPtr];
}
xmlStdPtr node = (xmlStdPtr)genericPtr;
- return [DDXMLNode nodeWithPrimitive:(xmlKindPtr)node->parent];
+ if(node->parent == NULL) return nil;
+
+ return [DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)node->parent];
}
/**
@@ -592,7 +550,7 @@ - (NSArray *)children
xmlNodePtr child = ((xmlStdPtr)genericPtr)->children;
while(child != NULL)
{
- [result addObject:[DDXMLNode nodeWithPrimitive:(xmlKindPtr)child]];
+ [result addObject:[DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)child]];
child = child->next;
}
@@ -627,7 +585,7 @@ - (DDXMLNode *)childAtIndex:(NSUInteger)index
{
if(i == index)
{
- return [DDXMLNode nodeWithPrimitive:(xmlKindPtr)child];
+ return [DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)child];
}
i++;
@@ -652,7 +610,9 @@ - (DDXMLNode *)previousSibling
xmlStdPtr node = (xmlStdPtr)genericPtr;
- return [DDXMLNode nodeWithPrimitive:(xmlKindPtr)node->prev];
+ if(node->prev == NULL) return nil;
+
+ return [DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)node->prev];
}
/**
@@ -668,7 +628,9 @@ - (DDXMLNode *)nextSibling
xmlStdPtr node = (xmlStdPtr)genericPtr;
- return [DDXMLNode nodeWithPrimitive:(xmlKindPtr)node->next];
+ if(node->next == NULL) return nil;
+
+ return [DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)node->next];
}
/**
@@ -701,12 +663,12 @@ - (DDXMLNode *)previousNode
lastChild = lastChild->last;
}
- return [DDXMLNode nodeWithPrimitive:(xmlKindPtr)lastChild];
+ return [DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)lastChild];
}
else
{
// The previous sibling has no children, so the previous node is simply the previous sibling
- return [DDXMLNode nodeWithPrimitive:(xmlKindPtr)previousSibling];
+ return [DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)previousSibling];
}
}
@@ -717,7 +679,7 @@ - (DDXMLNode *)previousNode
if(node->parent == NULL || node->parent->type == XML_DOCUMENT_NODE)
return nil;
else
- return [DDXMLNode nodeWithPrimitive:(xmlKindPtr)node->parent];
+ return [DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)node->parent];
}
/**
@@ -753,7 +715,7 @@ - (DDXMLNode *)nextNode
{
xmlNodePtr parentNextSibling = parent->next;
if(parentNextSibling != NULL)
- return [DDXMLNode nodeWithPrimitive:(xmlKindPtr)parentNextSibling];
+ return [DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)parentNextSibling];
else
parent = parent->parent;
}
@@ -1161,7 +1123,7 @@ -(NSArray *)nodesForXPath:(NSString *)xpath error:(NSError **)error
{
xmlNodePtr node = xpathObj->nodesetval->nodeTab[i];
- [mResult addObject:[DDXMLNode nodeWithPrimitive:(xmlKindPtr)node]];
+ [mResult addObject:[DDXMLNode nodeWithUnknownPrimitive:(xmlKindPtr)node]];
}
result = mResult;
View
22 DDXMLPrivate.h
@@ -11,13 +11,13 @@
@interface DDXMLNode (PrivateAPI)
-+ (id)nodeWithPrimitive:(xmlKindPtr)nodePtr;
-- (id)initWithCheckedPrimitive:(xmlKindPtr)nodePtr;
-- (id)initWithUncheckedPrimitive:(xmlKindPtr)nodePtr;
++ (id)nodeWithUnknownPrimitive:(xmlKindPtr)kindPtr;
-+ (id)nodeWithPrimitive:(xmlKindPtr)nodePtr nsParent:(xmlNodePtr)parentPtr;
-- (id)initWithCheckedPrimitive:(xmlKindPtr)nodePtr nsParent:(xmlNodePtr)parentPtr;
-- (id)initWithUncheckedPrimitive:(xmlKindPtr)nodePtr nsParent:(xmlNodePtr)parentPtr;
++ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr;
+- (id)initWithCheckedPrimitive:(xmlKindPtr)kindPtr;
+
++ (id)nodeWithPrimitive:(xmlNsPtr)ns nsParent:(xmlNodePtr)parent;
+- (id)initWithCheckedPrimitive:(xmlNsPtr)ns nsParent:(xmlNodePtr)parent;
+ (BOOL)isXmlAttrPtr:(xmlKindPtr)kindPtr;
- (BOOL)isXmlAttrPtr;
@@ -61,9 +61,8 @@
@interface DDXMLElement (PrivateAPI)
-+ (id)nodeWithPrimitive:(xmlKindPtr)nodePtr;
-- (id)initWithCheckedPrimitive:(xmlKindPtr)nodePtr;
-- (id)initWithUncheckedPrimitive:(xmlKindPtr)nodePtr;
++ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr;
+- (id)initWithCheckedPrimitive:(xmlKindPtr)kindPtr;
- (NSArray *)elementsWithName:(NSString *)name uri:(NSString *)URI;
@@ -74,8 +73,7 @@
@interface DDXMLDocument (PrivateAPI)
-+ (id)nodeWithPrimitive:(xmlKindPtr)nodePtr;
-- (id)initWithCheckedPrimitive:(xmlKindPtr)nodePtr;
-- (id)initWithUncheckedPrimitive:(xmlKindPtr)nodePtr;
++ (id)nodeWithPrimitive:(xmlKindPtr)kindPtr;
+- (id)initWithCheckedPrimitive:(xmlKindPtr)kindPtr;
@end

0 comments on commit 20a5afb

Please sign in to comment.
Something went wrong with that request. Please try again.