From: David ‘Bombe’ Roden Date: Thu, 24 Oct 2013 19:53:15 +0000 (+0200) Subject: Use XML files for all error conditions, expand test for complete Sone. X-Git-Url: https://git.pterodactylus.net/?a=commitdiff_plain;h=b7f0920c8296ab5b59c856e67c101c47fc2a3f14;p=Sone.git Use XML files for all error conditions, expand test for complete Sone. --- diff --git a/src/test/java/net/pterodactylus/sone/core/SoneParserTest.java b/src/test/java/net/pterodactylus/sone/core/SoneParserTest.java index ee6c82f..2ed984c 100644 --- a/src/test/java/net/pterodactylus/sone/core/SoneParserTest.java +++ b/src/test/java/net/pterodactylus/sone/core/SoneParserTest.java @@ -1,31 +1,35 @@ package net.pterodactylus.sone.core; -import static com.google.common.base.Optional.absent; -import static com.google.common.base.Optional.fromNullable; -import static com.google.common.base.Optional.of; +import static com.google.common.base.Objects.equal; import static java.lang.String.format; import static java.util.logging.Level.OFF; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.collection.IsIterableContainingInOrder.contains; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.util.logging.Logger; import net.pterodactylus.sone.data.Client; import net.pterodactylus.sone.data.Image; +import net.pterodactylus.sone.data.Post; +import net.pterodactylus.sone.data.PostReply; +import net.pterodactylus.sone.data.Profile.Field; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.database.Database; import net.pterodactylus.sone.database.SoneBuilder.SoneCreated; import net.pterodactylus.sone.database.memory.MemoryDatabase; -import com.google.common.base.Joiner; import com.google.common.base.Optional; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; import org.junit.Test; /** @@ -42,7 +46,6 @@ public class SoneParserTest { private final Core core = mock(Core.class); private final Database database = new MemoryDatabase(null); private final Sone originalSone = database.newSoneBuilder().by("test").using(new Client("TestClient", "1.0")).build(Optional.absent()); - private final SoneXmlBuilder soneXmlBuilder = new SoneXmlBuilder(); private final SoneParser soneParser = new SoneParser(); public SoneParserTest() { @@ -59,28 +62,28 @@ public class SoneParserTest { @Test public void verifyThatANegativeProtocolVersionCausesAnError() { - Optional sone = soneParser.parseSone(database, originalSone, soneXmlBuilder.setProtocolVersion("-1").get()); + Optional sone = soneParser.parseSone(database, originalSone, getXml("negative-protocol-version")); assertThat(sone, notNullValue()); assertThat(sone.isPresent(), is(false)); } @Test public void verifyThatATooLargeProtocolVersionCausesAnError() { - Optional sone = soneParser.parseSone(database, originalSone, soneXmlBuilder.setProtocolVersion("1").get()); + Optional sone = soneParser.parseSone(database, originalSone, getXml("too-large-protocol-version")); assertThat(sone, notNullValue()); assertThat(sone.isPresent(), is(false)); } @Test public void verifyThatAMissingTimeCausesAnError() { - Optional sone = soneParser.parseSone(database, originalSone, soneXmlBuilder.removeTime().get()); + Optional sone = soneParser.parseSone(database, originalSone, getXml("missing-time")); assertThat(sone, notNullValue()); assertThat(sone.isPresent(), is(false)); } @Test public void verifyThatAMissingClientCausesTheOriginalClientToBeUsed() { - Optional sone = soneParser.parseSone(database, originalSone, soneXmlBuilder.removeClientInformation().get()); + Optional sone = soneParser.parseSone(database, originalSone, getXml("missing-client")); assertThat(sone, notNullValue()); assertThat(sone.isPresent(), is(true)); assertThat(sone.get().getClient(), notNullValue()); @@ -104,108 +107,104 @@ public class SoneParserTest { assertThat(sone.get().getProfile().getBirthMonth(), is(10)); assertThat(sone.get().getProfile().getBirthDay(), is(22)); assertThat(sone.get().getProfile().getAvatar(), is("96431abe-3add-11e3-8a46-67047503bf6d")); - } + assertThat(sone.get().getProfile().getFields(), contains( + fieldMatcher("Field1", "Value1"), + fieldMatcher("Field2", "Value2") + )); + assertThat(sone.get().getPosts(), contains( + postMatcher("d8c9586e-3adb-11e3-bb31-171fc040e645", "0rpD4gL8mszav2trndhIdKIxvKUCNAe2kjA3dLV8CVU", 1382420181000L, "Hello, User!"), + postMatcher("bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3", null, 1382420140000L, "Hello, World!") + )); + assertThat(sone.get().getReplies(), containsInAnyOrder( + postReplyMatcher("f09fa448-3adb-11e3-a783-ab54a11aacc4", "bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3", 1382420224000L, "Talking to myself."), + postReplyMatcher("0a376440-3adc-11e3-8f45-c7cc157436a5", "11ebe86e-3adc-11e3-b7b9-7f2c88018a33", 1382420271000L, "Talking to somebody I can't see.") + )); + assertThat(sone.get().getLikedPostIds(), containsInAnyOrder( + "bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3", + "305d85e6-3adc-11e3-be45-8b53dd91f0af" + )); + assertThat(sone.get().getLikedReplyIds(), containsInAnyOrder( + "f09fa448-3adb-11e3-a783-ab54a11aacc4", + "3ba28960-3adc-11e3-93c7-6713d170f44c" + )); - public InputStream getInputStream(String content) throws UnsupportedEncodingException { - return new ByteArrayInputStream(content.getBytes("UTF-8")); } - private InputStream getXml(String name) { - return getClass().getResourceAsStream(format("/sone-parser/%s.xml", name)); - } + private Matcher postReplyMatcher(final String id, final String postId, final long time, final String text) { + return new TypeSafeMatcher() { + @Override + protected boolean matchesSafely(PostReply postReply) { + return postReply.getId().equals(id) && postReply.getPostId().equals(postId) && (postReply.getTime() == time) && postReply.getText().equals(text); + } - private static class SoneXmlBuilder { - - private Optional time = of(1000L); - private Optional protocolVersion = of("0"); - private Optional clientInformation = of("Test-Client1.0"); - private Optional profile = of(Joiner.on("").join( - "First", - "M.", - "Last", - "2000", - "9", - "13", - "avatar-id", - "", - "Custom FieldCustom Value", - "" - )); - private Optional posts = of("post-idrecipientHello!"); - private Optional replies = of("reply-idpost-idReply!"); - - public SoneXmlBuilder removeTime() { - time = absent(); - return this; - } - - public SoneXmlBuilder setProtocolVersion(String protocolVersion) { - this.protocolVersion = fromNullable(protocolVersion); - return this; - } - - public SoneXmlBuilder removeProtocolVersion() { - this.protocolVersion = absent(); - return this; - } - - public SoneXmlBuilder setClientInformation(String name, String version) { - clientInformation = of("" + name + "" + version + ""); - return this; - } - - public SoneXmlBuilder removeClientInformation() { - clientInformation = absent(); - return this; - } - - public SoneXmlBuilder removeProfile() { - profile = absent(); - return this; - } - - public SoneXmlBuilder removePost() { - posts = absent(); - return this; - } - - public SoneXmlBuilder removeReply() { - replies = absent(); - return this; - } - - public InputStream get() { - StringBuilder content = new StringBuilder(); - content.append(""); - if (time.isPresent()) { - content.append(createXmlElement("time", String.valueOf(time.get()))); + @Override + public void describeTo(Description description) { + description.appendText("PostReply(") + .appendValue(id).appendText(", ") + .appendValue(postId).appendText(", ") + .appendValue(time).appendText(", ") + .appendValue(text).appendText(")"); + } + + @Override + protected void describeMismatchSafely(PostReply postReply, Description mismatchDescription) { + mismatchDescription.appendText("PostReply(") + .appendValue(postReply.getId()).appendText(", ") + .appendValue(postReply.getPostId()).appendText(", ") + .appendValue(postReply.getTime()).appendText(", ") + .appendValue(postReply.getText()).appendText(")"); } - if (protocolVersion.isPresent()) { - content.append(createXmlElement("protocol-version", protocolVersion.get())); + }; + } + + private Matcher postMatcher(final String id, final String recipient, final long time, final String text) { + return new TypeSafeMatcher() { + @Override + protected boolean matchesSafely(Post post) { + return post.getId().equals(id) && equal(post.getRecipientId().orNull(), recipient) && (post.getTime() == time) && post.getText().equals(text); } - if (clientInformation.isPresent()) { - content.append(createXmlElement("client", clientInformation.get())); + + @Override + public void describeTo(Description description) { + description.appendText("Post(") + .appendValue(id).appendText(", ") + .appendValue(recipient).appendText(", ") + .appendValue(time).appendText(", ") + .appendValue(text).appendText(")"); } - if (profile.isPresent()) { - content.append(createXmlElement("profile", profile.get())); + + @Override + protected void describeMismatchSafely(Post post, Description mismatchDescription) { + mismatchDescription.appendText("Post(") + .appendValue(post.getId()).appendText(", ") + .appendValue(post.getRecipientId().orNull()).appendText(", ") + .appendValue(post.getTime()).appendText(", ") + .appendValue(post.getText()).appendText(")"); } - if (posts.isPresent()) { - content.append(createXmlElement("posts", posts.get())); + }; + } + + private Matcher fieldMatcher(final String name, final String value) { + return new TypeSafeMatcher() { + @Override + protected boolean matchesSafely(Field field) { + return field.getName().equals(name) && field.getValue().equals(value); } - content.append(""); - try { - String xmlString = content.toString(); - return new ByteArrayInputStream(xmlString.getBytes("UTF-8")); - } catch (UnsupportedEncodingException e) { - /* ignore. */ + + @Override + public void describeTo(Description description) { + description.appendText("field named ").appendValue(name).appendText(" with value ").appendValue(value); } - return null; - } - private String createXmlElement(String xmlElement, String content) { - return format("<%s>%s", xmlElement, content); - } + @Override + protected void describeMismatchSafely(Field field, Description mismatchDescription) { + mismatchDescription.appendText("field named ").appendValue(field.getName()).appendText(" with value ").appendValue(field.getValue()); + } + }; + } + private InputStream getXml(String name) { + return getClass().getResourceAsStream(format("/sone-parser/%s.xml", name)); } } diff --git a/src/test/resources/sone-parser/missing-client.xml b/src/test/resources/sone-parser/missing-client.xml new file mode 100644 index 0000000..56fe480 --- /dev/null +++ b/src/test/resources/sone-parser/missing-client.xml @@ -0,0 +1,131 @@ + + + + + 0 + + + First + M. + Last + 22 + 10 + 2013 + 96431abe-3add-11e3-8a46-67047503bf6d + + + Field1 + Value1 + + + Field2 + Value2 + + + + + + + bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3 + + + Hello, World! + + + d8c9586e-3adb-11e3-bb31-171fc040e645 + 0rpD4gL8mszav2trndhIdKIxvKUCNAe2kjA3dLV8CVU + + Hello, User! + + + + + + f09fa448-3adb-11e3-a783-ab54a11aacc4 + bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3 + + Talking to myself. + + + 0a376440-3adc-11e3-8f45-c7cc157436a5 + 11ebe86e-3adc-11e3-b7b9-7f2c88018a33 + + Talking to somebody I can't see. + + + + + bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3 + 305d85e6-3adc-11e3-be45-8b53dd91f0af + + + + f09fa448-3adb-11e3-a783-ab54a11aacc4 + 3ba28960-3adc-11e3-93c7-6713d170f44c + + + + + 6a73c6e6-3adc-11e3-b091-577b10a725ad + Album1 + First album with stuff. + e3707102-3adc-11e3-b828-9f4de99f0bc4 + + + 8966f69a-3adc-11e3-802d-0f57b63c8809 + 1382420473000 + SSK@JvW9oZ8AriNGbwBosJD1gyMdiMHc5AgSmhNBU1CmAb8,na1IPpMcYiZLaWSv9EWq9NcDPPGplQBw8kJsLobXIG4,AQACAAE/8966f69a-3adc-11e3-802d-0f57b63c8809.jpg + Stuff + Yes, it's stuff! + 640 + 480 + + + e3707102-3adc-11e3-b828-9f4de99f0bc4 + 1382420624000 + SSK@dM1er7A9tG242bG-Xxy0kmprD7YkqEDE9mrZ98C~L3E,Np3iWiaGyd~er86edP9ndpH3pPKk2owDmAT2TQZNBA0,AQACAAE/e3707102-3adc-11e3-b828-9f4de99f0bc4.jpg + More Stuff + Yes, it's more stuff! + 640 + 360 + + + + + 1e73b52a-3add-11e3-ba45-cb0c28da9c2a + 6a73c6e6-3adc-11e3-b091-577b10a725ad + Nested Album + Nested album with stuff. + 312182ba-3add-11e3-bd76-13e7278f0161 + + + 312182ba-3add-11e3-bd76-13e7278f0161 + 1382420756000 + SSK@0rpD4gL8mszav2trndhIdKIxvKUCNAe2kjA3dLV8CVU,2KP8WDSaQvyJ16pXBHQrE1vj~fAaYPIsk35lM-ec4B0,AQACAAE/312182ba-3add-11e3-bd76-13e7278f0161.jpg + Other Stuff + Yes, it's other stuff! + 640 + 272 + + + + + 8a04b5fa-3add-11e3-afe2-676e721c04bd + Avatars + The avatar collection. + 96431abe-3add-11e3-8a46-67047503bf6d + + + 96431abe-3add-11e3-8a46-67047503bf6d + 1382420923000 + SSK@v6Js3ZJBMB23IB0JvdgiPynHQBYEvkFSi3~D8RDdj3s,FfLhjRC4bqYLHVexT33Pv6agXl6Ft~TDhX1jIM5w2n4,AQACAAE/96431abe-3add-11e3-8a46-67047503bf6d.png + Avatar 1 + The first avatar. + 64 + 64 + + + + + + diff --git a/src/test/resources/sone-parser/missing-time.xml b/src/test/resources/sone-parser/missing-time.xml new file mode 100644 index 0000000..41d2937 --- /dev/null +++ b/src/test/resources/sone-parser/missing-time.xml @@ -0,0 +1,135 @@ + + + + 0 + + + Sone + 0.8.7 + + + + First + M. + Last + 22 + 10 + 2013 + 96431abe-3add-11e3-8a46-67047503bf6d + + + Field1 + Value1 + + + Field2 + Value2 + + + + + + + bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3 + + + Hello, World! + + + d8c9586e-3adb-11e3-bb31-171fc040e645 + 0rpD4gL8mszav2trndhIdKIxvKUCNAe2kjA3dLV8CVU + + Hello, User! + + + + + + f09fa448-3adb-11e3-a783-ab54a11aacc4 + bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3 + + Talking to myself. + + + 0a376440-3adc-11e3-8f45-c7cc157436a5 + 11ebe86e-3adc-11e3-b7b9-7f2c88018a33 + + Talking to somebody I can't see. + + + + + bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3 + 305d85e6-3adc-11e3-be45-8b53dd91f0af + + + + f09fa448-3adb-11e3-a783-ab54a11aacc4 + 3ba28960-3adc-11e3-93c7-6713d170f44c + + + + + 6a73c6e6-3adc-11e3-b091-577b10a725ad + Album1 + First album with stuff. + e3707102-3adc-11e3-b828-9f4de99f0bc4 + + + 8966f69a-3adc-11e3-802d-0f57b63c8809 + 1382420473000 + SSK@JvW9oZ8AriNGbwBosJD1gyMdiMHc5AgSmhNBU1CmAb8,na1IPpMcYiZLaWSv9EWq9NcDPPGplQBw8kJsLobXIG4,AQACAAE/8966f69a-3adc-11e3-802d-0f57b63c8809.jpg + Stuff + Yes, it's stuff! + 640 + 480 + + + e3707102-3adc-11e3-b828-9f4de99f0bc4 + 1382420624000 + SSK@dM1er7A9tG242bG-Xxy0kmprD7YkqEDE9mrZ98C~L3E,Np3iWiaGyd~er86edP9ndpH3pPKk2owDmAT2TQZNBA0,AQACAAE/e3707102-3adc-11e3-b828-9f4de99f0bc4.jpg + More Stuff + Yes, it's more stuff! + 640 + 360 + + + + + 1e73b52a-3add-11e3-ba45-cb0c28da9c2a + 6a73c6e6-3adc-11e3-b091-577b10a725ad + Nested Album + Nested album with stuff. + 312182ba-3add-11e3-bd76-13e7278f0161 + + + 312182ba-3add-11e3-bd76-13e7278f0161 + 1382420756000 + SSK@0rpD4gL8mszav2trndhIdKIxvKUCNAe2kjA3dLV8CVU,2KP8WDSaQvyJ16pXBHQrE1vj~fAaYPIsk35lM-ec4B0,AQACAAE/312182ba-3add-11e3-bd76-13e7278f0161.jpg + Other Stuff + Yes, it's other stuff! + 640 + 272 + + + + + 8a04b5fa-3add-11e3-afe2-676e721c04bd + Avatars + The avatar collection. + 96431abe-3add-11e3-8a46-67047503bf6d + + + 96431abe-3add-11e3-8a46-67047503bf6d + 1382420923000 + SSK@v6Js3ZJBMB23IB0JvdgiPynHQBYEvkFSi3~D8RDdj3s,FfLhjRC4bqYLHVexT33Pv6agXl6Ft~TDhX1jIM5w2n4,AQACAAE/96431abe-3add-11e3-8a46-67047503bf6d.png + Avatar 1 + The first avatar. + 64 + 64 + + + + + + diff --git a/src/test/resources/sone-parser/negative-protocol-version.xml b/src/test/resources/sone-parser/negative-protocol-version.xml new file mode 100644 index 0000000..0a7cf8b --- /dev/null +++ b/src/test/resources/sone-parser/negative-protocol-version.xml @@ -0,0 +1,136 @@ + + + + + -1 + + + Sone + 0.8.7 + + + + First + M. + Last + 22 + 10 + 2013 + 96431abe-3add-11e3-8a46-67047503bf6d + + + Field1 + Value1 + + + Field2 + Value2 + + + + + + + bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3 + + + Hello, World! + + + d8c9586e-3adb-11e3-bb31-171fc040e645 + 0rpD4gL8mszav2trndhIdKIxvKUCNAe2kjA3dLV8CVU + + Hello, User! + + + + + + f09fa448-3adb-11e3-a783-ab54a11aacc4 + bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3 + + Talking to myself. + + + 0a376440-3adc-11e3-8f45-c7cc157436a5 + 11ebe86e-3adc-11e3-b7b9-7f2c88018a33 + + Talking to somebody I can't see. + + + + + bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3 + 305d85e6-3adc-11e3-be45-8b53dd91f0af + + + + f09fa448-3adb-11e3-a783-ab54a11aacc4 + 3ba28960-3adc-11e3-93c7-6713d170f44c + + + + + 6a73c6e6-3adc-11e3-b091-577b10a725ad + Album1 + First album with stuff. + e3707102-3adc-11e3-b828-9f4de99f0bc4 + + + 8966f69a-3adc-11e3-802d-0f57b63c8809 + 1382420473000 + SSK@JvW9oZ8AriNGbwBosJD1gyMdiMHc5AgSmhNBU1CmAb8,na1IPpMcYiZLaWSv9EWq9NcDPPGplQBw8kJsLobXIG4,AQACAAE/8966f69a-3adc-11e3-802d-0f57b63c8809.jpg + Stuff + Yes, it's stuff! + 640 + 480 + + + e3707102-3adc-11e3-b828-9f4de99f0bc4 + 1382420624000 + SSK@dM1er7A9tG242bG-Xxy0kmprD7YkqEDE9mrZ98C~L3E,Np3iWiaGyd~er86edP9ndpH3pPKk2owDmAT2TQZNBA0,AQACAAE/e3707102-3adc-11e3-b828-9f4de99f0bc4.jpg + More Stuff + Yes, it's more stuff! + 640 + 360 + + + + + 1e73b52a-3add-11e3-ba45-cb0c28da9c2a + 6a73c6e6-3adc-11e3-b091-577b10a725ad + Nested Album + Nested album with stuff. + 312182ba-3add-11e3-bd76-13e7278f0161 + + + 312182ba-3add-11e3-bd76-13e7278f0161 + 1382420756000 + SSK@0rpD4gL8mszav2trndhIdKIxvKUCNAe2kjA3dLV8CVU,2KP8WDSaQvyJ16pXBHQrE1vj~fAaYPIsk35lM-ec4B0,AQACAAE/312182ba-3add-11e3-bd76-13e7278f0161.jpg + Other Stuff + Yes, it's other stuff! + 640 + 272 + + + + + 8a04b5fa-3add-11e3-afe2-676e721c04bd + Avatars + The avatar collection. + 96431abe-3add-11e3-8a46-67047503bf6d + + + 96431abe-3add-11e3-8a46-67047503bf6d + 1382420923000 + SSK@v6Js3ZJBMB23IB0JvdgiPynHQBYEvkFSi3~D8RDdj3s,FfLhjRC4bqYLHVexT33Pv6agXl6Ft~TDhX1jIM5w2n4,AQACAAE/96431abe-3add-11e3-8a46-67047503bf6d.png + Avatar 1 + The first avatar. + 64 + 64 + + + + + + diff --git a/src/test/resources/sone-parser/too-large-protocol-version.xml b/src/test/resources/sone-parser/too-large-protocol-version.xml new file mode 100644 index 0000000..27b2d0b --- /dev/null +++ b/src/test/resources/sone-parser/too-large-protocol-version.xml @@ -0,0 +1,136 @@ + + + + + 1 + + + Sone + 0.8.7 + + + + First + M. + Last + 22 + 10 + 2013 + 96431abe-3add-11e3-8a46-67047503bf6d + + + Field1 + Value1 + + + Field2 + Value2 + + + + + + + bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3 + + + Hello, World! + + + d8c9586e-3adb-11e3-bb31-171fc040e645 + 0rpD4gL8mszav2trndhIdKIxvKUCNAe2kjA3dLV8CVU + + Hello, User! + + + + + + f09fa448-3adb-11e3-a783-ab54a11aacc4 + bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3 + + Talking to myself. + + + 0a376440-3adc-11e3-8f45-c7cc157436a5 + 11ebe86e-3adc-11e3-b7b9-7f2c88018a33 + + Talking to somebody I can't see. + + + + + bbb7ebf0-3adb-11e3-8a0b-630cd8f21cf3 + 305d85e6-3adc-11e3-be45-8b53dd91f0af + + + + f09fa448-3adb-11e3-a783-ab54a11aacc4 + 3ba28960-3adc-11e3-93c7-6713d170f44c + + + + + 6a73c6e6-3adc-11e3-b091-577b10a725ad + Album1 + First album with stuff. + e3707102-3adc-11e3-b828-9f4de99f0bc4 + + + 8966f69a-3adc-11e3-802d-0f57b63c8809 + 1382420473000 + SSK@JvW9oZ8AriNGbwBosJD1gyMdiMHc5AgSmhNBU1CmAb8,na1IPpMcYiZLaWSv9EWq9NcDPPGplQBw8kJsLobXIG4,AQACAAE/8966f69a-3adc-11e3-802d-0f57b63c8809.jpg + Stuff + Yes, it's stuff! + 640 + 480 + + + e3707102-3adc-11e3-b828-9f4de99f0bc4 + 1382420624000 + SSK@dM1er7A9tG242bG-Xxy0kmprD7YkqEDE9mrZ98C~L3E,Np3iWiaGyd~er86edP9ndpH3pPKk2owDmAT2TQZNBA0,AQACAAE/e3707102-3adc-11e3-b828-9f4de99f0bc4.jpg + More Stuff + Yes, it's more stuff! + 640 + 360 + + + + + 1e73b52a-3add-11e3-ba45-cb0c28da9c2a + 6a73c6e6-3adc-11e3-b091-577b10a725ad + Nested Album + Nested album with stuff. + 312182ba-3add-11e3-bd76-13e7278f0161 + + + 312182ba-3add-11e3-bd76-13e7278f0161 + 1382420756000 + SSK@0rpD4gL8mszav2trndhIdKIxvKUCNAe2kjA3dLV8CVU,2KP8WDSaQvyJ16pXBHQrE1vj~fAaYPIsk35lM-ec4B0,AQACAAE/312182ba-3add-11e3-bd76-13e7278f0161.jpg + Other Stuff + Yes, it's other stuff! + 640 + 272 + + + + + 8a04b5fa-3add-11e3-afe2-676e721c04bd + Avatars + The avatar collection. + 96431abe-3add-11e3-8a46-67047503bf6d + + + 96431abe-3add-11e3-8a46-67047503bf6d + 1382420923000 + SSK@v6Js3ZJBMB23IB0JvdgiPynHQBYEvkFSi3~D8RDdj3s,FfLhjRC4bqYLHVexT33Pv6agXl6Ft~TDhX1jIM5w2n4,AQACAAE/96431abe-3add-11e3-8a46-67047503bf6d.png + Avatar 1 + The first avatar. + 64 + 64 + + + + + +