diff --git a/blog.hugo/assets/styles/layouts/_default/list.scss b/blog.hugo/assets/styles/layouts/_default/list.scss deleted file mode 100644 index 6bbb71d..0000000 --- a/blog.hugo/assets/styles/layouts/_default/list.scss +++ /dev/null @@ -1,15 +0,0 @@ -main._default-list { - display: flex; - flex-flow: column; - .pages { - flex-grow: 1; - display: flex; - padding-inline: var(--pad-x, 1rem); - .container { - flex-grow: 1; - .paginator { - height: 100%; - } - } - } -} \ No newline at end of file diff --git a/blog.hugo/assets/styles/layouts/_default/single.scss b/blog.hugo/assets/styles/layouts/_default/single.scss deleted file mode 100644 index 6a6e0c7..0000000 --- a/blog.hugo/assets/styles/layouts/_default/single.scss +++ /dev/null @@ -1,57 +0,0 @@ -main._default-single { - .container { - display: grid; - gap: 1em; - @media (min-width: 40rem) { - grid-template-columns: 1fr minmax(auto, 80ch) 1fr; - > * { - grid-column: 2; - } - } - } - .page { - @media (min-width: 40rem) { - font-size: 1.25em; - } - } - .page-header { - hr {display: none;} - padding-block: 2em; - } - .page-title { - font-weight: bold; - font-size: 1.953em; - line-height: 1; - } - .page-summary { - max-inline-size: 65ch; - font-size: 1.25em; - line-height: 1.4; - font-style: italic; - } - .page-date { - font-size: 1em; - line-height: 1; - } - .page-author { - display: none; - } - .page-content { - padding-block: 2em; - blockquote { - padding-block: 1rem; - padding-inline-start: 1rem; - border-inline-start: 4px solid black; - background: #eee; - font-style: italic; - } - h1 {font-size: 1.953em} - h2 {font-size: 1.563em} - h3 {font-size: 1.25em} - h4 {font-size: 1em} - h1, h2, h3, h4 {margin-block-start: 1em} - ul, ol { - margin-inline-start: 1em; - } - } -} \ No newline at end of file diff --git a/blog.hugo/content/_dump/services-vs-communities.md b/blog.hugo/content/_dump/services-vs-communities.md deleted file mode 100644 index 3fa5ee0..0000000 --- a/blog.hugo/content/_dump/services-vs-communities.md +++ /dev/null @@ -1,13 +0,0 @@ -https://mastodon.social/@trwnh/110329802576726213 - -services aren't communities - -the gmail community - -imo the biggest mistake of fedi is tying together the social and technical layers. local timelines should have been group chats all along - -it's a huge misunderstanding because some people want services and some people want communities and they are not the same thing. some people can run a community but offer bad service. some people offer great service but can't run a community - -instances shouldn't exist as the only model. the service layer and the community layer should be separate. combining the two makes both of them worse -- as can be seen if you violate the rules of your community, you lose access not just to the community, but to the service entirely. and if the community cannot continue to provide service, you again lose both. - -i do think there is some value in being both, because then people feel more likely to donate as they are personally invested. but you could have incentives to donate even while keeping them separate. \ No newline at end of file diff --git a/blog.hugo/content/_dump/social-media-failure.md b/blog.hugo/content/_dump/social-media-failure.md deleted file mode 100644 index 81af6f1..0000000 --- a/blog.hugo/content/_dump/social-media-failure.md +++ /dev/null @@ -1,7 +0,0 @@ -the more i think about and research communication paradigms, i'm starting to think more and more that this whole "social network" thing is just fundamentally flawed. in pure terms you might send a message or publish a resource. but with these social networks it's not that clear cut. you're never unambiguously sending a message or publishing a resource, but instead, some weird hybrid that we call a "post". not quite message, not quite resource. it exists in part or in whole exclusively on-network - -and i guess that makes it easier to put in a silo which is how companies maintain their profit motive. - -but in replicating the design of these social networks we replicate their properties too. fedi hasn't entirely moved past silos because it's embedded in the design level. thankfully not the protocol level, but still. it's going to persist in implementations as long as we limit ourselves to "twitter but better", "instagram but better", etc. we're not building the commons that we could build. - -and the lack of clarity in our metaphors and associated abstractions leads to subtle violations of what people expect. there should be a clearer split. consider the duality of tumblr as both a social network and a publishing platform. they're making this split more apparent than it used to be. in addition to username.tumblr.com for blogs they now have tumblr.com/username for network profiles. \ No newline at end of file diff --git a/blog.hugo/content/threads/_index.md b/blog.hugo/content/blog/_index.md similarity index 100% rename from blog.hugo/content/threads/_index.md rename to blog.hugo/content/blog/_index.md diff --git a/blog.hugo/content/_dump/activitypub-proglang.md b/blog.hugo/content/blog/activitypub-proglang/index.md similarity index 78% rename from blog.hugo/content/_dump/activitypub-proglang.md rename to blog.hugo/content/blog/activitypub-proglang/index.md index 30bb62b..9d18fe2 100644 --- a/blog.hugo/content/_dump/activitypub-proglang.md +++ b/blog.hugo/content/blog/activitypub-proglang/index.md @@ -1,3 +1,10 @@ ++++ +title = "an analogy between activitypub and programming languages" +summary = "you don't say \"compatible with c++\" you say \"written in/with c++\". similarly, we might say that fedi is \"written with activitypub\" or \"implemented using activitypub\"" +date = "2023-03-28T09:13:00-06:00" +source = "https://mastodon.social/@trwnh/110101321320240671" ++++ + people think activitypub is a network protocol when it's really more like a programming language. you don't say "compatible with c++" you say "written in/with c++". similarly, we might say that fedi is "written with activitypub" or "implemented using activitypub", not "compatible with activitypub" or anything suggesting a network. analogously: diff --git a/blog.hugo/content/threads/art-not-commodity/index.md b/blog.hugo/content/blog/art-not-commodity/index.md similarity index 100% rename from blog.hugo/content/threads/art-not-commodity/index.md rename to blog.hugo/content/blog/art-not-commodity/index.md diff --git a/blog.hugo/content/threads/blocked/index.md b/blog.hugo/content/blog/blocked/index.md similarity index 100% rename from blog.hugo/content/threads/blocked/index.md rename to blog.hugo/content/blog/blocked/index.md diff --git a/blog.hugo/content/threads/boktai-3/index.md b/blog.hugo/content/blog/boktai-3/index.md similarity index 100% rename from blog.hugo/content/threads/boktai-3/index.md rename to blog.hugo/content/blog/boktai-3/index.md diff --git a/blog.hugo/content/threads/camera-gear/index.md b/blog.hugo/content/blog/camera-gear/index.md similarity index 100% rename from blog.hugo/content/threads/camera-gear/index.md rename to blog.hugo/content/blog/camera-gear/index.md diff --git a/blog.hugo/content/threads/crossposters/index.md b/blog.hugo/content/blog/crossposters/index.md similarity index 100% rename from blog.hugo/content/threads/crossposters/index.md rename to blog.hugo/content/blog/crossposters/index.md diff --git a/blog.hugo/content/threads/deactivating-twitter/index.md b/blog.hugo/content/blog/deactivating-twitter/index.md similarity index 100% rename from blog.hugo/content/threads/deactivating-twitter/index.md rename to blog.hugo/content/blog/deactivating-twitter/index.md diff --git a/blog.hugo/content/_dump/defining-quotes.md b/blog.hugo/content/blog/defining-quote-posts/index.md similarity index 86% rename from blog.hugo/content/_dump/defining-quotes.md rename to blog.hugo/content/blog/defining-quote-posts/index.md index c715e5e..3271385 100644 --- a/blog.hugo/content/_dump/defining-quotes.md +++ b/blog.hugo/content/blog/defining-quote-posts/index.md @@ -1,5 +1,8 @@ +++ -date = 2023-05-02 +title = "defining quote posts" +summary = "to me, the way i see quote posts is essentially as a \"loud reply\" or as a \"breakout thread\"" +date = "2023-05-01T12:07:00-06:00" +source = "https://mastodon.social/@trwnh/110294523321644375" +++ fwiw my take about quotes is that either @@ -14,13 +17,13 @@ in an alternate timeline we could have had generic rendering of activities based such a generic renderer would be something like... -> -> -> +> ` ` \ +> `` \ +> `` filling in the last two lines for summary and content -> Darius boosted a post: "The problem with this is..." +> alice boosted a post: "The problem with this is..." \ > "I disagree with this analysis." also this just highlights what i think a "quote post" should really be: more like a "loud reply". in a more ideal world it would use `inReplyTo` + a new `context`. @@ -59,13 +62,13 @@ the other functional difference between those two is whether the "quote" gets ad --- -also tangentially i've thought about what people think a quote is vs what it actually is, the dimensions, its primary function, etc +also tangentially i've thought about what people think a quote post is vs what it actually is, the dimensions, its primary function, etc -to me, the way i see quotes is essentially as a "loud reply" or as a "breakout thread". +to me, the way i see quote posts is essentially as a "loud reply" or as a "breakout thread". the former use-case could be handled by reply+boost. this is actually very easy in the API: just make a button that fires off 2 API calls. -the latter could be handled by copypasting a link into a new post. this is much harder to detect and display. optinally mention +the latter could be handled by copypasting a link into a new post. this is much harder to detect and display. optionally mention really the problem with twitter "quote tweets" is that they conflated the two use-cases diff --git a/blog.hugo/content/_dump/drowning-in-awareness.md b/blog.hugo/content/blog/drowning-in-awareness/index.md similarity index 71% rename from blog.hugo/content/_dump/drowning-in-awareness.md rename to blog.hugo/content/blog/drowning-in-awareness/index.md index 88fb8c0..ea949ed 100644 --- a/blog.hugo/content/_dump/drowning-in-awareness.md +++ b/blog.hugo/content/blog/drowning-in-awareness/index.md @@ -1,5 +1,8 @@ +++ -date = "2023-01-20" +title = "drowning in awareness" +summary = "if you don't have a material call to action, you have nothing. [...] \"awareness\" on its own is not enough; it can even be an actively bad thing if you end up paralyzed by inaction and despair [...] like, ok, i'm aware. now what?" +date = "2023-01-20T00:16:00-0600" +source = "https://mastodon.social/@trwnh/109720070743856424" +++ i am reminded of an essay i read once called "avoid news" which might sound extreme to some people but it actually has a simple premise: most of what you encounter in media suffers from context collapse and/or is not actionable. therefore it can never truly be relevant. what is far more valuable is filtering through the news for anything actionable worth educating people about, and presenting it in a more relevant and digestible way. not everyone should have to do this. diff --git a/blog.hugo/content/_dump/fedi-as-reformist-option.md b/blog.hugo/content/blog/fedi-as-reformist-option/index.md similarity index 93% rename from blog.hugo/content/_dump/fedi-as-reformist-option.md rename to blog.hugo/content/blog/fedi-as-reformist-option/index.md index 7c30ff8..6d5fbb4 100644 --- a/blog.hugo/content/_dump/fedi-as-reformist-option.md +++ b/blog.hugo/content/blog/fedi-as-reformist-option/index.md @@ -1,9 +1,10 @@ +++ -date = 2023-04-30 +title = "fedi as a reformist option" +summary = "[...] it's holding us back from better things. it's like the \"reform\" option when we need radical change. and it keeps getting \"worse\" [...] ad-free and chronological ain't enough." +date = "2023-04-30T20:27:00-0600" +source = "https://mastodon.social/@trwnh/110290827199480228" +++ -https://mastodon.social/@trwnh/110290827199480228 - nobody asked but i think fedi as a whole is actually kinda "bad" in the sense that it's holding us back from better things. it's like the "reform" option when we need radical change. and it keeps getting "worse". somewhere along the way we seem to have dropped the "blogging" from "microblogging", and what remains is incredibly muddled. contextual and ergonomic failure. we're copying "social media" and inheriting its flaws. ad-free and chronological ain't enough. see, we're all mostly here to just hang out and spill a stream of consciousness, right? but there are problems inherent to the structure. context collapse (or no context at all), misuse of the medium (doing a "thread" instead of writing an article), and so on. everything just goes into the square hole. diff --git a/blog.hugo/content/threads/fedi-vs-web/index.md b/blog.hugo/content/blog/fedi-vs-web/index.md similarity index 100% rename from blog.hugo/content/threads/fedi-vs-web/index.md rename to blog.hugo/content/blog/fedi-vs-web/index.md diff --git a/blog.hugo/content/threads/gun-culture-in-america/index.md b/blog.hugo/content/blog/gun-culture-in-america/index.md similarity index 100% rename from blog.hugo/content/threads/gun-culture-in-america/index.md rename to blog.hugo/content/blog/gun-culture-in-america/index.md diff --git a/blog.hugo/content/blog/implicit-vs-explicit-collections/create-note.png b/blog.hugo/content/blog/implicit-vs-explicit-collections/create-note.png new file mode 100644 index 0000000..79d9fa9 Binary files /dev/null and b/blog.hugo/content/blog/implicit-vs-explicit-collections/create-note.png differ diff --git a/blog.hugo/content/_dump/implicit-vs-explicit.md b/blog.hugo/content/blog/implicit-vs-explicit-collections/index.md similarity index 84% rename from blog.hugo/content/_dump/implicit-vs-explicit.md rename to blog.hugo/content/blog/implicit-vs-explicit-collections/index.md index 8991c4f..00d2eb7 100644 --- a/blog.hugo/content/_dump/implicit-vs-explicit.md +++ b/blog.hugo/content/blog/implicit-vs-explicit-collections/index.md @@ -1,3 +1,14 @@ ++++ +title = "collections should be explicitly managed" +summary = "the way to maintain an authoritative collection is [...] not to have everyone send out Create and then expect everyone else to reconstruct the collection for themselves [...] we're just replicating stuff around and then every server assembles it however it *thinks* it should be put together." +date = "2023-03-18T03:51:00-06:00" +source = "https://mastodon.social/@trwnh/110043428576595588" ++++ + +how it feels to talk about #activitypub and how #fedi implements it + +![](create-note.png) + the way to maintain an authoritative collection is to send out Add/Remove, not to have everyone send out Create and then expect everyone else to reconstruct the collection for themselves i can't say i blame developers for taking the lazy route and doing the bare minimum to be compatible with what already exists, but that is so limiting and i'm not here for it diff --git a/blog.hugo/content/threads/liberalism-and-trump/index.md b/blog.hugo/content/blog/liberalism-and-trump/index.md similarity index 100% rename from blog.hugo/content/threads/liberalism-and-trump/index.md rename to blog.hugo/content/blog/liberalism-and-trump/index.md diff --git a/blog.hugo/content/_dump/mainstreaming-mastodon.md b/blog.hugo/content/blog/mainstreaming-mastodon/index.md similarity index 92% rename from blog.hugo/content/_dump/mainstreaming-mastodon.md rename to blog.hugo/content/blog/mainstreaming-mastodon/index.md index d5380ee..af0f587 100644 --- a/blog.hugo/content/_dump/mainstreaming-mastodon.md +++ b/blog.hugo/content/blog/mainstreaming-mastodon/index.md @@ -1,5 +1,8 @@ +++ -date = "2023-02-02" +title = "mainstreaming mastodon" +summary = "[...] one of the replies was something along the lines of how we should be \"turning Mastodon from a small platform for the fringes and oppressed minorities to a platform that welcomes more mainstream members\" and i legit shuddered while reading that. what a terrifying thought." +date = "2023-02-02T08:40:00-06:00" +source = "private" +++ the shit i see on the mastodon issue tracker is driving me to just build my own thing because i honestly think whatever good culture mastodon has is quite possibly not long for this world diff --git a/blog.hugo/content/blog/making-better-stuff-is-unprofitable/index.md b/blog.hugo/content/blog/making-better-stuff-is-unprofitable/index.md new file mode 100644 index 0000000..1cd654b --- /dev/null +++ b/blog.hugo/content/blog/making-better-stuff-is-unprofitable/index.md @@ -0,0 +1,10 @@ ++++ +title = "making better stuff is unprofitable" +summary = "there will inevitably be a point where it is unprofitable to improve a product any further." +date = "2017-12-22T06:06:00-0600" +source = "https://mastodon.social/@trwnh/99217860566004390" ++++ + +There will inevitably be a point where it is unprofitable to improve a product any further. + +i.e., if Apple's primary goal was to make useful products, it would make choices that result in a better product even if it was slightly more expensive. But their primary goal is profit, as it is for every corporation under capitalism. Making better stuff is unprofitable. \ No newline at end of file diff --git a/blog.hugo/content/_dump/mastodon-api-value.md b/blog.hugo/content/blog/mastodon-api-value/index.md similarity index 66% rename from blog.hugo/content/_dump/mastodon-api-value.md rename to blog.hugo/content/blog/mastodon-api-value/index.md index 91b9673..64319a3 100644 --- a/blog.hugo/content/_dump/mastodon-api-value.md +++ b/blog.hugo/content/blog/mastodon-api-value/index.md @@ -1,10 +1,10 @@ +++ -date = 2023-02-06 -published = 2023-02-06T00:56:00Z +title = "the primary value of mastodon is in its api" +summary = "mastodon isn't really all that special [...] but the second you try to have a mobile app, you immediately recognize the value of the mastodon api [...] it's a shame it isn't a real standard..." +date = "2023-02-06T00:56:00Z" +source = "https://mastodon.social/@trwnh/109815069913581608" +++ -https://mastodon.social/@trwnh/109815069913581608 - to what extent can it be said that the primary value of mastodon is in its api mastodon isn't really all that special in the fediverse or as a software, because you have so many options and differing implementations of the activitypub protocol. but the second you try to have a mobile app, you immediately recognize the value of the mastodon api. it's a pseudo-standard at this point because it mostly just works, and pleroma/pixelfed/gotosocial copied it for compatibility with existing clients. it's a shame it isn't a real standard... diff --git a/blog.hugo/content/threads/mastodon-as-twitter-do-over/index.md b/blog.hugo/content/blog/mastodon-as-twitter-do-over/index.md similarity index 100% rename from blog.hugo/content/threads/mastodon-as-twitter-do-over/index.md rename to blog.hugo/content/blog/mastodon-as-twitter-do-over/index.md diff --git a/blog.hugo/content/threads/misc.md b/blog.hugo/content/blog/misc.md similarity index 100% rename from blog.hugo/content/threads/misc.md rename to blog.hugo/content/blog/misc.md diff --git a/blog.hugo/content/_dump/socialhub-threads/multi-protocol-approach.md b/blog.hugo/content/blog/multi-protocol-approach/index.md similarity index 97% rename from blog.hugo/content/_dump/socialhub-threads/multi-protocol-approach.md rename to blog.hugo/content/blog/multi-protocol-approach/index.md index d6893fb..08a7a68 100644 --- a/blog.hugo/content/_dump/socialhub-threads/multi-protocol-approach.md +++ b/blog.hugo/content/blog/multi-protocol-approach/index.md @@ -1,7 +1,7 @@ +++ title = "re: starting to investigate other protocols" -summary = "The main thing I'm trying to formulate right now is a generic understanding of what is a protocol and what makes up a protocol." -date = "2023-01-02T21:00:00-06:00" +summary = "The main thing I'm trying to formulate right now is a generic understanding of what is a protocol and what makes up a protocol [...] The \"implicit protocol of the fediverse\" is not sufficiently described by \"the ActivityPub specification\"" +date = "2024-09-29T19:53:00-06:00" source = "https://socialhub.activitypub.rocks/t/socialwebfoundation-what-do-people-think/4564/13" inReplyTo = "https://socialhub.activitypub.rocks/t/socialwebfoundation-what-do-people-think/4564/12" +++ diff --git a/blog.hugo/content/threads/multiple-accounts/index.md b/blog.hugo/content/blog/multiple-accounts/index.md similarity index 100% rename from blog.hugo/content/threads/multiple-accounts/index.md rename to blog.hugo/content/blog/multiple-accounts/index.md diff --git a/blog.hugo/content/_dump/nation-stateificiation.md b/blog.hugo/content/blog/nation-stateification/index.md similarity index 100% rename from blog.hugo/content/_dump/nation-stateificiation.md rename to blog.hugo/content/blog/nation-stateification/index.md diff --git a/blog.hugo/content/threads/necromancy/index.md b/blog.hugo/content/blog/necromancy/index.md similarity index 100% rename from blog.hugo/content/threads/necromancy/index.md rename to blog.hugo/content/blog/necromancy/index.md diff --git a/blog.hugo/content/threads/neoliberalism/index.md b/blog.hugo/content/blog/neoliberalism/index.md similarity index 100% rename from blog.hugo/content/threads/neoliberalism/index.md rename to blog.hugo/content/blog/neoliberalism/index.md diff --git a/blog.hugo/content/threads/net-neutrality-repealed/index.md b/blog.hugo/content/blog/net-neutrality-repealed/index.md similarity index 100% rename from blog.hugo/content/threads/net-neutrality-repealed/index.md rename to blog.hugo/content/blog/net-neutrality-repealed/index.md diff --git a/blog.hugo/content/blog/one-piece-thematic-breakdown/index.md b/blog.hugo/content/blog/one-piece-thematic-breakdown/index.md new file mode 100644 index 0000000..db59314 --- /dev/null +++ b/blog.hugo/content/blog/one-piece-thematic-breakdown/index.md @@ -0,0 +1,42 @@ ++++ +title = "a thematic breakdown of one piece" +summary = "east blue = dreams. paradise = family. new world = liberation." +date = "2024-09-30T11:22:54-0600" +source = "original" ++++ + +i was idly thinking about one piece this morning, as one does. mainly thinking about how east blue was peak one piece for me, and those first 100 chapters could honestly stand as their own self-contained story. one piece could have ended right there and i would have come away satisfied with what i read. but of course, it didn't end there, and i'm also glad it didn't end there. but it got me thinking about the overall theme of one piece, and specifically the overall theme of east blue as a self-contained saga. + + + +## from "romance dawn" onward to the "grand line" + +honestly, we could go further and say that the first chapter of one piece is also a self-contained story, and in fact, it actually *was* a self-contained story. romance dawn was of course released in various forms as one-shots, before it eventually became the first chapter of one piece. + +the story of that first chapter is very simple: it's about a boy with a dream. but it's everything else about the story that grips you, like the reason for that dream, and the magnitude of that dream, and what that dream involves. + +for the time spent in east blue, the story mainly covers a great adventure filled with romanticism. the character arcs in this part of the story are mainly centered around following your dreams. as you meet new characters, you learn about their dreams, and in learning about their dreams, you get to know them as people. everyone has a reason to keep going. everyone has drive and motivation. it's honestly a dynamic world that feels alive, even though it's pretty small at this point in the series. + +throughout it all, there is the end goal of entering the grand line, which is portrayed as a paradise for pirates, where wacky things happen all the time, and the adventure never ends. everyone has their reasons for seeking it out. luffy wants to become the pirate king, and to do that he needs to find the great treasure "one piece" at the end of the grand line. zoro wants to become the world's greatest swordsman, and to do that he needs to challenge the current world's greatest swordsman who lives in the grand line. nami wants to draw a map of the world, and that means she'll need to enter the grand line at some point. usopp wants to be a brave warrior of the sea, and the grand line is just the thing to toughen him up. sanji wants to find the all blue, which might exist somewhere in the grand line. + +## i still have my nakama + +once things go into the grand line, the theme of adventure is still there, but the focus of each arc is better summarized by the theme of "family". chopper is abandoned by his reindeer family, but finds new family in dr. hiruluk and later dr. kureha before eventually joining the crew. vivi knows that the straw hats will always be her family because of the whole x thing. robin finds family in the ohara researchers and in saul, only for the buster call to take it all. franky has tom and iceberg and later the franky family. brook's entire crew dies and his dream is to reunite with laboon. luffy's entire crew gets sent flying by kuma and he despairs over this because he lost his family. then he finds out his sworn brother is set to be executed, and he goes to save him. when he loses his brother he feels like he has no family left. until he is reminded that he still has his crew. + +## power, authority, and liberation + +by the time we enter the new world, it's endgame territory. this is the realm of the emperors. luffy has always been a liberator, but this part of the story is where it takes center stage. every arc has luffy liberating people and islands. and then you find out he's literally the warrior of liberation. + +it's all about the power struggle, the emperors who rule their territories, the world government who controls everything, and the warrior of liberation who is being set up to set the whole world free. + +## wealth. fame. power. he had it all + +in that order. + +## so what's the conclusion here + +idk i don't have a conclusion i'm just rambling \ No newline at end of file diff --git a/blog.hugo/content/threads/physical-bodies/index.md b/blog.hugo/content/blog/physical-bodies/index.md similarity index 100% rename from blog.hugo/content/threads/physical-bodies/index.md rename to blog.hugo/content/blog/physical-bodies/index.md diff --git a/blog.hugo/content/threads/product-vs-profit/index.md b/blog.hugo/content/blog/product-vs-profit/index.md similarity index 100% rename from blog.hugo/content/threads/product-vs-profit/index.md rename to blog.hugo/content/blog/product-vs-profit/index.md diff --git a/blog.hugo/content/_dump/context-unaware.md b/blog.hugo/content/blog/publishing-vs-discussing/index.md similarity index 85% rename from blog.hugo/content/_dump/context-unaware.md rename to blog.hugo/content/blog/publishing-vs-discussing/index.md index c19ad1e..98f7830 100644 --- a/blog.hugo/content/_dump/context-unaware.md +++ b/blog.hugo/content/blog/publishing-vs-discussing/index.md @@ -1,3 +1,10 @@ ++++ +title = "publishing vs discussing" +summary = "eventually this kind of \"posting\" we have today would be split up and merged into the two new things. the UI would give you an option: do you want to publish a Post, or do you want to start a Discussion?" +date = "2023-03-24T10:33:00-0600" +source = "https://mastodon.social/@trwnh/110078983668243890" ++++ + i am more and more taking the position that we should have forums, and we should have blogs, and nothing in between. "social media" carries inherently poor ergonomics and a lack of clarity of purpose. you're never clearly "publishing" anything when you post on social media, unlike when you post on your own blog or website. you're never clearly "discussing" anything either, because threads aren't actual topics or conversations. so my ideal flow is kinda like diff --git a/blog.hugo/content/threads/reading-theory/index.md b/blog.hugo/content/blog/reading-theory/index.md similarity index 100% rename from blog.hugo/content/threads/reading-theory/index.md rename to blog.hugo/content/blog/reading-theory/index.md diff --git a/blog.hugo/content/threads/responsive-web-design/index.md b/blog.hugo/content/blog/responsive-web-design/index.md similarity index 100% rename from blog.hugo/content/threads/responsive-web-design/index.md rename to blog.hugo/content/blog/responsive-web-design/index.md diff --git a/blog.hugo/content/blog/services-vs-communities/index.md b/blog.hugo/content/blog/services-vs-communities/index.md new file mode 100644 index 0000000..98c19ae --- /dev/null +++ b/blog.hugo/content/blog/services-vs-communities/index.md @@ -0,0 +1,24 @@ ++++ +title = "services aren't communities" +summary = "imo the biggest mistake of fedi is tying together the social and technical layers [...] some people want services and some people want communities and they are not the same thing" +date = "2023-05-07T17:39:00-06:00" +source = "https://mastodon.social/@trwnh/110329802576726213" ++++ + +services aren't communities + +the gmail community + +imo the biggest mistake of fedi is tying together the social and technical layers. local timelines should have been group chats all along + +it's a huge misunderstanding because some people want services and some people want communities and they are not the same thing. some people can run a community but offer bad service. some people offer great service but can't run a community + +instances shouldn't exist as the only model. the service layer and the community layer should be separate. combining the two makes both of them worse -- as can be seen if you violate the rules of your community, you lose access not just to the community, but to the service entirely. and if the community cannot continue to provide service, you again lose both. + +i do think there is some value in being both, because then people feel more likely to donate as they are personally invested. but you could have incentives to donate even while keeping them separate. + +--- + +> Yes! I think I've been spiralling towards a less well articulated version of this for a while. Too many people have been trying to make the Fediverse just one big social network with many servers and erase the aspect that's many small social networks that can communicate, and it's exactly that they're viewing it purely as service and not as community, and it absolutely needs to be both or else it can't meaningfully be either. + +i have a slightly different view, which is that multiple communities exist here and their organization and distribution is very dysfunctional because of the "instance" model being both and neither at the same time \ No newline at end of file diff --git a/blog.hugo/content/_dump/shorts-are-too-long.md b/blog.hugo/content/blog/shorts-are-too-long/index.md similarity index 62% rename from blog.hugo/content/_dump/shorts-are-too-long.md rename to blog.hugo/content/blog/shorts-are-too-long/index.md index e7b53a9..2d1014c 100644 --- a/blog.hugo/content/_dump/shorts-are-too-long.md +++ b/blog.hugo/content/blog/shorts-are-too-long/index.md @@ -1 +1,8 @@ ++++ +title = "shorts are too long" +summary = "if you're going to take away the video controls, prevent me from seeking, maybe autoloop? then i am NOT sitting there for a whole minute while you fail to get to the point." +date = "2023-01-25T08:40:00-06:00" +source = "https://mastodon.social/@trwnh/109750363384335885" ++++ + i fucking hate the "shorts" format. vine was okay purely because it was limited to 6 or 7 seconds -- if you're going to take away the video controls, prevent me from seeking, maybe autoloop? then i am NOT sitting there for a whole minute while you fail to get to the point. i'm not doing more than 10 seconds, maybe 15 seconds at the most. anything over that should let me seek through the video!!!! videos should always be seekable but if you're not going to make them seekable then at least limit them to one coherent logical "moment" \ No newline at end of file diff --git a/blog.hugo/content/threads/smartphones-and-capitalism/index.md b/blog.hugo/content/blog/smartphones-and-capitalism/index.md similarity index 100% rename from blog.hugo/content/threads/smartphones-and-capitalism/index.md rename to blog.hugo/content/blog/smartphones-and-capitalism/index.md diff --git a/blog.hugo/content/blog/social-media-flawed/index.md b/blog.hugo/content/blog/social-media-flawed/index.md new file mode 100644 index 0000000..5d9d17d --- /dev/null +++ b/blog.hugo/content/blog/social-media-flawed/index.md @@ -0,0 +1,14 @@ ++++ +title = "social media is fundamentally flawed" +summary = "in pure terms you might send a message or publish a resource. but with these social networks [...] you're never unambiguously sending a message or publishing a resource, but instead, some weird hybrid that we call a \"post\". not quite message, not quite resource" +date = "2023-02-16T19:43:00-06:00" +source = "https://mastodon.social/@trwnh/109877540362444317" ++++ + +the more i think about and research communication paradigms, i'm starting to think more and more that this whole "social media" thing is just fundamentally flawed. in pure terms you might send a message or publish a resource. but with these social media platforms it's not that clear cut. you're never unambiguously sending a message or publishing a resource, but instead, some weird hybrid that we call a "post". not quite message, not quite resource. it exists in part or in whole exclusively on the platform. + +and i guess that makes it easier to put in a silo which is how companies maintain their profit motive. + +but in replicating the design of these social media sites we replicate their properties too. fedi hasn't entirely moved past silos because it's embedded in the design level. thankfully not the protocol level, but still. it's going to persist in implementations as long as we limit ourselves to "twitter but better", "instagram but better", etc. we're not building the commons that we could build. + +and the lack of clarity in our metaphors and associated abstractions leads to subtle violations of what people expect. there should be a clearer split. consider the duality of tumblr as both a social network and a publishing platform. they're making this split more apparent than it used to be. in addition to username.tumblr.com for blogs they now have tumblr.com/username for network profiles. \ No newline at end of file diff --git a/blog.hugo/content/_dump/activitypub-2.md b/blog.hugo/content/blog/specs-arent-enough/index.md similarity index 88% rename from blog.hugo/content/_dump/activitypub-2.md rename to blog.hugo/content/blog/specs-arent-enough/index.md index e3e9c07..d4dc3b5 100644 --- a/blog.hugo/content/_dump/activitypub-2.md +++ b/blog.hugo/content/blog/specs-arent-enough/index.md @@ -1,8 +1,13 @@ -https://mastodon.social/@trwnh/109979200684979970 ++++ +title = "specs aren't enough" +summary = "the question of \"interoperability\" makes no sense on its own. you must always ask, interoperability with what? and on which conditions? [...] is your view of the \"fediverse\" limited only to the conceptual space of existing projects? and, if so, then which ones?" +date = "2023-03-06T18:37:00-06:00" +source = "https://mastodon.social/@trwnh/109979200684979970" ++++ @ people who keep saying we should rewrite the activitypub spec to ensure better interoperability with existing fedi projects -[](specs-are-enough.jpg) +![](specs-are-enough.png) idk how else to say that if you want to be compatible with a project then you need to have a shared worldview and conceptual space, and this necessarily involves communicating with that project on some level (by reading their documentation, asking their devs questions, etc) in order to know what their expectations and requirements are @@ -32,4 +37,4 @@ is your view of the "fediverse" limited only to the conceptual space of existing or will you allow yourself to dream a little bigger? -https://www.youtube.com/watch?v=WcGbnX8Ay38 \ No newline at end of file +{{}} \ No newline at end of file diff --git a/blog.hugo/content/blog/specs-arent-enough/specs-are-enough.png b/blog.hugo/content/blog/specs-arent-enough/specs-are-enough.png new file mode 100644 index 0000000..dab867a Binary files /dev/null and b/blog.hugo/content/blog/specs-arent-enough/specs-are-enough.png differ diff --git a/blog.hugo/content/threads/syndicalism-is-dead/index.md b/blog.hugo/content/blog/syndicalism-is-dead/index.md similarity index 100% rename from blog.hugo/content/threads/syndicalism-is-dead/index.md rename to blog.hugo/content/blog/syndicalism-is-dead/index.md diff --git a/blog.hugo/content/threads/the-web-not-only-for-profit/index.md b/blog.hugo/content/blog/the-web-not-only-for-profit/index.md similarity index 100% rename from blog.hugo/content/threads/the-web-not-only-for-profit/index.md rename to blog.hugo/content/blog/the-web-not-only-for-profit/index.md diff --git a/blog.hugo/content/threads/ubi/index.md b/blog.hugo/content/blog/ubi/index.md similarity index 100% rename from blog.hugo/content/threads/ubi/index.md rename to blog.hugo/content/blog/ubi/index.md diff --git a/blog.hugo/content/threads/voluntarism/index.md b/blog.hugo/content/blog/voluntarism/index.md similarity index 100% rename from blog.hugo/content/threads/voluntarism/index.md rename to blog.hugo/content/blog/voluntarism/index.md diff --git a/blog.hugo/content/_dump/w3c-http-supremacy.md b/blog.hugo/content/blog/w3c-http-supremacy/index.md similarity index 78% rename from blog.hugo/content/_dump/w3c-http-supremacy.md rename to blog.hugo/content/blog/w3c-http-supremacy/index.md index 05ba8ac..e3190e9 100644 --- a/blog.hugo/content/_dump/w3c-http-supremacy.md +++ b/blog.hugo/content/blog/w3c-http-supremacy/index.md @@ -1,4 +1,9 @@ -https://mastodon.social/@trwnh/109886416964217719 ++++ +title = "http uri maximalism" +summary = "if you just wanna obtain a resource from a given organization or whatever, it is generally a given that the org has its own domain name and can assign ids on that domain. but the whole thing falls apart when you need a global namespace that can be requested from multiple domains" +date = "2023-02-18T09:20:00-06:00" +source = "https://mastodon.social/@trwnh/109886416964217719" ++++ reading a lot of old w3 literature and while there's a lot of good stuff in there, it is *infuriating* how they are so blindly in support of using http for everything, including identifiers. they probably just failed to predict the future, but they keep stopping just short of admitting http's biggest problem: when the server goes down, your uri can't be dereferenced anymore! diff --git a/blog.hugo/hugo.toml b/blog.hugo/hugo.toml index 5b7429d..946f1c3 100644 --- a/blog.hugo/hugo.toml +++ b/blog.hugo/hugo.toml @@ -1,8 +1,8 @@ baseURL = 'https://trwnh.com/blog/' languageCode = 'en-us' title = '~a blog' -markup.goldmark.renderer.unsafe = true +markup.goldmark.renderer.unsafe = true pagination.pagerSize = 100 [outputs] diff --git a/public/unstable/fedi-vs-web.html b/public/unstable/fedi-vs-web.html index db7420a..f488b2c 100644 --- a/public/unstable/fedi-vs-web.html +++ b/public/unstable/fedi-vs-web.html @@ -40,6 +40,7 @@

fedi vs web

on the distinction between social network and social web, where activitypub straddles both

published around

+

the disconnect between activitypub and the fediverse

diff --git a/unified.test.hugo/archetypes/default.md b/unified.test.hugo/archetypes/default.md new file mode 100644 index 0000000..c6f3fce --- /dev/null +++ b/unified.test.hugo/archetypes/default.md @@ -0,0 +1,5 @@ ++++ +title = '{{ replace .File.ContentBaseName "-" " " | title }}' +date = {{ .Date }} +draft = true ++++ diff --git a/unified.test.hugo/assets/scripts/main.js b/unified.test.hugo/assets/scripts/main.js new file mode 100644 index 0000000..b336f2a --- /dev/null +++ b/unified.test.hugo/assets/scripts/main.js @@ -0,0 +1,15 @@ +/* +Use a window's inner dimensions for viewport units. +This fixes some mobile bugs +*/ + +var root = document.documentElement; +let vh = window.innerHeight * 0.01; +root.style.setProperty('--vh', `${vh}px`); + +// We listen to the resize event +window.addEventListener('resize', () => { + // We execute the same script as before + let vh = window.innerHeight * 0.01; + root.style.setProperty('--vh', `${vh}px`); +}); \ No newline at end of file diff --git a/unified.test.hugo/assets/scripts/search.js b/unified.test.hugo/assets/scripts/search.js new file mode 100644 index 0000000..5b51c52 --- /dev/null +++ b/unified.test.hugo/assets/scripts/search.js @@ -0,0 +1,227 @@ +/* +tutorials used: +- https://aaronluna.dev/blog/add-search-to-static-site-lunrjs-hugo-vanillajs/#codepen-with-final-code +- https://victoria.dev/blog/add-search-to-hugo-static-sites-with-lunr/ +*/ + +let pagesIndex, searchIndex +const MAX_SUMMARY_LENGTH = 30 +const SENTENCE_BOUNDARY_REGEX = /\b\.\s/gm +const WORD_REGEX = /\b(\w*)[\W|\s|\b]?/gm + +async function initSearch() { + try { + const indexJsonUrl = document.getElementById("baseUrl").dataset["baseUrl"] + "/index.json"; + // const indexJsonUrl = "/wiki/index.json"; + const response = await fetch(indexJsonUrl); + pagesIndex = await response.json(); + searchIndex = lunr(function () { + this.field("title"); + this.field("content"); + this.ref("href"); + pagesIndex.forEach((page) => this.add(page)); + }); + } catch (e) { + console.log(e); + } + console.log("Search index initialized") + // Get the query parameter(s) + const params = new URLSearchParams(window.location.search) + const query = params.get('query') + + // Perform a search if there is a query + if (query) { + // Retain the search input in the form when displaying results + document.getElementById('search-input').setAttribute('value', query) + + // Update the list with results + console.log("search performed") + let results = searchSite(query) + renderSearchResults(query, results) + } +} + +initSearch(); + +function searchSite(query) { + const originalQuery = query; + query = getLunrSearchQuery(query); + let results = getSearchResults(query); + return results.length + ? results + : query !== originalQuery + ? getSearchResults(originalQuery) + : []; +} + +function getLunrSearchQuery(query) { + const searchTerms = query.split(" "); + if (searchTerms.length === 1) { + return query; + } + query = ""; + for (const term of searchTerms) { + query += `+${term} `; + } + return query.trim(); +} + +function getSearchResults(query) { + return searchIndex.search(query).flatMap((hit) => { + if (hit.ref == "undefined") return []; + let pageMatch = pagesIndex.filter((page) => page.href === hit.ref)[0]; + pageMatch.score = hit.score; + return [pageMatch]; + }); +} + +function renderSearchResults(query, results) { + clearSearchResults(); + updateSearchResults(query, results); +} + +function clearSearchResults() { + const results = document.querySelector("#search-results"); + while (results.firstChild) results.removeChild(results.firstChild); +} + +function updateSearchResults(query, results) { + document.getElementById("results-query").innerHTML = query; + document.querySelector("#search-results").innerHTML = results + .map( + (hit) => ` +
  • + ${createTitleBlurb(query, hit.title)} +

    ${createSearchResultBlurb(query, hit.content)}

    +
  • + ` + ) + .join(""); + const searchResultListItems = document.querySelectorAll("#search-results li"); + document.getElementById("results-count").innerHTML = searchResultListItems.length; + document.getElementById("results-count-text").innerHTML = searchResultListItems.length === 1 ? "result" : "results"; + // searchResultListItems.forEach( + // (li) => (li.firstElementChild.style.color = getColorForSearchResult(li.dataset.score)) + // ); +} + +function createTitleBlurb(query, title) { + const searchQueryRegex = new RegExp(createQueryStringRegex(query), "gmi"); + return title.replace( + searchQueryRegex, + "$&" + ) +} + +function createSearchResultBlurb(query, pageContent) { + const searchQueryRegex = new RegExp(createQueryStringRegex(query), "gmi"); + const searchQueryHits = Array.from( + pageContent.matchAll(searchQueryRegex), + (m) => m.index + ); + const sentenceBoundaries = Array.from( + pageContent.matchAll(SENTENCE_BOUNDARY_REGEX), + (m) => m.index + ); + let searchResultText = ""; + let lastEndOfSentence = 0; + for (const hitLocation of searchQueryHits) { + if (hitLocation > lastEndOfSentence) { + for (let i = 0; i < sentenceBoundaries.length; i++) { + if (sentenceBoundaries[i] > hitLocation) { + const startOfSentence = i > 0 ? sentenceBoundaries[i - 1] + 1 : 0; + const endOfSentence = sentenceBoundaries[i]; + lastEndOfSentence = endOfSentence; + parsedSentence = pageContent.slice(startOfSentence, endOfSentence).trim(); + searchResultText += `${parsedSentence} ... `; + break; + } + } + } + const searchResultWords = tokenize(searchResultText); + const pageBreakers = searchResultWords.filter((word) => word.length > 50); + if (pageBreakers.length > 0) { + searchResultText = fixPageBreakers(searchResultText, pageBreakers); + } + if (searchResultWords.length >= MAX_SUMMARY_LENGTH) break; + } + return ellipsize(searchResultText, MAX_SUMMARY_LENGTH).replace( + searchQueryRegex, + "$&" + ); +} + +function createQueryStringRegex(query) { + const searchTerms = query.split(" "); + if (searchTerms.length == 1) { + return query; + } + query = ""; + for (const term of searchTerms) { + query += `${term}|`; + } + query = query.slice(0, -1); + return `(${query})`; +} + +function tokenize(input) { + const wordMatches = Array.from(input.matchAll(WORD_REGEX), (m) => m); + return wordMatches.map((m) => ({ + word: m[0], + start: m.index, + end: m.index + m[0].length, + length: m[0].length, + })); +} + +function fixPageBreakers(input, largeWords) { + largeWords.forEach((word) => { + const chunked = chunkify(word.word, 20); + input = input.replace(word.word, chunked); + }); + return input; +} + +function chunkify(input, chunkSize) { + let output = ""; + let totalChunks = (input.length / chunkSize) | 0; + let lastChunkIsUneven = input.length % chunkSize > 0; + if (lastChunkIsUneven) { + totalChunks += 1; + } + for (let i = 0; i < totalChunks; i++) { + let start = i * chunkSize; + let end = start + chunkSize; + if (lastChunkIsUneven && i === totalChunks - 1) { + end = input.length; + } + output += input.slice(start, end) + " "; + } + return output; +} + +function ellipsize(input, maxLength) { + const words = tokenize(input); + if (words.length <= maxLength) { + return input; + } + return input.slice(0, words[maxLength].end) + "..."; +} + +if (!String.prototype.matchAll) { + String.prototype.matchAll = function (regex) { + "use strict"; + function ensureFlag(flags, flag) { + return flags.includes(flag) ? flags : flags + flag; + } + function* matchAll(str, regex) { + const localCopy = new RegExp(regex, ensureFlag(regex.flags, "g")); + let match; + while ((match = localCopy.exec(str))) { + match.index = localCopy.lastIndex - match[0].length; + yield match; + } + } + return matchAll(this, regex); + }; +} \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/common.scss b/unified.test.hugo/assets/styles/common.scss new file mode 100644 index 0000000..acc1c5c --- /dev/null +++ b/unified.test.hugo/assets/styles/common.scss @@ -0,0 +1,27 @@ +@import "common/reset"; +@import "common/colors"; +@import "common/base"; +@import "common/content"; + +@import "features/links"; + +// default layout + +@import "layouts/_default/list"; +@import "layouts/_default/single"; + +@import "partials/mf2/h-card"; +@import "shortcodes/mf2/h-cite"; + +// wiki layout + +@import "layouts/wiki/list"; +@import "layouts/wiki/single"; +@import "partials/wiki/site-header"; + +@import "partials/wiki/breadcrumbs"; + +@import "features/autonumbering"; +@import "features/search"; + +@import "components/table-of-contents"; \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/common/base.scss b/unified.test.hugo/assets/styles/common/base.scss new file mode 100644 index 0000000..a389f4b --- /dev/null +++ b/unified.test.hugo/assets/styles/common/base.scss @@ -0,0 +1,48 @@ +:root { + --site-max-width: 120ch; +} + +html { + font-family: sans-serif; + background: var(--ui-background); + color: var(--ui-text); +} + +/* Single column layout, where main content stretches to fill. */ +body { + display: flex; + flex-flow: column; + min-height: calc(var(--vh, 1vh) * 100); + max-width: 100vw; + margin: auto; +} +main {flex-grow: 1;} + +/* +Sections are primary block units, usually of type
    . +Containers are an immediate child
    , purely for constraining width. +*/ +.section { + padding: 2em 0; /* we apply a vertical padding only to sections */ + box-sizing: border-box; +} +.container { + box-sizing: border-box; + width: 100%; + max-width: var(--site-max-width); + margin: 0 auto; + padding: 0 1em; /* and we apply a horizontal padding only to containers */ +} + +/* Ensure consistent colors for text selection and element focus */ +::selection { + background: var(--primary-accent); + color: var(--primary-accent-text); +} + +*:focus { + border-radius: 2px; + text-decoration: none; + outline: 1px dashed var(--ui-text); + outline-offset: 4px; +} \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/common/colors.scss b/unified.test.hugo/assets/styles/common/colors.scss new file mode 100644 index 0000000..c352836 --- /dev/null +++ b/unified.test.hugo/assets/styles/common/colors.scss @@ -0,0 +1,35 @@ +:root { + --link-color: #3371cf; + --link-visited: #594288; + + --primary-accent: hsl(210, 100%, 80%); + --primary-accent-transparent: hsla(210, 100%, 20%, 0.25); + --primary-accent-text: #fff; + + --ui-background: hsl(210, 100%, 92.5%); + --ui-text: hsl(210, 100%, 10%); + --ui-text-muted: #666; + --ui-text-bold: #000; + + --ui-overlay: hsl(210, 100%, 87.5%); + --ui-overlay-text: var(--ui-text); +} + +@media (prefers-color-scheme: dark) { + :root { + --link-color: hsl(210, 100%, 65%); + --link-visited: hsl(270, 100%, 75%); + + --primary-accent: hsl(210, 100%, 20%); + --primary-accent-transparent: hsla(210, 100%, 20%, 0.45); + --primary-accent-text: #fff; + + --ui-background: hsl(210, 100%, 10%); + --ui-text: hsl(210, 100%, 90%); + --ui-text-muted: #999; + --ui-text-bold: #fff; + + --ui-overlay: hsl(210, 100%, 20%); + --ui-overlay-text: var(--ui-text); + } +} \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/common/content.scss b/unified.test.hugo/assets/styles/common/content.scss new file mode 100644 index 0000000..4cf6910 --- /dev/null +++ b/unified.test.hugo/assets/styles/common/content.scss @@ -0,0 +1,206 @@ +.hugo-content { + /* text */ + p, li {max-inline-size: 80ch;} + h1 {font-size: 1.8em} + h2 {font-size: 1.6em} + h3 {font-size: 1.423em} + h4 {font-size: 1.265em} + h5 {font-size: 1.125em} + h6 {font-size: 1em} + h1, h2, h3, h4, h5, h6 { + line-height: 1.2; + margin-block-start: 2rem; + margin-block-end: 1rem; + font-weight: 700; + } + p { + line-height: 2; + margin-block-end: 1em; + } + a { + word-wrap: break-word; + } + /* semantics */ + em {font-style: italic} + strong {font-weight: 700} + /* text formatting */ + --script-size: 0.65em; + sup { + position: relative; + font-size: var(--script-size); + inset-block-start: -1em; + } + sub { + position: relative; + font-size: var(--script-size); + } + @supports #{'selector\(:has(kbd))'} { + /* style individual keys only (for the innermost element) */ + kbd kbd, + kbd:not(:has(kbd)) { + font-family: monospace; + padding: 0.25em; + background: var(--ui-overlay); + color: var(--ui-overlay-text); + } + } + @supports not #{'selector\(:has(kbd))'} { + /* style the entire key sequence */ + kbd { + font-family: monospace; + padding: 0.25em; + background: var(--ui-overlay); + color: var(--ui-overlay-text); + } + /* and prevent double-styling for nested keys */ + kbd kbd { + background: none; + } + } + mark { + background: var(--primary-accent-transparent); + color: var(--ui-text); + --pad-x-highlight: 0.125em; + padding-inline-start: var(--pad-x-highlight); + padding-inline-end: var(--pad-x-highlight); + } + abbr[title]:after { + content: '?'; + font-size: var(--script-size); + color: var(--ui-text-muted); + } + /* lists */ + ul, ol { + padding-inline-start: 0; + margin-block: 1em; + position: relative; + } + ul {list-style: disc;} + ol {list-style: decimal;} + li {margin-block-end: 1em; line-height: 1.4; margin-inline-start: 1em;} + dl {margin-block: 1em; line-height: 1.4;} + dt {font-weight: 700;} + dd {margin-inline-start: 1em;} + /* block elements */ + img { + width: 100%; + margin-block-end: 1em; + } + blockquote { + font-style: italic; + font-size: 1em; + margin: 1em 0; + border-inline-start: 0.25rem solid var(--ui-text-bold); + padding-inline-start: 0.75em; + line-height: 1.4; + } + pre { + font-family: monospace; + padding: 1em; + line-height: 1.4; + overflow-inline: auto; + white-space: pre; + display: grid; + tab-size: 3; + margin-block-end: 1em; + } + code { + font-family: monospace; + background: var(--ui-overlay); + color: var(--ui-overlay-text); + padding: 0.25rem; + } + :not(.highlight) > pre { + line-height: 1.5; + background: var(--ui-overlay); + color: var(--ui-overlay-text); + padding: 1em; + } + pre code { + background: inherit; + padding: 0; + } + .highlight pre { + padding-block: 1em; + } + /* figures */ + figure { + margin-block-end: 1em; + } + figure img { + width: 100%; + margin-block-end: -0.125em; + } + figcaption { + background: #212121; + color: white; + font-style: italic; + padding: 1em; + font-size: 0.8em; + line-height: 1.2; + } + /* tables */ + table {text-align: center;} + thead { + font-weight: 700; + background: var(--ui-overlay); + color: var(--ui-overlay-text); + } + th, td { + border: 1px solid var(--ui-text); + padding: 0.5em; + } + /* {{}} shortcode */ + .hint, .callout { + padding: 1em; + line-height: 2; + &.info, &.tip + { + background: rgba(142, 226, 142, 0.2); + border-inline-start: 4px solid rgb(142, 226, 142); + } + &.warning { + background: rgba(218, 226, 142, 0.2); + border-inline-start: 4px solid rgb(218, 226, 142); + } + &.danger { + background: rgba(226, 142, 142, 0.2); + border-inline-start: 4px solid rgb(226, 142, 142); + } + } + /* hugo-specific citation footnote */ + cite sup { + position: inherit; + font-size: inherit; + a { + padding: 0.25em; + } + &:before { + content: ' ['; + } + &:after { + content: ']'; + } + } + /* the actual footnotes section */ + .footnotes { + hr { + display: flex; + align-items: center; + border: 0; + &:before { + content: 'Footnotes'; + color: var(--ui-text); + text-transform: uppercase; + font-weight: 900; + font-size: 0.8em; + } + &:after { + content: ''; + width: 100%; + margin-inline-start: 1rem; + border-block-end: 1px solid var(--ui-text-muted); + } + } + } +} \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/common/reset.scss b/unified.test.hugo/assets/styles/common/reset.scss new file mode 100644 index 0000000..d3c150d --- /dev/null +++ b/unified.test.hugo/assets/styles/common/reset.scss @@ -0,0 +1,3 @@ +body { + margin: 0; +} \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/components/table-of-contents.scss b/unified.test.hugo/assets/styles/components/table-of-contents.scss new file mode 100644 index 0000000..22042f1 --- /dev/null +++ b/unified.test.hugo/assets/styles/components/table-of-contents.scss @@ -0,0 +1,29 @@ +.toc-title { + margin-block-end: 0.5em; + font-weight: 900; + text-transform: uppercase; +} +#TableOfContents { + ul, ol { + list-style: none; + margin: 0; + padding: 0; + } + li { + margin-block: 0.5em; + margin-inline: 0; + } + a { + display: inline-block; + line-height: 1.5; + } + li > ul, li > ol { /* indent subheadings */ + margin-inline-start: 1em; + } +} +.toc details { + max-width: 45ch; + background: rgba(0,0,0,0.1); + padding: 1em; + border-radius: 0.5em; +} \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/features/autonumbering.scss b/unified.test.hugo/assets/styles/features/autonumbering.scss new file mode 100644 index 0000000..c705206 --- /dev/null +++ b/unified.test.hugo/assets/styles/features/autonumbering.scss @@ -0,0 +1,94 @@ +h2.heading { + border-block-end: 1px solid var(--ui-text-muted); + padding-block-end: 1rem; +} + +/* headings with no numbers */ + +article:not([autonumbering]) .heading { + position: relative; + margin-inline-end: 2.5rem; + &__anchor-link { + display: inline-flex; + align-content: center; + margin-inline-start: 0.25em; + position: absolute; + inset-inline-end: -2.5rem; + inset-block-start: 3px; + font-size: 1rem; + } +} + +/* headings with autonumbering support */ + +body {counter-reset: h2} +h2 {counter-reset: h3} +h3 {counter-reset: h4} +h4 {counter-reset: h5} + +article[autonumbering] { + h2:before { + counter-increment: h2; + content: counter(h2) " "; + } + h3:before { + counter-increment: h3; + content: counter(h2) "." counter(h3) " "; + } + h4:before { + counter-increment: h4; + content: counter(h2) "." counter(h3) "." counter(h4) " "; + } + h2:before, + h3:before, + h4:before + { + margin-inline-end: 1em; + font-family: monospace; + font-size: 1em; + } + + .heading { + display: grid; + grid-template-columns: 1fr auto; + grid-template-rows: auto auto; + grid-gap: 0.5rem; + &__text { + grid-column: span 2; + } + &__anchor-link { + font-size: 1rem; + grid-column: 2; + grid-row: 1; + justify-self: end; + } + } + + #TableOfContents :is(ol, ul) { + /* + each list gets a new counter + */ + counter-reset: item; + margin-inline-start: 0; + } + #TableOfContents li:before { + /* + the counter is added as a pseudo-element, + and nested counters are joined by a dot + */ + content: counters(item, ".") " "; + counter-increment: item; + /* ensure the counters align visually */ + font-family: monospace; + font-weight: bold; + margin-inline-end: 1em; + } + #TableOfContents > ul > li { + /* + top-level items wrap after the number, + in order to add some visual separation + */ + display: flex; + flex-flow: column; + } +} \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/features/links.scss b/unified.test.hugo/assets/styles/features/links.scss new file mode 100644 index 0000000..d9da7bd --- /dev/null +++ b/unified.test.hugo/assets/styles/features/links.scss @@ -0,0 +1,37 @@ +a:link { + transition: all 0.1s ease-out; + color: var(--link-color); + text-decoration-thickness: .0625rem; + text-underline-offset: 0.125em; + text-decoration-skip-ink: none; +} + +a:visited { + color: var(--link-visited); +} + +a:focus { + +} + +a:hover { + text-decoration-thickness: 0.125em; + text-underline-offset: 0.25em; +} + +@media (prefers-reduced-motion) { + a:link {transition: none} +} + +a:link[target=_blank] { + svg { + margin-inline-start: 0.35em; + margin-inline-end: 0.15em; + vertical-align: baseline; + font-size: 0.65em; + } +} + +a:link[title] { + text-decoration-style: dotted; +} \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/features/search.scss b/unified.test.hugo/assets/styles/features/search.scss new file mode 100644 index 0000000..a8080e3 --- /dev/null +++ b/unified.test.hugo/assets/styles/features/search.scss @@ -0,0 +1,71 @@ +.search-results__title { + display: block; + font-size: 2em; + line-height: 1; + margin-block-end: 1em; +} + +.search-results strong { + font-weight: 900; + background: var(--primary-accent-transparent); + color: var(--ui-text-bold); +} + +#search-results { + display: flex; + flex-flow: column; + max-inline-size: 80ch; +} + +#search-results li:not(:first-child) { + border-block-start: 1px solid var(--ui-text-muted); +} + +#search-results li { + padding-block: 1em; +} + +.search-result-page-title { + font-size: 1.25em; + display: block; + margin-block-end: 1rem; +} + +.search-result-item p { + line-height: 1.5; +} + +#search-form { + width: 100%; + max-width: 18rem; + display: grid; + grid-template-columns: 20ch 8ch; + gap: 1rem; +} + +#search-input { + background: var(--ui-overlay); + color: var(--ui-overlay-text); + border-radius: 100rem; + border: 0; + padding: 0.5rem 1rem; + box-sizing: border-box; + resize: horizontal; + width: 100%; + grid-column: 1; + block-size: 2rem; + line-height: 1rem; + font-size: 0.75rem; +} + +#search-submit { + padding: 0.5rem 1rem; + border: 0; + background: var(--primary-accent); + color: var(--primary-accent-text); + border-radius: 4px; + grid-column: 2; + block-size: 2rem; + line-height: 1rem; + font-size: 0.75rem; +} \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/features/syntax-highlighting.scss b/unified.test.hugo/assets/styles/features/syntax-highlighting.scss new file mode 100644 index 0000000..32b14fa --- /dev/null +++ b/unified.test.hugo/assets/styles/features/syntax-highlighting.scss @@ -0,0 +1,110 @@ +/* syntax highlighting */ + +.highlight { + --background: var(--ui-overlay); + --error: #cc0000; + --keyword: rgb(25, 80, 162); + --class: #f57900; + --variable: #194869; + --number: #323030; + --operator: #5400c2; + --highlight: rgb(196, 196, 196); + + @media (prefers-color-scheme: dark) { + --background: var(--ui-overlay); + --error: #cc0000; + --keyword: #85ddff; + --class: #8700f5; + --variable: #bed5f2; + --number: #53ca24; + --operator: #ebe995; + --highlight: #555; + } + +} + +/* Background */ .bg { background-color: var(--background); } +/* PreWrapper */ .chroma { background-color: var(--background); } +/* Other */ .chroma .x { color: var(--ui-text-bold) } +/* Error */ .chroma .err { color: var(--error) } +/* CodeLine */ .chroma .cl { color: var(--ui-text) } +/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; } +/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; } +/* LineHighlight */ .chroma .hl { background-color: var(--highlight) } +/* LineNumbersTable */ .chroma .lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f } +/* LineNumbers */ .chroma .ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f } +/* Line */ .chroma .line { display: flex; white-space: pre } +/* Keyword */ .chroma .k { color: var(--keyword); font-weight: bold } +/* KeywordConstant */ .chroma .kc { color: var(--keyword); font-weight: bold } +/* KeywordDeclaration */ .chroma .kd { color: var(--keyword); font-weight: bold } +/* KeywordNamespace */ .chroma .kn { color: var(--keyword); font-weight: bold } +/* KeywordPseudo */ .chroma .kp { color: var(--keyword); font-weight: bold } +/* KeywordReserved */ .chroma .kr { color: var(--keyword); font-weight: bold } +/* KeywordType */ .chroma .kt { color: var(--keyword); font-weight: bold } +/* Name */ .chroma .n { color: var(--ui-text-bold) } +/* NameAttribute */ .chroma .na { color: var(--ui-text-bold) } +/* NameBuiltin */ .chroma .nb { color: var(--name) } +/* NameBuiltinPseudo */ .chroma .bp { color: #3465a4 } +/* NameClass */ .chroma .nc { color: var(--ui-text-bold) } +/* NameConstant */ .chroma .no { color: var(--ui-text-bold) } +/* NameDecorator */ .chroma .nd { color: var(--class); font-weight: bold } +/* NameEntity */ .chroma .ni { color: var(--name) } +/* NameException */ .chroma .ne { color: var(--error); font-weight: bold } +/* NameFunction */ .chroma .nf { color: var(--ui-text-bold) } +/* NameFunctionMagic */ .chroma .fm { color: var(--ui-text-bold) } +/* NameLabel */ .chroma .nl { color: var(--name) } +/* NameNamespace */ .chroma .nn { color: var(--ui-text-bold) } +/* NameOther */ .chroma .nx { color: var(--ui-text-bold)} +/* NameProperty */ .chroma .py { color: var(--ui-text-bold) } +/* NameTag */ .chroma .nt { color: var(--keyword); font-weight: bold } +/* NameVariable */ .chroma .nv { color: var(--variable) } +/* NameVariableClass */ .chroma .vc { color: var(--ui-text-bold)} +/* NameVariableGlobal */ .chroma .vg { color: var(--ui-text-bold) } +/* NameVariableInstance */ .chroma .vi { color: var(--ui-text-bold) } +/* NameVariableMagic */ .chroma .vm { color: var(--ui-text-bold) } +/* Literal */ .chroma .l { color: var(--ui-text-bold) } +/* LiteralDate */ .chroma .ld { color: var(--ui-text-bold) } +/* LiteralString */ .chroma .s { color: var(--variable) } +/* LiteralStringAffix */ .chroma .sa { color: var(--variable) } +/* LiteralStringBacktick */ .chroma .sb { color: var(--variable) } +/* LiteralStringChar */ .chroma .sc { color: var(--variable) } +/* LiteralStringDelimiter */ .chroma .dl { color: var(--variable) } +/* LiteralStringDoc */ .chroma .sd { color: var(--keyword); font-style: italic } +/* LiteralStringDouble */ .chroma .s2 { color: var(--variable) } +/* LiteralStringEscape */ .chroma .se { color: var(--variable) } +/* LiteralStringHeredoc */ .chroma .sh { color: var(--variable) } +/* LiteralStringInterpol */ .chroma .si { color: var(--variable) } +/* LiteralStringOther */ .chroma .sx { color: var(--variable) } +/* LiteralStringRegex */ .chroma .sr { color: var(--variable) } +/* LiteralStringSingle */ .chroma .s1 { color: var(--variable) } +/* LiteralStringSymbol */ .chroma .ss { color: var(--variable) } +/* LiteralNumber */ .chroma .m { color: var(--number); font-weight: bold } +/* LiteralNumberBin */ .chroma .mb { color: var(--number); font-weight: bold } +/* LiteralNumberFloat */ .chroma .mf { color: var(--number); font-weight: bold } +/* LiteralNumberHex */ .chroma .mh { color: var(--number); font-weight: bold } +/* LiteralNumberInteger */ .chroma .mi { color: var(--number); font-weight: bold } +/* LiteralNumberIntegerLong */ .chroma .il { color: var(--number); font-weight: bold } +/* LiteralNumberOct */ .chroma .mo { color: var(--number); font-weight: bold } +/* Operator */ .chroma .o { color: var(--operator); font-weight: bold } +/* OperatorWord */ .chroma .ow { color: var(--keyword); font-weight: bold } +/* Punctuation */ .chroma .p { color: var(--ui-text-bold); font-weight: bold } +/* Comment */ .chroma .c { color: var(--ui-text-muted); font-style: italic } +/* CommentHashbang */ .chroma .ch { color: var(--ui-text-muted); font-style: italic } +/* CommentMultiline */ .chroma .cm { color: var(--ui-text-muted); font-style: italic } +/* CommentSingle */ .chroma .c1 { color: var(--ui-text-muted); font-style: italic } +/* CommentSpecial */ .chroma .cs { color: var(--ui-text-muted); font-style: italic } +/* CommentPreproc */ .chroma .cp { color: var(--ui-text-muted); font-style: italic } +/* CommentPreprocFile */ .chroma .cpf { color: var(--ui-text-muted); font-style: italic } +/* Generic */ .chroma .g { color: var(--ui-text-bold) } +/* GenericDeleted */ .chroma .gd { color: var(--error) } +/* GenericEmph */ .chroma .ge { color: var(--ui-text-bold); font-style: italic } +/* GenericError */ .chroma .gr { color: var(--error) } +/* GenericHeading */ .chroma .gh { color: var(--ui-text-bold); font-weight: bold } +/* GenericInserted */ .chroma .gi { color: var(--ui-text) } +/* GenericOutput */ .chroma .go { color: var(--ui-text-bold); font-style: italic } +/* GenericPrompt */ .chroma .gp { color: var(--ui-text) } +/* GenericStrong */ .chroma .gs { color: var(--ui-text-bold); font-weight: bold } +/* GenericSubheading */ .chroma .gu { color: var(--ui-text-bold); font-weight: bold } +/* GenericTraceback */ .chroma .gt { color: var(--error); font-weight: bold } +/* GenericUnderline */ .chroma .gl { color: var(--ui-text-bold); text-decoration: underline } +/* TextWhitespace */ .chroma .w { color: var(--ui-text-muted); text-decoration: underline } \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/layouts/_default/list.scss b/unified.test.hugo/assets/styles/layouts/_default/list.scss new file mode 100644 index 0000000..f747513 --- /dev/null +++ b/unified.test.hugo/assets/styles/layouts/_default/list.scss @@ -0,0 +1,27 @@ +._default-list { + .list-header { + padding: 1em; + hr {display: none;} + } + .list-title { + margin-block: 0; + } + .list-author {} + .list-summary {} + .list-content {} + .list-permalink { + .u-url {font-family: monospace;} + } + .list-pages { + padding-inline: 1em; + } + .list-page { + max-width: 80ch; + .p-name { + font-weight: bold; + } + .p-summary { + font-style: italic; + } + } +} \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/layouts/_default/single.scss b/unified.test.hugo/assets/styles/layouts/_default/single.scss new file mode 100644 index 0000000..f600abc --- /dev/null +++ b/unified.test.hugo/assets/styles/layouts/_default/single.scss @@ -0,0 +1,41 @@ +._default-single { + .page-header { + padding: 2em 1em; + hr {display: none;} + .container { + max-width: 80ch; + margin-inline: auto; + } + } + .page-title { + margin-block-start: 0; + font-size: 2.025rem; + line-height: 1.15; + letter-spacing: -0.022rem; + grid-area: title; + } + .page-summary { + font-style: italic; + font-size: 1.266rem; + line-height: 1.15; + letter-spacing: -0.022rem; + margin-block-start: 0.5rem; + grid-area: summary; + } + .page-author { + grid-area: author; + margin-block: 0; + } + .page-date { + grid-area: date; + margin-block-end: 0; + } + .page-permalink { + margin-block-end: 0; + align-self: end; + } + .page-content { + max-width: 80ch; + margin-inline: auto; + } +} \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/layouts/wiki/list.scss b/unified.test.hugo/assets/styles/layouts/wiki/list.scss new file mode 100644 index 0000000..d6a96cc --- /dev/null +++ b/unified.test.hugo/assets/styles/layouts/wiki/list.scss @@ -0,0 +1,29 @@ +.wiki-list { + .subsections, + .subpages { + list-style: disc; + padding: 0; + margin-block-start: 1em; + margin-block-end: 2em; + li { + margin-inline-start: 1em; + margin-block-end: 1em; + } + a { + + } + } + .section-title { + font-size: 2em; + border-block-end: 1px solid var(--ui-text-muted); + padding-block-end: 0.5em; + margin-block-start: 0; + margin-block-end: 1em; + } + .subsections-title, + .subpages-title { + margin-block-start: 1em; + font-weight: 500; + text-decoration: underline; + } +} \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/layouts/wiki/single.scss b/unified.test.hugo/assets/styles/layouts/wiki/single.scss new file mode 100644 index 0000000..a3075fc --- /dev/null +++ b/unified.test.hugo/assets/styles/layouts/wiki/single.scss @@ -0,0 +1,5 @@ +.wiki-single { + .content { + padding-top: 0; + } +} \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/partials/mf2/h-card.scss b/unified.test.hugo/assets/styles/partials/mf2/h-card.scss new file mode 100644 index 0000000..01af18c --- /dev/null +++ b/unified.test.hugo/assets/styles/partials/mf2/h-card.scss @@ -0,0 +1,14 @@ +.h-card { + .u-url { + text-decoration: none; + color: inherit; + font-weight: bold; + display: inline-flex; + align-items: center; + gap: 0.5em; + } + .u-photo { + width: 3em; + border-radius: 100em; + } +} \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/partials/wiki/breadcrumbs.scss b/unified.test.hugo/assets/styles/partials/wiki/breadcrumbs.scss new file mode 100644 index 0000000..2eb7645 --- /dev/null +++ b/unified.test.hugo/assets/styles/partials/wiki/breadcrumbs.scss @@ -0,0 +1,27 @@ +.breadcrumbs { + display: flex; + flex-flow: row wrap; + padding: 0; + li:not(:first-child) { + margin-inline-start: 1.5rem; + margin-block-end: 1rem; + } + li::marker { + content: "/ "; + } + li:first-child::marker { + content: ""; + } + li:first-child { + margin-inline-start: 0; + } + font-family: monospace; +} +.breadcrumb-nav { + .title { + margin-block-end: 0.5em; + color: var(--ui-text-muted); + text-transform: uppercase; + font-weight: 900; + } +} \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/partials/wiki/site-header.scss b/unified.test.hugo/assets/styles/partials/wiki/site-header.scss new file mode 100644 index 0000000..967983c --- /dev/null +++ b/unified.test.hugo/assets/styles/partials/wiki/site-header.scss @@ -0,0 +1,57 @@ +.wiki { + .site-masthead { + display: inline-flex; + flex-flow: row; + align-items: center; + gap: 1em; + text-decoration: none; + } + .site-icon { + block-size: 2em; + } + .site-title { + font-weight: 900; + letter-spacing: -0.5px; + font-size: 1.25em; + margin: 0; + } + .site-masthead, .site-masthead:visited { + color: inherit + } + + .site-masthead:focus { + color: var(--primary-accent-text); + } + + .site-header {padding: 1em 0;} + + .site-header a { + font-weight: 500; + } + .site-header .container { + display: flex; + flex-flow: row wrap; + justify-content: space-between; + gap: 1em; + } + + .header-nav { + display: flex; + flex-flow: row wrap; + justify-content: center; + align-items: center; + .menu { + display: flex; + flex-flow: row wrap; + gap: 1em; + a { + display: flex; + align-items: center; + gap: 0.5em; + &:after { + display: none; + } + } + } + } +} \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/print.scss b/unified.test.hugo/assets/styles/print.scss new file mode 100644 index 0000000..16c1f57 --- /dev/null +++ b/unified.test.hugo/assets/styles/print.scss @@ -0,0 +1,22 @@ +@import "common"; + +#search-form, +.header-nav, +.docs-nav, +.site-footer, +.edit-link, +.footnote-backref, +.heading__anchor-link, +.section-nav +{ + display: none; +} +.page-header {padding: 0;} + +.page abbr[title]::after { + content: " (" attr(title) ") "; +} + +a[href^="http"]:after { + content: " (" attr(href) ") "; +} \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/screen.scss b/unified.test.hugo/assets/styles/screen.scss new file mode 100644 index 0000000..b86cc78 --- /dev/null +++ b/unified.test.hugo/assets/styles/screen.scss @@ -0,0 +1,3 @@ +@import "common"; + +@import "features/syntax-highlighting"; \ No newline at end of file diff --git a/unified.test.hugo/assets/styles/shortcodes/mf2/h-cite.scss b/unified.test.hugo/assets/styles/shortcodes/mf2/h-cite.scss new file mode 100644 index 0000000..4c22ada --- /dev/null +++ b/unified.test.hugo/assets/styles/shortcodes/mf2/h-cite.scss @@ -0,0 +1,7 @@ +.h-cite { + background: #eee; + padding-inline-start: 1em; + padding-block: 1em; + margin-inline-start: 0; + border-inline-start: 0.5em solid black; +} \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/articles/_index.md b/unified.test.hugo/content/_dump/articles/_index.md new file mode 100644 index 0000000..e69de29 diff --git a/unified.test.hugo/content/_dump/articles/att-ftc-fcc-doublespeak/fcc.jpg b/unified.test.hugo/content/_dump/articles/att-ftc-fcc-doublespeak/fcc.jpg new file mode 100644 index 0000000..7e9b8bc Binary files /dev/null and b/unified.test.hugo/content/_dump/articles/att-ftc-fcc-doublespeak/fcc.jpg differ diff --git a/unified.test.hugo/content/_dump/articles/att-ftc-fcc-doublespeak/ftc.jpg b/unified.test.hugo/content/_dump/articles/att-ftc-fcc-doublespeak/ftc.jpg new file mode 100644 index 0000000..40b3a4f Binary files /dev/null and b/unified.test.hugo/content/_dump/articles/att-ftc-fcc-doublespeak/ftc.jpg differ diff --git a/unified.test.hugo/content/_dump/articles/att-ftc-fcc-doublespeak/index.md b/unified.test.hugo/content/_dump/articles/att-ftc-fcc-doublespeak/index.md new file mode 100644 index 0000000..feddda7 --- /dev/null +++ b/unified.test.hugo/content/_dump/articles/att-ftc-fcc-doublespeak/index.md @@ -0,0 +1,33 @@ ++++ +title = "AT&T is pulling some serious doublespeak right now." +summary = "Is AT&T a common carrier, according to AT&T? It depends on who's asking." +date = "2015-01-10T12:00:00-0600" +tags = [] +categories = [] +syndication = [ + "https://medium.com/trwnh/at-t-is-pulling-some-serious-doublespeak-right-now-8fc64f268f36" +] +inReplyTo = [ + "https://arstechnica.com/tech-policy/2015/01/att-defends-unlimited-data-throttling-says-the-ftc-cant-stop-it/", + "https://arstechnica.com/information-technology/2015/01/att-tells-fcc-it-cant-treat-mobile-data-as-a-common-carrier-service/" +] +[[resources]] +name = "featured" +src = "opengraph.jpg" ++++ + +The FTC is suing AT&T over its mobile data policies, particularly throttling "unlimited" customers. [AT&T filed a motion to dismiss this suit](https://arstechnica.com/tech-policy/2015/01/att-defends-unlimited-data-throttling-says-the-ftc-cant-stop-it/), saying that since AT&T is a common carrier, they fall under the jurisdiction of the FCC instead. + +
    +Ars Technica headline, January 8, 2015: AT&T defends unlimited data throttling, says the FTC can't stop it +
    "You have no power here. Only the FCC can stop us."
    +
    + +Except just a few days later, [AT&T tells the FCC](https://arstechnica.com/information-technology/2015/01/att-tells-fcc-it-cant-treat-mobile-data-as-a-common-carrier-service/) that mobile data doesn't fall under common carrier rules, and cannot be regulated without Title II. + +
    +Ars Technica headline, January 9, 2015: AT&T tells FCC it can't treat mobile data as a common carrier service. +
    "You can't stop us. You don't have that power."
    +
    + +So, which is it? \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/articles/att-ftc-fcc-doublespeak/opengraph.jpg b/unified.test.hugo/content/_dump/articles/att-ftc-fcc-doublespeak/opengraph.jpg new file mode 100644 index 0000000..ab16000 Binary files /dev/null and b/unified.test.hugo/content/_dump/articles/att-ftc-fcc-doublespeak/opengraph.jpg differ diff --git a/unified.test.hugo/content/_dump/articles/no-right-to-profit/download.png b/unified.test.hugo/content/_dump/articles/no-right-to-profit/download.png new file mode 100644 index 0000000..4d88f43 Binary files /dev/null and b/unified.test.hugo/content/_dump/articles/no-right-to-profit/download.png differ diff --git a/unified.test.hugo/content/_dump/articles/no-right-to-profit/index.md b/unified.test.hugo/content/_dump/articles/no-right-to-profit/index.md new file mode 100644 index 0000000..75759ad --- /dev/null +++ b/unified.test.hugo/content/_dump/articles/no-right-to-profit/index.md @@ -0,0 +1,54 @@ ++++ +title = "You don't have a right to profit." +summary = "People will go to ridiculous lengths in the name of protecting the “right” to profit. Let’s be real here. No one has a “right” to profit." +indieweb_type = "article" +tags = ["capitalism", "profit", "music", "music industry", "piracy", "distribution", "access"] +categories = ["Uncategorized"] +date = "2015-07-08T12:00:00-0600" +attachment = [] +syndication = [ + "https://medium.com/trwnh/you-dont-have-a-right-to-profit-2a0f977d4917" +] +[[resources]] +name = "featured" +src = "download.png" ++++ + +

    These days, you see a lot of ridiculous things like copyright claims on the download pages of free software, because they contain the word “download”. A lot of these stupid actions are done in the name of “protecting the artists”. People will go to ridiculous lengths in the name of protecting the “right” to profit.

    + +
    + +
    Pages for Skype, Java, CCleaner, OpenOffice, Eclipse, Ubuntu, Python, and more were claimed to be infringing copyright, simply because the URL contained the word "download".
    +
    + +

    Let’s be real here. No one has a “right” to profit. No one is guaranteed to make money just because they make something. If you are offering something, then you are an entrepreneur. You have to make people WANT to give you money. If you can’t do that, you find a better business plan, or you quit.

    + +

    I’m really tired of these “protect the artists” sentiments that are only used to prop up an archaic business model. Do we have problems? Sure, but egregious litigation is definitely not the answer. Smart competition is. Wanna reduce piracy? Be more convenient. It should be pretty well-established by now that people are willing to pay for something if it’s available in an easy-to-access way.

    + +Ask yourself: why do people even pirate? Reasons people pirate: + +1) no legal alternative +2) drm failed after purchase +3) it’s easier +4) no money +5) too greedy to pay + +

    You’re never getting money from #5, and chances are you’ll never be able to stop them. #4 has no money to begin with, so they’re not worth considering when analyzing piracy, either. But #1, #2, and #3 are access issues. Make your stuff available in all countries, with no DRM, in an easily accessible way, and piracy is no longer a compelling alternative to most people. (Personally, I’m 3+4. I have no money, but when I do have money, I’ll pay if something is easier and worth paying for.)

    + +To date, I have bought exactly one album: Circa Survive’s Violent Waves. Why? + +1) It was $5 self-produced. +2) It was available for purchase directly. +3) I WANTED to give them my money. + +

    What converts me from a pirate in that situation to a paying customer is that the purchase was accessible. $5 is a low price, that I am perfectly capable of paying without too much thought. All I had to do was give them my money directly, no intermediaries, no DRM, no BS, just one payment, immediate delivery of MP3 + FLAC files, and a CD shipped out soon after. For $25, I could get the exclusive pre-order t-shirt, too. And Circa Survive is my favorite band, so I wanted to support them and their indie efforts.

    + +For any other artist? For the rest of my music collection? There are excellently tagged discographies, in high quality or ripped straight from a CD. Even the legal copy isn’t that good. [edit July 2015] Since writing this post, I’ve also purchased Anberlin’s Never Take Friendship Personal: Live in NYC. There were spelling mistakes and other incorrect things in the tags. This was the OFFICIAL RELEASE, and it wasn’t tagged properly. Not to mention it came in MP3 only. Not a pleasant shopping experience. [edit February 2018] And furthermore, the download link to that album has expired due to Tooth & Nail abandoning SendOwl for digital deliveries. The link claims to allow 3 download attempts, but as of now, it will allow 0. The only thing you’ll get is a 404 error. + +Basically, I’ll only ever buy CDs or high quality FLAC files, because buying anything else cannot match the alternative of just downloading the pirated copy. My copy of Violent Waves is right here, and I got the FLAC digital download immediately after purchase. Much of the pirating scene is dedicated to quality releases, so when a legal alternative can’t match up, it needs to offer something else. It needs to offer a compelling reason to give up your money. + +

    If you can match the quality of pirated CD-rips, then you can differentiate your legal option with convenience. Why do you think streaming services are gaining popularity? Because it’s easier to pay one fee and listen to anything you want, ever. At the touch of a button, you can play millions of songs spanning decades of creativity and culture. But even at its core, streaming is just plain convenient. No dealing with physical CDs, which take up space and need to be stored carefully. No giving up your storage space to MP3s. You don’t even have to bother with the payment processing. No downloads to make. Just play songs immediately. That kind of convenience is unmatched, and is a big reason why Spotify can compete seriously with piracy. Pure convenience, and there’s a free tier that’s ad-supported, so they can generate slightly more revenue than $0.00.

    + +My ideal purchasing situation: when you buy an album, not only can you get a CD, but you also get streaming rights, with an option to download. No DRM, no BS. You bought it. A smart label would partner up and get something like that done. Amazon does this to some extent with their AutoRip service, and Google Play Music gives you streaming + download when you purchase music. Since originally writing this, Apple Music has been introduced, which means you should get streaming rights to your iTunes purchases as well (to a limited extent). I just wish that this was more standardized somehow. Perhaps if labels started their own streaming service (and again updated, with the seizure of Grooveshark and its intellectual property, this is an opportunity for labels if they wish to increase their revenues…), or gave streaming rights on particular services (or all services) if you have a purchase code of some sort that could be included with each CD physical. This could even be accomplished with a more innocuous form of DRM like linking each code to one account only, so that only you can get streaming rights. + +

    I realize a lot of people don’t buy albums anymore, but that’s the music industry’s fault for commoditizing the individual tracks. Labels like to complain that various things are ruining the music industry, but the truth is that the music industry is ruining the music industry. Rather than innovating, they litigated. Then they devalued albums with the era of the digital single. Then they focused on mega-stardom and manufactured celebrity, pouring a lot of money into already-established artists and causing the music industry to contract and shrink. If the music industry had capitalized on the growth of the internet, if they had competed with Napster instead of shutting it down, if they hadn’t relied on iTunes for so long, if they had been quicker to adopt streaming and worked with Grooveshark and Spotify, if the labels reorganized their business plan from owning artists to doing publicity and media management and distribution… maybe things would be going better for them right about now, huh?

    \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/articles/perfect-unified-messaging-client/hangouts-new-conversation.png b/unified.test.hugo/content/_dump/articles/perfect-unified-messaging-client/hangouts-new-conversation.png new file mode 100644 index 0000000..5c3d486 Binary files /dev/null and b/unified.test.hugo/content/_dump/articles/perfect-unified-messaging-client/hangouts-new-conversation.png differ diff --git a/unified.test.hugo/content/_dump/articles/perfect-unified-messaging-client/index.md b/unified.test.hugo/content/_dump/articles/perfect-unified-messaging-client/index.md new file mode 100644 index 0000000..6edd1ac --- /dev/null +++ b/unified.test.hugo/content/_dump/articles/perfect-unified-messaging-client/index.md @@ -0,0 +1,75 @@ ++++ +title = "What makes a unified messaging client perfect?" +summary = "A rant in which I focus on what I like and hate about messaging apps, the characteristics I would implement if I were designing the perfect unified mobile messenger, and which current offerings are the closest to perfect." +date = "2014-08-08T12:00:00-0600" +tags = [] +categories = [] +syndication = [ + "https://medium.com/trwnh/what-makes-a-unified-messaging-client-perfect-322a83e3aa64" +] +[[resources]] +name = "featured,opengraph" +src = "messaging-apps-folder.jpg" ++++ + +## A brief history of (mobile) communication. + +I've grown a bit frustrated sometimes with contacting people. Why can't I just send a message through a nonspecific service and get a reply? What features are missing from today's current offerings that would REALLY make things better? If I made my own app, what aspects would I include in its design? + +In the 2000s, if you wanted to send a message to someone, you would either use SMS to reach them on their phone, or some IM platform if they were sitting at their computer. With the rise of mobile data and smartphones, however, the line between the two became blurred. Suddenly, we had phones that could be always-connected, just like computers. This led to the proliferation of a wide swathe of mobile messaging apps that utilize our new mobile data connections. + +## Mobile messaging is extremely diverse and fragmented. + +
    +11 apps in a folder titled "Communication". The apps are: Hangouts, Gmail, Allo, Duo, Skype, Wire, Kik, the stock SMS Messages app, Outlook, Sid, and Riot.im. +
    These are the apps I use... AFTER actively trying to reduce how many apps I use.
    +
    + +Mobile messaging apps are a dime a dozen — there are too many out there, and they all do basically the exact same things. There's not much differentiation between these apps; every app will let you send text messages to your friends, and probably picture messages, too. Many will let you send different types of media, like videos, voice recordings, or files. Some will let you make voice or video calls. Certain characteristics make each app notable, but no one app is perfect. + +Among Whatsapp, Facebook Messenger, Google Hangouts, Apple iMessage, LINE, WeChat, GroupMe, Kik, Viber, Tango, Skype, KakaoTalk, and Nimbuzz (to name only a few of the most popular offerings), there's [less and less reason to use SMS](https://www.gsmaintelligence.com/research/2011/11/sms-on-the-decline-as-third-party-messaging-gains-traction/307/) for most people around the world. Despite that, SMS remains in high usage for most people (at least in the USA), but for the most part, [different methods of communication control different regions](https://techcrunch.com/2012/12/04/global-messaging-market/), and no one app has a real majority worldwide. + +## Apps have different approaches to handling your contacts. + +Most apps fall into one of two categories: phone-number-based or email-based, the only truly federated communication systems that are widespread. Mobile phones are a staple in communication, and if you're online, chances are you've got an email address. Most services ask for an email upon signing up, to create your account. Generally, you'll also choose a username. (This is the case for Skype and Kik.) Some services won't ask for a username, opting to use account IDs internally and connect via your name. (This is the case for Facebook Messenger and Google Hangouts.) Other services will choose to link with your mobile phone number instead. (This is the case for Whatsapp and Viber.) + +These approaches cause subtle differences in the philosophy that an app has towards contacts. Either you connect with people through the phone number you already have, or you connect through an email that you already have. Or, you find people by name. + +
    +The "new conversation" UI in Hangouts provides you with a search bar and asks you to "Enter name, email, or phone". +
    This is where Hangouts does something right.
    +
    + +## All these apps have issues, but some are better than others. + +The biggest problem with all these apps is that they don't intercommunicate. This means that using an app locks you into your circle of friends who also use the same app. In order to build a meaningful user base, an app has to provide a clear benefit for its use case. So, which app do you pick? + +Personally, my primary communication method is Google Hangouts, for a few reasons: + +1. it integrates into the Gmail account I have (and most people use Gmail, so it's easy to get others to join me), +2. it has all the necessary features (like picture messaging, group chat, voice/video calls), +3. it integrates some telephony (thanks to my Google Voice, and hopefully this integration will grow), +4. it works across many platforms (including web, iPhone, and Android, but not Blackberry, Windows Phone, or Symbian), and +5. it syncs messages across all my devices (thanks to it being cloud-based). + +Other apps have other advantages. Facebook Messenger relies on the large user-base that Facebook already has worldwide, as after email and phone numbers, Facebook may be the third-most widely used communication platform. (That said, some people do not use Facebook, either due to refusal or lack of interest.) Whatsapp lowers the barrier to entry by automatically linking with a user's phone number, minimizing the interaction necessary to start using their service. iMessage is tightly integrated into Apple's ecosystem, and it requires zero thought from users since messages will automatically be converted if both people are using iDevices (plus, it has SMS as a fallback, but more on that later). + +## These are the features that I would implement in my app. + +In the last section, I mentioned that iMessage is seamless because it has SMS as a fallback, and this is the biggest pain point for most apps: in addition to lock-in, mobile messaging apps fail to be backwards-compatible or accessible. The reality is that, while mobile messaging apps are rising, and mobile data (or Wi-Fi) availability spreads, most people still rely on SMS and email. Those technologies aren't dead. Hangouts is the closest to "perfect" for me because it (independently) handles SMS and exists inside my Gmail, and the things it lacks are features of Google Talk and Google Voice that haven't made their way in yet. (The Android app for Facebook Messenger was my SMS app previously, due only to Chat Heads. I'd made a Facebook account only for Chat Heads, and once Facebook stopped supporting SMS, I deleted that account.) The perfect app would include some sort of federation. + +A truly unified mobile messaging app would be completely channel-agnostic. It wouldn't matter if you were communication with someone by telephony, email, or data. Obviously, data would be preferred as the primary channel, but it needs fallbacks to email and SMS for people who haven't made the switch yet. + +Consider iMessage's transition back to SMS for people who are offline. Google lets you do something similar with [SMS for Hangouts](https://www.google.com/settings/smsextensions) , a setting hidden in the Google Account settings menu (accessed by clicking on your profile icon in the upper right and clicking "Account") that lets you "receive your conversation messages as SMS, when you don't use Hangouts elsewhere" (similar to Twitter's "tweet via SMS" option), but this only applies to you. Google Voice lets you send SMS, but it's not fully integrated into Hangouts at the time of this writing. SMS fallback when offline should go both ways. + +Email fallback is something that is mostly overlooked. Facebook messages can be optionally sent as email notifications, and Hangouts shows up in Gmail as "Chats", but most services tend to avoid this. Hop, an email app for iOS (formerly called Ping), [turns email inboxes into a chat analogy](https://gethop.com/). This would be useful for a chat app, which could communicate with people who haven't signed up yet and don't have accounts. It would be possible for Hangouts to send a message as an email to someone not using Hangouts, and the other user could reply to that email to have it show up in Hangouts, much like Google Voice's SMS-to-email feature works. + +Imagine the following use-case diagram: A message is sent to Friend. If Friend is online, the app sends a push notification. If Friend isn't online, the app sends an email notification that Friend can reply to, and/or an SMS that Friend can reply to. A picture message would have the picture attached to an email, and/or utilize MMS. Group messages would be sent to all involved emails, and/or create a group MMS. The app would make no distinction between friends that haven't signed up and friends that have. When starting a conversation with friends that haven't signed up, messages would go straight to the specified email or phone number, unless matched to a contact that has signed up. + +For voice calls, the app would have the option to call either contacts (over data) or phone numbers (still over data, but your friend is connected through telephony). Video calls would obviously have to be data-only, and would require your friend to use the app, at least until federated video chat becomes possible. + +## A final summary... + +A perfect app would communicate with friends through its service, through email, or through SMS. For friends that don't use the service, emails or phone numbers are used. Attachments would be handled with email attachments or MMS attachments. For friends that use the service, messages are pushed to the client if online, and fallback to SMS/email if not. These fallbacks can be optionally disabled/enabled by your friend. + +Of the current apps, Google Hangouts + Google Voice would be the closest, once it integrates VoIP, full SMS integration, adds in better fallback options, and handles federation or open access through APIs. Chat Heads would be cool, but Google probably won't add them (which is why open APIs are important, because [someone could just write an app with floating bubbles like Tweet Balloon](https://forum.xda-developers.com/showthread.php?t=2751745)). \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/articles/perfect-unified-messaging-client/messaging-apps-folder.jpg b/unified.test.hugo/content/_dump/articles/perfect-unified-messaging-client/messaging-apps-folder.jpg new file mode 100644 index 0000000..d89b66f Binary files /dev/null and b/unified.test.hugo/content/_dump/articles/perfect-unified-messaging-client/messaging-apps-folder.jpg differ diff --git a/unified.test.hugo/content/_dump/articles/rip-grooveshark/index.md b/unified.test.hugo/content/_dump/articles/rip-grooveshark/index.md new file mode 100644 index 0000000..40a3f4a --- /dev/null +++ b/unified.test.hugo/content/_dump/articles/rip-grooveshark/index.md @@ -0,0 +1,30 @@ ++++ +title = "RIP Grooveshark." +summary = "I last used Grooveshark earlier today. I refreshed the page and found that it was dead. [...] I find myself feeling about Grooveshark similarly as when I found out that Megaupload had been shut down, and that many of my files were lost forever." +date = "2015-05-01T10:11:00-0600" +tags = ["grooveshark", "music", "music industry", "culture", "user generated content", "capitalism", "copyright"] +categories = ["Uncategorized"] +syndication = [ + "https://medium.com/trwnh/rip-grooveshark-e28cbda5911b" +] +[[resources]] +name = "featured" +src = "rip.png" ++++ + +I last used Grooveshark earlier today. I refreshed the page and found that it was dead. Grooveshark has finally shut down. UMG et al have won. Effective immediately, the Grooveshark service no longer works, all music has been wiped entirely from the site, user data has been lost, curated playlists are inaccessible, VIP users are unable to get refunds, all social media accounts have been deleted, and the grooveshark.com website shows only an apology that admits wrongdoing and directs users to whymusicmatters.org, the RIAA’s website. + +
    + +
    This message almost reads like it was written by someone with a mafia gun pointed to their head.
    +
    + +

    I find it amazing that the music labels found absolutely nothing of value in the remains of Grooveshark. They seized the intellectual property and the resources, and simply shuttered the rest. You couldn’t have done anything with the massive social media userbase? Grooveshark had 142,000 followers. You couldn’t have come up with a tweet to send to all of them? The Grooveshark service itself could have been legitimized, or could have had its infringing content deleted. Why wipe ALL of it? Why abandon a userbase of 35 million users? Surely you could do something more profitable or useful with Grooveshark than just shutting it down.

    + +

    There are things that Grooveshark was legitimately good at. Things that weren’t illegal. Things that could be used to improve other services. Things like being able to share a song with a URL and have someone be able to listen to it without logging in. Being able to do the same with an entire playlist. Only YouTube does this, and YouTube of course includes additional overhead from having to load videos with the songs. (As an app, Atraci is built around loading audio-only YouTube, but sharing a URL does not allow for this functionality.) Spotify forces me to create an account and login. Could Spotify not monetize anonymous users by simply playing an ad before allowing users to listen to shared music? Spotify could even allow logged-in users to skip the pre-roll ad and start listening to the playlist immediately. As it currently stands, it’s not at all friendly to share music from Spotify to the public. Nor is it like that for any other music service besides YouTube.

    + +

    As a personal user of Grooveshark VIP (renewed just a week ago on April 23, ironically), my losses don’t include the ability to access licensed content. I never cared for the licensed content, but it’s the obscure stuff that Grooveshark excelled at. Nowhere else could you find that one-of-a-kind glitch song, or that video-game remix that someone made and decided to upload it to Grooveshark, because Grooveshark had an ecosystem built around user uploads. No surprise that users chose to upload infringing songs at first, but I find myself feeling about Grooveshark similarly as when I found out that Megaupload had been shut down, and that many of my files were lost forever. The feeling I had walking into 11th-grade precalculus class on my phone, in disbelief and shock, realizing I would never be able to access the wealth of papercraft that was no longer accessible. The OSTs that people had meticulously created, the indie games that people had made, all of it was gone and I would never be able to download it again. And now, the feeling of sitting down at my computer, refreshing my Grooveshark tab, seeing that message, and realizing that my carefully-built playlists were gone, that I could never again easily discover new ambient and glitch and video-game music, that I could never again simply look for something that I wanted to try and figure out if it was worth downloading it and supporting that artist directly. Where are the broadcasts of people choosing tracks that are much better curated than anything you could ever find on Pandora?

    + +

    UMG et al didn’t have to shut down Grooveshark, and it would have been wiser not to do so. There would have been much to gain from spinning Grooveshark into a licensed service, or allowing it to continue without infringing material, or even perhaps turning Grooveshark into a streaming service wholly owned by the major labels, [a concept I’ve been thinking about and might write about later.] Any of those options would have been much more beneficial to the music labels than to have simply wiped every record that Grooveshark had ever existed. And of course, the eternal debate about music piracy rages on. What possible effects did this closure have? What repercussions will be felt in the music piracy scene? Knowing how things always play out, absolutely nothing will happen. Music piracy will continue unabated, just as it has outside of Grooveshark all this time. Will people start to buy more music now that Grooveshark is dead? Probably not. Will any of this matter to anyone outside of the Grooveshark community? Nope, not a chance.

    + +

    I will say this: I enjoyed all that Grooveshark offered while it lasted. I have bought more music due to Grooveshark and supported more artists than I ever would have without it. But absolutely none of that money would have ever gone to UMG, anyway.

    diff --git a/unified.test.hugo/content/_dump/articles/rip-grooveshark/rip.png b/unified.test.hugo/content/_dump/articles/rip-grooveshark/rip.png new file mode 100644 index 0000000..810dcfa Binary files /dev/null and b/unified.test.hugo/content/_dump/articles/rip-grooveshark/rip.png differ diff --git a/unified.test.hugo/content/_dump/articles/twitter-not-social/failwhale.png b/unified.test.hugo/content/_dump/articles/twitter-not-social/failwhale.png new file mode 100644 index 0000000..1eb30dc Binary files /dev/null and b/unified.test.hugo/content/_dump/articles/twitter-not-social/failwhale.png differ diff --git a/unified.test.hugo/content/_dump/articles/twitter-not-social/index.md b/unified.test.hugo/content/_dump/articles/twitter-not-social/index.md new file mode 100644 index 0000000..7b5613b --- /dev/null +++ b/unified.test.hugo/content/_dump/articles/twitter-not-social/index.md @@ -0,0 +1,65 @@ ++++ +title = "Twitter is no longer a social network." +summary = "" +indieweb_type = "article" +tags = ["twitter", "social network", "social media", "analysis", "capitalism"] +categories = ["Communication"] +date = "2018-04-27T12:00:00-0600" +attachment = [] +syndication = [ + "https://medium.com/trwnh/twitter-is-no-longer-a-social-network-3cd03f51cd5f" +] ++++ + +

    "We are not a social network. We do not benefit from social graphs," Dorsey said. "People come to us when they're interested in events happening in the world or with a niche interest. We've been biasing a lot more of the service towards interest and topics."

    + +

    Perhaps this is something many of us suspected, as we stared at our timelines, watching them devolve steadily from 2014 onward. But for the first time ever, here it is, in written form, straight from the CEO, staring right back at us.

    + +

    An admittance that Twitter, the social network, is dead.

    + +
    "We are not a social network."
    + +

    What are "we", then?

    + +
    "We do not benefit from social graphs."
    + +

    What does this mean for the social graphs we've all built over the past decade?

    + +
    "We've been biasing a lot more of the service towards interest and topics."
    + +

    What does this mean for those of us who used Twitter as a conversational platform and not as a source for "topics"?

    + +

    Twitter, the social network, is dead.

    + +
    + +

    Thanks, Jack. Twitter the social network is dead. That service that started out as a way to send status updates to your friends has been replaced by Twitter, a bloated, lumbering mess trying to force-feed you a stale diet of whatever Content™ floats to the top of the river of shit.

    + +
    +failwhale +
    Pictured above: a whale being lifted out of sludgy waters, which, aside from being reminiscent of a more whimiscal Twitter dot com from 2008, is also an apt metaphor for massively-viral content being surfaced from what is otherwise a toxic environment.
    +
    + +

    The short and bitter truth is that Twitter found out, regrettably, that being a conversational platform is not monetizable or profitable. It just took about four years for them to finally admit that they gave up on being an open, conversational platform and they are now a content aggregator.

    + +

    Now, anyone looking for a conversational platform is not going to find it on Twitter. How can there be conversation when you can't even be sure of the visibility of your messages? I, for one, have already mostly abandoned this network-that-is-not-a-network-anymore, as have several others.

    + +

    In a world where the big "social networks" are trying very hard to no longer be social networks  —  with Facebook trying to be your news feed and Twitter trying much the same before pivoting to surfacing viral content —  there is a big void for people who still want to communicate. To be social, among their network of friends.

    + +

    At least for me, I'm filling that void with Mastodon, which — *gasp* — doesn't try to be something that it's not. Just a way to keep up with other people, with no ads and no algorithmic shuffling — just your friends' statuses, in reverse-chronological order.

    + +

    And even though Mastodon has only been usable for barely over a year, it's growing and improving quickly enough that I feel comfortable enough to use it full-time. It's absolutely refreshing to have a laid-back conversational hangout again. You can find me at https://mastodon.social/@trwnh for now — and if you want to learn more, go to https://joinmastodon.org and read about how it works.

    + +

    It's probably going to be a bit of a shock at first, and hard to understand if you're used to being a product. But it makes way more sense when you do get it. Because we've been conditioned by the past decade to view everything through the lens of capital and profit; we've grown dependent on corporations to provide our platforms, for their benefit and not for ours. We're just a metric for them, another pair of eyeballs to view ads.

    + +

    We think it's ridiculous for things to be open and accessible and free, because we're used to everything being locked down and user-hostile. It's absolutely heartbreaking — the darkest timeline. But not inevitably so. We have an actual chance to redeem ourselves, however slim. And that starts with realizing where we came from — how everything used to be open and free, before it was encircled and carved up by corporations for profit. You can email anyone, on any service. You can call/text anyone, on any carrier. But NOT on the internet. That's sad.

    + +

    Our phone networks are free.
    +Our email networks are free.
    +Our browsers are free.
    +Our World Wide Web is free, with some challenges and attacks.
    +Our internet platforms are not free. They are fiefdoms and empires.

    + +

    Is this what we've sunk to? To give away our social interactions and let other people make money off of it? To surrender our discourse, our very zeitgeist, to entities that couldn't care less about any of that? To lock our public participation behind an advertising paywall?

    + +

    It doesn't have to be this way.

    \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/aspects-circles-audiences-vs-lists-vs-collections.md b/unified.test.hugo/content/_dump/aspects-circles-audiences-vs-lists-vs-collections.md new file mode 100644 index 0000000..a56a5d6 --- /dev/null +++ b/unified.test.hugo/content/_dump/aspects-circles-audiences-vs-lists-vs-collections.md @@ -0,0 +1,23 @@ +2017-11-12 13:43 | https://mastodon.social/@trwnh/98991746572627131 + +problem with diaspora*'s aspects (and by extension, Google+ circles which aped it) is that it's a bidirectional metaphor for a unidirectional relationship. you're supposed to pick who can see a post, but they might not even follow you. I would understand if instead it functioned and was advertised as a way to split your timeline into multiple timelines. As is, sharing to aspects/circles/etc. is needlessly confusing. + +although having a way to tag/categorize your own toots could come in handy as well, if you post about multiple disparate topics. it's a nightmare to maintain one Twitter account per interest/community. + +--- + +2017-12-17 09:55 | https://mastodon.social/@trwnh/99189033326279405 + +unrelated thought: been trying to hash out a solution to the "multiple accounts" issue with social media. namely: why/when do people use multiple accounts, and what features can be implemented to reduce the friction in using just one account? would appreciate feedback. + +off the top of my head: + +- private vs public accounts for trusted people (answered by privacy options on toots) +- multiple interests (not really solved currently; perhaps implementing a tag system and letting people mute certain tags? Diaspora*-style aspects can get complicated) +- separate identity (unsolvable and would be insecure to attempt with one account) + +wrt multiple interests, this really is my biggest pain point with ANY social media (coming from someone who has had like 15 birdsite accounts at once) + +perhaps not exactly tags, but having a category system like google+ would be nice and perhaps easiest to manage when considering tootboosts. but this also might complicate the issue? nevertheless, it could be optional (default behavior would be to boost to your profile, no categorization involved) + +the tag approach would be easiest for your own toots, but the categories wouldn't be too bad and would also allow for separating different boosts \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/blocklists-as-hoa.md b/unified.test.hugo/content/_dump/blocklists-as-hoa.md new file mode 100644 index 0000000..b2b1f92 --- /dev/null +++ b/unified.test.hugo/content/_dump/blocklists-as-hoa.md @@ -0,0 +1,35 @@ ++++ +draft = true ++++ + +it's a bit weird that some fedi blocklists use language like "fence" because whenever i see that, i don't think "safety", i think "homeowners association", and i think the HOA characterization of certain blocklist efforts is actually not wrong. it is reminiscent of the abstract desire for "safety" rather than any sort of concrete safety or just treatment. "freedom of association" only goes so far to justify punitive and destructive actions at an instance-state level + +of course, what is to be done? what is a more appropriate solution? i think whenever such blocklists are circulated, it usually represents a failure mode at an institutional level. the rise of blocktogether on twitter was due to the systemic failure of their moderation. earlier fedi users may or may not remember the infamous "wil wheaton blocklist" that imported from infamous terf randi harper, who billed her list as "99% gaters and mras" (and i guess 1% trans ppl?) + +so i think the "question of the day" now, is, what is the failure of fedi and how could we have avoided it and how can we proceed to mitigate it. + +for my part i think it comes down to the "instance" model. no one cares if you have to ban someone from a building, but evicting them from their house or expelling them from their country is disproportionate. so naturally, it becomes an issue when the "community" and "living space" are the same thing. + +every day more and more it becomes clear we need to restructure around actual communities at a separate layer. + +similar to the dynamics of a cliquey community instance, but without the expanded audience that federation brings. imagine just turning off federation. + +maybe in some ways that's exactly what is going on -- clique communities are feeling threatened by the inherent lack of control. overblocking is in that vein similar to defensive centralization; after all, what is centralization if not simply blocking *all* remotes? and the balance is set by how much control they want to wrest back. + +i think the "objectionable" part to me is that clique mentality. especially as it tries to assert itself over others. the other day i had someone ask me which instance to join and i realized for the first time in 6 or 7 years that i didn't have an answer. they just wanted to exist. they didn't want to have to care about border controls and digital embargoes. and they didn't really have *any* good options. + +there isn't really any well-connected generalist instance that isn't overly blocked or doesn't overly block. much less an art-focused one. or a fandom-based one. so they stayed on tumblr and discord even though they *want* to join fedi. there just isn't anywhere for them to find a home in an area that is both good to live in *and* free of HOA type behavior. they don't want a gated community and they don't want a place with drive-by harassment. and they want to actually reach people. + +> [I] suspect that the reaching people, the lack of harassment, and lack of blocking are kind of corners of a triangle. + +yeah it certainly does seem like a trilemma + +instance moderation is absolutely a huge job if you want to stay on top of it. it can be easier if you take a reactive rather than proactive stance. but the problem with proactive stances is that you now need to judge someone *before* they have harassed you. and the way people approach recommended blocks, they might not have been harassed either. you'll never know the difference unless you investigate for yourself... and that's hard rn. + +now, if people just said "hey we dont like them, they failed the vibe check and we're not gonna spill any tears", that's more respectable than making something up. i can't count how many times i've seen people blocked for reasons that are patently absurd if you know the people. you use a reclaimed slur, you get blocked for using slurs. somewhere along the line that becomes "hate speech". a while ago it was "federates with the usual suspects". guilt by association morphed into "alt fedi" + +the hard part is... they're not always wrong! a lot of blocks make sense when you look into them. but it's a mix, and the false positive rate is a bit too high imo. and there's no indication when you lose friends over your admin's decisions. and the policies aren't always visible, bc some admins are hiding them now to prevent scrapers tracking them. it just becomes this whole uncertain mess where you never know who blocks who and why. + +--- + +my problem with oliphant is that there really should be a "tier negative one", given that the "tier 0" list doesn't have 100% consensus. my problem with thebadspace is that every single entry has the same tags, even where it makes no sense. my problem with blocklist culture in general is that there's zero accountability, review, or forgiveness built into them; often, they lack any sort of context, and if there is any reason given, the reasons are laughably flat-out ridiculous, incorrect, or inaccurate. i've seen blocks for being "channers" or "edgelord" being levelled against people who couldn't be any further than that. i've seen blocks for "no moderation" when no reports were filed. i've seen blocks for reasons such as "underage" or "reclaimed slurs" or vague unspecified "accusations". there's no differentiation between "hosts twitter crosspost bots" and "contains literal nazis that will send you death threats". fundamentally, i do not think that it is healthy to conflate safety with mere annoyance or a misalignment of "our" values. this is before you even get into the subjectivity of all such judgements... it is, of course, everyone's freedom of association to do whatever they want for themselves, but it is the point at which people start recommending or expecting that you do the same, that it then becomes a problem. and the real problem is not who you do or do not block. the problem is that there are no clear boundaries or clearly-established spaces or contexts for people's communications. you talk to someone that happens to be on someone else's shitlist, and you just might end up on that same shitlist for "federating with the usual suspects", where "the usual suspects" is an unbounded and growing set of people that seems to propagate further every time you look at it. it very frequently leads into policing who any given person mentions offhand or boosts in passing. \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/default-server-paradigm.md b/unified.test.hugo/content/_dump/default-server-paradigm.md new file mode 100644 index 0000000..bf6aed0 --- /dev/null +++ b/unified.test.hugo/content/_dump/default-server-paradigm.md @@ -0,0 +1,13 @@ +https://mastodon.social/@trwnh/110310774875374491 + +re: mastodon and matrix having "default servers" that end up being too big: i feel like if they were easier to selfhost it would be less of a problem. the "default server" paradigm is more effective when you can't easily set up other servers. + +you ever try to host matrix? it's awful. like 2GB memory usage just for a single user in a big room. + +mastodon is getting to be pretty similar, not because of the base software per se, but because of how many moving parts it has and how much resource usage accrues as a result. rails, postgres, redis, optional elasticsearch if you want working search, a nodejs streaming server and frontend... that's before you even get to the network traffic due to architectural decisions + +sure, but you can at least block entire bad servers with little-to-no collateral damage. and you can also use allowlist federation or some other restriction mechanism to avoid fully open federation. just like avoiding fully open registrations. + +i've oft thought about an opt-in federation of instances that require human approval for registrations. or a closed "federation" in the irc distributed sense. + +it'll never happen because gargron wants more users, and approval-based signup makes a lot of disinterested people bounce before actually trying the software. but it's worth considering imo at least as a thought experiment \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/documentation-first.md b/unified.test.hugo/content/_dump/documentation-first.md new file mode 100644 index 0000000..a91be69 --- /dev/null +++ b/unified.test.hugo/content/_dump/documentation-first.md @@ -0,0 +1,5 @@ +https://mastodon.social/@trwnh/109826683171183861 + +if/when i get around to building [untitled social app] i want to set some hard design expectations for it before even thinking about if/when/how to release it (and which parts of it). there's a lot of expectations i want to challenge, i don't want to take anything for granted. if anything, whatever i build will simply be the practical application of my grand unified communication theory. it's as much an experiment and learning process as it is a tool or utility. + +which is to say: any code i write or software i build, it will not be the primary product. the primary product will be the documentation and reasoning behind it. it will be in researching existing protocols and ecosystems, then identifying how they map onto the theoretical patterns and structures. nail the recipe before baking the cake. \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/domain-number-system.md b/unified.test.hugo/content/_dump/domain-number-system.md new file mode 100644 index 0000000..58d3c15 --- /dev/null +++ b/unified.test.hugo/content/_dump/domain-number-system.md @@ -0,0 +1,40 @@ +https://mastodon.social/@trwnh/109965906891374818 + +we have a domain name system but why don't we have a domain number system + +just like we can register human-friendly names, we should be able to register persistent machine-friendly numbers to websites and domains. the name and number are aliased together, or we map name => number => ip address + +yes this idea is copied from xri i-names and i-numbers, it's one of the best ideas to come out of that effort (aside from delegation of authority at any point in the identifier) + +the world if xri took off + +future.jpg + +i've talked/thought about doing something similar with webfinger, but the "authority delegation" bit is really hard without a persistent unchanging identifier in some common authoritative namespace. you can defer to some other DNS domain's webfinger endpoint, but that doesn't get rid of the fragility in expiring or reassigning domain names. + +it's interesting that bluesky comes to a similar conclusion with its "placeholder" DID scheme, did:plc: -- identifiers are centralized around a single "PLC server". the DNS stuff maps to a did:plc: that gets resolved by the centralized resolution server. + +we could do something similar with a centralized server/domain that did nothing but assign identifiers and map to current location... of course, that doesn't solve the problem, it just shifts the burden. + +so here's a crackpot idea that requires "minimal" changes to the way the world works + +1. register a TLD with the IANA/ICANN -- let's call it something like .uuid +2. allow anyone to register UUIDs on this TLD -- this should be as easy as registering any other domain name, but instead of getting to pick the name, it's auto-assigned to you +3. CNAME your desired public-facing domain name to the .uuid domain you registered +4. optionally: run some software to "reverse map" your .uuid URIs (Webfinger) + +you could also use plain old HTTP redirects instead of Webfinger, if you trusted the thing at the other end to stay online + +but the main thing would be being able to use + +trwnh.com/some-resource => 05517367-0a6a-42c1-9810-9fcf264a505b.uuid/some-resource + +and then later change trwnh.com to some other domain + +any software/application dealing with identifiers SHOULD support using the "canonical" identifier, so you can signal that the .uuid-assigned URI is the canonical one + +crucially, the .uuid registry would never expire, and probably it should be free. the goal is to never let the .uuid registration lapse, ever + +maybe your domain name registrar could even host a reverse-mapping server for you, if they wanted to expand their services? + +also something to consider: under what circumstances might an entire TLD lapse? like this is super unlikely, sure, but what happens if the entity behind some TLD in the IANA root zone database goes insolvent? \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/notes/100040916509633482/index.md b/unified.test.hugo/content/_dump/notes/100040916509633482/index.md new file mode 100644 index 0000000..dd63b60 --- /dev/null +++ b/unified.test.hugo/content/_dump/notes/100040916509633482/index.md @@ -0,0 +1,11 @@ ++++ +indieweb_type = "note" +tags = [] +date = "2018-05-16T20:40:00Z" +attachment = [] +original = "https://mastodon.social/@trwnh/100040916509633482" ++++ + +I like Mastodon but I'm scared it might become a de facto standard, basically the IE6 of the fediverse. there's plenty of opportunities to learn from the "mistakes" of Mastodon but the longer it remains the only usable experience, the more entrenched it becomes and the more all new projects will have to make concessions to maintain compatibility. + +if i ever did go ahead with making my own alternative to mastodon, then i think i'd focus on making it MUCH easier to run and manage... but i'm all talk tho. i haven't got the time or energy to do it or to teach myself enough to be able to pursue it. :/ \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/notes/108588546793521204/image.png b/unified.test.hugo/content/_dump/notes/108588546793521204/image.png new file mode 100644 index 0000000..7a53309 Binary files /dev/null and b/unified.test.hugo/content/_dump/notes/108588546793521204/image.png differ diff --git a/unified.test.hugo/content/_dump/notes/108588546793521204/index.md b/unified.test.hugo/content/_dump/notes/108588546793521204/index.md new file mode 100644 index 0000000..967cf4a --- /dev/null +++ b/unified.test.hugo/content/_dump/notes/108588546793521204/index.md @@ -0,0 +1,7 @@ ++++ +indieweb_type = "note" +tags = [] +date = "2022-07-04T05:15:00Z" +attachment = ["image.png"] ++++ +is this anything \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/notes/99865201213509948/index.md b/unified.test.hugo/content/_dump/notes/99865201213509948/index.md new file mode 100644 index 0000000..4e5d110 --- /dev/null +++ b/unified.test.hugo/content/_dump/notes/99865201213509948/index.md @@ -0,0 +1,8 @@ ++++ +indieweb_type = "note" +tags = ["boktai"] +date = "2018-04-15T19:54:00Z" +attachment = [] +original = "https://mastodon.social/@trwnh/99865201213509948" ++++ +i'm so emo that boktai 3 never launched outside of japan and also that boktai as a series is super dead and konami will never continue it and kojima probably can't/won't either due to copyright and the fact that it's been over 10 years since boktai ds and also kojima doesn't work for konami anymore UGH. where do you go to find quirky existentialist video games based on norse mythology and spaghetti westerns in the year of your lord 2018, you ask? you don't ;_; [#boktai](/tags/boktai) diff --git a/unified.test.hugo/content/_dump/notes/99918136079992108/index.md b/unified.test.hugo/content/_dump/notes/99918136079992108/index.md new file mode 100644 index 0000000..2079bb1 --- /dev/null +++ b/unified.test.hugo/content/_dump/notes/99918136079992108/index.md @@ -0,0 +1,8 @@ ++++ +indieweb_type = "note" +tags = [] +date = "2018-04-25T04:16:00Z" +attachment = [] +original = "https://mastodon.social/@trwnh/99918136079992108" ++++ +hello friends it is almost may 2018 and i am down to using pretty much only mastodon and inoreader, and dropping into twitter once a week or so. it's been almost a year since i posted on instagram and at least half a year since i last logged in. i'm only really checking 2 of my twitter accounts and only very sporadically since january 2018. and about half a month ago or so i stopped absentmindedly browsing reddit. i... i'm almost free... wow, this feels... zen diff --git a/unified.test.hugo/content/_dump/notes/99963583159619719/index.md b/unified.test.hugo/content/_dump/notes/99963583159619719/index.md new file mode 100644 index 0000000..0d7b3b2 --- /dev/null +++ b/unified.test.hugo/content/_dump/notes/99963583159619719/index.md @@ -0,0 +1,14 @@ ++++ +indieweb_type = "note" +tags = [] +date = "2018-05-03T04:53:00Z" +attachment = [] +original = "https://mastodon.social/@trwnh/99963583159619719" ++++ +sometimes you come across a youtube video from an alt-righter indirectly calling you out (or a thing you worked on) and you wanna respond, but... the video has 48 views and it's from september 2017, so i think i'll let it slide. it's not like it's logically consistent or significant, either. + +i wonder if i'll ever be able to safely take credit for all the work i've done? not that i really have a reason to except perhaps if i'm in a really tight spot and need money to live... and i've mostly given up on twitter anyway, so it feels a bit... "late". + +there's just a very real danger of fascists targeting me if they ever connect me to that account, though. "hey i maintained this thing for over a year, can anyone help me survive" doesn't really balance out with "oh, we finally have a name to track down and harass" + +then again i've gotten private offers of donations and turned them down bc idk, i don't feel worthy of accepting money for it, it's simple (if occasionally time-consuming) to me, even if it helps hundreds or thousands of people on twitter... i don't really know what to do about the whole thing. diff --git a/unified.test.hugo/content/_dump/notes/99987017261137486/index.md b/unified.test.hugo/content/_dump/notes/99987017261137486/index.md new file mode 100644 index 0000000..9e985b1 --- /dev/null +++ b/unified.test.hugo/content/_dump/notes/99987017261137486/index.md @@ -0,0 +1,12 @@ ++++ +indieweb_type = "note" +tags = [] +date = "2018-05-07T08:13:00Z" +attachment = [] +original = "https://mastodon.social/@trwnh/99987017261137486" ++++ +tbh like 90% of my day-to-day angst against capitalism is from how shit the smartphone market has become. if capitalism is so great then where the fuck is my <70mm-wide phone with a removable battery? fucking profit motives means that the entire market has abandoned me. I haven't been satisfied with any phone since 2010. hell, I'd buy an updated Nexus One with newer, more efficient internals. + +"capitalism brought you your smartphone!" yeah, and that phone /fucking sucks/. + +I wish I could build my own phone or have one built to spec, but alas, I do not own a machining and assembly factory, and I don't have the requisite circuitry knowledge... if only I could, I dunno, *cooperate* with some like-minded people, and we had *public ownership of those factories*... \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/notes/99999893512052394/index.md b/unified.test.hugo/content/_dump/notes/99999893512052394/index.md new file mode 100644 index 0000000..8c8f830 --- /dev/null +++ b/unified.test.hugo/content/_dump/notes/99999893512052394/index.md @@ -0,0 +1,8 @@ ++++ +indieweb_type = "note" +tags = [] +date = "2018-05-09T14:48:00Z" +attachment = [] +original = "https://mastodon.social/@trwnh/99999893512052394" ++++ +physical bodies are so encumbering. it would be great to never again have to feel pain from a stomach too empty, or perhaps too full; to never have crusty eyes after sleeping too much, or perhaps too little; to never suffer from physiology that at best will decay, and at worst will actively punish us. \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/notes/_index.md b/unified.test.hugo/content/_dump/notes/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/_dump/notes/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/plaintext-xml-json.md b/unified.test.hugo/content/_dump/plaintext-xml-json.md new file mode 100644 index 0000000..15fb627 --- /dev/null +++ b/unified.test.hugo/content/_dump/plaintext-xml-json.md @@ -0,0 +1,8 @@ +actually it's kinda interesting how every single spec largely breaks down along one of three ideological lines: plaintext, xml, or json + +i'm seeing a general analogy between DNS, XRI, and Webfinger resolution + +- DNS returns a plaintext answer +- XRI returns an XRD +- Webfinger returns a JRD + diff --git a/unified.test.hugo/content/_dump/replies/4564-37/index.md b/unified.test.hugo/content/_dump/replies/4564-37/index.md new file mode 100644 index 0000000..074dc6d --- /dev/null +++ b/unified.test.hugo/content/_dump/replies/4564-37/index.md @@ -0,0 +1,45 @@ ++++ +inReplyTo = "https://socialhub.activitypub.rocks/t/socialwebfoundation-what-do-people-think/4564/36" +original = "https://socialhub.activitypub.rocks/t/socialwebfoundation-what-do-people-think/4564/37" +date = "2024-09-30T17:41:00-0600" +tags = ["capitalism", "social", "capital", "mastodon", "utility", "analysis"] +indieweb_type = "reply" ++++ + +{{< mf2/h-cite +post-url = "https://socialhub.activitypub.rocks/t/socialwebfoundation-what-do-people-think/4564/36" +author = "socialhub.activitypub.rocks/eprodrom" +>}} +I think that, before we had an open standard for social networking, protocol experimentation was more important. Now that we have an open standard, with a hundred implementations, tens of thousands of nodes, and tens of millions of users, I think efforts should go into encouraging the use of that standard and enhancing it through backwards-compatible extensions, rather than starting the whole process from the ground up. +{{< /mf2/h-cite >}} + +I think this is a bit too conservative of a take regarding backwards-compatibility. I really don’t think we’re at any sort of broad alignment, even within the ActivityPub space alone. Just about the only thing we universally do is POST to inbox. That payload is AS2 Activities. Things tighten up a bit when you consider e.g. the "Mastodon Protocol" as defined by https://docs.joinmastodon.org/spec/activitypub but even then, not everyone follows this protocol, and as a protocol, it’s got a lot of missing bits that are very important for a "social networking protocol" to have, not to mention it doesn’t closely follow the requirements laid out in AP or AS2. The main criticism that several people have raised (@hrefna @stevebate and @jenniferplusplus in particular) is that any interop we have on the fediverse today is more the result of the blood, sweat, and tears of implementers than it is the “open standard” that pretty much no one implements to the letter. The far more common outcome is to reverse-engineer Mastodon, or reverse-engineer Lemmy, with the aid of their documentation, with lots of hours spent looking at the code, and with outreach and collaboration involving other implementers. + +Honestly, looking at the ActivityPub spec over and over and over and over and over (as I’ve done countless times), the well-defined parts that stick out are: + +- A "following protocol". You send `Follow`, you get back `Accept` or `Reject`, you add to `followers` and `following` as appropriate, and you can later `Undo`. This is the core functionality of ActivityPub. +- A "liking protocol". You send `Like`, which should get added to the `likes` collection. +- A "(re)sharing protocol". You send `Announce`, which should get added to the `shares` collection. + +But besides that, most of the activities that got specced in AP are for C2S CRUD resource management or Collection management. The way that these activities get used (or not used) in the fediverse doesn't line up with the spec. For example, `Create` is described in S2S as having "surprisingly few side effects". But in the fediverse it actually has more side effects, which aren't described by ActivityPub. It also has unstated requirements on the "shape" of the activity, which properties are required, and how those properties get interpreted (which only *somewhat* aligns with the definitions provided in AS2). + +I think there's a lot of work that one would need to do to describe "the implicit protocol of the fediverse", which is not sufficiently described by "the ActivityPub specification". If you want to frame this in AP terms, the "server-to-server" bits aren't the "real" protocol, but rather there are *client-to-client* protocols that are currently undescribed. These "client-to-client" protocols would be defined and layered on top of the AP S2S delivery mechanism, which is just LDN but with the restriction that the notification payload is an AS2 Activity and with some basic side effects sprinkled on top. And yes, most existing fediverse implementations ought to be considered Clients more than they can be considered Servers; they just happen to be monolithic and have subsumed the server component into the client, as if Thunderbird came with its own IMAP+SMTP implementation embedded into the application. + +So, given all this, I have to ask: what are we targeting here? What are we trying to be backwards-compatible with? If it's the existing install base of Mastodon and Mastodon-compatible software, then I think a blind adherence to backwards-compatibility is actually going to severely hold back the future potential of the social web. If it's Threads, then I honestly don't think that many of the smaller and independent implementers are interested in implementing and adhering to the Threads Protocol. Is it some kind of synthesis of the lowest-common-denominator of all fediverse implementations? Well, in that case, you can't target something that isn't clearly defined. + +To bring up the perennial example of a chess extension to ActivityPub, you could imagine implementing a "chess protocol" that works client-to-client. You could even declare support for this protocol somehow, probably at an actor level you could indicate which clients are connected to your actor, but I'm getting ahead of myself here. The point is that just like we could have a "chess protocol", we similarly could define a "social media post" protocol, which isn't currently defined. Such a "protocol" would include things like interpreting a Create Note as a "status", and it would include which properties are required or recommended or optional, and it would include guidance on how to interpret those properties and how to render them to the user, but also very importantly it would include a description of the side effects that you can expect that client to perform. Using Mastodon as an example, one of the side effects of receiving a Create Note currently is that the "status" it gets transformed into will be stored indefinitely in the local database, irrespective of HTTP caching headers. The "protocol" would ideally also define how the "status" should be deleted, and when, under which circumstances. For example, sending a Delete of your own actor is not defined anywhere as deleting your "statuses" as well. And I don't think this belongs in the ActivityPub spec necessarily, because it's just as valid to say that all activities delivered by the actor prior to its own deletion are notification messages that could be stored indefinitely or externally in your on-disk cache (barring the presence of HTTP caching headers which would cause them to be expired from cache). Perhaps if that "social media protocol" actually existed in explicit, unambiguous, documented form, then it would be possible to target it with backward-compatible extensions. But we don't have any such thing today. The closest thing we have to that is https://docs.joinmastodon.org/spec/activitypub which is itself an incomplete description. + +{{< mf2/h-cite +post-url = "https://socialhub.activitypub.rocks/t/socialwebfoundation-what-do-people-think/4564/36" +author = "socialhub.activitypub.rocks/eprodrom" +>}} +But protocols are about interoperability, and having incompatible protocols reduces interoperability. And protocol diversity is just not as important to me as connecting more people on the social web. +{{< /mf2/h-cite >}} + +If this were the entire argument, then I would (facetiously) say to just use SMTP. After all, SMTP has billions of users, which is far more than ActivityPub has. Why does ActivityPub exist when the same mechanisms could have been specified on top of SMTP? Isn't the existence of ActivityPub harmful to the email social network? + +Hopefully you can see why this argument doesn't (or shouldn't) make sense. Not even when you switch out the protocols for different protocols. + +If what truly matters is, as you say, "connecting more people on the social web", then I think we're going to have to come up with a definition for "social web" that we can agree upon. Because as it stands, the "social web" is more than just ActivityPub. And if the "social web" were limited to being just ActivityPub, and specifically limited to what current fediverse implementations do (or don't do) with ActivityPub, then that's not much of a "social web" and it doesn't exactly inspire hope for the future. + +Now, this isn't to say that we should throw away ActivityPub entirely. But I do think we need to broaden our horizons and think really hard about what makes up a "protocol", and which building blocks should be developed to form that "protocol". We have a lot of work to do. \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/replies/_index.md b/unified.test.hugo/content/_dump/replies/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/_dump/replies/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/replies/smartphones-arent-as-exciting-as-they-used-to-be/index.md b/unified.test.hugo/content/_dump/replies/smartphones-arent-as-exciting-as-they-used-to-be/index.md new file mode 100644 index 0000000..e144f73 --- /dev/null +++ b/unified.test.hugo/content/_dump/replies/smartphones-arent-as-exciting-as-they-used-to-be/index.md @@ -0,0 +1,25 @@ ++++ +indieweb_type = "reply" +title = "in response to \"You're not wrong -- smartphones aren't as exciting as they used to be\" from Android Police" +summary = "Honestly, phones really aren't even getting better anymore — they're getting worse since 2013. And the factors are mostly not technological — the technology continues to improve, of course. It's the corporate decisions that go into the making of the phones, which are based not on what makes a “better” phone, but on what they think will be most profitable. I want to call out [...]" +date = 2018-08-02T04:37:00Z +tags = ["capitalism", "technology", "mobile", "smartphones"] +inReplyTo = "https://www.androidpolice.com/2018/08/01/youre-not-wrong-smartphones-arent-exciting-used/" +original = "https://disqus.com/home/discussion/androidpolice/youre_not_wrong_smartphones_arent_as_exciting_as_they_used_to_be/#comment-4017813937" ++++ + +Honestly, phones really aren't even getting better anymore — they're getting worse since 2013. And the factors are mostly not technological — the technology continues to improve, of course. It's the corporate decisions that go into the making of the phones, which are based not on what makes a “better” phone, but on what they think will be most profitable. I want to call out a few specific quotes from this article and add my thoughts: + +> we've witnessed a consolidation of the phones themselves into ever-more similar permutations. And that's because we've largely solved the problems the early smartphone presented us [...] That is to say, our smartphones basically do all the stuff we want them to. And therein lies the rub: we're running out of meaningful problems for the phone to solve and, equally, out of meaningful flaws to correct in the phones themselves. Smartphones have matured enough as a product category and become so standardized that essentially all we're left with is optimization. + +One negative side-effect of this consolidation is that we've implicitly narrowed the scope of what we consider to be a “problem”. For all the early problems that are no longer problems, we didn't bother solving all of them — and some new problems were created and ignored. There are a lot of assumptions being made that simply aren't 100% true. If you look at the modern smartphone market, the overwhelming assumption is that everyone wants big phones and non-removable batteries. Trends like removing headphone jacks and adding notches spread throughout the industry, because making a good phone isn't enough anymore — the new stuff has to be “innovative” even in a sector where there isn't much more innovation to be had. The end result is that phones actually aren't as good as they could be for everyone. The worst assumption of them all is that every single potential user has exactly the same desires and same tastes, with minimal or negligible differences. + +> phones are becoming appliances [...] we all know what we want to do with our phones, it's just a question of which one best fulfills our needs. [...] phones break, they get outdated (a problem no company is keen to solve!), and they don't last forever on a charge. But solving these “problems” seems, if I'm to draw an analogy, is like trying to develop a car tire that never needs to be replaced. No one wants to, and even if they did, most of the potential solutions are probably unworkable. So, much like that tire, the smartphone has been relegated to annual, incremental improvements. It lasts longer, goes faster, and works better. + +You touch upon this here: companies are not keen to solve these problems because it would advantage the disparate users and disadvantage the company's profits. If the question is about which phone fulfills your needs, then companies are assuming those needs are basically the same, for billions of people, which simply isn't true. And if we were to properly examine the analogy of the car tire, then we can consider nonremovable batteries as nonremovable tires. Yes, we can develop tires or batteries that last longer — but they will eventually wear out. Imagine having to buy an entirely new car just because one tire's treads are worn out. Oh, and of course, the cars are all the same style — every single car is an SUV, no sedans; just like today's average phones have made the term “phablet” practically obsolete. All the cars are the same color and the same trim — black or white, maybe grey, and the interiors are all leather despite the fact that many users prefer cloth. + +> It's easy to understand why that sounds dull: because unless you're an engineer, it really is. Your phone five years from now will be a better version of what you have today. Cars have four wheels, smartphones have a touchscreen [...] Even as companies worth hundreds of billions of dollars work tirelessly to implement new technologies and make them better, what we have right now is basically really good, and it would be silly to change what's been an excellent product formula simply for the sake of doing so. Unfortunately, that means your next phone will probably be a lot like your current one, and so will the one after that, and probably the one after that, too. It's not exactly exciting, but no one said phones had to be. + +It's ironic that phones aren't exciting anymore (even to engineers, I'd daresay) — the marketing around each phone practically demands advertising every single phone as an exciting new product. And the product formula, as refined as it may be by now, is getting stale. But my biggest worry is that this formula is too restrictive; it's one thing to say that cars have four wheels and smartphones have touchscreens, but the current paradigms are far more specific than that. Smartphones aren't just touchscreens — they're massive slabs, with more and more glass, and no way to service them. Straying from this paradigm can't be done effectively, because the profitability margins have been squeezed thinner and thinner by the juggernauts leading the pack. + +My next phone might not be anything like my current phone, because phones like my current phone might very well cease to exist. I'm already using a phone from 2016, with legitimately ZERO similar options out of the 2017/2018 offerings. And the phone from 2016 was already a compromise, that I purchased in 2018. And without an easily-replaceable battery, I can't keep using this phone for more than another year or so, because the battery will inevitably degrade. To me, this is beyond unexciting — this is legitimately revolting. diff --git a/unified.test.hugo/content/_dump/replies/status-as-a-service/index.md b/unified.test.hugo/content/_dump/replies/status-as-a-service/index.md new file mode 100644 index 0000000..251daa6 --- /dev/null +++ b/unified.test.hugo/content/_dump/replies/status-as-a-service/index.md @@ -0,0 +1,18 @@ ++++ +inReplyTo = "https://www.eugenewei.com/blog/2019/2/19/status-as-a-service" +original = "https://www.eugenewei.com/blog/2019/2/19/status-as-a-service#comment-5c823ae54e17b6230bbb5137" +date = 2019-03-08T09:50:29Z +title = "in response to \"Status as a Service (StaaS)\" from Eugene Wei" +tags = ["capitalism", "social", "capital", "mastodon", "utility", "analysis"] +indieweb_type = "reply" ++++ + +Hmm. I must preface this comment by saying that I read this article as a Mastodon user, due to your brief mention of Mastodon within the article. But after having read the article, I would in particular make the distinction that there is less of a focus on copying the status game, and more of a focus on utility. Which is to say, I have made the observation that most people coming to Mastodon seeking an alternative to Twitter have generally followed one of two patterns: + +1) They find that the status game on Mastodon is lacking, or rather, intentionally de-emphasized by comparison, and so they go back to Twitter where they can proclaim to their followers that Mastodon sucks. + +2) They came to Mastodon seeking utility and an escape from the pervasive status game of Twitter, and thus they come to appreciate the fact that there are no ads, that timelines are chronological, that actual human moderators exist to deal with trolls and abusers, etc. + +Which isn't to say that Mastodon is in itself immune to social capital, but rather, that an emphasis on utility is to be expected or even necessary, if a network is to survive. Of course, there's the advantage that Mastodon's network is actually a network of networks similar to email, and so Mastodon's success or failure is instead bound to how well it allows its users to access that existing network. + +For a network that, for the past decade, has largely been against capital itself (including social capital), perhaps the main takeaway is that we should be building sustainable utility-driven solutions in order to counteract the necessity of relying on social capital. diff --git a/unified.test.hugo/content/_dump/shares/99985686693364517/index.md b/unified.test.hugo/content/_dump/shares/99985686693364517/index.md new file mode 100644 index 0000000..b016365 --- /dev/null +++ b/unified.test.hugo/content/_dump/shares/99985686693364517/index.md @@ -0,0 +1,16 @@ ++++ +indieweb_type = "repost" +date = "2018-05-07T02:35:00Z" +title = "I watched an entire Flat Earth Convention for my research – here’s what I learnt" +original = "https://theconversation.com/i-watched-an-entire-flat-earth-convention-for-my-research-heres-what-i-learnt-95887" ++++ + +> While flat earthers seem to trust [...] scientific methods, what they don’t trust is scientists [...] those in power control what is considered to be correct [...] According to Foucault, there is therefore an intimate [...] relationship between power and knowledge. + +> With the increased voice afforded by social media, knowledge has been increasingly decentralised, and competing narratives have emerged. + +> one of the physicists pleaded with the audience to avoid trusting YouTube and bloggers. The audience and the panel of flat earthers took exception to this, noting that “now we’ve got the internet and mass communication … we’re not reliant on what the mainstream are telling us in newspapers, we can decide for ourselves”. + +> Attendees were [...] warned against blindly trusting what they were told [...] “Don’t believe what I say, research what I say.” + +Overall a really interesting article. \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/social.md b/unified.test.hugo/content/_dump/social.md new file mode 100644 index 0000000..6b83b34 --- /dev/null +++ b/unified.test.hugo/content/_dump/social.md @@ -0,0 +1,83 @@ +is2g ifwhen i make my thing i am going to put a lot of effort into a filter system that actually makes sense. i will not be supporting "mute" or "block" as binary features, but rather, everything flows through the filter system. mastodon filter v2 system is an improvement but doesn't go far enough + +--- + +in any case yes it would be better to encrypt everything or just not peer/replicate at all. fedi has a problem with this because for some unknown reason we all decided it would be a convoluted distributed state machine which is a bad idea when you don't trust all participants, and also worse when those participants are explicitly redistributing it while attributed to you. at that point you might as well go all-in on syndication rather than federation. put another way: federation makes sense for message passing but not for publishing (and fedi is an awkward and unclear hybrid between messaging and publishing) + +--- + +idle thought: idk if i care so much about "fedi" as much as it is "people who are on fedi". either in the abstract or in the concrete, i just wanna make friends and talk to cool people. fedi is little more than a place for fateful encounters based on the streams of consciousness we put out there. the important thing is that no one meddles with this for profit or otherwise. the second fedi stops providing that, i'm out. + +it's a big part of why i don't really relate or sympathize with people who just want fedi to grow. i think any growth has to be sustainable. the values are valuable. if the values are compromised then fedi isn't valuable to me anymore. + +note that there's a big distinction between this and communicating with people you know. if some people are only on fedi then that has a different type of value. network value is not the same as the value of the network. + +it's always the people, i'm only here for the people. i do not want to keep track of the diplomatic politics of tens of thousands of nation-states. no one should! we made a wrong turn somewhere back in 2017 when people started making "community" instances, and arguably we were on the wrong path from the very beginning. maybe the whole thing is wrong tbh. we need to go back to actual forums. the ergonomics are all wrong. the model is wrong. we're just trying to mash everything roughly into the shape of twitter. and worse, every twitter has its own culture and community and is assumed to be homogeneous! how do you atomize all this? + +--- + +[asking natalie what should be removed or what is missing from misskey](https://mastodon.social/@trwnh/109958119755489250) + +
    + +i like that it's an outsider take on fedi and is not afraid to push boundaries and go beyond what mastodong has envisioned + +what's missing is muting/blocking actually being functional. i'd also like to see Room come back lol + +what should be removed: basically nothing. maybe proxy accounts. if i wanted minimal i'd go use some useless software like honk, misskey maximalism is actually really fun + +
    + +--- + +the general objection is "that's not how we currently federate", as if the way we currently federate should be preserved forever + +--- + +"relays" on fedi are like the worst possible interpretation of relays. imagine one big irc room that has no topic whatsoever. just thousands of people posting whatever they want. why + +also imagine your irc client had autologging turned on, and didn't have an easy way to clear specific logs + +--- + +this shit should be generic and it can be browsed by a social web browser or a linked data renderer + +i think it makes the most sense to lean into the Web and just focus on making the publishing as easy and straightforward as possible. i think most people (ideologues aside) don't actually want "federation" as commonly thought of. in absolute terms they want their posts to show up in a reader. + +there still is a place for federation, the "federation" i'm interested in is more like replication in a distributed database. and i'd like to link it all up across domains like "nomadic identity". + +example: imagine a network of generic servers + +your server shuts down, you walk up to any server that has your posts already, prove your identity, pick up like nothing happened + +basically you should be able to "claim" your federated profile on other domains, kind of like how on a centralized site you can claim your profile page if you're a celebrity or whatever + +nomadic identity is literally just doing this process yourself beforehand by setting up mirrors/replicas of your key + +--- + +i forget who it was that said "a single timeline is unsustainable" (aaron parecki?) but i'm feeling more like the real cardinal sin is publishing to a single profile. i don't mind *reading* everything in a single view, although making lists certainly helps. it's the *publishing* that annoys me. i almost *never* want to send a post to *all* of my followers. and this goes doubly for replies. i often want to reply within a specific context and only *optionally* tell my followers about it. + +"one account per feed" is a goddamn travesty. an account should be able to have multiple profiles, and a profile should be able to have multiple feeds, and you should be able to follow individual feeds instead of being forced to follow an entire profile. + +yeah, i was thinking similarly. except i was going to make Collections into actors that could be followed. which would be incompatible with mastodon, because mastodon assumes wrongly that actors must be exactly one of The Five Types. but then again, i am somewhat losing interest in this whole "social media" thing and would prefer to focus on a purer model of publishing web resources and managing them with collections. so maybe "mastodon compatibility" is not all it's cracked up to be... + +if anything, i was thinking of treating "mastodon compatibility" similar to a crossposter up until such point that mastodon relaxes or removes its unnecessary type-checking. you'd have an actor that you can send your activities to, and it will translate them into mastodon-flavoured activitypub and deliver out that translated copy. this actor would have its preferredUsername and all that compat stuff. + +--- + +btw i think that deletes being so costly is something that is entirely a consequence of having essentially replicated the data with a ttl of forever. that's the default mode of every "fedi" software. it makes no sense for most people and it stems from the ideological decisions of over a decade ago + +by which i mean: there's a word for having your published content be replicated to other sites, and it's "syndication". we had this technology for really simple syndication... rss. it later evolved into atom. the "fediverse" was founded on ostatus built on atom feeds. when we say we're "federating" we're really more accurately "syndicating". you just don't have control over the accounts being created on other domains, on your behalf. + +i keep talking about how the metaphors are wrong, like how we merged the concepts of publishing and messaging to the detriment of both. we're sending messages that contain the entirety of a resource that we meant to be published. of course it's going to lead to outcomes that don't make sense. maybe one day people will understand this + +also... authorized fetch won't solve this. if you have a password protected blog, and someone is saving every new post and republishing it, and you let this happen continually, then what's the point of the password? + +--- + +i think it's very important that users be able to understand and reason about the software that they are using! when it "does the thing", it should do so predictably. + +the argument for generic AP is that generic AP allows you to manage resources predictably, without having to care what others will do. it's a standardized storage layer. without it, you need a mastodon account, a pixelfed account, etc... every "platform" owns your data separately. + +imagine if switching from outlook to thunderbird necessitated losing all your emails and maybe even your contacts. \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/socialhub-threads/_index.md b/unified.test.hugo/content/_dump/socialhub-threads/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/_dump/socialhub-threads/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/socialhub-threads/dereferencing-non-https.md b/unified.test.hugo/content/_dump/socialhub-threads/dereferencing-non-https.md new file mode 100644 index 0000000..a597fa7 --- /dev/null +++ b/unified.test.hugo/content/_dump/socialhub-threads/dereferencing-non-https.md @@ -0,0 +1,127 @@ ++++ +title = "Dereferencing non-HTTPS URIs as `id`" +date = "2019-10-11" ++++ + +{{toc}} + +## Preserved text + + + +--- + +@trwnh: + +> 3.1 Object Identifiers +> +> All Objects in [ActivityStreams] should have unique global identifiers. ActivityPub extends this requirement; all objects distributed by the ActivityPub protocol MUST have unique global identifiers, unless they are intentionally transient […] These identifiers must fall into one of the following groups: +> +> 1. Publicly dereferencable URIs, such as HTTPS URIs, with their authority belonging to that of their originating server. (Publicly facing content SHOULD use HTTPS URIs). +> 2. An ID explicitly specified as the JSON null object, which implies an anonymous object (a part of its parent context) +> +> Identifiers MUST be provided for activities posted in server to server communication, unless the activity is intentionally transient. However, for client to server communication, a server receiving an object posted to the outbox with no specified id SHOULD allocate an object ID in the actor’s namespace and attach it to the posted object. +> +> All objects have the following properties: +> +> id +> +> The object’s unique global identifier (unless the object is transient, in which case the id MAY be omitted). +> +> type +> +> The type of the object. + +One thing I've wondered about is point 1 under 3.1 -- the id MUST be publicly dereferencable, with its authority belonging to the origin server... but it only SHOULD be https. + +So, does this mean that there are other possible choices for a publicly dereferencable id with proper authority, that *isn't* HTTPS? I assume that the intention was to suggest using HTTPS over HTTP (e.g. section 3.2 assumes HTTP GET and content negotiation, as well as headers and 403/404 error codes; section 5.1/5.2 specifies HTTP POST to outbox/inbox; Section 6 uses MUST for making an HTTP POST to actor outboxes and 201 codes), but my curiosity is with other URI schemes entirely. + +Perhaps one practical consideration (as there are various impractical ones, such as file://, ftp://, ftps://, sftp://, and so on) is to not use a URL but instead use a URN (such as doi, isbn, and other urn: URIs). Of course, this requires us to do a little more work to treat them as "dereferencable", such as by including a HTTPS proxy or some other resolver service. I wonder how that might be done, and whether this is at all worth pursuing. It could be used for deduplication, for example, by assigning a network-wide URN, with the authority deferred to the lookup service/proxy used as an instrument. + +--- + +@cwebber: + +> So, does this mean that there are other possible choices for a publicly dereferencable id with proper authority, that isn’t HTTPS? + +Yes and the [Golem demo](https://gitlab.com/spritely/golem/blob/master/README.org) shows exactly an example of this, using a (very-cut-down demo) of using [Datashards](https://datashards.net/) with ActivityPub (it was called “magenc” back then) to distribute activities. A similar example could be done with IPFS, for instance (though that doesn’t provide the privacy/security properties that Datashards does). + +Similarly, [bearcaps](https://github.com/cwebber/rwot9-prague/blob/bearcaps/topics-and-advance-readings/bearcaps.md) are a possible non-https URI scheme that we might use. + +[...] Wanting to support Tor Onion Services is a reason I explicitly pushed back against pressure to make the spec https-only, which some people wanted. + +--- + +@trwnh: + +I guess what I’m trying to comprehend the most would be, how would compatibility work between the HTTPS linked-data web, and the non-HTTPS documents? If we start passing around AP JSON-LD documents with non-HTTPS `id` then it would obviously break due to basically all implementations assuming that all they need to do is HTTP GET `id`. + +I remember reading the [RWoT paper about DIDs in ActivityPub](https://github.com/WebOfTrustInfo/rwot5-boston/blob/master/final-documents/activitypub-decentralized-distributed.pdf) and having the same confusion at the time about how it would work practically. The closest thing I could find was [`instrument`](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-instrument) in the AS2 Vocab, but that has a domain of `Activity` only, and is described as "Identifies one or more objects used (or to be used) in the completion of an `Activity`", so it would have to be redefined to work on `Object` as well. + +--- + +@rinpatch: + +Wouldn't an array of `id` work? + +--- + +@trwnh: + +Actually, multiple `id` seems interesting to me for a different thing: nomadic identity. Consider a case where an Object has multiple HTTPS URIs. + +That might not be the best way to do it, though. In fact, one shortcoming that is immediately apparent to me is the question of what to do if the document retrieved from one `id` is different from that retrieved from another `id`. So it would be better to have one canonical `id` only, where possible. But technically, the problem of differing documents can still happen, due to something as simple as a desync. + +[[future errata: this is what `alsoKnownAs` could be used for?]] + +I’d really like to focus on modeling how to dereference non-HTTPS in a way that is still roughly compatible with the HTTPS Web-based network. So far the following options have been mentioned: + +* `id` as Array; pick whichever one you understand. +* `url` as Array; pick whichever one you understand but leave `id` as HTTPS. +* just break compat and let implementations figure out how to resolve `id` (if they can) +* use a local proxy directly as `id` (technically still globally unique but represents change of authority) +* use a proxy Service as `instrument` (and extend `instrument` to be applied to `Object` and not just `Activity`) + +--- + +@how: + +I’m a bit concerned about extending to objects what could be done with creating an object-specifc actor acting as a proxy. The `instrument` service seems to be adapted to this use-case: you get a representation of the object’s metadata but must use the out of band service to retrieve the actual object. Best of both worlds? + +--- + +@nightpool: + +The ActivityPub standard does not define that any given server must support any one scheme. I don’t understand what the purpose of having it do so would be? it would just limit the flexibility of the protocol for no practical benefit (If two servers don’t support the same schemes, then they’re obviously not going to be able to talk to each other, MUST or no MUST) + +--- + +@trwnh: + +I think there’s probably mixing of concerns to treat non-HTTPS as primarily an issue of nomadic content; while there is *potential* application toward this, I think the incompatibility issue is probably more pressing in the long run. You can claim that a software is “compatible with ActivityPub”, but this is a statement that needs clarification and qualification. And this is also something that would become even more of an issue if ActivityPub is implemented via networks other than HTTP(S). + +In that sense, there is no “ActivityPub network” – there is only currently an “ActivityPub over HTTPS network” (using HTTPS ids), as well as a sub-network of “ActivityPub over HTTPS network, with WebFinger” (perhaps more colloquially referred to as “the Mastodon network”). + +Even if every (or the majority of) software implementation(s) moves to adopt `bear:` URIs as `id`, there is now still the question of which URI schemes are supported with the `u` parameter of the bearcap. The draft for bearcaps defines `u` as “The stable URL that the bearer capability URI is associated with for requests”, which is, again, not specifically HTTP(S). But even then, specifying a “stable URL” means that we are precluding URNs as a form of reference. + +As nightpool mentions: + +> If two servers don’t support the same schemes, then they’re obviously not going to be able to talk to each other + +So I guess my main concern is that so-called “ActivityPub” software will settle around the lowest common denominator or the most restrictive set of requirements for interoperability. I’d like to lessen that if possible, so that individual implementations have the option to explore alternative lookup strategies for other “publicly dereferencable” schemes without that implying a choice between “hard break in network compatibility” or “stuck using HTTPS for `id` because everyone else is”. Although a hard break might be desirable in some cases, e.g. “if you don’t understand bearcaps then you can’t interact with this object”. + +--- + +## current thoughts + +we've well and truly collapsed into the "https only" world by now. any attempt to use a different scheme represents a sort of netsplit. this is not all good or bad though; it just means that the only network we have is the World Wide Web. + +`alsoKnownAs` may be useful here as well: + +> i see a few possible approaches: +> +> 1. defer `alsoKnownAs` to mastodon's usage (concept 2, controlling the listed actor). define a new term `aliases` (pending name) to represent concept 1, different identifiers for the same subject. we might also define `subject` or some similar term to identify a "canonical" identifier? +> +> 1. defer `alsoKnownAs` to the DID core definition (concept 1, different identifiers for the same subject). implement a transitional period in which mastodon and other projects switch to a different mechanism more along the lines of rel-me. eventually deprecate the use of `alsoKnownAs` for determining rel-me. + +aside from that, the `instrument` idea still has some potential \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/socialhub-threads/exposing-edit-history.md b/unified.test.hugo/content/_dump/socialhub-threads/exposing-edit-history.md new file mode 100644 index 0000000..1690d2e --- /dev/null +++ b/unified.test.hugo/content/_dump/socialhub-threads/exposing-edit-history.md @@ -0,0 +1,24 @@ ++++ +title = "Notifying remote servers that they should refetch an object" +date = "2019-11-01" ++++ + +{{toc}} + +## Preserved text + + + +@trwnh: + +Per [expose edit history in ActivityPub representation · Issue #23292 · mastodon/mastodon · GitHub ](https://github.com/mastodon/mastodon/issues/23292) + +@Johann150 raises a feature request for being able to view earlier versions of an activity or object before an Update was received. In the case where an object is Created and then Updated, someone receiving the Update who didn’t receive the Create first would have no way of knowing what was contained in the original version. Someone fetching the object without having received either of the activities would be able to know that it was edited based on the presence of the `updated` property, but likewise would not be able to retrieve any additional information about previous versions. + +Looking at the existing Activity Vocabulary we see that the only existing way to do this would be in the case that `context` was published, although this requires that the context MUST be a Collection, and you would have to dig through all the items to filter for Update activities (plus the initial Create). Additional issues arise from the ordering of Collections not always being consistent, but in general you will still have to traverse the entire context collection. + +Therefore it likely makes sense to propose a new property called something like `history` or `revisions`. If there is any prior art or some existing specifications that could apply here, it would be helpful to know about them. + +## current thoughts + +idk \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/socialhub-threads/follow-arbitrary-collections.md b/unified.test.hugo/content/_dump/socialhub-threads/follow-arbitrary-collections.md new file mode 100644 index 0000000..1840bd0 --- /dev/null +++ b/unified.test.hugo/content/_dump/socialhub-threads/follow-arbitrary-collections.md @@ -0,0 +1,436 @@ ++++ +title = "Unresolved issues surrounding Follow activities" +date = "2019-10-10" ++++ + +{{}} + +## Preserved text + + + +
    +# First, some context… + +What the C2S spec says: + +> 6.5 Follow Activity +> +> +> +> The Follow activity is used to subscribe to the activities of another actor. +> +> +> +> The side effect of receiving this in an outbox is that the server SHOULD add the object to the actor’s following Collection when and only if an Accept activity is subsequently received with this Follow activity as its object. + +What the S2S spec says: + +> 7.5 Follow Activity +> +> +> +> The side effect of receiving this in an **inbox** is that the server *SHOULD* generate either an `Accept` or `Reject` activity with the Follow as the `object` and deliver it to the `actor` of the Follow. The `Accept` or `Reject` *MAY* be generated automatically, or *MAY* be the result of user input (possibly after some delay in which the user reviews). Servers *MAY* choose to not explicitly send a `Reject` in response to a `Follow` , though implementors ought to be aware that the server sending the request could be left in an intermediate state. For example, a server might not send a `Reject` to protect a user’s privacy. +> +> +> +> In the case of receiving an `Accept` referencing this `Follow` as the object, the server *SHOULD* add the `actor` to the object actor’s [Followers Collection ](https://www.w3.org/TR/activitypub/#followers). In the case of a `Reject` , the server *MUST NOT* add the actor to the object actor’s [Followers Collection ](https://www.w3.org/TR/activitypub/#followers). +> > Note +> > +> > +> > +> > Sometimes a successful `Follow` subscription may occur but at some future point delivery to the follower fails for an extended period of time. Implementations should be aware that there is no guarantee that actors on the network will remain reachable and should implement accordingly. For instance, if attempting to deliver to an actor for perhaps six months while the follower remains unreachable, it is reasonable that the delivering server remove the subscriber from the `followers` list. Timeframes and behavior for dealing with unreachable actors are left to the discretion of the delivering server. + +Special collections: + +> 5.3 Followers Collection +> +> +> +> Every [actor ](https://www.w3.org/TR/activitypub/#actors) *SHOULD* have a `followers` collection. This is a list of everyone who has sent a [Follow](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-follow) activity for the actor, added as a [side effect](https://www.w3.org/TR/activitypub/#follow-activity-outbox). This is where one would find a list of all the actors that are following the actor. The `followers` collection *MUST* be either an [ `OrderedCollection` ](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollection) or a [ `Collection` ](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collection) and *MAY* be filtered on privileges of an authenticated user or as appropriate when no authentication is given. +> > Note: Default for notification targeting +> > +> > +> > +> > The follow activity generally is a request to see the objects an actor creates. This makes the Followers collection an appropriate default target for [delivery](https://www.w3.org/TR/activitypub/#delivery) of notifications. +> +> +> 5.4 Following Collection +> +> +> +> Every actor *SHOULD* have a `following` collection. This is a list of everybody that the actor has followed, added as a [side effect](https://www.w3.org/TR/activitypub/#follow-activity-outbox). The `following` collection *MUST* be either an [ `OrderedCollection` ](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-orderedcollection) or a [ `Collection` ](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collection) and *MAY* be filtered on privileges of an authenticated user or as appropriate when no authentication is given. + +In summary… C2S Follow puts a Follow activity in your outbox, your server waits for an Accept, then adds that actor to following. S2S Follow takes a Follow activity in your inbox, your server wraps it in Accept/Reject and delivers that. S2S Accept Follow adds that actor to followers. (All of this is SHOULD language.) + +However, this leaves some things too ambiguous… + +# Following only a *subset* of activities + +By default, when you Follow an Actor, most implementations interpret that as a sign of interest in every single activity that the actor publishes, similar to the note in 5.3 (“The follow activity generally is a request to see the objects an actor creates.”). But there is no way to signal an interest in receiving only *some* of the activities. Perhaps the only possible concession here is the `streams` property of an actor, but there is basically nothing to guide implementations aside from a passing mention that is only 10 words long: + +> **streams** +> A list of supplementary Collections which may be of interest. + +This suggests a pull-based approach, where you can GET the `streams` of an actor… but you cannot have the actor deliver any activities from those streams. Nor is it explicitly defined whether these collections contain activities or objects, or what the collections are actually for (aside from heuristically guessing based on the name of the collection?) Perhaps there could be a way to consistently understand these collections and maybe follow just those streams instead of the actors, but that would require… + +# Following non-actor objects + +Per 6.5, “The Follow activity is used to subscribe to the activities of another actor.” But sometimes you don’t necessarily care what a single actor does with multiple objects, you care about what multiple actors are doing with a single object. + +AFAIK some implementations interpret Follow Object to generally mean that the software will deliver any activities targeting that object to any actor that has expressed interest through the Follow Object activity. Perhaps this should be formalized, as the following are currently not agreed upon: + +* Who should you send the Follow Object to? The `attributedTo` actor? Does following that object imply also following the actor? +* How should you keep track of followed objects? Should they be added to the `following` collection like actors? Should individual objects define a `followers` collection? +* How do you know if an object is followable? If you send a Follow Object to remote software, it may not understand it. Is the presence of a `followers` collection enough for this? Does it also need `attributedTo`? Some other method? + +# Practical applications + +As prior art, Google+ Collections come to mind. For each post made to Google+, a user could choose to address it to Public, or to selected users (like actors), or to a Circle (like a collection of actors), or to a Community (like a group), or to a Collection (like a category/stream). This could be seen as confusing since it wasn’t really well-explained to users what any of these concepts meant, and Google+ also used Circles both for addressing those users *and* for viewing posts from those users, whereas most other services have a separate Lists feature for viewing posts from a subset of users. In essence, users can categorize their posts at the same time as they choose who to address them to. Consider the following hypothetical documents: + +``` +{ +"id": "https://social.example/actors/1", +"type": "Person", +"inbox": "https://social.example/inboxes/1", +"outbox": "https://social.example/outboxes/1", +"followers": "https://social.example/actors/1/followers", +"streams": ["https://social.example/collections/1"] +} +``` + +``` +{ +"id": "https://social.example/objects/1", +"type": "Note", +"content": "a simple note", +"attributedTo": "https://social.example/actors/1", +"followers": "https://social.example/objects/1/followers" +} +``` + +``` +{ +"id": "https://social.example/collections/1", +"type": "OrderedCollection", +"items": ["https://social.example/objects/1"], +"followers": "https://social.example/collections/1/followers" +} +``` + +``` +{ +"id": "https://social.example/activities/1", +"type": ["Create", "Add"], +"actor": "https://social.example/actors/1", +"object": "https://social.example/objects/1", +"target": "https://social.example/collections/1", +"to": + [ + "https://social.example/actors/1/followers", + "https://social.example/objects/1/followers", + "https://social.example/collections/1/followers" + ] +, +"cc": ["as:Public"] +} +``` + +# Etc + +Any comments, additions, etc. about this? + +
    + +--- + +@trwnh: + +I should also add some discarded approaches that I considered at one point while thinking about this but determined to be too problematic: + +* interpreting a Follow as subscribing to multiple actors instead of just one +* multiple outboxes (although this might still be applicable to other problems, just not this one for now) +* using Profiles instead of Actors (though this could still be done, it would be unsupported in current implementations; it would however become possible to Follow Profile instead of Follow Actor) +* having objects just be made into actors, a la the concept of message passing in computer science (although this adds a lot of complexity because objects generally only need a small part of what Actor provides) +* hackily having multiple actors representing the same Person, but using them to create objects, then Announcing those from a more “central” actor (too complicated and unwieldy) + +--- + +@trwnh: + +Sure, but how should we discover this? + +As stated above I went with `attributedTo` and the presence of a `followers` property, but perhaps it may be better to use an explicit endpoint like `inbox`? + +--- + +@trwnh: + +It’s almost 3 years later and I think I’ve come around on this a bit – + +> As stated above I went with `attributedTo` and the presence of a `followers` property, but perhaps it may be better to use an explicit endpoint like `inbox`? + +I think explicit is better than implicit. All that’s required for an Object to be an Actor is to have `inbox` and `outbox`. The only issue with current language in the spec is that + +> The outbox stream contains activities the user has published, + +and semantically speaking actors are not equivalent to users, nor is the attribution required to match the same actor (or even *be* an actor – `attributedTo` can include another activity, for example). + +Where the previous approach fails is that the `followers` collection may not be included or published. The `followers` property is only a SHOULD and not a MUST. + +For delivery of the Follow activity, we can refer to the guidance on delivery: + +> The [inbox](https://www.w3.org/TR/activitypub/#inbox) is determined by first [ retrieving the target actor’s JSON-LD representation](https://www.w3.org/TR/activitypub/#retrieving-objects) and then looking up the `inbox` property. If a recipient is a `Collection` or `OrderedCollection`, then the server *MUST* dereference the collection (with the user’s credentials) and discover inboxes for each item in the collection. Servers *MUST* limit the number of layers of indirections through collections which will be performed, which *MAY* be one. + +Which, again, implies that we should just attach `inbox` on anything followable. And if we do that, then we should/must attach `outbox` as well to make it an actor (although in practice this may not be strictly required – it is possible to model having an inbox but no outbox, and some implementations might do this already in apparent violation of the spec). + +--- + +@macgirvin: + +I do recall when Mastodon first implemented ActivityPub and some folks were still using OStatus. In this case the inbox was set to NULL. We implemented AP at exactly the same time and this threw exceptions in my code. Was going to file a bug, but technically speaking I think it’s spec compliant. The language states that an actor must have the “following properties” and these records had the required properties, except they weren’t de-reference-able. In any case I consider this to be a legal interpretation and have code to handle it appropriately. + +A more serious issue is that we implement access permissions to several collections and these are not de-reference-able unless the requestor has permission to access the collection. The spec is incredibly weak where it comes to dealing with permissions, but I have every right to restrict access of a resource to anybody I desire - even if it means my software isn’t technically compliant. This makes the quoted section in your reply contentious. These are deliverable through the forward-to-owner sections referenced elsewhere in the spec so everything still works; but not all collections are de-reference-able by every actor that receives an activity — nor should they be. + +--- + +@trwnh: + +[quote="macgirvin, post:8, topic:114"] +In this case the inbox was set to NULL. +[/quote] + +Hmm. My interpretation is that `inbox` and `outbox` properties MUST be provided, but not necessarily be public. I’m not sure whether it makes sense to set `inbox` to `null` explicitly; is that not the same as excluding it? In any case, the practical implication of the current network (“ActivityPub over HTTPS”, or as I’ve taken to calling it recently, “ActivityPub over HTTPS with Webfinger and HTTP Signatures” :stuck_out_tongue: ) is that one can simply POST to an inbox IRI and have it either return successfully or error out with a 405 Not Allowed (if federation is not implemented). I’d be curious to hear any objections or concerns regarding this. + +[quote="macgirvin, post:8, topic:114"] +I have every right to restrict access of a resource to anybody I desire - even if it means my software isn’t technically compliant. +[/quote] + +I’m not sure if it’s technically “incompliant” to do so, but for what it’s worth, Pixelfed for example provides `inbox` for actors (currently equivalent to users, but under this proposal, it doesn’t have to be), and this `inbox` only supports POST and not GET, for obvious reasons – federation works by POSTing to the `inbox` and GET is only needed for C2S fetching your own inbox with authorization. That doesn’t seem like a problem to me; if anything, it seems natural since the inbox is only for delivery. Setting `inbox: null` or leaving it out implies that the object is not an actor, since it does not have both `inbox` and `outbox` (the only two required properties for actors). Aside from this heuristic, there doesn’t seem to be any other meaning to being an actor. So I would agree that yes, access to resources may be restricted without authorization. This doesn’t seem like an issue, although I may be misunderstanding or overlooking something. + +[quote="macgirvin, post:8, topic:114"] +This makes the quoted section in your reply contentious. These are deliverable through the forward-to-owner sections referenced elsewhere in the spec so everything still works; but not all collections are de-reference-able by every actor that receives an activity — nor should they be. +[/quote] + +Inbox forwarding could perhaps be applicable, but not any more so than it already is. + +To clarify, the assumed / proposed flow is something like this: + +1. I GET an actor at `https://example.social/actors/1` and see that their `streams` advertises `https://example.social/collections/1`: + +``` +GET https://example.social/actors/1 HTTP/1.1 +Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams" + +{ +"@context": [...], +"id": "https://example.social/actors/1", +"type": "Person", +"inbox": "https://example.social/inboxes/1", +"outbox": "https://example.social/outboxes/1", +"streams": ["https://example.social/collections/1"], +... +} +``` + +2. I want to `Follow` the `Collection` at `https://example.social/collections/1` for updates. (Let’s say this `Collection` is advertised within `streams` and represents some categorization of posts, similar to Wordpress categories or Google+ Collections. Its items contain some arbitrary objects like `Note`s that have been published within the category/stream.) +3. I perform `GET https://example.social/collections/1`, optionally with an HTTP Signature for my actor `https://ap.trwnh.com/actors/1`. The server responds with a `Collection` containing only the items I am authorized to see, based on the HTTP Signature attached. If no signature is attached, then only items with `audience: as:Public` will be returned (likewise for `to`/`cc`/etc if the server software uses those for addressing instead of `audience`). + +``` +GET https://example.social/collections/1 HTTP/1.1 +Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams" +Signature: keyId="https://ap.trwnh.com/actors/1/publicKey",... + +{ +"@context": [...], +"id": "https://example.social/collections/1", +"type": "OrderedCollection", +"totalItems": 1312, +"first": "https://example.social/collections/1?page=1", +"last": "https://example.social/collections/1?page=132", +"inbox": "https://example.social/inboxes/1", +"outbox": "https://example.social/outboxes/2" +} +``` + +4. From this response, I parse for the `Collection`’s `inbox` property. If it does not have one, I assume it cannot be followed. If it does have one, then I assume I can send a `Follow` there. In this example, `https://example.social/collections/1` has `inbox: https://example.social/inboxes/1`. (This happens to be the inbox for `https://example.social/actors/1`, but it doesn’t have to be. This is an implementation detail.) To follow the stream for updates: + +``` +POST https://example.social/inboxes/1 HTTP/1.1 +Content-Type: application/ld+json; profile="https://www.w3.org/ns/activitystreams" + +{ +"@context": [...], +"type": "Follow", +"actor": "https://ap.trwnh.com/actors/1", +"object": "https://example.social/collections/1" +} +``` + +5. The remote server then responds as per the individual implementation’s logic, e.g. with an `Accept Follow` + +This is of course open to different methods of access control, object capability delegation, etc. – the key point is that the followable object has an `inbox` to `POST` a `Follow`, which I prefer over heuristics like dereferencing `attributedTo` and looking for an `inbox` there. It is simpler to just provide the `inbox` directly. And you might as well provide an `outbox` too and make it a full-fledged actor, since being an actor doesn’t actually imply much. Neither `inbox` nor `outbox` has to be public, anyway – they just have to be there. + +One other addendum is that, last I looked into this, I saw some discussion around Friendica and Zap having or planning support for `Follow Note`, but I was not able to find how this support was implemented, if it was. + +--- + +@macgirvin: + +Interesting. Yeah, that all make sense. + +As I recall the rationale for inbox = null was a hint that an actor exists at this address, but it is only useful by some other protocol from ActivityPub. If you perform some alternate or broader scoped discovery (outside of AP) you might find that you can actually communicate with it. + +We perform Follow Note and if I recall Ignore Note as internal activities to indicate you want to see (or not see) notifications for this thread in the future. We currently don’t federate these activities - they’re strictly for internal use. The object is always the top-level post in a thread as these platforms default to conversation/threaded display. + +Oh and the comment about permissions wasn’t really about inbox/outbox but about recipient collections. We permit people to hide who is in their followers/following and circles/aspects collections if they don’t feel like sharing these with the world. These will return 403 if the owner doesn’t want anybody to see their contents. This affects the address de-duplication sections of the spec since these collections can only be expanded/iterated by their origin server. We do filter outbox contents based on the request http-signature but I think this is common practice. + +--- + +@trwnh: + +This may be off-topic but it’s worth pointing out that most projects I’m familiar with tend to respond with some valid JSON(-LD), but intentionally leaving out any details the author does not want visible. + +* Mastodon’s “Hide your network” option will return an `OrderedCollection` with the only useful property being `totalItems`. This is because Mastodon’s philosophy is to hide only the contents of the collection while still revealing metadata (presumably out of some concern for signaling “trustworthiness”, which to me seems flawed, but I digress): + +``` +GET https://mastodon.social/users/trwnh/followers HTTP/1.1 +Accept: application/activity+json + +{ + "@context": "https://www.w3.org/ns/activitystreams", + "id": "https://mastodon.social/users/trwnh/followers", + "type": "OrderedCollection", + "totalItems": 2482 +} +``` + +* Pixelfed currently does something similar, but intentionally “lies” and claims that there are 0 items while explicitly returning an empty array as the value: + +``` +GET https://pixelfed.social/users/trwnh/followers HTTP/1.1 +Accept: application/activity+json + +{ + "@context": "https://www.w3.org/ns/activitystreams", + "id": "https://pixelfed.social/users/trwnh/followers", + "type": "OrderedCollectionPage", + "totalItems": 0, + "orderedItems": [] +} +``` + +* Pleroma has separate toggles for hiding either the items or the count (or both). If the items are hidden, the `orderedItems` will simply not be present. If the count is hidden, the `totalItems` will simply not be present. If both are hidden, both properties will simply not be present. On a UX level, hiding the counts requires hiding the items, because hiding only the count leaves you open to manually counting the items yourself. + +``` +GET https://letsallovela.in/users/at/followers HTTP/1.1 +Accept: application/activity+json + +{ + "@context": [...], + "first": "https://letsalllovela.in/users/at/followers?page=1", + "id": "https://letsalllovela.in/users/at/followers", + "type": "OrderedCollection" +} +``` + +* Misskey does the same thing as what you described: 403 Forbidden. + +--- + +@trwnh: + +In any case, I don’t think that the spec necessarily intended to have the *sender* dereference follower collections for other actors – rather, that role falls on the *receiver*, and the logic/rationale is as described in the Inbox Forwarding section, “avoiding ghost replies”: + +> When Activities are received in the [inbox](https://www.w3.org/TR/activitypub/#inbox), the server needs to forward these to recipients that the origin was unable to deliver them to. To do this, the server *MUST* target and [deliver](https://www.w3.org/TR/activitypub/#delivery) to the values of `to`, `cc`, and/or `audience` if and only if all of the following are true: +> +> * This is the first time the server has seen this Activity. +> * The values of `to`, `cc`, and/or `audience` contain a Collection **owned by the server**. +> * The values of `inReplyTo`, `object`, `target` and/or `tag` are objects **owned by the server**. The server *SHOULD* recurse through these values to look for linked objects **owned by the server**, and *SHOULD* set a maximum limit for recursion (ie. the point at which the thread is so deep the recipients followers may not mind if they are no longer getting updates that don’t directly involve the recipient). The server *MUST* **only target the values of `to`, `cc`, and/or `audience` on the original object** being forwarded, and **not pick up any new addressees** whilst recursing through the linked objects (in case these addressees were purposefully amended by or via the client). +> +> The server *MAY* filter its delivery targets according to implementation-specific rules (for example, spam filtering). + +Essentially, inbox forwarding is a failsafe that allows a sender to say “look, here’s the Activity, I don’t know what this collection contains, so you deal with it, since it’s ostensibly under your authority.” This is why the “owned by the server” language is used multiple times in the above quoted section. Replying to, tagging, or performing an activity with the (locally owned) actor should trigger some discovery behavior. I must admit I find this recursive discovery behavior a bit problematic, although it is easier to swallow if you take it to mean “remote server implementations may notify / deliver to local actors that you reply to, tag, or act upon”. Perhaps it makes sense to notify someone if they were tagged or replied to, even if they were not explicitly addressed. Perhaps the implication is that they should be careful while doing so to not expand the scope of delivery. Perhaps the language in this third bullet point is simply bad language or bad guidance. + +With that said, what matters for the purpose of inbox forwarding is that, if you are delivering to someone else’s followers collection, then the sender needs to know how to refer to the `followers` IRI. But `followers` as a property is only a SHOULD and not a MUST. And I guess the “spam filtering” clause above also opens the door to implementations simply choosing *not* to forward to someone else’s followers. (I think Mastodon does indeed filter out activities delivered to someone else’s followers collection, based on a friend’s testing, but I can’t remember for sure.) Anyway, a server that only implements S2S and not C2S might as well leave out the `followers` and `following` entirely, for privacy purposes. I don’t think this would break anything – if it does, that points to bugs in existing implementations. (Okay, it might break sharedInbox.) + +One other tangent about inbox forwarding and addressing in general, that I might follow up on in another topic: I wish implementations would use `audience` more. It should be standard behavior to comment on someone’s post and address them, plus the value of `audience` (plus any other arbitrarily mentioned/added people, plus maybe your own followers). The audience of a post should be used even above `to`/`cc`, because to me `audience` carries human semantics while `to`/`cc`/`bto`/`bcc` are for server communication. For S2S purposes, the server implementation is actually free to deliver several slightly different activities to different inboxes, and in the case of `bto` and `bcc` this differing behavior is actually required. This, combined with the previous paragraph, leads to an issue where one may target their own `followers` collection without actually advertising it as their `followers` collection. I’m not sure what kind of undefined behavior that would lead to… it’s things like this that make me think sharedInbox was a mistake. + +--- + +@macgirvin: + +This whole clause is about “conversational delivery” ; which is completely different from microblog use. We use conversational delivery so I understand it very well. This is the two fediverses problem I speak about quite often. + +I’ll put it in very simple terms. We have the Twitter fediverse and the Facebook fediverse. The protocol supports the Facebook fediverse through inbox forwarding but Twitter-like projects don’t understand it and do things that break the Facebook fediverse. We can get along together but the first step is acknowledging that both models exist and learning how to implement both. The Facebook fediverse is important for things like private groups (ok “restricted”) and circles (restricted collections), so Twitter-like projects can get some benefit from supporting both. + +And we can implement both. In the Facebook fediverse all comments to a restricted (not public) post go back to the sender of the top-level post and to nobody else. The actor that sent the top-level post delivers the comments downstream to all of the original recipients of the top-level post - and to nobody else. If it’s a public conversation commenters can send to whoever they want. This is the secret sauce that makes restricted conversations work. + +In this model the sender of the top-level post is the only delivery authority for the entire threaded conversation. Now realise that this section was added to ActivityPub so that Facebook-like projects such as Friendica, Diaspora, and Hubzilla could exist in an ActivityPub fediverse, but the people writing the spec were nearly all from the Twitter side of the fediverse and to this day the Twitter side doesn’t recognise that the Facebook side exists and has a different addressing/delivery model than they do. + +It seems from your reply that conversational delivery is a bit alien to you as well. No worries. I’ve proposed a mechanism to let everybody know for any given conversation which model to use. It’s pretty simple and uses ‘replyTo’ and works the same as email’s reply-to. If it’s set, that’s who you reply to - and you don’t cc or deliver to anybody else; and you also copy that replyTo to your own comment before sending. If it isn’t set, send your comment to whoever you want. Twitter-like projects will never set it except maybe in circles/aspects or private/restricted groups. Facebook-like projects will probably always set it except maybe in public conversations when their posts benefit from exponentially widening reach. And everybody lives happily ever after in the same fediverse. We support this today. + +--- + +@trwnh: + +Small point of contention: “Twitter fedi” projects like Mastodon implement inbox forwarding, but they don’t make it the main mechanism of delivering replies in the same way that “Facebook fedi” projects expect to redistribute comments. + +I am familiar with that model, and in fact Dennis Schubert proposed it some years back in criticism of the “twitter fedi” approach – [ActivityPub - one protocol to rule them all? - Dennis Schubert ](https://overengineer.dev/blog/2018/02/01/activitypub-one-protocol-to-rule-them-all.html#replies-and-interactions) proposed back in 2018 that “Alice’s host is the one who delivered the shareable, so it feels somewhat natural to also ask Alice’s host to distribute the interactions […] a more sensible, reliable, and even more AcitivityStream’y way of handling replies would probably be adding the interaction to the replies collection and sending an `update`”. Whether the original activity is forwarded or whether an Update is sent doesn’t particularly matter to me, since the model works the same either way – your interaction exists in context of some top-level object. + +In fact, we could be more explicit with this model by using the `context` property (which sadly goes largely unused on “twitter fedi”). If a post has a `context` of another post, it is a comment (Facebook-style). Otherwise, it is just a post (Twitter-style). These (Twitter-style) posts can exist in context of a Collection representing a conversation, or they can exist in a null context. + +> I’ve proposed a mechanism to let everybody know for any given conversation which model to use. It’s pretty simple and uses ‘replyTo’ and works the same as email’s reply-to. If it’s set, that’s who you reply to - and you don’t cc or deliver to anybody else; and you also copy that replyTo to your own comment before sending. If it isn’t set, send your comment to whoever you want. + +Hmm, I guess this makes sense as a mechanism – it’s like a more explicit version of `context`. Prior to this conversation I would have probably proposed something like the following algorithm: + +1. Try to resolve `context` and check for `attributedTo`. +2. Resolve everything in `attributedTo` and deliver to any `inbox` found. +3. If there was no `context.attributedTo` or no actors/inboxes could be found, or if there was no `context`, then deliver your reply to whomever (your followers, as:Public, etc). + +Again, though, I’m not sure if `context.attributedTo.inbox` is the best approach here. At least `replyTo.inbox` saves a lookup step, and allows delivering to different actors, which would allow modeling anonymous objects. + +As far as `context` goes, though, it would probably be a good idea to assign `context` = the top-level post (Facebook-style) or `context` = some Collection representing the conversation or thread, and then copy the `context` as-is when replying/commenting. + +Perhaps an algorithm which supports both `context` and `replyTo` would look like this in pseudocode: + +``` +# Determine to/cc addressing +if "replyTo" in activity: + to = [ + actor["inbox"] + for actor in activity["replyTo"] + if "inbox" in actor + ] + +elif ( +"context" in activity +and "attributedTo" in activity["context"] +): + to = [ + actor["inbox"] + for actor in activity["context"]["attributedTo"] + if "inbox" in actor + ] + +else: + to = ACTOR["followers"] + PUBLIC + +# Copy any values that should be copied +if "replyTo" in activity: + replyTo = activity["replyTo"] +if "context" in activity: + context = activity["context"] +``` + +--- + +@macgirvin: + +We also use context as you’ve described - but recently a number of new projects have started using context for other things than conversation ids. Fetching our context in fact returns a collection of the entire threaded conversation as seen by the root node - which is something I also wish more projects supported. But now that folks are doing other things with context and we also still have folks using them with OStatus semantics (which aren’t de-reference-able) I suppose we’ll eventually have to come up with a different cross-platform way of fetching the entire conversation. Oh well. + +Cheers. + +## current thoughts + +i plan to synthesize several things here -- a collection that could also be an actor, and maybe set as context. see FEP-7888 and a future FEP for that i guess \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/socialhub-threads/note-vs-article-distinction.md b/unified.test.hugo/content/_dump/socialhub-threads/note-vs-article-distinction.md new file mode 100644 index 0000000..ea075d0 --- /dev/null +++ b/unified.test.hugo/content/_dump/socialhub-threads/note-vs-article-distinction.md @@ -0,0 +1,159 @@ ++++ +title = "Resolving the Note vs. Article distinction" +date = "2019-11-01" ++++ + +## preserved text + +
    + +# Background + +[Activity Vocabulary - 3.3 Object Types ](https://www.w3.org/TR/activitystreams-vocabulary/#object-types): + +> **Note**: Represents a short written work typically less than a single paragraph in length. +> **Article**: represents any kind of multi-paragraph written work. + +Example 48 (Article): + +``` +{ + "@context": "https://www.w3.org/ns/activitystreams", + "type": "Article", + "name": "What a Crazy Day I Had", + "content": "
    ... you will never believe ...
    ", + "attributedTo": "http://sally.example.org" +} +``` + +Example 53 (Note): + +``` +{ + "@context": "https://www.w3.org/ns/activitystreams", + "type": "Note", + "name": "A Word of Warning", + "content": "Looks like it is going to rain today. Bring an umbrella!" +} +``` + +Semantically, the difference is never explicitly defined (how do you define a “paragraph”?), so the current fediverse has sort of assumed Article should be viewed natively on the remote website, while Note can be displayed as an inline status. Thus, Note is used to represent a status update, and a lot of the network just defaults to Note. The distinction is assumed to be formatting, but once again this is not an explicit definition (how do you define “formatting”?) + +# Disambiguation + +Going purely from the Activity Vocabulary descriptions and examples, I would possibly assume one or both of the following: + +* Note SHOULD be plain text, Article SHOULD use HTML (or should these be a MUST?) +* Note SHOULD NOT use newlines (but are technically allowed to do so) + +However, there is [ActivityPub 3.3 ](https://www.w3.org/TR/activitypub/#source-property), Example 8: + +``` +{ + "@context": ["https://www.w3.org/ns/activitystreams", + {"@language": "en"}], + "type": "Note", + "id": "http://postparty.example/p/2415", + "content": "

    I really like strawberries!

    ", + "source": { + "content": "I *really* like strawberries!", + "mediaType": "text/markdown"} +} +``` + +This example Note uses HTML for its `content`, in order to demonstrate the `source` property. + +Also, ActivityPub Example 4: + +``` +{"@context": "https://www.w3.org/ns/activitystreams", + "type": "Create", + "id": "https://chatty.example/ben/p/51086", + "to": ["https://social.example/alyssa/"], + "actor": "https://chatty.example/ben/", + "object": {"type": "Note", + "id": "https://chatty.example/ben/p/51085", + "attributedTo": "https://chatty.example/ben/", + "to": ["https://social.example/alyssa/"], + "inReplyTo": "https://social.example/alyssa/posts/49e2d03d-b53a-4c4c-a95c-94a6abf45a19", + "content": "

    Argh, yeah, sorry, I'll get it back to you tomorrow.

    +

    I was reviewing the section on register machines, + since it's been a while since I wrote one.

    "}} +``` + +This example Note uses two `

    ` elements, representing two short paragraphs (once again not “less than a single paragraph”). + +So even the specs themselves are inconsistent on any distinction. + +# How much does this actually matter? + +Arguably not much, since implementations often convert Note and Article into their own internal schema for statuses anyway. But it could still be beneficial to set a clearer distinction going forward on how these types should be assigned, ideally. + +

    + +--- + +@lanodan: + +The distinction I make between Article and Note isn’t related directly to it’s content but on how it’s supposed to be presented and used, Articles are more things for blogs where you have about a post per day and so articles should be easy to find back with a list of articles/tags and maybe a bit of search features, Notes are more stuff like microblogging where you can easily have hundreds in a day and aren’t that easy to find back even with good keywords in full text search. + +Also I find that formatting is actually very useful for notes because it allows to express more/equivalent with less (like a word-list vs a paragraph). + +This question goes a lot in the fediverse because they are the two mainly used activity types but one could also ask about the actor distinction between Organisation and Group, Application and Service. And so far I’ve only seen ActivityPub Document be used in the wild for Images with textual description (like if Image couldn’t have it in the first place), but Document has no inherent meaning either. + +Note: Pleroma keeps the distinction between Articles and Notes internally, no real differencies for the Mastodon API though but there could be a query filter. + +--- + +@trwnh: + +For prior art, I can think of semantic HTML’s `
    ` being a section of HTML that can be reproduced elsewhere in its entirety. + +W3Schools: "independent, self-contained content. An article should make sense on its own and it should be possible to distribute it independently from the rest of the site." + +MDN: "a self-contained composition in a document, page, application, or site, which is intended to be independently distributable or reusable e.g. in syndication." + +This could be a distinction worth making, maybe? that an Article should roughly map to an `
    `, whereas a Note is just arbitrary text? + +--- + +@nightpool: + +I think using `Article` is a perfectly fine solution for when the desired semantics are “I think it’s better in a short-form microblogging context to display a link to this thing rather then the full content itself”. + +When considering that some clients (especially native clients) often won’t support increasingly rich text formatting, I think using Article vs Note for content where you think plain-text fallback is unacceptable is a totally fine decision to make. (But you shouldn’t ignore the fact that it’s probably likely that people are going to write long-form clients that *do* support Articles but don’t support every possible type of rich text formatting, like the way RSS readers restrict allowed formatting for readability) + +--- + +@trwnh: + +I can’t remember where this was said to me, but I think someone (maybe nightpool?) suggested that Note could be used for message passing a la Discord, which would be a third distinction and perhaps better than length/newlines or plaintext (as explained previously why those are inconsistent). So in that case, we could say Note vs. Article is one of *formality*. IMO this could complement the Article-to-`
    ` suggestion above. + +Taken together: + +* Note = for informal message-passing +* Article = for publication or syndication + +The only thing unresolved with this distinction would be the blurry line that is microblogging. Microblogs are often both informal *and* intended for republishing in feeds. It’d be pretty clear-cut to use Note for a messaging application and Article for a blogging platform, but… perhaps this implies top-level microblogging posts should be an `Article` and replies should be `Note`? Or that they should all be `Article` regardless of the fact that they are informal? There’s still room for discussion there. + +--- + +@darius: + +I think this is right on the money. My main use case for Article is that it’s a way to say that “this is a publication” – I’ve often talked about how this might actually help solve the “quote-tweet” design problem in Mastodon (and presumably other software). If an Article is something that is formal and published then it’s also something that can reasonably be commented upon. Articles can be quoted-commented, and Notes cannot. So I can dunk on a New York Times article, but not on a random thing someone posted as a note. + +Edited to add: for composing posts on a microblogging service, I wonder if a “people can quote-comment on this post” checkbox or whatnot could be, at its most basic, a switch that underneath it all changes type for your post from Note to Article. + +--- + +@trwnh: + +quoting and commenting is kind of out-of-scope and it’s up to each platform to decide how they want to handle it, tbh. from a data view, it doesn’t really matter because you can put whatever you want in `content`, and `inReplyTo` is just metadata (like `tag`). You can have an Article inReplyTo another Article, just as you can have a Note inReplyTo another Note (or a Note inReplyTo an Article, or even vice-versa, etc etc.) + +the thing is, though, that it’s really seeming like if we use “syndication” as the distinction, then that would imply a lot of things that are currently Note might be better conceived of as Article. + +--- + +## current thoughts + +i wrote a whole thing abt this [here](https://trwnh.com/wiki/tech/spec/activitypub/confusion/note-vs-article/) \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/socialhub-threads/notification-to-refetch-object.md b/unified.test.hugo/content/_dump/socialhub-threads/notification-to-refetch-object.md new file mode 100644 index 0000000..8bffb3b --- /dev/null +++ b/unified.test.hugo/content/_dump/socialhub-threads/notification-to-refetch-object.md @@ -0,0 +1,60 @@ ++++ +title = "Notifying remote servers that they should refetch an object" +date = "2019-11-01" ++++ + +{{toc}} + +## Preserved text + + + +@trwnh: + +[quote="trwnh, post:1, topic:259, full:true"] +S2S Update: + +> 7.3 Update Activity +> +> For server to server interactions, an `Update` activity means that the receiving server *SHOULD* update its copy of the `object` of the same `id` to the copy supplied in the `Update` activity. Unlike the [ client to server handling of the Update activity ](https://www.w3.org/TR/activitypub/#update-activity-outbox), this is not a partial update but a complete replacement of the object. +> +> The receiving server *MUST* take care to be sure that the `Update` is authorized to modify its `object` . At minimum, this may be done by ensuring that the `Update` and its `object` are of same origin. + +Presumably sending something like this over S2S would just get the object replaced by an empty copy: + +``` +{ + "@context": "https://www.w3.org/ns/activitystreams", + "id": "https://example.com/activities/1", + "type": "Update", + "actor": "https://example.com/actors/1", + "object": "https://example.com/objects/1" +} +``` + +So how would this update/refetch notification be done properly? +[/quote] + +--- + +@nightpool: + +wait, what? why would the example posted not be compliant? The two representations (including an IRI to dereference vs including an embedded object) should be identical on the JSON-LD level. + +I agree that the spec might expect you to inline the object, but I absolutely disagree that it requires it. + +--- + +@kaniini: + +I agree with nightpool, a bare IRI is completely fine here. + +--- + +@trwnh: + +OK, then. If a bare IRI is fine, then the next question would probably be how this would be handled in existing implementations. If an ActivityPub implementation were to hypothetically use Update in this manner, would it be received and handled properly? + +## Current thoughts + +needs testing or review, but should be possible imo. and if it's possible then maybe it could be expected? \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/socialhub-threads/signaling-side-effects-async.md b/unified.test.hugo/content/_dump/socialhub-threads/signaling-side-effects-async.md new file mode 100644 index 0000000..5398236 --- /dev/null +++ b/unified.test.hugo/content/_dump/socialhub-threads/signaling-side-effects-async.md @@ -0,0 +1,82 @@ ++++ +title = "Signaling side effects asynchronously by generalizing Accept/Reject" +date = "2019-10-11" ++++ + +{{toc}} + +## Preserved text + + + +
    + +# Background + +Per S2S (since Accept/Reject are not described in C2S): + +> 7.6 Accept Activity +> +> The side effect of receiving this in an **inbox** is determined by the type of the `object` received, and it is possible to accept types not described in this document (for example, an `Offer` ). +> +> If the `object` of an `Accept` received to an **inbox** is a `Follow` activity previously sent by the receiver, the server *SHOULD* add the `actor` to the receiver’s [Following Collection](https://www.w3.org/TR/activitypub/#following). +> +> 7.7 Reject Activity +> +> The side effect of receiving this in an **inbox** is determined by the type of the `object` received, and it is possible to reject types not described in this document (for example, an `Offer` ). +> +> +> +> If the `object` of a `Reject` received to an **inbox** is a `Follow` activity previously sent by the receiver, this means the recipient did not approve the `Follow` request. The server *MUST NOT* add the `actor` to the receiver’s [Following Collection](https://www.w3.org/TR/activitypub/#following). + +Note that for S2S purposes, Accept/Reject is only really defined for Follow activities. Per the Activity Vocabulary, it is also implicitly appropriate for `Offer` and `Invite`, but also [Example 10](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-accept) shows a much more ambiguous Accept Person targeting Group, which seems semantically awkward. + +# Possible generalizations + +Currently, the majority of the network uses Accept/Reject only for Follow on an Actor, and thus Accept/Reject is used only in that narrow definition. But there are other Activities that might require these semantics… + +## Accept/Reject Join + +Closed-membership `Group` semantics is maybe the most obvious benefit of generalizing Accept/Reject. It is of course possible to both Follow and Join a Group; Follow Group would semantically translate to being interested in what the Group posts to its outbox, as per the base AP spec. Some softwares handle Group membership based on its `followers`, but this is a bit of a hacky way to do things that is motivated by compatibility with the existing “Follow Actor” network. A much more semantic way to handle things would be to allow Join/Leave Group, but then Join would need Accept/Reject to allow modeling closed groups (at least, in a way different than just using the `Group` `followers` with `manuallyRequiresApproval` + `Announce` any activities received at `inbox` – which is still a valid way of doing things for “mailing list” use cases). This would be clearer than Accepting a Person into a Group. + +## Accept/Reject Create + +When sending a Create to a remote server, there will generally be side effects interpreted by that remote server’s software. One common example is that sending Create Note with `inReplyTo` may attach your Note as a reply to another Note. But this is not guaranteed to happen, e.g. if the remote software has a concept of “disabled comments” or “approved comments”. In that case, the remote software may want to signal that the use of `inReplyTo` will not automatically cause side effects to be processed, in the same way Follow must first be Accepted or Rejected. It might not make sense to explicitly *require* Accept/Reject semantics for such a case (as they are for Follow), but they can still be used for hinting the result. + +## Accept/Reject Update/Add/Remove/Delete + +In cases where an actor is performing actions on an object other than creating it, these actions may require approval from another actor who “owns” or “manages” that object. You may want to Accept an Offer of an Update, but it would be simpler to just Accept the Update. Per the AP spec, the only considerations made are as follows: + +7.3 Update: + +> The receiving server *MUST* take care to be sure that the `Update` is authorized to modify its `object` . At minimum, this may be done by ensuring that the `Update` and its `object` are of same origin. + +7.4 Delete: + +> (assuming the `object` is owned by the sending actor / server) + +7.8 / 7.9, Add/Remove: + +> * the `target` is not owned by the receiving server, and thus they can’t update it. +> * the `object` is not allowed to be added/removed to the `target` collection for some other reason, at the receiver’s discretion. + +So we have some guidance toward the “receiver’s discretion”, but no formal way of signaling that discretion back to the author of the received activity. + +# But why not just use HTTP status codes? + +HTTP status codes are synchronously returned at the time of the request, even if the request is handled asynchronously. You may send out a `202 Accepted` to indicate that the document was successfully received, but later send out a `Reject` Activity after some manual action was taken by an actor. This manual action may be performed long after the initial delivery to the remote server. +[/quote] + +
    + +--- + +@nightpool: + +I think this is a good idea, but i would like to see some implementor support before defining it further. + +--- + +## current thoughts + +yeah, actually. let's do it \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/socialhub-threads/stricter-spec-for-collections.md b/unified.test.hugo/content/_dump/socialhub-threads/stricter-spec-for-collections.md new file mode 100644 index 0000000..fc4f4da --- /dev/null +++ b/unified.test.hugo/content/_dump/socialhub-threads/stricter-spec-for-collections.md @@ -0,0 +1,114 @@ ++++ +title = "Stricter specifications for pagination of Collections and OrderedCollections" +date = "2022-11-05" ++++ + +## Preserved text + + + +@trwnh: + +
    + +## Overview + +ActivityPub primarily depends on direct delivery of activities, but many implementations expose old post history via the `outbox`. In theory, you could fetch the outbox to discover old posts that weren’t delivered to you but should still be visible to you (e.g. Public posts that persist in the outbox). However, there is one big problem: pagination. + +Specifically, pagination is an issue because you will have to fetch multiple pages, and you don’t know exactly when to stop, or how to discover gaps. You may be able to fetch up until you see a post that you already have, but there may be other unseen posts beyond that one. The only way to be sure is to fetch every single page of the outbox, which can be a costly operation. + +## Recommendations + +Arguably, this situation can be improved by making some specific recommendations: + +### Construct chronologically, but present in reverse order + +Because an OrderedCollection is mandated to be “reverse chronological” specifically, extra care needs to be taken to allow stable page references. Perhaps pages should be built chronologically and simply presented in reverse order, crucially with the `first` page containing less than than the max page size. + +Example: A page size of 10 and a collection of 23 items should be split into pages of 3, 10, 10. These pages would be presented as such: + +``` +[ +[23 22 21] +[20 19 18 17 16 15 14 13 12 11] +[10 9 8 7 6 5 4 3 2 1] +] +``` + +### Stable page references should also be reversed + +Furthermore, in order to maintain stable page references, such that if you’ve fetched a page before you don’t have to fetch it again, page counters should be assigned in reverse order as well. + +Taking the example from above, the pages would be identified as 3, 2, 1: + +``` +[ +[23 22 21] // page 3 +[20 19 18 17 16 15 14 13 12 11] // page 2 +[10 9 8 7 6 5 4 3 2 1] // page 1 +] +``` + +### Deleted items should either be Tombstoned or change the page size + +All this work is useless if the pages have to be recalculated or the items get shifted to a different page. To prevent this, either serve a Tombstone in place of deleted items, or otherwise freeze the upper and lower bound of a page while allowing variable page sizes. + +For example, let’s say we delete post 17. The result might look like this: + +``` +[ +[23 22 21] // page 3 (3 items) +[20 19 18 T 16 15 14 13 12 11] // page 2 (10 items, 1 Tombstone) +[10 9 8 7 6 5 4 3 2 1] // page 1 (10 items) +] +``` + +Or, it might look like this: + +``` +[ +[23 22 21] // page 3 (3 items) +[20 19 18 16 15 14 12 11] // page 2 (9 items) +[10 9 8 6 5 4 3 2 1] // page 1 (10 items) +] +``` + +Notice that page 3 remains unchanged, rather than item 21 becoming part of the 2nd page. + +### Accessing pages should be done in a consistent way + +The final piece of the puzzle is a way to consistently load specific pages. For example, consider a collection at `/collection/id`. You might be able to attach a query parameter `?page=N` to access the Nth page via `/collection/id?page=N`. Or you might have some route such as `/collection/id/page/N`. Whatever the case, there should be a way of getting pages that can be expected to work across all implementations. Or, at the very least, a way that may be inferred easily, but a standard pagination technique would be better. + +My thinking is that `/page/N` would be better, because it would allow for static pages as an option more easily, + +Also for consistency: Tombstone is preferable to exclusion, because it allows dynamic page sizing on-the-fly in dynamic servers that use query parameters. + +
    + +--- + +@silverpill: + +Perhaps a timestamp filter could solve this problem? +For example, `/collection/id?after=1667766000` can return a paginated subset of the collection, and if the client knows the time of the last sync, it can retrieve missing objects with fewer requests. +This way implementations can continue to use their preferred pagination mechanism. + +--- + +@trwnh: + +Having a timestamp filter might work for dynamic server implementations but not for static server implementations. I took care in making sure, while writing the above post, that the recommendations would be applicable to both static and dynamic servers. + +--- + +@trwnh: + +in writing this up i seem to have overlooked the `startIndex` property of OrderedCollectionPage, which is basically just a positive offset for how far into the OrderedCollection you are with the first item. unfortunately this is less useful due to reverse chronology being mandated by ActivityPub; it would be far more useful in a forward-chronological collection. it also doesn’t apply to regular CollectionPage sadly. + +there is still the option of having a regular Collection contain OrderedCollectionPage, though, or otherwise simply disregarding the “MUST be reverse chronological” bit and committing a spec violation. + +--- + +## current thoughts + +idk. really wish the OrderedCollection wasn't mandated to be reverse-chron and it was instead forward-chron at least. this carries over to OrderedCollectionPage too... \ No newline at end of file diff --git a/unified.test.hugo/content/_dump/webfinger-as-dns.md b/unified.test.hugo/content/_dump/webfinger-as-dns.md new file mode 100644 index 0000000..fa53c11 --- /dev/null +++ b/unified.test.hugo/content/_dump/webfinger-as-dns.md @@ -0,0 +1,53 @@ +https://mastodon.social/@trwnh/110361352685140966 + +so we might reasonably recreate bluesky's "placeholder" nameserver by having a well-known endpoint for resolving identifiers to as2 documents (with possibly a layer of indirection, in which case webfinger would probably work) + +this basically replaces DNS for resolution. you'd just have to figure out how to assign ids in a distributed way without conflicts + +for that matter: why isn't xrpc a .well-known endpoint? it absolutely should have been + +i'm thinking if we wanted to reify webfinger and identity providers, we could just have identifiers assigned under the authority of webfinger subjects. where is the data? idk, check the current links via webfinger. + +problem with that is, your IdP better be long-lived... in fact, it makes sense for a persistent IdP to last basically "forever" and just point to your current data stores. and then i guess you'd want IdP federation to ease migration between IdPs? or otherwise conflict-free id minting + +tldr the open problems: + +- how to assign ids without conflict? (preferably without dns or key based authority, so you can change those later) + +- how to resolve those ids across multiple servers without tampering? (see also: dns poisoning and authoritative nameservers) + +there's a lot of prior art in DNS and you'd be moving it all down to the HTTP level over webfinger and oidc and related stuff + +basically instead of resolving names -> authoritative DNS nameservers -> IP addresses, you have to resolve uh... names -> authoritative Webfinger servers -> http(s) links + +so i guess we need an equivalent to DNSSEC but for WebFinger + +--- + +erincandescent writes: + +
    + +hash of public key; hash of first version of document (in chain), like they did. many decent options! + +the did:plc approach allows you to rotate keys because your current identity document will eventually chain back to the original one which hashes to the value of your account ID + +the bit the central server is doing in this system is - basically - ordering things & letting you use your recovery key to oblitterate any updates from your primary key from the last 72 hours (for if your primary key was compromised) + +the key difficulty without any central server is timestamping things to ensure & validate ordering + +
    + +cobaltvelvet writes: + +
    + +i think i just like the idea of a minimal relay as this resolver, that would keep the least state possible inside it, so it can be swapped in and out easily, maybe even transparently so by your instance. but it would always need A Way to validate the 'latest location', either the keypairs that arent very securely held atm but instances already have, or a third secret thing (a dedicated channel, like making the resolver email you to confirm a migration, or another layer of signatures) + +if i had to point to an inspiration, i think bittorrent trackers are great, easily replceable by a DHT, but also easy to just use two for redundency . ofc they don't really have to bother with any validation, but your instance can + +
    + +--- + +i'd just need to think through how to get consistency between different webfinger services, so that they agree on the response and serve you up the same JRD from some decentralized/distributed data store \ No newline at end of file diff --git a/unified.test.hugo/content/_index.md b/unified.test.hugo/content/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/articles/_index.md b/unified.test.hugo/content/articles/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/articles/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/articles/evolving-orderedcollection-to-be-more-useful/index.md b/unified.test.hugo/content/articles/evolving-orderedcollection-to-be-more-useful/index.md new file mode 100644 index 0000000..7bdfae9 --- /dev/null +++ b/unified.test.hugo/content/articles/evolving-orderedcollection-to-be-more-useful/index.md @@ -0,0 +1,297 @@ ++++ +title = "Evolving OrderedCollection to be more useful" +date = "2024-10-04T21:50:07-0600" +syndication = [ + "https://socialhub.activitypub.rocks/t/pre-fep-evolving-orderedcollection-to-be-more-useful/4608" +] +inReplyTo = [ + "https://github.com/w3c/activitypub/issues/439" +] ++++ + +Continuing from (and expanding on) this GitHub issue: https://github.com/w3c/activitypub/issues/439 + +Recently I've been thinking about OrderedCollection again and how the way it's specified doesn't actually match up with the way it's defined, or with what you'd need for it to be a useful data type. Some issues I could identify are laid out below. + +## Q1: Is it a List or a Set? + +Put another way: can you Add an item into an OrderedCollection more than once? + +### The argument for OrderedList + +If you define a Collection in terms of `items`, then it is pretty clearly a Set, and in JSON-LD it uses the `@set` container (which is the default container for every term's value). It seems pretty straightforward to look at Add and Remove as set operations which align with e.g. Python's set.add() and set.remove() functions. (In other languages, these operations may be called "insert" and "delete".) + +If you define OrderedCollection in terms of `orderedItems`, then this is simply a term which defines `as:items` with a `@container: @list`, so declaring `orderedItems` instead of `items` will use the JSON-LD `@list` container instead of using the JSON-LD `@set` container. One notable thing about the `@list` container is that it is not the same as an OrderedSet -- it can actually contain duplicates. In JSON-LD, this is clearly described as an "ordered list". For example: + +```json +{"@list": [{"@value": 10.0}, {"@value": 10.0}]} +``` + +### The argument for OrderedSet + +The problem with taking OrderedCollection to be defined in terms of `orderedItems` is that OrderedCollection in AS2-Vocab is actually defined as *inheriting from* Collection. The actual definitions given are the following: + +> Collection: A `Collection` is a subtype of `Object` that represents ordered or unordered sets of `Object or Link` instances. + +> OrderedCollection: A subtype of `Collection` in which members of the logical collection are assumed to always be strictly ordered. + +So if Collection is a set (ordered or unordered), and OrderedCollection inherits from Collection, then OrderedCollection is logically implied to also be a set (ordered). + +This is consistent with the use of Add and Remove to manipulate both Collection and OrderedCollection. But that leads into the next question... + +## Q2: If it's an ordered set, then is it an OrderedSet or a SortedSet? + +Put another way: does Adding an item into an OrderedCollection simply append at the end, or does it potentially cause the set to be reordered to match some kind of sorting? + +To give a concrete example, consider how ActivityPub mandates that OrderedCollection MUST be reverse chronological. (This has been the subject of an errata intending to relax this requirement to only apply to the properties defined as OrderedCollection *within ActivityPub*, but the general problem still applies.) ActivityPub gives this clarifying note: + +> What property is used to determine the reverse chronological order is intentionally left as an implementation detail. For example, many SQL-style databases use an incrementing integer as an identifier, which can be reasonably used for handling insertion order in most cases. In other databases, an insertion time timestamp may be preferred. What is used isn't important, but the ordering of elements must remain intact, with newer items first. A property which changes regularly, such a "last updated" timestamp, should not be used. + +So this clearly points toward using something like "insertion time" or "incrementing integer", which means that an Add targeting an OrderedCollection will by default insert the new item at the end of the `@list`. Or the beginning, once it's reversed. + +### So how do we determine ordering? + +By default, the ordering is assumed "reverse chronological by time of insertion", although with the relaxed restriction from the errata, you are free to order in any other way you wish. But if this is the case, then it would be a good idea to hint or signal what that ordering is. + +#### Prior art + +Looking at prior art, we have `https://schema.org/ItemList` which provides a property `https://schema.org/itemListOrder` which in turn can be either freeform text, or it can be one of the following `https://schema.org/ItemListOrderType` + +- `https://schema.org/ItemListOrderAscending` +- `https://schema.org/ItemListOrderDescending` +- `https://schema.org/ItemListUnordered` + +The ordering happens based on each `https://schema.org/ListItem` having a `https://schema.org/position` property. You can navigate a doubly-linked list with `https://schema.org/nextItem` or `https://schema.org/previousItem` on each ListItem. + +#### What can we do in AS2? + +It doesn't immediately make sense to put `nextItem` and `previousItem` style links directly on the object, because an object may be part of multiple collections. I guess you could maybe inject those properties when rendering or presenting an OrderedCollection, but this wouldn't really make sense either. The ordering in an OrderedCollection is already handled by JSON-LD's `@list` container, which in plain JSON would be an ordered array. (With paging, you can follow `as:first`/`as:next`* or you can follow `as:last`/`as:prev`* to traverse the entire OrderedCollection, one OrderedCollectionPage at a time.) + +So maybe we could define some property `orderType`, which gives a hint as to how the collection is ordered? The value of this property is left kind of open-ended, but it could be handled by vocabulary terms, if you just define the `orderType` term as `@type: @vocab`. This would allow you to explicitly define classes for things like `ReverseChronological`, `ForwardChronological`, or any other well-defined specific concept: + +```json +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + { + "orderType": { + "@id": "https://w3id.org/fep/xxxx/orderType", + "@type": "@vocab" + }, + "ReverseChronological": "https://w3id.org/fep/xxxx/ReverseChronological", + "ForwardChronological": "https://w3id.org/fep/xxxx/ForwardChronological" + } + ], + "id": "https://domain.example/some-collection", + "type": "OrderedCollection", + "orderedItems": [ + "https://domain.example/objects/3", + "https://domain.example/objects/2", + "https://domain.example/objects/1" + ], + "orderType": "ReverseChronological" +} +``` + +This at least gives us one more option to be expressive; we are no longer assuming everything to be reverse chronological, but we can instead be explicit about things being forward chronological or reverse chronological. + +### Maybe we need a SortedCollection type analogue to OrderedCollection? + +It may be that Adding something into the collection *doesn't* simply append it at the end, but rather causes the entire collection to be re-sorted. For example, consider a collection representing a conversation which is ordered "forward chronologically", but in constructing the collection, we missed an item somewhere in the middle. Rather than start over entirely, or just living with having the missed item be appended out-of-order at the end, we might instead define a new type of collection to handle this use case. Whereas the `Collection` represents an UnorderedSet data type, and an `OrderedCollection` represents an OrderedSet data type, we can define `SortedCollection` to represent a SortedSet. It inherits from OrderedCollection, since a SortedSet is just an OrderedSet that reorders itself upon any new insertion. We can also define a property `sortType` which is an analogue of the `orderType` we defined above. + +```json +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + { + "orderType": { + "@id": "https://w3id.org/fep/xxxx/orderType", + "@type": "@vocab" + }, + "ReverseChronological": "https://w3id.org/fep/xxxx/ReverseChronological", + "ForwardChronological": "https://w3id.org/fep/xxxx/ForwardChronological", + "SortedCollection": "https://w3id.org/fep/xxxx/SortedCollection", + "sortType": { + "@id": "https://w3id.org/fep/xxxx/sortType", + "@type": "@vocab" + } + } + ], + "id": "https://domain.example/some-collection", + "type": "SortedCollection", + "orderedItems": [ + "https://domain.example/objects/4", + "https://domain.example/objects/2", + "https://domain.example/objects/1" + ], + "sortType": "ReverseChronological" +} +``` + +But now we run into a caveat: it might not be sufficient to define classes/types for `sortType`, because the sorting might happen based on some property instead. So it looks like we're gonna need another mechanism... + +Maybe something like `sortedBy` and `sortOrder`? These would both be `@type: @vocab`. The `sortedBy` would be a functional property that indicates which property is being used for sorting, for example, we could sort by `as:published` (although perhaps we shouldn't?); the `sortOrder` would take one of two type/class/vocab values: either `Ascending` or `Descending`. So our example object and context is starting to look like this: + +```json +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + { + "orderType": { + "@id": "https://w3id.org/fep/xxxx/orderType", + "@type": "@vocab" + }, + "ReverseChronological": "https://w3id.org/fep/xxxx/ReverseChronological", + "ForwardChronological": "https://w3id.org/fep/xxxx/ForwardChronological", + "SortedCollection": "https://w3id.org/fep/xxxx/SortedCollection", + "sortedBy": { + "@id": "https://w3id.org/fep/xxxx/sortedBy", + "@type": "@vocab" + }, + "sortOrder": { + "@id": "https://w3id.org/fep/xxxx/sortOrder", + "@type": "@vocab" + }, + "Ascending": "https://w3id.org/fep/xxxx/Ascending", + "Descending": "https://w3id.org/fep/xxxx/Descending" + } + ], + "id": "https://domain.example/some-collection", + "type": "SortedCollection", + "orderedItems": [ + "https://domain.example/objects/4", + "https://domain.example/objects/2", + "https://domain.example/objects/1" + ], + "sortedBy": "published", + "sortOrder": "Descending" +} +``` + +Now finally, we can send an Add and know for sure that it will be inserted in the right index/position of the underlying `@list` container: + +```json +{ + "@context": "https://www.w3.org/ns/activitystreams", + "id": "https://domain.example/some-activity", + "actor": "https://domain.example/some-actor", + "type": "Add", + "object": "https://domain.example/objects/3", + "target": "https://domain.example/some-collection" +} +``` + +We now expect that the result will be `[4, 3, 2, 1]` instead of `[3,4,2,1]`. + +## Q3: Are there other ways to approach insertion into an OrderedCollection? + +We might not *want* our OrderedSet to be a SortedSet specifically. We might want some specific ordering that is also specifically not sorted according to any criteria or property. + +### Adding a new item at a specific position + +In the most basic case, this might be doable with a property like `insertAfter`? This would allow us to specify where in the `@list` to insert the new item. + +Say we have `orderedItems: [4, 2, 1]`. We might formulate the following Add activity: + +```json +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + { + "insertAfter": { + "@id": "https://w3id.org/fep/xxxx/insertAfter", + "@type": "@id" + } + } + ], + "id": "https://domain.example/some-activity", + "actor": "https://domain.example/some-actor", + "type": "Add", + "object": "https://domain.example/objects/3", + "insertAfter": "https://domain.example/objects/4" +} +``` + +Did you spot the flaw in this? We have a problem: the receiving server might not understand the `insertAfter` property, and therefore might process the `Add` in a way that we didn't expect! We end up with `[3, 4, 2, 1]` because the `insertAfter: 4` wasn't understood, and so we didn't get the desired result of `[4, 3, 2, 1]`. + +This can be fixed by changing the `Add` to an `Insert`. Now, the server has to specifically understand the Insert activity and its side effects, or else the activity will not be processed. + +```json +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + { + "insertAfter": { + "@id": "https://w3id.org/fep/xxxx/insertAfter", + "@type": "@id" + }, + "Insert": "https://w3id.org/fep/xxxx/Insert" + } + ], + "id": "https://domain.example/some-activity", + "actor": "https://domain.example/some-actor", + "type": "Insert", + "object": "https://domain.example/objects/3", + "insertAfter": "https://domain.example/objects/4" +} +``` + +We could also define an `insertBefore` property, but I think this isn't necessary and overall just complicates things. Generally when updating a linked list, you traverse it going forwards; the `@list` of `orderedItems` is also presented in forward ordering. It therefore makes the implementation simpler at a data structure level to only define `insertAfter` and no `insertBefore`. + +One remaining caveat has to do with ActivityPub delivery. In the case that we send an activity to our local server via C2S, we are not guaranteed that it will have any side effects processed; the activity may be malformed or otherwise not processable. But the presence of addressing properties like `to`, `cc` and `audience` will cause the activity to be delivered to the recipients regardless of whether it had any local side effects -- perhaps the remote server will know what to do with the activity. If the remote server also doesn't know how to process the activity, then you end up with a no-op on both your local server and on the remote server. Perhaps some human reading their `inbox` might be able to derive some meaning from it...? + +### Moving an item to a new position in the list? + +Just like we defined an Insert activity earlier, we might want to use something like a Move activity to reorder our OrderedCollection. Say we have a list in the form `orderedItems: [3, 4, 2, 1]`, perhaps by some permutation of aware or unaware servers leading to the error case from before. Well, how do we fix this? + +What we want in this case is to move `3` to be after `4`. (Alternatively, we can achieve the same result by moving `4` to come before `3`, but we already established that "insert before" is harder than "insert after". If we need to reconsider this, then it can be reconsidered.) + +We might formulate "move `3` to be after `4`" with the following Move activity: + +```json +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + { + "insertAfter": { + "@id": "https://w3id.org/fep/xxxx/insertAfter", + "@type": "@id" + }, + "Insert": "https://w3id.org/fep/xxxx/Insert" + } + ], + "id": "https://domain.example/some-activity", + "actor": "https://domain.example/some-actor", + "type": "Move", + "object": "https://domain.example/objects/3", + "insertAfter": "https://domain.example/objects/4" +} +``` + +This `Move` activity is equivalent to doing a `Remove` first, followed by a new `Insert`; compare to a `Move` activity normally being equivalent to doing a `Remove` first and then following up with an `Add`. + +### Completely reordering the items + +Given a complex enough OrderedCollection, you might find it easier to just create a new collection and Add or Insert items as appropriate... but this is not an option if you want to preserve the collection's id. (Well, it could be an option, but you'd have to define a mechanism to reassign identifiers first. Perhaps a `Migrate` activity could be defined in some other FEP? Alternatively, `Move` might work, but I'd be wary of overloading the semantics of "moving" an object. Of course, Mastodon's "account migration" feature already uses `Move` in exactly this overloading way, so...) + +So given the same OrderedCollection, we might consider an `Update` that changes the `orderedItems` around: + +```json +{ + "@context": "https://www.w3.org/ns/activitystreams", + "id": "https://domain.example/some-activity", + "actor": "https://domain.example/some-actor", + "type": "Update", + "object": { + "id": "https://domain.example/some-collection", + "orderedItems": [ + "https://domain.example/objects/4", + "https://domain.example/objects/3", + "https://domain.example/objects/2", + "https://domain.example/objects/1", + ] + } +} +``` + +In the case where an OrderedCollection is *unpaged* but just very very large, then the answer is to simply construct a similarly large Update activity. But the larger the collection grows, the more likely it is to be paged. So if the OrderedCollection is paged and the pages are reified, you might only be able to Update one page at a time. You might even find yourself needing to Move items between one reified page and another! So maybe you can construct a new OrderedCollectionPage and carefully update the `next` and `prev` links of what is effectively a linked list. The exact algorithm for doing this is left as an exercise for the reader, because this is already getting to be a very long post, and adding more examples for this increasingly niche and situation-dependent use case is going to make it even longer... eh, perhaps in a follow-up. \ No newline at end of file diff --git a/unified.test.hugo/content/buttons/devils.gay/devils1.gif b/unified.test.hugo/content/buttons/devils.gay/devils1.gif new file mode 100644 index 0000000..94fc5c9 Binary files /dev/null and b/unified.test.hugo/content/buttons/devils.gay/devils1.gif differ diff --git a/unified.test.hugo/content/buttons/devils.gay/devils2.gif b/unified.test.hugo/content/buttons/devils.gay/devils2.gif new file mode 100644 index 0000000..3cfc655 Binary files /dev/null and b/unified.test.hugo/content/buttons/devils.gay/devils2.gif differ diff --git a/unified.test.hugo/content/buttons/devils.gay/devils3.gif b/unified.test.hugo/content/buttons/devils.gay/devils3.gif new file mode 100644 index 0000000..e866d2a Binary files /dev/null and b/unified.test.hugo/content/buttons/devils.gay/devils3.gif differ diff --git a/unified.test.hugo/content/buttons/devils.gay/devils4.gif b/unified.test.hugo/content/buttons/devils.gay/devils4.gif new file mode 100644 index 0000000..bbc3cd0 Binary files /dev/null and b/unified.test.hugo/content/buttons/devils.gay/devils4.gif differ diff --git a/unified.test.hugo/content/buttons/disarray.sh/disarray.png b/unified.test.hugo/content/buttons/disarray.sh/disarray.png new file mode 100644 index 0000000..ae80d49 Binary files /dev/null and b/unified.test.hugo/content/buttons/disarray.sh/disarray.png differ diff --git a/unified.test.hugo/content/buttons/index.html b/unified.test.hugo/content/buttons/index.html new file mode 100644 index 0000000..fdd19c2 --- /dev/null +++ b/unified.test.hugo/content/buttons/index.html @@ -0,0 +1,41 @@ + + + + + + buttons! + + + +
    +

    buttons!

    +
    +
    +

    link back to me

    +
      +
    • trwnh.com
    • +
    • a@trwnh.com with a person laying down on it
    • +
    • a@trwnh.com with a person laying down on it and another copy of the same person waving hello. there is also a golden jiggy
    • +
    +
    +
    +

    friends

    +
      +
    • devils.gay
    • +
    • disarray
    • +
    • owlyfans
    • +
    +
    + + \ No newline at end of file diff --git a/unified.test.hugo/content/buttons/owly.fans/owlyfans.png b/unified.test.hugo/content/buttons/owly.fans/owlyfans.png new file mode 100644 index 0000000..cdca188 Binary files /dev/null and b/unified.test.hugo/content/buttons/owly.fans/owlyfans.png differ diff --git a/unified.test.hugo/content/buttons/trwnh.com/a-1.png b/unified.test.hugo/content/buttons/trwnh.com/a-1.png new file mode 100644 index 0000000..4e340ff Binary files /dev/null and b/unified.test.hugo/content/buttons/trwnh.com/a-1.png differ diff --git a/unified.test.hugo/content/buttons/trwnh.com/a-2.png b/unified.test.hugo/content/buttons/trwnh.com/a-2.png new file mode 100644 index 0000000..a12a2e2 Binary files /dev/null and b/unified.test.hugo/content/buttons/trwnh.com/a-2.png differ diff --git a/unified.test.hugo/content/buttons/trwnh.com/buttons.html b/unified.test.hugo/content/buttons/trwnh.com/buttons.html new file mode 100644 index 0000000..2742078 --- /dev/null +++ b/unified.test.hugo/content/buttons/trwnh.com/buttons.html @@ -0,0 +1,30 @@ + + + + + + buttons for trwnh.com + + + +
    +
      +
    • trwnh.com
    • +
    • a@trwnh.com
    • +
    • a@trwnh.com with a person laying down on it
    • +
    • a@trwnh.com with a person laying down on it and another copy of the same person waving hello. there is also a golden jiggy
    • +
    +
    + + \ No newline at end of file diff --git a/unified.test.hugo/content/buttons/trwnh.com/index.html b/unified.test.hugo/content/buttons/trwnh.com/index.html new file mode 120000 index 0000000..8c9653e --- /dev/null +++ b/unified.test.hugo/content/buttons/trwnh.com/index.html @@ -0,0 +1 @@ +buttons.html \ No newline at end of file diff --git a/unified.test.hugo/content/buttons/trwnh.com/trwnh.ase b/unified.test.hugo/content/buttons/trwnh.com/trwnh.ase new file mode 100644 index 0000000..b9297ea Binary files /dev/null and b/unified.test.hugo/content/buttons/trwnh.com/trwnh.ase differ diff --git a/unified.test.hugo/content/buttons/trwnh.com/trwnh.png b/unified.test.hugo/content/buttons/trwnh.com/trwnh.png new file mode 100644 index 0000000..c382f8b Binary files /dev/null and b/unified.test.hugo/content/buttons/trwnh.com/trwnh.png differ diff --git a/unified.test.hugo/content/buttons/trwnh.com/trwnh1.png b/unified.test.hugo/content/buttons/trwnh.com/trwnh1.png new file mode 100644 index 0000000..f90a253 Binary files /dev/null and b/unified.test.hugo/content/buttons/trwnh.com/trwnh1.png differ diff --git a/unified.test.hugo/content/buttons/trwnh.com/trwnh2.png b/unified.test.hugo/content/buttons/trwnh.com/trwnh2.png new file mode 100644 index 0000000..3f3b778 Binary files /dev/null and b/unified.test.hugo/content/buttons/trwnh.com/trwnh2.png differ diff --git a/unified.test.hugo/content/buttons/trwnh.com/trwnh2a.png b/unified.test.hugo/content/buttons/trwnh.com/trwnh2a.png new file mode 100644 index 0000000..df47ab4 Binary files /dev/null and b/unified.test.hugo/content/buttons/trwnh.com/trwnh2a.png differ diff --git a/unified.test.hugo/content/buttons/trwnh.com/trwnh3.png b/unified.test.hugo/content/buttons/trwnh.com/trwnh3.png new file mode 100644 index 0000000..70b15fa Binary files /dev/null and b/unified.test.hugo/content/buttons/trwnh.com/trwnh3.png differ diff --git a/unified.test.hugo/content/monologues/_index.md b/unified.test.hugo/content/monologues/_index.md new file mode 100644 index 0000000..dd842df --- /dev/null +++ b/unified.test.hugo/content/monologues/_index.md @@ -0,0 +1,9 @@ ++++ +title = "monologues" +name = "~a | monologues" +summary = "mostly a compilation of times i replied to myself on social media or in chat. what you see here is minimally curated and lightly formatted. it might disappear at any time or be upgraded to a proper blog post at some point." +[pagination] +pagerSize = 100 ++++ + +[[rejected outtakes]](misc) \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/activitypub-proglang/index.md b/unified.test.hugo/content/monologues/activitypub-proglang/index.md new file mode 100644 index 0000000..9d18fe2 --- /dev/null +++ b/unified.test.hugo/content/monologues/activitypub-proglang/index.md @@ -0,0 +1,27 @@ ++++ +title = "an analogy between activitypub and programming languages" +summary = "you don't say \"compatible with c++\" you say \"written in/with c++\". similarly, we might say that fedi is \"written with activitypub\" or \"implemented using activitypub\"" +date = "2023-03-28T09:13:00-06:00" +source = "https://mastodon.social/@trwnh/110101321320240671" ++++ + +people think activitypub is a network protocol when it's really more like a programming language. you don't say "compatible with c++" you say "written in/with c++". similarly, we might say that fedi is "written with activitypub" or "implemented using activitypub", not "compatible with activitypub" or anything suggesting a network. + +analogously: + +ap = inter-process communication (e.g. d-bus) +as2 = data interchange format (e.g. protobuf) +json-ld = media type +rdf = facts and logic + +if we're being honest the majority of "fedi" is part of the "network" that is "compatible with mastodon". mastodon *is* the network protocol. we just express it in terms of "mastodon-flavoured activitypub" + +put another way, there is no such thing as "fedi", but rather, multiple different and distinct "fedis" that only partially overlap. + +it occurs to me that activitypub may be best thought of as a cms with an optional distributed storage backend + +similarly: no one in fedi is doing real activitypub. it is probably more appropriate to say we are doing AS2 + Linked Data Notifications + +side effects are more accurately defined by the mastodon documentation than by the activitypub spec + +we're kind of in the situation where someone has invented the C Programming Language, maybe D-Bus, but we still don't have a FreeDesktop.org or XDG equivalent. \ No newline at end of file diff --git a/blog.hugo/content/_dump/copyright-is-theft.md b/unified.test.hugo/content/monologues/art-not-commodity/index.md similarity index 85% rename from blog.hugo/content/_dump/copyright-is-theft.md rename to unified.test.hugo/content/monologues/art-not-commodity/index.md index 6fddb98..b3bb94d 100644 --- a/blog.hugo/content/_dump/copyright-is-theft.md +++ b/unified.test.hugo/content/monologues/art-not-commodity/index.md @@ -1,3 +1,10 @@ ++++ +title = "art is not a commodity" +summary = "the real answer to making sure artists get paid is to actually pay them for the work they do, not to commodify what they produce" +date = "2023-01-02T21:00:00-06:00" +source = "https://mastodon.social/@trwnh/109623038871646811" ++++ + well opposing copyright isn't thievery, for a start. theft is the act of taking something without returning it, removing the original. digital information can be infinitely and perfectly copied. copyright enforcement is instead about giving certain parties exclusive monopolies on the spread of information. this gatekeeps culture and stifles free expression. in return for what? trying to sell access? diff --git a/unified.test.hugo/content/monologues/blocked/index.md b/unified.test.hugo/content/monologues/blocked/index.md new file mode 100644 index 0000000..4a347b0 --- /dev/null +++ b/unified.test.hugo/content/monologues/blocked/index.md @@ -0,0 +1,16 @@ ++++ +title = "blocked" +summary = "it's the finality of such a situation that bothers me the most; the knowledge that no amount of apology will matter, nor will any attempt at reconciliation even be seen" +date = "2018-02-27T21:23:00-00:00" +source = "https://mastodon.social/@trwnh/99599426061591957" ++++ + +i wish i wasn't autistic because i'm really bad at reading social situations and here i am thinking i'm making light banter when instead i'm one post away from being blocked, before i can even apologize for misreading intent. end result is i just feel extremely shitty and like i'm terrible at being a human. i don't know how to vent my frustrations without it seeming personal, apparently + +also it's the finality of such a situation that bothers me the most; the knowledge that no amount of apology will matter, nor will any attempt at reconciliation even be seen. i've never been able to properly handle irreversibility. even though a block is technically reversible, it isn't practically. one mistake and it's over. and i *will* make those mistakes, because not only am i not perfect, but i'm hopelessly broken beyond repair, no matter how hard i try to learn how to socialize. + +and yet... i've not really been blocked much in my life (bar some democrats on birdsite who refuse to listen to left-poc) so i'm not totally insufferable or an absolute troll or a toxic personality. but of the more "misunderstood" blocks, one particular one comes to mind, because it was the only case where that person actually unblocked me years later. but that was much worse and what i said then was extremely insensitive. i wish i knew why they unblocked me. i'm too afraid to ask. + +sometimes i wonder why i care what total strangers think of me, and i don't know if it's better or worse to not care. it's not "shame" or "approval-seeking"; it's more of an intense urge to not be hated or begrudged. + +i guess that's a part of life, but it's not a part i'm comfortable with and i don't know if i ever will be. \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/boktai-3/index.md b/unified.test.hugo/content/monologues/boktai-3/index.md new file mode 100644 index 0000000..b09ca22 --- /dev/null +++ b/unified.test.hugo/content/monologues/boktai-3/index.md @@ -0,0 +1,10 @@ ++++ +title = "boktai deserved better" +summary = "where do you go to find quirky existentialist video games based on norse mythology and spaghetti westerns in the year of your lord 2018, you ask? you don't ;_;" +date = "2018-04-15T19:54:00-00:00" +source = "https://mastodon.social/@trwnh/99865201213509948" ++++ + +i'm so emo that boktai 3 never launched outside of japan and also that boktai as a series is super dead and konami will never continue it and kojima probably can't/won't either due to copyright and the fact that it's been over 10 years since boktai ds and also kojima doesn't work for konami anymore UGH + +where do you go to find quirky existentialist video games based on norse mythology and spaghetti westerns in the year of your lord 2018, you ask? you don't ;_; #boktai \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/camera-gear/index.md b/unified.test.hugo/content/monologues/camera-gear/index.md new file mode 100644 index 0000000..5793393 --- /dev/null +++ b/unified.test.hugo/content/monologues/camera-gear/index.md @@ -0,0 +1,23 @@ ++++ +title = "don't worry about camera gear" +summary = "I wouldn't recommend going for ILCs unless you have a dedicated use case [...] Once you've picked a niche, then the gear choices will result naturally." +date = "2018-04-09T22:28:00-00:00" +source = "https://mastodon.social/@trwnh/99831836537266861" ++++ + +> On a less cranky note, I really want to get myself a nice digital camera. Any photographers out there with strong opinions on the matter? + +* What type of photos do you want to take? +* What's your budget? +* Do you want to deal with carrying multiple lenses / heavy bodies / etc? +* What's the destination / use case for your photos? + +> all kinds. Budget isn't too much of an issue I can just save up longer. Multiple lenses are fun and I'll probably get a couple solid bags so not too put out about weight. Destination unknown. + +Well, I'm just going to say that if you don't have any idea at all, then that also means you can't really get a good answer. I wouldn't recommend going for ILCs unless you have a dedicated use case -- a compact or even a smartphone will do fine in most general cases. (I picked up a Sony RX100 M2 used for a few hundred bucks for my general shots.) + +Once you've picked a niche, then the gear choices will result naturally. As a general rule, spend more on glass than on bodies. Probably pick two telephoto lenses, one below ~70mm (down to 35mm or 24mm) and one above (up to about 200mm). Get a body with a sensor that's at least APS-C, and at least 12MP. A Sony a6000 or a6300 will be most versatile in the $750-1000 range (body only). You'll be spending an additional $400-$1000 for each quality lens you also pick up. + +> fair enough! I'm just doing my research right now so I appreciate the honesty. + +you're welcome :) it's really important to know what you're getting yourself into. a lot of people buy in way too early and stick with a kit lens because they didn't budget for lens -- and at that point, you might as well get a 1" compact, maybe even a Micro Four-Thirds like the Fujifilm X100 series if you can afford it. \ No newline at end of file diff --git a/blog.hugo/content/_dump/stop-using-crossposters.md b/unified.test.hugo/content/monologues/crossposters/index.md similarity index 76% rename from blog.hugo/content/_dump/stop-using-crossposters.md rename to unified.test.hugo/content/monologues/crossposters/index.md index e22d2e6..b3d4fa1 100644 --- a/blog.hugo/content/_dump/stop-using-crossposters.md +++ b/unified.test.hugo/content/monologues/crossposters/index.md @@ -1,4 +1,12 @@ -2017-11-26 08:20 | https://mastodon.social/@trwnh/99069749589979672 ++++ +title = "stop using crossposters" +summary = "crossposts really don't engender organic engagement. They feel robotic and distant, largely because they're just that" +date = "2017-11-26T02:20:00-06:00" +source = [ + "https://mastodon.social/@trwnh/99069749589979672", + "https://mastodon.social/@trwnh/99093644445157168", +] ++++ Stop using crossposters. @@ -12,9 +20,7 @@ I've been through this kinda rigmarole before when I tried using diaspora*, and The problem, of course, is that you will inevitably gravitate to whichever platform nets you more interaction. And crossposts really don't engender organic engagement. They feel robotic and distant, largely because they're just that ---- - -2017-11-30 13:36 | https://mastodon.social/@trwnh/99093644445157168 +## followup ugh i really hope crossposters don't slowly choke mastodon like they did to diaspora* diff --git a/blog.hugo/content/_dump/deactivating-twitter.md b/unified.test.hugo/content/monologues/deactivating-twitter/index.md similarity index 62% rename from blog.hugo/content/_dump/deactivating-twitter.md rename to unified.test.hugo/content/monologues/deactivating-twitter/index.md index 7de3d77..267ac3d 100644 --- a/blog.hugo/content/_dump/deactivating-twitter.md +++ b/unified.test.hugo/content/monologues/deactivating-twitter/index.md @@ -1,4 +1,9 @@ -2017-12-20 10:53 | https://mastodon.social/@trwnh/99206247716252048 ++++ +title = "nothing is truly forever" +summary = "At some point, the final copy of any given data will be deleted. Or it will lose relevance. Or it will slip into obscurity." +date = "2017-12-20T04:53:00-06:00" +source = "https://mastodon.social/@trwnh/99206247716252048" ++++ I just deactivated some really old accounts I had on birdsite, ones I'd stopped using years ago, but had left up as a sort of archive... The last relics of a bygone era, of a personality long dead... A mark of my former selves. @@ -10,12 +15,4 @@ I can't back up the DMs that have been deleted, and the only copy of the replies Kind of a heavy feeling. -The pictures will be gone in 30 days, but I can't help but think of the pictures lost forever from Twitpic or Yfrog or all of those other image hosts we all used before image hosting became a standard part of any web app. - ---- - -2018-03-07 04:05 | https://mastodon.social/@trwnh/99640641359436224 - -twitter's culture since 2014 has been so machine-oriented, they probably trust machines more than actual people. like "i don't want to hear what's wrong, i want to know what The Algorithm says is wrong" - -essentially, right around the time twitter decided it wanted to be a media company instead of a conversational platform. it cracked down on third party API usage, put in absurd 100,000-user limits, and started breaking everything that was good pre-2014. \ No newline at end of file +The pictures will be gone in 30 days, but I can't help but think of the pictures lost forever from Twitpic or Yfrog or all of those other image hosts we all used before image hosting became a standard part of any web app. \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/defining-quote-posts/index.md b/unified.test.hugo/content/monologues/defining-quote-posts/index.md new file mode 100644 index 0000000..3271385 --- /dev/null +++ b/unified.test.hugo/content/monologues/defining-quote-posts/index.md @@ -0,0 +1,77 @@ ++++ +title = "defining quote posts" +summary = "to me, the way i see quote posts is essentially as a \"loud reply\" or as a \"breakout thread\"" +date = "2023-05-01T12:07:00-06:00" +source = "https://mastodon.social/@trwnh/110294523321644375" ++++ + +fwiw my take about quotes is that either + +- they're just links with special tag markup that lets them be identifiable as activitypub objects +- they're supported more at the protocol level a la Announce with content, or possibly a "quotes" collection a la "likes" and "shares" +- they represent a new context (assuming mastodon ever adopts a first-class concept of conversations or threads, instead of relying solely on inReplyTo chains for logical grouping) + +my further idea was to decide if it notifies based on whether the type is Link or Mention (a la webmentions) + +in an alternate timeline we could have had generic rendering of activities based on name/summary/content and maybe actor/type/object + +such a generic renderer would be something like... + +> ` ` \ +> `` \ +> `` + +filling in the last two lines for summary and content + +> alice boosted a post: "The problem with this is..." \ +> "I disagree with this analysis." + +also this just highlights what i think a "quote post" should really be: more like a "loud reply". in a more ideal world it would use `inReplyTo` + a new `context`. + +yes, a regular "reply" is in effect a "quote" the second you embed the post you are replying to. look at the IndieWeb for example. what is the functional difference? + +the problem of course is that mastodon doesnt show replies in timelines, and doesn't have a proper concept of contexts aside from reply-chains. but at least half of that is a matter of policy, so it could be changed. + +imagine a property `toot:quoteReply` that is a boolean. if true, it embeds the `inReplyTo`post above your post. it also sends such posts to follower timelines. + +fundamentally there's the intent and the interpretation, intent can be seen as how you author the activity, interpretation is the processing rules applied by the receiver. if this were a proper spec, the two would be the same and there'd be no ambiguity, but... well, y'know. + +there's also the rest of the ecosystem of course, there's the "tag a substring of your content" as Foundkey does, in the past there was even "attach the post you're quoting" which Hubzilla and/or Zap did, there was also the proposal to "add content on Announce" which gargron and lain favored but never implemented. and then there's the two new ones -- "just make it a special type of reply" as i propose, and "just make it a new Activity" as you expressed just now + +we should focus on generic data modeling, describing resources and how they are related. mastodon doesn't do a good job of that, sure... and that's how we end up with leaky abstractions. it's a good idea to leave as much of the app-specific stuff out of the data model as we can. otherwise we just end up with The Mastodon Protocol which is built to interop with the mastodon app specifically + +like we have tag, attachment, inReplyTo, Announce... + +- tag = describing entities within the natural language properties (often microsyntaxes) + +- attachment = sidecar entities (not necessarily media) + +- inReplyTo = referencing a prior object (or objects) for which your current object can be considered a response + +- Announce = add to `shares` collection if present (this is the weakest one, to be fair) + +> I do agree with you that quotes are basically a form of loud reply + +semantics aside, i think functionally the difference is really the fallback + +- an Announce with content is basically "reshare with additional content" semantically, but it falls back to being a regular boost, and to control quotes you'd need to similarly be able to control boosts + +- a Note with inReplyTo + quoteReply=true would fall back to a regular reply. this means that when reply controls get added, you get quote control "for free" + +the other functional difference between those two is whether the "quote" gets added to `shares` or to `replies` + +--- + +also tangentially i've thought about what people think a quote post is vs what it actually is, the dimensions, its primary function, etc + +to me, the way i see quote posts is essentially as a "loud reply" or as a "breakout thread". + +the former use-case could be handled by reply+boost. this is actually very easy in the API: just make a button that fires off 2 API calls. + +the latter could be handled by copypasting a link into a new post. this is much harder to detect and display. optionally mention + +really the problem with twitter "quote tweets" is that they conflated the two use-cases + +you were *always* notified, regardless of whether someone was talking "about" you or "to" you (no consideration for replies) + +plus the fact it was a new thread was stripping context, you could no longer see all the posts in one thread ("breaking out" isn't always wanted) \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/drowning-in-awareness/index.md b/unified.test.hugo/content/monologues/drowning-in-awareness/index.md new file mode 100644 index 0000000..ea949ed --- /dev/null +++ b/unified.test.hugo/content/monologues/drowning-in-awareness/index.md @@ -0,0 +1,12 @@ ++++ +title = "drowning in awareness" +summary = "if you don't have a material call to action, you have nothing. [...] \"awareness\" on its own is not enough; it can even be an actively bad thing if you end up paralyzed by inaction and despair [...] like, ok, i'm aware. now what?" +date = "2023-01-20T00:16:00-0600" +source = "https://mastodon.social/@trwnh/109720070743856424" ++++ + +i am reminded of an essay i read once called "avoid news" which might sound extreme to some people but it actually has a simple premise: most of what you encounter in media suffers from context collapse and/or is not actionable. therefore it can never truly be relevant. what is far more valuable is filtering through the news for anything actionable worth educating people about, and presenting it in a more relevant and digestible way. not everyone should have to do this. + +i'd really go further and say that these days, if you don't have a material call to action, you have nothing. what do you expect to accomplish by sharing what you're sharing? "awareness" on its own is not enough; it can even be an actively bad thing if you end up paralyzed by inaction and despairing over it. far better to actively educate people that need educating, instead of simply "raising awareness". + +like, ok, i'm aware. now what? \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/fedi-as-reformist-option/index.md b/unified.test.hugo/content/monologues/fedi-as-reformist-option/index.md new file mode 100644 index 0000000..6d5fbb4 --- /dev/null +++ b/unified.test.hugo/content/monologues/fedi-as-reformist-option/index.md @@ -0,0 +1,52 @@ ++++ +title = "fedi as a reformist option" +summary = "[...] it's holding us back from better things. it's like the \"reform\" option when we need radical change. and it keeps getting \"worse\" [...] ad-free and chronological ain't enough." +date = "2023-04-30T20:27:00-0600" +source = "https://mastodon.social/@trwnh/110290827199480228" ++++ + +nobody asked but i think fedi as a whole is actually kinda "bad" in the sense that it's holding us back from better things. it's like the "reform" option when we need radical change. and it keeps getting "worse". somewhere along the way we seem to have dropped the "blogging" from "microblogging", and what remains is incredibly muddled. contextual and ergonomic failure. we're copying "social media" and inheriting its flaws. ad-free and chronological ain't enough. + +see, we're all mostly here to just hang out and spill a stream of consciousness, right? but there are problems inherent to the structure. context collapse (or no context at all), misuse of the medium (doing a "thread" instead of writing an article), and so on. everything just goes into the square hole. + +i posit we can do better. but it's gonna require going back to basics and building out communication paradigms from the ground up. with thought given to effective communication, not profitability + +but. (and this is where i am afraid of shit-stirring) + +no one wants to do that + +the people working on fedi past and present seem mostly invested in mass adoption, and the way to do that is to keep building on broken foundations. and it feels kinda cultish at this point, like the goal is "success" defined by "growth", and it's a branding game, it's lip service. + +"mastodon", even "activitypub" itself, is seemingly about mindshare more than anything tangible. + +i don't particularly want to call out specific people for this, because it's not just a few people, it seems to be a cultural issue. the framing is that we can replace those social media platforms instead of tearing them down as we ought to. mastodon wants to become the next twitter. pixelfed wants to become the next instagram. and so on. + +on some level i think the people are just looking for validation of their work. but this leads to a kind of conservative outlook toward actually improving... + +yes, this thread could have been a blog post. that's part of the problem + +--- + +i mean we stop doing "social media" as twitter and facebook made, and go (go back?) to clearly publishing and clearly discussing, as two separate things. remember blogs and forums? on blogs, you publish. on forums, you discuss. on "social media", this distinction gets collapsed. a "post" and its "replies" are all in this one big global context by default. who is the audience? what is the purpose? these questions don't have clear answers on "social media". corpos profit from this ambiguity. + +in "social media", the audience is "whoever we put this in front of" and the purpose is "an endless feed of posts for you to graze from". contrast this with the intentionality of cultivating your own audience, and of communicating with them. fedi gets us halfway. we move away from the profit-oriented mindset, but we keep the trappings and mechanisms that were created in service of them. + +tldr we're on the Web and we should remember that. death to "platforms". empower actual people to set up their own spaces and domains. + +--- + +there is an argument to be made that the right thing would not have been made clear if we hadn't kept making mistakes like chasing the big corporate players. i'd be open to this argument 10 or 15 years ago around the time of identica or diaspora, but since then it's just become more apparent that this whole space will never be anything more than a transitional holding-place for people who leave the walled gardens for... fenced gardens, i gues? and the better thing hasn't been built yet. + +--- + +here on the World Wide Web you have two threats: capitalist enclosure, and toxic community. and honestly the latter is probably less bad, because at least you have the self-determination to make your own community with your valued friends if the current one gets too bad. with the former, you have no escape. + +in short, "social media" is a failed model invented by capitalists. what we need is a "social web". focus on people, not "content". + +want to entertain yourself? that's fine, there can be media hubs and curators for that. but your communications and your media consumption should be separate. + +--- + +honestly as much as meta gets tiring, at least these are conversations that can actually be had with a nonzero chance at actually shaping things. + +you think twitter or instagram gives a shit what its users want or think? nope, it's all about driving ad revenue \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/fedi-vs-web/index.md b/unified.test.hugo/content/monologues/fedi-vs-web/index.md new file mode 100644 index 0000000..b63b750 --- /dev/null +++ b/unified.test.hugo/content/monologues/fedi-vs-web/index.md @@ -0,0 +1,220 @@ ++++ +title = "fedi vs web" +summary = "this is the fundamental divide between #fediverse thinking and #Web thinking, where #ActivityPub straddles the line between both." +date = "2024-09-24T07:06:00-06:00" +source = "https://mastodon.social/@trwnh/113192442723669483" ++++ + +idk where to really put this (might turn into a blog post later or something). it's what you might call a "hot take", certainly a heterodox one to some parts of the broader #fediverse community. this is in response to recent discussion on "what do you want to see from AP/AS2 specs" (in context of wg rechartering) mostly devolving into people complaining about JSON-LD and extensibility, some even about namespacing in general (there was a suggestion to use UUID vocab terms. i'm not joking) + +the main contention is a disconnect between #ActivityPub as a spec and #fediverse as a protocol/network. a lot of problems cited were with the fediverse as implemented, wishful thinking about what could be changed in spec, many backwards-incompatible, mostly in service of making fediverse impl less painful. + +there is a recurring refrain about implementers deciding they don't care to implement AP as specified, and that this indicates a problem with the spec, not a problem with implementers. + +i think this disconnect between #ActivityPub and #fediverse honestly goes a lot deeper than people might realize. and that is because the problem AP tries to solve is actually completely different from what fedi is trying to do. + +the concept of a nebulous but mostly singular "network" or "protocol" (made up of partially overlapping parts) is core to what i'll call "fedi mindset". the assumption is that you can join the fedi "network" by implementing the fedi "protocol". and that AP is this. + +but this assumption starts to break down when you look a little closer. + +first, consider #ActivityPub C2S. why is there close to zero usage of this in #fediverse software? simple: it doesn't solve any needs for building a "network" "protocol". + +now consider S2S. why are there zero compliant impls in fedi? because AP as specified doesn't address the needs of fedi. what does fedi need? well, i find it telling that the "real" reason AP was adopted was... to implement followers-only posts. + +which is to say: the primary reason that #ActivityPub is used (to the extent you can say it is being used at all) in the #fediverse is mostly historical. + +fedi grew out of a long line of open protocols, and before AP was adopted, it was at the point where people primarily used "activity streams" as their vocabulary and data model, stuffed into atom feeds. atom feeds don't do private posts unless you make an entirely new access-controlled feed, possibly with a token of some sort. hence, AS2. + +when #ActivityPub was being standardized alongside AS2 it basically had two compelling reasons for what would become the #fediverse to adopt it: + +- it was built on AS2, which was an evolution of AS1, which was already being used. so it wasn't hard to make the jump. +- it made followers-only posts possible, because while atom feeds *could* do this, it was wildly inconvenient to actually do it that way. posting something private to an inbox is a lot simpler, no juggling access control tokens. + +but beyond that, what does #ActivityPub actually do for #fediverse as a "network" "protocol"? basically nothing. you have a basic mechanism for delivering activities directly to subscribers, but no specified shape or structure for that payload. and you still need a lot of other specs to end up with something that talks to the "network". even with AS2 vocab, you need more vocab extensions to express things you want to. + +simply put, AP is not enough for a "protocol" to build a "network". + +but before you build a "protocol" for a "network", consider: what even is a "network", in this context? and, here's the hot take: do you even *want* that kind of "network"? do you want a separate reified #fediverse network? + +because the answer that #ActivityPub gives is actually a different one. There is no "AP network", because AP as a protocol is not enough to build a concrete network. it is intended to provide, and exists in context of, the larger #Web. + +this is the fundamental divide between #fediverse thinking and #Web thinking, where #ActivityPub straddles the line between both. + +i've seen it said that the "open-world assumption" at the foundation of the Web is actually an undesirable thing for a "social networking protocol", and as a consequence, specs built on that open-world assumption are "completely unsuitable" for that "protocol". + +but do we need a "social networking protocol"? do we even need "social networks" in the first place? + +to build the #fediverse as its own "social networking protocol" then seemingly requires that we instead go with the closed-world assumption, contrary to the #Web + +it requires ahead-of-time communication and coordination, where implementers need to be willing and available to talk to any other implementer, and this load grows with every new implementer. + +it requires you to be aware of other extensions, present and future, because your extension might conflict with someone else's extension. + +the way extensibility works in a closed-world #fediverse is that "every implementer talks to every other implementer". or maybe there is a central registry of extensions that everyone submits to their authority, as stewards of the "protocol" that is used to build the "network". this trades out the n:n relation between implementers and other implementers, for an n:1 relation between implementers and the central registry. + +the way extensibility works in an open-world #Web is you just do it. + +the challenge in closed-world systems is how to scale communication and coordination as the number of implementers grows. without a central authority, it almost inevitably leads to power coalescing in the hands of the few most popular or largest implementations, who become the "de facto" standard and get to mostly do what they want, and everyone else mostly has to follow if they want to be compatible. + +sound familiar? it should, because this is the model that the #fediverse follows today. + +indeed, the #fediverse is more closed-world than open-world. you see this in the so-called "rejection" of json-ld among presumably the majority of fedi implementations. because for the most part, AS2 lets you ignore json-ld. it only matters for extensibility, and (specific criticisms of json-ld aside) json-ld also mostly allows you to ignore it. + +so why do people still complain about it? + +well, there is the concept of "context" in json-ld, which represents shared understanding. + +when i say "john knows sally", there are several ambiguities. we can solve ambiguities by disambiguating. one way to disambiguate is to be explicit about what any term or symbol means. one way to be explicit is to use uniform identifiers. + +in particular, http/https uris have some convenient properties + +- they have authority, so you can qualify an id based on who's assigning it. +- you can use the authority component as a namespace +- you can fetch the uri and it might return something useful + +so let's say john is example.com/people/john and sally is example.com/people/sally + +what do we use for "knows"? + +well, there are multiple senses of the word "knows": + +1) is aware of the existence of +2) is familiar with +3) is having sexual intercourse with + +we mean definition 1. so we might use example.com/vocab/knows/1 + +now we have the statement: + + + + + +this is unambiguous, but we can go one step further: we can provide definitions at the uri + +say some random person sees the statement above. they don't know who john or sally are, and they don't know what "knows" means in this context. + +well, if we do a little work upfront, they actually *can* know what all of these terms mean, **without ever asking us directly** + +we put a resource on example.com for each of these terms, and each resource describes the subject of that identifier -- it is a "resource descriptor". + +the resource for knows/1 can define itself explicitly with a schema + +so at minimum we have the following schema for knows/1 + +- how to represent it in plain text: "knows" +- how to define it: "is aware of the existence of" + +the RDF Schema gives us `label` and `comment`, as defined by the RDF Schema. + +- :label "knows" +- :comment "is aware of the existence of" + +but we need to know what "label" and "comment" mean as well! not to worry, we qualify those terms with the rdfs namespace: + +- rdfs:label "knows" +- rdfs:comment "is aware of the existence of" + +now at this point you're probably wondering what this has to do with social networking. and on a practical level, if you're just interested in building a "social networking protocol", this is mostly all extraneous. + +the part that implementers have to deal with is the notion of "context" and, more specifically, how json-ld handles it, and even more specifically, what to do when two shorthand terms conflict. + +remember, the open-world solution is namespacing. what does closed-world do? + +well, let's look at `actor`. in AS2 terms it refers to the entity that performed an activity. but in schema.org terms it refers to someone playing a role in a movie or other performance. + +in a closed-world sense, you don't want to be aware of context. you don't want to have to deal with it. but even so, you still have an "implicit context" that you are using, based on how you define each term in your own understanding, what you hardcode into your software. + +what json-ld does, or what it allows you to do, is explicitly declare a `@context` that is equivalent to your "implicit context". + +this works fine if there is only one declaration that is shared exactly between two parties, but it gets complicated when the "implicit context" differs or isn't an exact match. + +this means that there cannot ever be a singular #fediverse network, because the "implicit context" differs between each software project. the only guaranteed overlap is the AS2 one. + +but it's not like AS2 didn't think of this. they wrote in this requirement: https://www.w3.org/TR/activitystreams-core/#extensibility + +> Activity Streams 2.0 implementations that wish to fully support extensions MUST support Compact URI expansion as defined by the JSON-LD specification. + +note, you aren't required to implement all of json-ld. you just need to handle the bit where you can identify the equivalence between a uri and some arbitrary string. + +but #fediverse mostly decided this is too hard, and ignore context. + +now there's a few thoughts i have here: + +#fediverse culturally seems to ignore a lot of other things as well. they ignore http caching for example. they ignore http status codes like 301 Permanent Redirect. these requirements are arguably more important than context, and they *still* get ignored. + +in fact, most fedi software is mostly just reimplementing Web browsers, but with what they consider to be the "bare minimum" of compliance. and the web they let you browse is smaller than the Web + +are these things part of the "protocol"? how far does the "protocol" extend to cover? because, as we established, #ActivityPub is not enough to build a fully functional #fediverse -- and a lot of extensions and additional specs are things that ought to be included in this "protocol", insofar as this "protocol" is desirable. + +the other thought: + +if you ignore things, that means there are cases you're not handling, losing out on robustness. ignoring context is to ignore shared understanding. + +so what do you actually lose out on when you ignore json-ld context? + +you first have to fall back to the "implicit context", where AS2 terms are generally agreed upon, but nothing else is guaranteed. + +take something like `discoverable` from mastodon. what does it mean? well, it means whatever is defined in the mastodon codebase and documentation. so we could represent that as `http://joinmastodon.org/ns#discoverable` or shorten that with a prefix. but if we do, then most #fediverse will choke on that. + +this is because #fediverse is ignoring context. the implicit context is that `discoverable` means `http://joinmastodon.org/ns#discoverable` but they don't know that. so they can't actually handle the extension in its fullest form. + +what AS2 calls out as "full support for extensions" requires being able to identify this equivalence and handle it. again, fedi does... let's call it "partial support". + +the "implicit context" is now a hardcoded but unstated requirement of this "protocol". + +which is to say: #fediverse software generally expects LD-aware producers to compact against their own "implicit context", but they don't always define that context. it's left undeclared and undefined. or it actually *is* declared, but if you give them their own expanded form then they'll not understand it. + +it's like someone saying hey, when i say "knows", i mean "is familiar with" + +and then you say "john is familiar with sally" + +and they respond WTF? what does "is familiar with" mean? + +it's like... you literally just told me "knows" = "is familiar with", but because of your own ignoring of your own context, you can't handle me saying "is familiar with"? + +in this way, as long as the #fediverse remains ignorant of context, they will remain fragile and without any sort of robustness in their "protocol". + +the alternative they have is to extend the only context they share, which is the AS2 one. but this doesn't solve the problem. it just officially blesses a single term. + +if you want to turn "activitystreams" into a "protocol" then sure i guess you can do that + +but why? what are the needs we're trying to address here? of what purpose is your "protocol"? social networking? you want a "social networking protocol"? + +before you convince people that a "social networking protocol" is necessary, you have to convince people that a "social network" is necessary. + +but more importantly, you are contrasting that "social networking protocol" against the "social Web". + +it is my personal belief that this whole "closed-world social network" vs "open-world social Web" thing is leading to a big disconnect that makes addressing people's needs harder. + +because, to be on the "network", you neglect being on the "Web". + +sure, your software might still publish your "posts" as Web resources, but that's it. you're not actually granted control or ability to manage Web resources for yourself. + +and that's why #ActivityPub C2S is being neglected, among many other things + +i am personally more in favor of a "social Web" than a "social network". + +what i want to do is make it easier for anyone to make a website, and to manage that website. + +i want those websites to be able to link to each other in well-defined and clearly-understood ways. + +i want to make friends and express myself to the fullest, in varying contexts on various websites, without context collapse. + +but it feels like #fediverse is more interested in replicating the "social network" paradigm. + +--- + +addendum 1 + +there's a whole lot of things i could say about "how we get there" but the thread was getting long enough and i want to cut it off here and clean it up into a blog post or something, without drifting too far off the original topic which was to voice my thoughts about the divide itself + +addendum 2 + +there's a separate thought experiment you could do about what it really takes for a "social networking protocol" because honestly you don't even need http. you can do "social networking" over xmpp or email or whatever. or invent your own way to send bytes over tcp/udp/whatever (inb4 xkcd) + +seriously tho, newsletters and deltachat and movim and a bunch of other things show that you can do it + +--- + +also i should mention since this is happening kind of simultaneously, this is not about the social web foundation's use of the terms "social web" and "fediverse", although the blog post did go live in the middle of me writing the thread which is a kind of irony i guess. another irony is that even though it's not about that, it could still be kinda about that. if nothing else, it demonstrates that "social web" and "fediverse" are not synonyms. diff --git a/unified.test.hugo/content/monologues/gun-culture-in-america/index.md b/unified.test.hugo/content/monologues/gun-culture-in-america/index.md new file mode 100644 index 0000000..24df00c --- /dev/null +++ b/unified.test.hugo/content/monologues/gun-culture-in-america/index.md @@ -0,0 +1,16 @@ ++++ +title = "gun culture in america" +summary = "a reactionary gun culture that perceives any attempt to curb it as an assault on their very identity" +date = "2018-02-18T01:48:00-00:00" +source = "https://mastodon.social/@trwnh/99543874314017409" ++++ + +[...] although in fact, having a permanent standing army is less legally supported than gun ownership. constitutionally, the longest that congress can raise/fund an army is 2 years... + +the larger problem is that the culture around violence in america is absolutely toxic. the war of 1812 eroded the resistance to standing armies, the fugitive slave act of 1850 let the army act as a police force (only on the president's orders post-1878), in 1904 then-sec of war decided to station foreign troops, and in 1947 the dept of defense was formed to integrate the army into the govt. so militias aren't really a modern application of civilian defense, since the govt "took over" it. + +the biggest strain was actually when the black panthers decided to arm themselves for community self-defense; white supremacists were scared and started to push for gun control. not really the first gun-scare about black people; one of the arguments used during the dred scott case was that freed slaves couldn't be citizens because then they would legally be allowed to have guns. + +anyway, the NRA got taken over in the 1970s and converted from a marksmanship club to a political advocacy group. most of the people involved in this takeover decided to try another approach: take a hardline stance against any gun licensing (to better form white militias), and to strip the black community of its guns by criminalizing them, usually in conjunction with something else...that thing was the introduction of drugs and crack into black communities, which was criminalized once people got addicted to it. furthermore, gun possession drastically increased sentencing if convicted for drug offenses. + +the end result of all that is a reactionary gun culture that perceives any attempt to curb it as an assault on their very identity. and when you call them out on this, they deflect to something else like "mental illness" instead. in other words, the whole of american gun culture revolves around a false sense of freedom and safety, directly descended from white supremacy and toxic masculinity. people commit shootings out of a desire for fame or notoriety, or out of some perceived slight or grievance, largely based on ideological assumptions or entitlement. \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/implicit-vs-explicit-collections/create-note.png b/unified.test.hugo/content/monologues/implicit-vs-explicit-collections/create-note.png new file mode 100644 index 0000000..79d9fa9 Binary files /dev/null and b/unified.test.hugo/content/monologues/implicit-vs-explicit-collections/create-note.png differ diff --git a/unified.test.hugo/content/monologues/implicit-vs-explicit-collections/index.md b/unified.test.hugo/content/monologues/implicit-vs-explicit-collections/index.md new file mode 100644 index 0000000..00d2eb7 --- /dev/null +++ b/unified.test.hugo/content/monologues/implicit-vs-explicit-collections/index.md @@ -0,0 +1,46 @@ ++++ +title = "collections should be explicitly managed" +summary = "the way to maintain an authoritative collection is [...] not to have everyone send out Create and then expect everyone else to reconstruct the collection for themselves [...] we're just replicating stuff around and then every server assembles it however it *thinks* it should be put together." +date = "2023-03-18T03:51:00-06:00" +source = "https://mastodon.social/@trwnh/110043428576595588" ++++ + +how it feels to talk about #activitypub and how #fedi implements it + +![](create-note.png) + +the way to maintain an authoritative collection is to send out Add/Remove, not to have everyone send out Create and then expect everyone else to reconstruct the collection for themselves + +i can't say i blame developers for taking the lazy route and doing the bare minimum to be compatible with what already exists, but that is so limiting and i'm not here for it + +the bigger problem is that there's so many assumptions being made with zero basis or foundation in anything. we're just replicating stuff around and then every server assembles it however it *thinks* it should be put together. + +we're getting to the point that the contradictions and shortcomings are starting to become more apparent... + +- things like moderated conversations are impossible if you don't actually have a concept of a "conversation". + +- there's so many different ways to do "groups" that it's a running joke at this point, because everyone has a different idea of what a "group" is. it's the "blind men feeling an elephant" problem. + +- things like forums and subforums, chat rooms, etc are not easily possible rn. + +the "trick" is that there isn't actually any difference between all these different presentations. if you understand "objects" and "collections" you can construct whatever you want: forums, walls, chat rooms, conversations, aggregators, whatever. it's all just objects in collections. + +right now, no one understands "collections". we just pass around objects with Create and Announce and leave it up to the consumer to figure out how they should be grouped. + +it's not even a new idea. Dennis Schubert raised a similar criticism of "replies" distribution back in 2018: https://overengineer.dev/blog/2018/02/01/activitypub-one-protocol-to-rule-them-all.html#replies-and-interactions + +> As per the ActivityStreams spec, all objects [can] have a replies property. So, a more sensible, reliable, and even more AcitivityStream’y way of handling replies would probably be adding the interaction to the replies collection + +this is not always optimal of course -- it was proposed 5 years ago. but something similar could be done. + +i think the key disagreement, misunderstanding, lack of shared reality, etc, is this: + +are we just creating a bunch of "posts"? microblogging or regular blogging, we have our own websites or web profiles, and we only care about what we ourselves are sharing? + +or are we trying to collaborate across domains? are we building a Web, a Social Web, a Linked Data Web, a Semantic Web? where our actions have side effects, and there exists some state that we care about? + +we lack that clarity of purpose + +basically we're not doing one or the other, we're kind of mishmashing them together. when you post on most fedi projects, you are publishing to your profile locally, *but* you are also sending out an activity to notify your followers. and typically, that has side-effects on remote servers. usually that side-effect is "keep a locally cached archive of that post and show it to followers." + +i think we should be clearer about the separate use-cases and concerns. \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/liberalism-and-trump/index.md b/unified.test.hugo/content/monologues/liberalism-and-trump/index.md new file mode 100644 index 0000000..fb9f0c8 --- /dev/null +++ b/unified.test.hugo/content/monologues/liberalism-and-trump/index.md @@ -0,0 +1,63 @@ ++++ +title = "liberalism and the rise of trump" +summary = "there's some broad historical revisionism going on" +date = "2018-01-14T10:35:00-00:00" +source = [ + "https://mastodon.social/@trwnh/99347736716090638", + "https://mastodon.social/@trwnh/99355650165263881", + "https://mastodon.social/@trwnh/99359516579847229", +] ++++ + +> some vox article about trump and liberalism + +eh, the article and its analysis has many issues with it + +- liberals aren't leftist +- "reforms" were gained by strikes and protests, and it was anarchists and communists that led the struggle, not liberals +- presents japanese internment as a "flaw" and not a great injustice +- "whether the state has a responsibility to ensure a moral and socially desirable distribution of wealth" is irrelevant; welfare capitalism is still capitalism +- you can't "correct" inequities by using the institutions that exist to propagate them; they are working as intended +- "appealing to national pride" is fascist +- anticommunism and mccarthyism WAS a major reactionary force, not a "purity test" by the left +- the "strategy" you quoted has mostly been adopted by modern democrats in reaction to the rise of the "religious right" and other ratfucking attempts +- the left was sabotaged by the fbi/cia +- academia and technocracy aren't hallmarks of the left, either +- "the hard work of liberal democratic politics" is, again, fruitless; the real issue is the complete defanging of the left by COINTELPRO and other initiatives; we need more haymarket squares and more may days, not endlessly begging politicians to not murder us +- in short: yes a revolt is justified because america was founded on a fascist mythos of expansionism and exceptionalism + +i guess in conclusion i'd say that the "make america great again" point is really close to being on the money + +- the right = "make america great again" by national rebirth (one of the 3 main tenets of fascism) + +- the liberals = "america is already great" because we just need a bit of reform (and all horrors are simply aberrations) + +- the left = "america was never great" because it was explicitly founded as colonialist/imperialist/white-supremacist + +> [...] + +no, the extreme right wants a reactionary / openly fascist state that broadly uses violence to liquidate "degenerates" and other "undesirables". the state would be an even stronger force of national supremacy and authority than it already is. + +I guess the larger point I'm trying to make is that there's some broad historical revisionism going on, as an attempt to maintain authority. the idea of the nonviolent reformist solution to everything is not how most social revolutions work. this wasn't new to the 1960s; a much longer history of struggle against state violence exists, going back through all of america's colonial history + +i.e. as a nation, we've never "reformed" anything. radical abolitionists like john brown and the free soil party did more to end slavery than abraham lincoln ever did. the black panther party's community policing and radical housing and food programs were effective despite the fbi assassinating almost every single one of their leaders. fdr proclaimed to businesses that the new deal would "save capitalism" from the labor insurgency. + +the original article kind of glosses over all this in an attempt to paint trump as a new phenomenon and not the natural result of weak reformism utterly failing to uplift anyone. the central thesis is that the left failed because of a lack of bourgeois democracy, not because of pervasive sabotage efforts by the state like cointelpro + +> [...] + +i can see that. i grew up in alabama, and there's a rich history of communism down here. (Hammer and Hoe is a good book to read about this) + +the big switch from dem to GOP was an orchestrated effort to create an "identitarian" base of support. that is, by building up whiteness, by having politicians speak at churches and then funding preachers to spread political messages, etc... political parties hope to become functions of identity + +the alt-right is, in fact, the most modern outgrowth of the "identitarian" movement -- their politics are descended directly from the cynical traditionalism employed by the political right for over half a century. the people who grew up with this stuff eventually realized that the GOP was in the same boat as the dems; that military contracts and tax subsidies was their only real aim. + +but the real problem was that there was no opposition to this idea -- the fbi destroyed it with cointelpro and by assassinating anyone who became too influential. + +in this void, the liberals decided that they would try to minimize racial tensions rather than approach them head-on. the outgrowth of this was the dlc, which argued that the democrats had gone "too far to the left" with the new deal and great society legislation. + +if i had to pick a reason why much of the south doesn't like democrats, it would be that they just don't trust them. and their visible options have been restricted to the democrats and republicans, which is barely a choice at all. so some people vote gop because they think it'll trickle down or their taxes will go down. democrats are stuck in this perception that taxes and welfare are the only way forward, which doesn't really net much + +but way more people around me are nonpolitical. most people don't vote. they're too busy working at jobs that don't pay enough, and either voting hasn't done anything for them, or they CAN'T vote. the conversation is dominated by republicans who promise lower taxes, and by democrats who insult them. every time alabama comes up in national news it's always derisively, and people notice that stuff. + +i very much believe that if were any legitimate opposition to the established order, it would gain supporters in droves... but the state has prevented that from being viable by neutralizing opposition wherever it finds it. the FBI and CIA, as part of the "national security" apparatus, take the view that any subversion is harmful to national security. and i mean, they're kinda right. but that's the whole problem... \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/mainstreaming-mastodon/index.md b/unified.test.hugo/content/monologues/mainstreaming-mastodon/index.md new file mode 100644 index 0000000..af0f587 --- /dev/null +++ b/unified.test.hugo/content/monologues/mainstreaming-mastodon/index.md @@ -0,0 +1,44 @@ ++++ +title = "mainstreaming mastodon" +summary = "[...] one of the replies was something along the lines of how we should be \"turning Mastodon from a small platform for the fringes and oppressed minorities to a platform that welcomes more mainstream members\" and i legit shuddered while reading that. what a terrifying thought." +date = "2023-02-02T08:40:00-06:00" +source = "private" ++++ + +the shit i see on the mastodon issue tracker is driving me to just build my own thing because i honestly think whatever good culture mastodon has is quite possibly not long for this world + +some people literally just walk in and ask "why is this not like twitter" and demand that it be changed to suit their whims. and i feel like gargron is starting to take their side because gargron just wants More. old users be damned, they're just a vocal minority now. + +i mean, i wanna be wrong, but i don't actually think there are any guiding principles behind mastodon except "whatever gargron wants", so it is at the very least a possibility, if not a credible threat + +there was a post i saw earlier yesterday about something like, idk, i think biz stone said he was advising gargron, and one of the replies was something along the lines of how we should be "turning Mastodon from a small platform for the fringes and oppressed minorities to a platform that welcomes more mainstream members" and i legit shuddered while reading that. what a terrifying thought. + +on some level, sure, it's probably cool for "mainstream" people to have something healthier than corporate social media. but i'm really concerned that they'll ruin it for the rest of us, exactly those "fringe and oppressed minorities" who were here for years. years ago we talked about the sort of "detoxification cycle" that new users would go through, and with every new wave, people acclimate less and less. they import more of their old behaviors uncritically. + +ultimately? i think things will probably settle in at a point that's better than others but worse than it could have been. + +this exact kind of mentality by newcomers who feel entitled to influence + +> you don't owe the top of the pyramid jack squat. The early movers *need* you more than you need them. + +if i may be so frank, can i just say: we don't "need" you *at all*. our experiences are rich and valuable and span over half a decade. you're certainly welcome to be around here, and you're welcome to use this software, but you have no right to demand we center you above ourselves. + +also the idea that there's some sort of "secret mastodon development cabal" is ridiculous. for better or worse, there's gargron, and i guess in some ways there's claire, and that's about it. everyone else is simply acting independently in their own interests and on their own agendas. the entire reason i worry can be summed up by the fact that gargron has unilateral decision-making power and final say. but, to his credit, he does consider the consequences. + +anyway, anything i say is with the disclaimer that i am not a representative of anyone else, but perhaps i should be more overt and assertive about it. when i say something "without 100% certainty" i am not implying a vague recollection of events, i am only indicating that i have no decision power. + +tangentially, the real problem with these design decisions in mastodon is that they're inconsistent, precisely because it's all on gargron, and gargron is not strongly in favour of these decisions. it all depends on the feedback and advocacy of community members to convince him to do anything, and then he'll do it however he wants to or ends up doing it. + +real consistency? we'd not have numbers in explore/trending either, nor on detailed status views, nor in api. no "1+". it'd probably be some boolean like `has_replies` or something, which translates to an icon indicator to show the thread. + +but doing it that way takes commitment. it takes decisiveness. and that's simply not there. + +there's a lot of these scattered around the project codebase -- places where gargron wanted to do something one way, a lot of the community had to vocally disagree, and we ended up with a half-measure + +there was a similar case around hiding your follower counts, where gargron decided to only allow hiding the contents because he thought follower counts were important signals of account quality. even though the counts can be faked (and they have been!) + +once again, though... you have to give the guy credit for not rejecting all this outright. it's the only reason we ended up with anything better than twitter instead of Yet Another Twitter Clone. + +to quote someone anonymously: + +> i don't like a lot of the decisions mastodon makes but i god damn respect "we have a philosophy and that's why we are doing it that way" in particular if the philosophy is thinking carefully about how decisions affect the minority \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/making-better-stuff-is-unprofitable/index.md b/unified.test.hugo/content/monologues/making-better-stuff-is-unprofitable/index.md new file mode 100644 index 0000000..1cd654b --- /dev/null +++ b/unified.test.hugo/content/monologues/making-better-stuff-is-unprofitable/index.md @@ -0,0 +1,10 @@ ++++ +title = "making better stuff is unprofitable" +summary = "there will inevitably be a point where it is unprofitable to improve a product any further." +date = "2017-12-22T06:06:00-0600" +source = "https://mastodon.social/@trwnh/99217860566004390" ++++ + +There will inevitably be a point where it is unprofitable to improve a product any further. + +i.e., if Apple's primary goal was to make useful products, it would make choices that result in a better product even if it was slightly more expensive. But their primary goal is profit, as it is for every corporation under capitalism. Making better stuff is unprofitable. \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/mastodon-api-value/index.md b/unified.test.hugo/content/monologues/mastodon-api-value/index.md new file mode 100644 index 0000000..64319a3 --- /dev/null +++ b/unified.test.hugo/content/monologues/mastodon-api-value/index.md @@ -0,0 +1,12 @@ ++++ +title = "the primary value of mastodon is in its api" +summary = "mastodon isn't really all that special [...] but the second you try to have a mobile app, you immediately recognize the value of the mastodon api [...] it's a shame it isn't a real standard..." +date = "2023-02-06T00:56:00Z" +source = "https://mastodon.social/@trwnh/109815069913581608" ++++ + +to what extent can it be said that the primary value of mastodon is in its api + +mastodon isn't really all that special in the fediverse or as a software, because you have so many options and differing implementations of the activitypub protocol. but the second you try to have a mobile app, you immediately recognize the value of the mastodon api. it's a pseudo-standard at this point because it mostly just works, and pleroma/pixelfed/gotosocial copied it for compatibility with existing clients. it's a shame it isn't a real standard... + +or, rather, what would a real standardized microblogging api look like? the nearest thing is probably micropub/microsub which doesn't quite do as much \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/mastodon-as-twitter-do-over/index.md b/unified.test.hugo/content/monologues/mastodon-as-twitter-do-over/index.md new file mode 100644 index 0000000..2d76cb6 --- /dev/null +++ b/unified.test.hugo/content/monologues/mastodon-as-twitter-do-over/index.md @@ -0,0 +1,112 @@ ++++ +title = "mastodon as a twitter do-over" +summary = "it would probably behoove us all to consider what mistakes twitter did and how we can avoid them." +date = "2018-01-12T06:20:00-06:00" +source = "https://mastodon.social/@trwnh/99336824877757248" ++++ + +i wonder if it would be a good idea or a bad idea for mastodon to adopt a way to view popular hashtags + +pros: better discovery +cons: going down the same road twitter did + +actually it's kind of interesting to think of mastodon as a twitter do-over, because it would probably behoove us all to consider what mistakes twitter did and how we can avoid them. + +## hashtags + +we're obviously past the age of posting toots via sms, so let's start with hashtags. + +* aug 2007: hashtags proposed by users as irc-channel metaphor +* july 2009: twitter starts hyperlinking hashtags +* 2010: twitter starts tracking "trending topics" + +but of course the mistakes that twitter did were to attempt to apply an algorithm to trends, meaning words and phrases could trend, and some hashtags could be filtered out or censored. + +## external media + +i think we're also past the point of external media hosting on twitpic/yfrog/etc, since internal media hosting has become far more widespread. + +## replying + +so the next thing is to look at replying and boosting statuses. starting with replies, because boosting is a bit more involved in analysis. + +* nov 2006: @ reply first used +* may 2007: @replies adopted by twitter + +not much to say here. i guess i'd note that it makes a service more conversation than status-oriented, but that's about it? conversation is good + +## boosting + +now, about boosts... + +* apr 2007: "ReTweet" first used +* jan 2008: "RT @user" first used +* nov 2009: twitter adds retweet button + +so far so good. no need to clog up feeds with multiples of the same stuff. now here's the problem: + +* ~2009: people add comments to manual RTs +* apr 2015: twitter adds quote tweets + +the biggest problems with quotes? they break context, and they lead to dogpiling. mastodon hasn't adopted quote toots, and probably never should. + +## conversation vs content + +just about the last thing to add at this point is twitter's attempt to transition from a conversational platform to a curated content provider, especially since 2015. that's bad. + +--- + +## further discussion + +### replying to boosts + +> who replying to boosts mentions (on twitter, the reply tags both the person who retweeted and the person who posted, whereas on masto only the person who posted it gets the reply) +> +> the 2nd is more nebulous on how it _should_ work and i go back and forth on it tbh. like there's a lot of confusion on who someone is replying to on twitter +> +> but also i have had someone point out that by automatically tagging in the person who boosted it, it takes some responsibility off of the original poster to reply, which helps when you have posts getting more attention than you can handle + +when someone boosts a status, and you reply to that boosted status: are you replying to the original poster, or to the person who boosted it? that's the primary consideration there. + +twitter steamrolls everyone into the conversation, mastodon doesn't. i like the current behavior. if it's relevant to the person who boosted, i'll manually tag them in, perhaps as a sort of cc. + +### replies in home feeds + +> how replies to multiple people show up in your feed (generally this has worked by "if you follow one person who is mentioned in the reply it shows up") +> +> i think the 1st is annoying as fuck personally since i'm missing pieces of conversations, especially on mastodon with private posts (and this in turn can affect social ettiquette as people go "my friends are talking, i'll join in" without acknowledging the extra party privately posting) + +maybe break it down to decide who's relevant to each new status? + +if it's two people you both follow, then i guess it's not too bad to show you their conversation. but social etiquette might mean you shouldn't butt in, if it doesn't involve you. so there's a potential argument to be made to NOT show other people's conversations. + +on the other hand, it's generally more useful to follow your friend's conversations, because there is a high chance you'll be interested in them. this is what both twitter and mastodon do right now, and it's kind of taken for granted. + +when multiple people get involved, it gets a bit more tricky. + +possibility 1: only show the conversation if you follow everyone mentioned +* still shows you friends, and allows friends to join in +* if an external person joins the convo, the convo will continue in their mentions, but will not reach your timeline? it's debatable whether you would want to see ALL of the posts in the convo, or just the ones with your friends. could lead to abrupt disappearance of convos from your timeline. + +twitter's behavior is to show you the conversation if you follow the poster + the *first* mention. the assumption is that the post is targeted primarily at the first person mentioned. this may or may not be actually true, though. for completeness, it's assumed to be true. + +the only possible extension is to show ANY post from people you follow that mention ANYONE you also follow, which balloons pretty fast. + +i don't really have any thoughts about private accounts, because this isn't really an issue on mastodon. mastodon's idea of a locked account revolves around approving followers, but locked users can still post publicly. it's just impossible to see their followers-only toots without them approving you. so, post-level privacy sidesteps this issue; private accounts can still post publicly. much better than twitter's all-or-nothing approach. + +### private posts on mastodon + +> where private post issues arise is like: +A posts privately, B replies, C replies to B +> +> I follow B and C so I see C's reply to B in my timeline, despite not being able to see the original context AT ALL because it's private + +so does C follow A? I would say that ideally, if the original post is privated to A-followers, then all replies are also privated to A-followers. I'm not entirely sure if this is indeed the case; I assume not, since you're asking about it. + +It seems easier to handle this for post-comment systems rather than post-reply systems, though the distinction between the two is rather arbitrary. Privacy in the first is encompassing; the second cascades. + +Due to specifics of how post-reply systems are implemented differently than post-comment systems (namely, in treating follow-ups as linked nodes rather than as children), I don't really know how best to propagate privacy attributes. It seems a bit strange, protocol-wise, to say that D's reply to C should be limited to A's followers. Perhaps this meshes back with the "multiple reply" issue above. + +So I guess the two-birds-one-stone solution is to only show you toots where you follow EVERYONE mentioned. But this has downsides, again as mentioned above... it stifles expansion of social circles. You'd have to go to someone's profile to see all their toots. + +Tweetdeck, before being bought out, used to have an option to show ALL replies from people you followed. Maybe bad for social etiquette to jump in with strangers, but it had a use case. \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/misc.md b/unified.test.hugo/content/monologues/misc.md new file mode 100644 index 0000000..d9890da --- /dev/null +++ b/unified.test.hugo/content/monologues/misc.md @@ -0,0 +1,126 @@ ++++ +title = "miscellaneous" +summary = "stuff that didn't get its own post" +draft = true ++++ + +## https://mastodon.social/@trwnh/2264242 [i disagree with my past self somewhat] + +the profile model itself is dead [...] streams are the future and also they make way more sense + +## https://mastodon.social/@trwnh/99346993416792417 + +not trying to sell ya, just fawning over how much i'm in love with xfce lol. it's just wild how microsoft decided everything would be 96dpi forever + +## https://mastodon.social/@trwnh/99557570047763492 + +I wish there was a way to search up the title of old children's novels published before 2000 by plot summary or keywords... there are two different books that are on the tip of my mind, but whose titles I've long since forgotten. I doubt they've been digitized or republished, so they may be lost to time forever. + +## https://mastodon.social/@trwnh/99793615497112400 + +hot take: mastodon should be more like email than it already is + +## https://mastodon.social/@trwnh/99899695933102322 + +idk, the thing about e.g. python or ruby is that they focus a lot more on having clean syntax and being easy to understand. + +## https://mastodon.social/@trwnh/99937186098244775 + +> I was under the impression that including "cisgender" in straight was controversial? + +I mean... the "controversy" is in how being transgender intersects with heterosexual / heteroromantic. some might argue that "trans people aren't straight" is transphobic because it denies their association with a binary gender. others disagree because being trans is inherently queer and deviates from the "norm" of society. + +## https://mastodon.social/@trwnh/99992566429566674 + +In a way, it's like saying paper should never have been invented, and we should all have continued chiseling stone. That doesn't mean we should forget how to chisel stone; it just means that we shouldn't chisel new stones for *everything* -- paper will do fine in most cases. + +## https://mastodon.social/@trwnh/99997039233920487 + +Hmm... I wouldn't say it's "security by obscurity" in a pejorative way -- there is a very real and very bad habit on Twitter of people "namesearching", or tracking specific terms so that they can jump into conversations. + +## https://mastodon.social/@trwnh/100009272925737468 + +until maybe as late as 2016, twitter thought of itself as a "real time update news network and discussion platform" but now it thinks of itself as "consuming interests and topics" + +## https://mastodon.social/@trwnh/100053713095158984 + +"anarchists are real enemies of marxism" is a self-fulfilling prophecy, fuck. treat someone as an enemy and they become your enemy. + +[...] + +concept: parody of that old relacore ad ("stress induces cortisol. relacore reduces cortisol.") but replace stress with twitter and relacore with mastodon + +## https://mastodon.social/@trwnh/100063071127017012 + +people aren't always paid to disrupt, they may be doing it for personal reasons, ideology, etc. call them "trolls", it's accurate re: the practice of trolling for attention. + +## https://mastodon.social/@trwnh/100072299035734958 + +it's a false assumption that crypto is trustless + +## https://mastodon.social/@trwnh/100085567120616255 + +hard to say; what makes for a good discourse platform? + +## https://mastodon.social/@trwnh/100087757497941062 + +there's a sort of fetishism around commodity goods from america throughout much of the middle east + +## https://mastodon.social/@trwnh/100097247421492501 + +how to pick a mastodon server + +https://mastodon.social/@trwnh/100097303707813337 + +servers shut down + +## https://mastodon.social/@trwnh/100103662264850023 + +on some level i understand the ignorant desire for change, simply for change's sake [...] + +## https://mastodon.social/@trwnh/100105279502219193 + +by "contradictions" of liberalism I mean things like +- "job creation" when we have the technology to reduce work +- "violence is bad" in the face of endless wars +- "competition is good" when the natural end result is a monopoly + +https://mastodon.social/@trwnh/100105523140235220 + +in general, the liberal/neoliberal split isn't very useful + +https://mastodon.social/@trwnh/100109839779411064 + +"conservative" and "liberal" is a meaningless dichotomy + +## https://mastodon.social/@trwnh/100128470703676020 + +all my friends are cute + +## https://mastodon.social/@trwnh/100131913998697452 + +yeah, idk how i would have gotten off twitter if they hadn't made it extremely easy for me by breaking 3rd-party apps, shadowbanning me being blocked by too many TERFs, and refusing to ban fascists + +## https://mastodon.social/@trwnh/100141167073699878 + +the chronological stuff was like 20% why i left twitter but the other 80% was the "reactionary sensationalist culture" as you put it + +## https://mastodon.social/@trwnh/100164745640244312 + +i don't think it can ever be said that the state is acting in "self-defense". self-preservation? maybe. but self-defense is the domain of the oppressed. at the very least, merely surviving is a radical act. the long-term solution is to defang power and build alternative power. + +## some holodomor stuff in 4 subchains + +https://mastodon.social/@trwnh/100206391621628088 +https://mastodon.social/@trwnh/100206500940583286 +https://mastodon.social/@trwnh/100206609835191626 +https://mastodon.social/@trwnh/100206657397747867 + +## https://mastodon.social/@trwnh/100234428636106449 + +To use Twitter as the perennial example of bad design: say you want to indicate that something is bad. You could previously .@ to make it show up to your followers. Now, you quote tweet it, which exclusively shows it to your followers and not the participants of the old thread. But the third and harder option is to not do a public callout at all. + +## actor types idk not rly important + +https://mastodon.social/@trwnh/100240521462320522 +https://mastodon.social/@trwnh/100240555863529471 diff --git a/unified.test.hugo/content/monologues/multi-protocol-approach/index.md b/unified.test.hugo/content/monologues/multi-protocol-approach/index.md new file mode 100644 index 0000000..08a7a68 --- /dev/null +++ b/unified.test.hugo/content/monologues/multi-protocol-approach/index.md @@ -0,0 +1,56 @@ ++++ +title = "re: starting to investigate other protocols" +summary = "The main thing I'm trying to formulate right now is a generic understanding of what is a protocol and what makes up a protocol [...] The \"implicit protocol of the fediverse\" is not sufficiently described by \"the ActivityPub specification\"" +date = "2024-09-29T19:53:00-06:00" +source = "https://socialhub.activitypub.rocks/t/socialwebfoundation-what-do-people-think/4564/13" +inReplyTo = "https://socialhub.activitypub.rocks/t/socialwebfoundation-what-do-people-think/4564/12" ++++ + +
    +

    And from an activist perspective, I’d be very loud about starting to investigate other protocols – and why you’re doing it.

    +
    + +If anything, the recent developments have definitely gotten me to more seriously revisit some ideas I had a few years back about a multi-protocol approach[^multi-proto-approach] and how best to synthesize several different protocols that have similar or different approaches to certain things. The main thing I'm trying to formulate right now is a generic understanding of what is a protocol and what makes up a protocol. To give an example limited to just 3 "protocols" that mostly work off of from/to semantics, we can look at SMTP, XMPP, and ActivityPub. + +- Data format: SMTP is more or less plaintext, XMPP is XML, and ActivityPub is JSON. +- Message payload format: SMTP uses RFC 822 messages, XMPP uses stanzas, and ActivityPub uses AS2 Activities. +- Message semantics: SMTP messages have headers and body content. XMPP stanzas can be message, presence, or information query. ActivityPub activities... are activities. That's it. + +So before you even get to the part where you can do anything interesting, you find that ActivityPub is really not much of a protocol. All three of these protocols let you "send and receive", but there's more to communication than just sending and receiving. So, given that, what does ActivityPub *actually* provide? + +The best I can describe it right now, ActivityPub provides the following "protocols" layered on top of LDN: + +- A protocol for "following". You send a `Follow`, it can trigger an `Accept` or `Reject`, you can `Undo` it later, and there are side effects of being added to `followers`/`following`. +- A protocol for "liking". You send a `Like`, there are side effects of being added to the `likes` collection. +- A protocol for "(re)sharing". You send an `Announce`, there are side effects of being added to the `shares` collection. + +Everything else is far too undefined or under-defined to constitute much of a "protocol". Things like Create have "surprisingly few side effects" according to the ActivityPub TR, because they were intended for the C2S API to be able to do basic CRUD and Collection management. But in the fediverse, Create actually has a lot more to it! So if we were to define a basic "social media post" application protocol for the lowest common denominator of most of the current fediverse, then we need to define more than what the ActivityPub spec concerns itself with, just to get to "hello world" levels of functionality. We need to explicitly define the following additional things to get from "AP Create notification" to "social media post" in its most limited form: + +- You send a `Create` where the `object` is a `Note`. + - The object MUST have `content` whose value is a string. + - The content MUST conform to some sanitized subset of HTML. + - The object MUST have a `published` whose value is a string containing a timestamp. + - The object MUST have an `attributedTo` whose value is exactly one actor. + - The actor MUST be of type `Person`. + - The actor MUST have a `name` whose value is a string. + - The name MUST be plain text, and will be interpreted as plain text. + - The actor MUST have an `icon` whose value is the URL to a 1:1 image file. + - The actor MUST have a `preferredUsername` whose value is a string. + - The username MUST be unique on the domain. + - The username MUST link back to the actor when querying that actor's domain's WebFinger endpoint for an `acct:` URI formed of the username and the domain. + - The object MUST have `to` or `cc` or both, whose value is an array which contains at least `https://www.w3.org/ns/activitystreams#Public`. + +Now, I'm simplifying a bit, so the above has the following caveats: + +- Requirements can be relaxed or willfully violated as various needs arise. For example, if an actor is missing an `icon`, the protocol can be modified such that a "default avatar" is assumed instead. +- Requirements can also be added or extended as the protocol matures and develops. For example, support for `inReplyTo`, `attachment`, `tag` can be added over time. +- Protocols may require other protocols or specifications. For example, WebFinger in the above "social media post" protocol. +- Additional protocols would be need to be defined for each use case. For example, a similar protocol for "making a blog post" could be defined using `Create Article`. +- Specifications ideally ought to be followed, but ultimately the real protocol is what implementers end up doing, and the above protocol codifies some mistakes and errors into itself. For example, hard assumptions of actor and object types, hard requirements on the maximum cardinality of properties like `attributedTo`, soft requirements for specifically `https://www.w3.org/ns/activitystreams#Public` instead of `as:Public`. (All of these things represent real incorrect assumptions by real implementers.) + +When you put it like this, it becomes clear that if the fediverse wants to continue to make use of ActivityPub, then there are a *lot* of things that need to be explicitly defined as protocols layered[^protocol-layering] on top of ActivityPub. The "implicit protocol of the fediverse" is not sufficiently described by "the ActivityPub specification". We need to standardize and align on common patterns and common protocols for those patterns. + +And the challenge here, the issue is, that if we don't do this work at a grassroots level, then Meta will do it for us. (Can you imagine a "developer portal" for "interoperating with Threads"?) Things like the FEP process allow writing up these "micro-protocols", and then after that, the difficult task of cat-herding begins, as you need to get implementers onboard with adhering to these specifications. And of course, we're all mostly doing this in our free time and without access to the resources that larger organizations have or can gain access to. So it's going to be an uphill battle. But whichever "protocol building blocks" we can agree and align upon, let's go for it. + +[^multi-proto-approach]: I was specifically looking at a "unified communication" project, which mapped abstract forms of communication like "messaging", "publishing", "discussing", "reading" onto existing protocols like SMTP, XMPP, ActivityPub, IRC, RSS, ATOM, HTTP. There's a risk of ending up with something like Pidgin here, but maybe that's not the worst thing. +[^protocol-layering]: And of course, other protocols and other layerings are possible. Libervia (formerly Salut a Toi) does AS2 with PubSub over XMPP, but offers an "ActivityPub gateway". You could, if you wanted to, send AS2 over an SMTP transport. \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/multiple-accounts/index.md b/unified.test.hugo/content/monologues/multiple-accounts/index.md new file mode 100644 index 0000000..afaaaa0 --- /dev/null +++ b/unified.test.hugo/content/monologues/multiple-accounts/index.md @@ -0,0 +1,26 @@ ++++ +title = "multiple accounts" +summary = "why/when do people use multiple accounts, and what features can be implemented to reduce the friction in using just one account?" +date = "2017-12-17T03:55:00-06:00" +source = "https://mastodon.social/@trwnh/99189033326279405" ++++ + +unrelated thought: been trying to hash out a solution to the "multiple accounts" issue with social media. namely: why/when do people use multiple accounts, and what features can be implemented to reduce the friction in using just one account? would appreciate feedback. + +off the top of my head: + +- private vs public accounts for trusted people (answered by privacy options on toots) +- multiple interests (not really solved currently; perhaps implementing a tag system and letting people mute certain tags? Diaspora*-style aspects can get complicated) +- separate identity (unsolvable and would be insecure to attempt with one account) + +wrt multiple interests, this really is my biggest pain point with ANY social media (coming from someone who has had like 15 birdsite accounts at once) + +perhaps not exactly tags, but having a category system like google+ would be nice and perhaps easiest to manage when considering tootboosts. but this also might complicate the issue? nevertheless, it could be optional (default behavior would be to boost to your profile, no categorization involved) + +the tag approach would be easiest for your own toots, but the categories wouldn't be too bad and would also allow for separating different boosts + +--- + +## further discussion + +problem with diaspora*'s aspects (and by extension, Google+ circles which aped it) is that it's a bidirectional metaphor for a unidirectional relationship. you're supposed to pick who can see a post, but they might not even follow you. I would understand if instead it functioned and was advertised as a way to split your timeline into multiple timelines. As is, sharing to aspects/circles/etc. is needlessly confusing. \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/nation-stateification/index.md b/unified.test.hugo/content/monologues/nation-stateification/index.md new file mode 100644 index 0000000..752211c --- /dev/null +++ b/unified.test.hugo/content/monologues/nation-stateification/index.md @@ -0,0 +1,12 @@ ++++ +title = "fedi nation-states" +summary = "i forgot we live in a geopolitical climate of tens of thousands of digital nation-states each with their own culture and borders. for a second there i thought i was using a general communication service" +date = "2023-03-24T10:25:00-0600" +source = "https://mastodon.social/@trwnh/110078954614492914" ++++ + +oh right i forgot we live in a geopolitical climate of tens of thousands of digital nation-states each with their own culture and borders. for a second there i thought i was using a general communication service + +anarchist, but against fediverse "instances" + +the dilemma of fedi is that i don't want to host my own service using current software, but i don't want to be judged by whose service i use or by who else uses that service \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/necromancy/index.md b/unified.test.hugo/content/monologues/necromancy/index.md new file mode 100644 index 0000000..6451247 --- /dev/null +++ b/unified.test.hugo/content/monologues/necromancy/index.md @@ -0,0 +1,14 @@ ++++ +title = "necromancy" +summary = "\"i saw the soul of my grandpa and he told me to keep working hard\" is almost mystic and folkloric, not really like \"i summoned the soul of my grandpa to give me encouragement\" and still one step removed from \"i inserted my grandpa's soul into a corpse / some bones to give him physical form\"" +date = "2018-04-12T07:31:00-00:00" +source = "https://mastodon.social/@trwnh/99845293118930539" ++++ + +i always have to stop and realize people don't mean actual necromancy (learning from the dead) and instead they mean some kinda pseudo-resurrection/reanimation thing in pop culture, haha + +> honestly, is divination through dead people's spirits any better? + +there's not as much stigma against it, compared to the physical. "i saw the soul of my grandpa and he told me to keep working hard" is almost mystic and folkloric, not really like "i summoned the soul of my grandpa to give me encouragement" and still one step removed from "i inserted my grandpa's soul into a corpse / some bones to give him physical form" + +it seems like souls are free to either stay in heaven or roam the land of the living, but giving them physical form is like playing god \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/neoliberalism/index.md b/unified.test.hugo/content/monologues/neoliberalism/index.md new file mode 100644 index 0000000..6e86462 --- /dev/null +++ b/unified.test.hugo/content/monologues/neoliberalism/index.md @@ -0,0 +1,18 @@ ++++ +title = "what is neoliberalism" +summary = "in short, everything is a market and the experts should decide the best policies to help the market" +date = "2018-03-14T08:10:00-00:00" +source = "https://mastodon.social/@trwnh/99681239150233207" ++++ + +> What is #neoliberalism? Is it a set defined thing or a term just like liberalism that could mean lots of different things to different people? + +kinda both? liberalism and neoliberalism have academic meanings, but get used differently by different people + +ie neoliberalism is just largely a return to liberalism; the idea that govt's role is to help business, that markets can be used as a force for good https://en.wikipedia.org/wiki/Neoliberalism + +maybe best exemplified by thatcher, reagan, greenspan, clinton; the support of "free trade" agreements like NAFTA and TPP or organizations like the IMF or WTO; opposition to people like ralph nader in the 1970s; concepts like "the marketplace of ideas" or "soft power"; in short, everything is a market and the experts should decide the best policies to help the market + +> [...] + +Neoliberalism seems like a big tent, but that's really only because it's ideologically sparse and lacks substance. Most of the Western world holds a neoliberal economic and domestic policy, and a neoconservative foreign policy. \ No newline at end of file diff --git a/blog.hugo/content/_dump/fcc-repeals-net-neutrality.md b/unified.test.hugo/content/monologues/net-neutrality-repealed/index.md similarity index 74% rename from blog.hugo/content/_dump/fcc-repeals-net-neutrality.md rename to unified.test.hugo/content/monologues/net-neutrality-repealed/index.md index ae0e101..fe3e583 100644 --- a/blog.hugo/content/_dump/fcc-repeals-net-neutrality.md +++ b/unified.test.hugo/content/monologues/net-neutrality-repealed/index.md @@ -1,4 +1,14 @@ -2017-12-15 01:35 ++++ +title = "the day net neutrality was repealed" +summary = "The Open Internet Order of 2015 which was just repealed was not too much. It was not enough." +date = "2017-12-15T01:35:00-00:00" +source = [ + "https://mastodon.social/@trwnh/99175742733649566", + "https://mastodon.social/@trwnh/99175781630692764", +] ++++ + +> [...] Hey, remember when Comcast filtered P2P traffic including BitTorrent, Skype, and Spotify? @@ -8,17 +18,17 @@ Remember when Verizon throttled all video except mysteriously for their subsidia Because I remember. -If you're celebrating today, then what you're saying is, it's a GOOD thing to have no legal authority to challenge ISPs when they pull the shit they clearly already did. +[Is it] a GOOD thing to have no legal authority to challenge ISPs when they pull the shit they clearly already did? Because that's literally all that happened in 2015, w/ forbearance In fact, Wheeler ONLY pursued the clauses of Title II that dealt with nondiscrimination (common carrier status), and didn't apply rate regulation or taxes or last-mile unbundling. -He did this because Verizon successfully sued to prevent the FCC from using Section 706, and the judge told Wheeler he needed to reclassify as Title II. +He did this because Verizon successfully sued to prevent the FCC from using S706, and the judge told Wheeler he needed to reclassify as Title II. It should be obvious that the "free market" will not solve a problem created by the market. This is market failure, plain and simple. ---- +> [...] Which rules "allow" ISPs to monopolize regions? ISPs collude to not enter markets, renege on coverage expansion contracts, and prevent competition by claiming ownership of the backbone. diff --git a/unified.test.hugo/content/monologues/one-piece-thematic-breakdown/index.md b/unified.test.hugo/content/monologues/one-piece-thematic-breakdown/index.md new file mode 100644 index 0000000..db59314 --- /dev/null +++ b/unified.test.hugo/content/monologues/one-piece-thematic-breakdown/index.md @@ -0,0 +1,42 @@ ++++ +title = "a thematic breakdown of one piece" +summary = "east blue = dreams. paradise = family. new world = liberation." +date = "2024-09-30T11:22:54-0600" +source = "original" ++++ + +i was idly thinking about one piece this morning, as one does. mainly thinking about how east blue was peak one piece for me, and those first 100 chapters could honestly stand as their own self-contained story. one piece could have ended right there and i would have come away satisfied with what i read. but of course, it didn't end there, and i'm also glad it didn't end there. but it got me thinking about the overall theme of one piece, and specifically the overall theme of east blue as a self-contained saga. + + + +## from "romance dawn" onward to the "grand line" + +honestly, we could go further and say that the first chapter of one piece is also a self-contained story, and in fact, it actually *was* a self-contained story. romance dawn was of course released in various forms as one-shots, before it eventually became the first chapter of one piece. + +the story of that first chapter is very simple: it's about a boy with a dream. but it's everything else about the story that grips you, like the reason for that dream, and the magnitude of that dream, and what that dream involves. + +for the time spent in east blue, the story mainly covers a great adventure filled with romanticism. the character arcs in this part of the story are mainly centered around following your dreams. as you meet new characters, you learn about their dreams, and in learning about their dreams, you get to know them as people. everyone has a reason to keep going. everyone has drive and motivation. it's honestly a dynamic world that feels alive, even though it's pretty small at this point in the series. + +throughout it all, there is the end goal of entering the grand line, which is portrayed as a paradise for pirates, where wacky things happen all the time, and the adventure never ends. everyone has their reasons for seeking it out. luffy wants to become the pirate king, and to do that he needs to find the great treasure "one piece" at the end of the grand line. zoro wants to become the world's greatest swordsman, and to do that he needs to challenge the current world's greatest swordsman who lives in the grand line. nami wants to draw a map of the world, and that means she'll need to enter the grand line at some point. usopp wants to be a brave warrior of the sea, and the grand line is just the thing to toughen him up. sanji wants to find the all blue, which might exist somewhere in the grand line. + +## i still have my nakama + +once things go into the grand line, the theme of adventure is still there, but the focus of each arc is better summarized by the theme of "family". chopper is abandoned by his reindeer family, but finds new family in dr. hiruluk and later dr. kureha before eventually joining the crew. vivi knows that the straw hats will always be her family because of the whole x thing. robin finds family in the ohara researchers and in saul, only for the buster call to take it all. franky has tom and iceberg and later the franky family. brook's entire crew dies and his dream is to reunite with laboon. luffy's entire crew gets sent flying by kuma and he despairs over this because he lost his family. then he finds out his sworn brother is set to be executed, and he goes to save him. when he loses his brother he feels like he has no family left. until he is reminded that he still has his crew. + +## power, authority, and liberation + +by the time we enter the new world, it's endgame territory. this is the realm of the emperors. luffy has always been a liberator, but this part of the story is where it takes center stage. every arc has luffy liberating people and islands. and then you find out he's literally the warrior of liberation. + +it's all about the power struggle, the emperors who rule their territories, the world government who controls everything, and the warrior of liberation who is being set up to set the whole world free. + +## wealth. fame. power. he had it all + +in that order. + +## so what's the conclusion here + +idk i don't have a conclusion i'm just rambling \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/physical-bodies/index.md b/unified.test.hugo/content/monologues/physical-bodies/index.md new file mode 100644 index 0000000..9715b61 --- /dev/null +++ b/unified.test.hugo/content/monologues/physical-bodies/index.md @@ -0,0 +1,6 @@ ++++ +title = "physical bodies are so encumbering" +summary = "it would be great to never again have to feel pain from a stomach too empty, or perhaps too full; to never have crusty eyes after sleeping too much, or perhaps too little; to never suffer from physiology that at best will decay, and at worst will actively punish us." +date = "2018-05-09T14:42:00-00:00" +source = "https://mastodon.social/@trwnh/99999872996282760" ++++ \ No newline at end of file diff --git a/blog.hugo/content/_dump/making-better-stuff-is-unprofitable.md b/unified.test.hugo/content/monologues/product-vs-profit/index.md similarity index 57% rename from blog.hugo/content/_dump/making-better-stuff-is-unprofitable.md rename to unified.test.hugo/content/monologues/product-vs-profit/index.md index c975e25..d99fe9d 100644 --- a/blog.hugo/content/_dump/making-better-stuff-is-unprofitable.md +++ b/unified.test.hugo/content/monologues/product-vs-profit/index.md @@ -1,4 +1,11 @@ -2017-12-22 12:06 | https://mastodon.social/@trwnh/99217860566004390 ++++ +title = "product vs profit" +summary = "There will inevitably be a point where it is unprofitable to improve a product any further." +date = "2017-12-22T12:06:00-00:00" +source = "https://mastodon.social/@trwnh/99217860566004390" ++++ + +> maybe providing useful products turns a profit hmmm... Only to a certain extent. There will inevitably be a point where it is unprofitable to improve a product any further. diff --git a/unified.test.hugo/content/monologues/publishing-vs-discussing/index.md b/unified.test.hugo/content/monologues/publishing-vs-discussing/index.md new file mode 100644 index 0000000..98f7830 --- /dev/null +++ b/unified.test.hugo/content/monologues/publishing-vs-discussing/index.md @@ -0,0 +1,36 @@ ++++ +title = "publishing vs discussing" +summary = "eventually this kind of \"posting\" we have today would be split up and merged into the two new things. the UI would give you an option: do you want to publish a Post, or do you want to start a Discussion?" +date = "2023-03-24T10:33:00-0600" +source = "https://mastodon.social/@trwnh/110078983668243890" ++++ + +i am more and more taking the position that we should have forums, and we should have blogs, and nothing in between. "social media" carries inherently poor ergonomics and a lack of clarity of purpose. you're never clearly "publishing" anything when you post on social media, unlike when you post on your own blog or website. you're never clearly "discussing" anything either, because threads aren't actual topics or conversations. + +so my ideal flow is kinda like + +- you make a "post" to your website/profile +- it may or may not be "in reply to" some other post. this is just metadata +- it may or may not be part of some "context". this is a moderated conversation or logical grouping owned by someone +- the "audience" is up to you, completely arbitrary. it might be only visible from within the context of some other webpage, or it might be given a permalink on your website/profile + +fedi dropped the ball hard on those last two... + +we could realistically move toward something more context-and-audience-aware but it's gonna be a bit rough for the existing "instance" model because of structural limitations. you'd basically be building a new fediverse in the shell of the old. but i think it can be done... + +one prong is to support actual "publishing" with articles and a more fleshed-out web profile as a website. add webmentions as an optional thing. + +the other prong is to support "discussing" within walls/forums/rooms "context" + +eventually this kind of "posting" we have today would be split up and merged into the two new things. the UI would give you an option: do you want to publish a Post, or do you want to start a Discussion? + +--- + +in my mental model. i have the following areas mapped out: + +- Publishing (posts) +- Reading (feeds/timelines) +- Discussing (forums) +- Messaging (chats) + +all of these are types of communication, and naturally some apps are going to expand to cover more areas. but it's all dependent on context and presentation. a "chat room" and a "forum topic" and a "social media wall" are all just collections of objects, really. \ No newline at end of file diff --git a/blog.hugo/content/_dump/why-read-theory.md b/unified.test.hugo/content/monologues/reading-theory/index.md similarity index 69% rename from blog.hugo/content/_dump/why-read-theory.md rename to unified.test.hugo/content/monologues/reading-theory/index.md index 0edb2e7..09a9c67 100644 --- a/blog.hugo/content/_dump/why-read-theory.md +++ b/unified.test.hugo/content/monologues/reading-theory/index.md @@ -1,4 +1,9 @@ -2018-01-27 08:44 | https://mastodon.social/@trwnh/99420908783601966 ++++ +title = "reading theory" +summary = "the point of reading theory is to see what ideas other people already came up with, so you don't have to spend time formulating them yourselves." +date = "2018-01-27T08:44:00-00:00" +source = "https://mastodon.social/@trwnh/99420908783601966" ++++ the point of reading theory is to see what ideas other people already came up with, so you don't have to spend time formulating them yourselves. like... you start out with political beliefs and experiences, but they can always be solidified if you have a framework to contextualize them. diff --git a/unified.test.hugo/content/monologues/responsive-web-design/index.md b/unified.test.hugo/content/monologues/responsive-web-design/index.md new file mode 100644 index 0000000..6f7ace5 --- /dev/null +++ b/unified.test.hugo/content/monologues/responsive-web-design/index.md @@ -0,0 +1,12 @@ ++++ +title = "fully responsive web design" +summary = "my pipe dream is to redesign my website to be fully responsive -- not across mere pixel widths, but by aspect ratio and overall size" +date = "2018-04-22T15:42:00-00:00" +source = "https://mastodon.social/@trwnh/99903847448978099" ++++ + +my pipe dream is to redesign my website to be fully responsive -- not across mere pixel widths, but by aspect ratio and overall size. + +does anyone consider what their website looks like when it's fullscreened across one of those samsung 3840x1080 monitors? probably not, and why would you? + +but i do \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/services-vs-communities/index.md b/unified.test.hugo/content/monologues/services-vs-communities/index.md new file mode 100644 index 0000000..98c19ae --- /dev/null +++ b/unified.test.hugo/content/monologues/services-vs-communities/index.md @@ -0,0 +1,24 @@ ++++ +title = "services aren't communities" +summary = "imo the biggest mistake of fedi is tying together the social and technical layers [...] some people want services and some people want communities and they are not the same thing" +date = "2023-05-07T17:39:00-06:00" +source = "https://mastodon.social/@trwnh/110329802576726213" ++++ + +services aren't communities + +the gmail community + +imo the biggest mistake of fedi is tying together the social and technical layers. local timelines should have been group chats all along + +it's a huge misunderstanding because some people want services and some people want communities and they are not the same thing. some people can run a community but offer bad service. some people offer great service but can't run a community + +instances shouldn't exist as the only model. the service layer and the community layer should be separate. combining the two makes both of them worse -- as can be seen if you violate the rules of your community, you lose access not just to the community, but to the service entirely. and if the community cannot continue to provide service, you again lose both. + +i do think there is some value in being both, because then people feel more likely to donate as they are personally invested. but you could have incentives to donate even while keeping them separate. + +--- + +> Yes! I think I've been spiralling towards a less well articulated version of this for a while. Too many people have been trying to make the Fediverse just one big social network with many servers and erase the aspect that's many small social networks that can communicate, and it's exactly that they're viewing it purely as service and not as community, and it absolutely needs to be both or else it can't meaningfully be either. + +i have a slightly different view, which is that multiple communities exist here and their organization and distribution is very dysfunctional because of the "instance" model being both and neither at the same time \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/shorts-are-too-long/index.md b/unified.test.hugo/content/monologues/shorts-are-too-long/index.md new file mode 100644 index 0000000..2d1014c --- /dev/null +++ b/unified.test.hugo/content/monologues/shorts-are-too-long/index.md @@ -0,0 +1,8 @@ ++++ +title = "shorts are too long" +summary = "if you're going to take away the video controls, prevent me from seeking, maybe autoloop? then i am NOT sitting there for a whole minute while you fail to get to the point." +date = "2023-01-25T08:40:00-06:00" +source = "https://mastodon.social/@trwnh/109750363384335885" ++++ + +i fucking hate the "shorts" format. vine was okay purely because it was limited to 6 or 7 seconds -- if you're going to take away the video controls, prevent me from seeking, maybe autoloop? then i am NOT sitting there for a whole minute while you fail to get to the point. i'm not doing more than 10 seconds, maybe 15 seconds at the most. anything over that should let me seek through the video!!!! videos should always be seekable but if you're not going to make them seekable then at least limit them to one coherent logical "moment" \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/smartphones-and-capitalism/index.md b/unified.test.hugo/content/monologues/smartphones-and-capitalism/index.md new file mode 100644 index 0000000..e8a0a0c --- /dev/null +++ b/unified.test.hugo/content/monologues/smartphones-and-capitalism/index.md @@ -0,0 +1,26 @@ ++++ +title = "i hate the smartphone market" +summary = "profit motives means that the entire market has abandoned me" +date = "2018-05-07T08:13:00-00:00" +source = "https://mastodon.social/@trwnh/99987017261137486" ++++ + +tbh like 90% of my day-to-day angst against capitalism is from how shit the smartphone market has become. if capitalism is so great then where the fuck is my <70mm-wide phone with a removable battery? fucking profit motives means that the entire market has abandoned me. I haven't been satisfied with any phone since 2010. hell, I'd buy an updated Nexus One with newer, more efficient internals. + +"capitalism brought you your smartphone!" yeah, and that phone /fucking sucks/. + +I wish I could build my own phone or have one built to spec, but alas, I do not own a machining and assembly factory, and I don't have the requisite circuitry knowledge... if only I could, I dunno, *cooperate* with some like-minded people, and we had *public ownership of those factories*... :thaenkin: + +> do you know about this company? https://www.fairphone.com/en/ . They do their best to source all their components ethically, and work with worker's organisations in the countries they are producing phones in. The fair phone also comes with root access by default, so you can install your own ROM if you want. + +yeah; they're well-intentioned but still restricted to operating within the confines of capitalism. and it's still too big of a phone for my liking, personally + +like, i'm using a sony xperia x compact right now because it's 4.6" and fits in one hand. the snapdragon 650 means the battery is *decent*, but for how long? i got it lightly used in september, and now it's may and the battery is starting to heat up and degrade after 8 months of heavy usage and all those recharge cycles. + +> my fair phone 1 is still working nicely after 3 years or so [...] + +I feel like the same could be said about several more devices from 2013 than could be said today. my mom is still using a Nexus 7 2013 tablet just fine. our Nexus 5 could have lasted until now, if she hadn't broken it accidentally in a fit of rage. my htc one m7 is still close to the "ideal" device for me, except its battery has long gone to shit and is a nightmare to replace. + +I wish there were like 400 more fairphones, because just 1 is too limited to accomplish much for my case. and part of why there's only 1, I imagine, is because they can't be profiting too much; they still rely on profit, don't they? It's not "sustainable" for companies to provide services at-cost under capitalism. + +[...] it's extremely hard to "build it yourself" at sufficient scale to make a difference... and even then, you're bound by the laws of capital. you need to make money to survive, so at-cost operation is not viable without external funding \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/social-media-flawed/index.md b/unified.test.hugo/content/monologues/social-media-flawed/index.md new file mode 100644 index 0000000..5d9d17d --- /dev/null +++ b/unified.test.hugo/content/monologues/social-media-flawed/index.md @@ -0,0 +1,14 @@ ++++ +title = "social media is fundamentally flawed" +summary = "in pure terms you might send a message or publish a resource. but with these social networks [...] you're never unambiguously sending a message or publishing a resource, but instead, some weird hybrid that we call a \"post\". not quite message, not quite resource" +date = "2023-02-16T19:43:00-06:00" +source = "https://mastodon.social/@trwnh/109877540362444317" ++++ + +the more i think about and research communication paradigms, i'm starting to think more and more that this whole "social media" thing is just fundamentally flawed. in pure terms you might send a message or publish a resource. but with these social media platforms it's not that clear cut. you're never unambiguously sending a message or publishing a resource, but instead, some weird hybrid that we call a "post". not quite message, not quite resource. it exists in part or in whole exclusively on the platform. + +and i guess that makes it easier to put in a silo which is how companies maintain their profit motive. + +but in replicating the design of these social media sites we replicate their properties too. fedi hasn't entirely moved past silos because it's embedded in the design level. thankfully not the protocol level, but still. it's going to persist in implementations as long as we limit ourselves to "twitter but better", "instagram but better", etc. we're not building the commons that we could build. + +and the lack of clarity in our metaphors and associated abstractions leads to subtle violations of what people expect. there should be a clearer split. consider the duality of tumblr as both a social network and a publishing platform. they're making this split more apparent than it used to be. in addition to username.tumblr.com for blogs they now have tumblr.com/username for network profiles. \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/specs-arent-enough/index.md b/unified.test.hugo/content/monologues/specs-arent-enough/index.md new file mode 100644 index 0000000..d4dc3b5 --- /dev/null +++ b/unified.test.hugo/content/monologues/specs-arent-enough/index.md @@ -0,0 +1,40 @@ ++++ +title = "specs aren't enough" +summary = "the question of \"interoperability\" makes no sense on its own. you must always ask, interoperability with what? and on which conditions? [...] is your view of the \"fediverse\" limited only to the conceptual space of existing projects? and, if so, then which ones?" +date = "2023-03-06T18:37:00-06:00" +source = "https://mastodon.social/@trwnh/109979200684979970" ++++ + +@ people who keep saying we should rewrite the activitypub spec to ensure better interoperability with existing fedi projects + +![](specs-are-enough.png) + +idk how else to say that if you want to be compatible with a project then you need to have a shared worldview and conceptual space, and this necessarily involves communicating with that project on some level (by reading their documentation, asking their devs questions, etc) in order to know what their expectations and requirements are + +the question of "interoperability" makes no sense on its own. you must always ask, interoperability with what? and on which conditions? + +like, we all use activitypub more or less according to the spec, and that's because the spec is simple, it's basically just "HTTP POST to inbox". we could theoretically construct any as2 payload we wanted, but we largely limit ourselves to Create Note... why? because you want to be compatible with mastodon, right? and that's the real issue. + +there are things that mastodon et al do that are within some spec -- webfinger for translating usernames to actors, for example. then there are things that are technically a spec but outdated, like http signatures (cavage draft) and ld signatures (obsoleted entirely). and then there are things that are not specced -- quirks of the implementation that must be respected, things like using Note, how to structure a Mention, the use of specific algorithms for signatures. maybe these can be negotiated + +crucially, sometimes the assumptions you make, the quirks your software has, these will not line up with the assumptions that others make, the quirks that their software has. you might even disagree entirely, and without the possibility of reconciling those opposing assumptions. + +consider the assumption that every actor has a username, and that this username identifies them more canonically than their own activitypub identifier. what if you disagree? well, that's an incompatibility. + +how do you handle the root of identity being the activitypub id, versus the root of identity being the username, versus the root of identity being some cryptographic key? what is one to do, if one wants to be "compatible" and "interoperate" with three different softwares each following a different one of the above assumptions about identity? are these softwares even meaningfully part of the same network? and which of these three networks is the "true" "fediverse"? + +and even within those identity schemes, we might still have to consider further parameters, like the expectation of only supporting HTTPS URIs. or, let's imagine that we choose to use or support DIDs -- now, which DID methods do we support? + +all of these are decisions that each project has to either make for itself, or vest authority in some other entity to make those decisions in a binding way -- by publishing some meta-spec, some conformance profile, basically a bundle of specs that should be followed and their particulars. + +and even *then*, you will find some quirks remain, some projects are coded in a way which has implicit expectations. the more you try to eliminate these, the narrower the scope or conceptual space becomes. + +with enough limitations, you end up with what is basically the same software, just with different implementations. if mastodon, pleroma, and misskey all were overspecced like this, you may as well view them as "fedi implemented in rails", "fedi implemented in elixir", and "fedi implemented in nodejs". + +so, in closing, i leave with this to consider: + +is your view of the "fediverse" limited only to the conceptual space of existing projects? and, if so, then which ones? + +or will you allow yourself to dream a little bigger? + +{{}} \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/specs-arent-enough/specs-are-enough.png b/unified.test.hugo/content/monologues/specs-arent-enough/specs-are-enough.png new file mode 100644 index 0000000..dab867a Binary files /dev/null and b/unified.test.hugo/content/monologues/specs-arent-enough/specs-are-enough.png differ diff --git a/unified.test.hugo/content/monologues/syndicalism-is-dead/index.md b/unified.test.hugo/content/monologues/syndicalism-is-dead/index.md new file mode 100644 index 0000000..1cb87c8 --- /dev/null +++ b/unified.test.hugo/content/monologues/syndicalism-is-dead/index.md @@ -0,0 +1,18 @@ ++++ +title = "syndicalism in the 21st century" +summary = "syndicalism is dead because the labor industry is dead. it's been replaced by the service industry today" +date = "2018-01-03T19:42:00-06:00" +source = "https://mastodon.social/@trwnh/99289017794408922" ++++ + +> Is syndicalism relevant in the 21st century? + +there's a reason why crimethinc call themselves an "ex"-worker collective. syndicalism is dead because the labor industry is dead. it's been replaced by the service industry today. factories are either on the decline or they're being exported. so i guess in that sense, syndicalism can still live in china, or wherever else production is a significant part of the economy so that a general strike can bring it to its knees + +or, alternatively, i suppose all food servers and retail employees could go on strike but the capitalist powers have created an abundance of unemployed people ready to bust that strike + +i see it as much more likely that the masses will revolt wholesale, before any trade-unionist path could ever make itself viable again + +very likely within the next 20 years, and almost certainly by the end of the century. too many crises are coming to a head "by 2040, 2050, 2080, 2100" etc. natural and anthropogenic conflicts will arise more easily than ever before + +to be clear: organizing workers is still the most effective way forward; unionism can help but isn't an effective avenue for change anymore compared to agitation. but there's only so much we can gain by lobbying for labor standards; we need to push for fundamental transformation of the entirety of class relations \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/the-web-not-only-for-profit/index.md b/unified.test.hugo/content/monologues/the-web-not-only-for-profit/index.md new file mode 100644 index 0000000..af3772f --- /dev/null +++ b/unified.test.hugo/content/monologues/the-web-not-only-for-profit/index.md @@ -0,0 +1,15 @@ ++++ +title = "the web is not only for profit" +summary = "i just want to find some inspiration on how to express myself, not market myself" +date = "2023-01-03T01:58:00-06:00" +source = "https://mastodon.social/@trwnh/109624210338690804" ++++ + +it's funny how a lot of help articles can be boiled down to one of + +a) it's really easy, just give us money +b) it's really hard, so give us money + +people act like the only worthwhile use case of the web is financial gain. no one has any tips or hints on how to make a personal website, it's always "build your brand" or "showcase your portfolio" or some other transparently profit-motivated initiative. everyone is always talking about the sales funnel or the call to action or whatever. it's just *assumed* you are also like this. + +i just want to find some inspiration on how to express myself, not market myself \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/ubi/index.md b/unified.test.hugo/content/monologues/ubi/index.md new file mode 100644 index 0000000..0024f8a --- /dev/null +++ b/unified.test.hugo/content/monologues/ubi/index.md @@ -0,0 +1,10 @@ ++++ +title = "the problem with universal basic income" +summary = "market forces on basic needs need to be abolished" +date = "2018-03-16T02:00:00-00:00" +source = "https://mastodon.social/@trwnh/99691112300163044" ++++ + +my only problem with UBI is if you're going to guarantee a basic income then why not just guarantee the basics and cut down on the bureacracy? also you can't just give everyone a lump sum of money and not expect a market to react to that flood of monetary supply -- market forces on basic needs need to be abolished + +tldr UBI is a bandage on capitalism in the same way the New Deal was, but even less accountable \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/voluntarism/index.md b/unified.test.hugo/content/monologues/voluntarism/index.md new file mode 100644 index 0000000..aeb6003 --- /dev/null +++ b/unified.test.hugo/content/monologues/voluntarism/index.md @@ -0,0 +1,12 @@ ++++ +title = "voluntarism vs socialism" +summary = "If two people are inequal, then they can never come to a voluntary agreement -- the power of one will coerce the other" +date = "2018-04-06T23:19:00-00:00" +source = "https://mastodon.social/@trwnh/99815047195372515" ++++ + +My point is that pursuing pure voluntarism as an ideology (and not simply an ideal) tends to ignore the realities of power imbalances. If two people are inequal, then they can never come to a voluntary agreement -- the power of one will coerce the other, even if subconsciously. + +Consider whether one can "voluntarily" become a slave. Or, more relevant today, consider the wage labor system. Is it truly "voluntary" if your food, shelter, and very survival depends on such a "voluntary" arrangement? + +The cold reality is that voluntarism is merely idealism so long as any social class or hierarchy exists. Maybe some prefigurative politics are necessary, but you have to push for progress without 100% support or you'll wait forever. \ No newline at end of file diff --git a/unified.test.hugo/content/monologues/w3c-http-supremacy/index.md b/unified.test.hugo/content/monologues/w3c-http-supremacy/index.md new file mode 100644 index 0000000..e3190e9 --- /dev/null +++ b/unified.test.hugo/content/monologues/w3c-http-supremacy/index.md @@ -0,0 +1,21 @@ ++++ +title = "http uri maximalism" +summary = "if you just wanna obtain a resource from a given organization or whatever, it is generally a given that the org has its own domain name and can assign ids on that domain. but the whole thing falls apart when you need a global namespace that can be requested from multiple domains" +date = "2023-02-18T09:20:00-06:00" +source = "https://mastodon.social/@trwnh/109886416964217719" ++++ + +reading a lot of old w3 literature and while there's a lot of good stuff in there, it is *infuriating* how they are so blindly in support of using http for everything, including identifiers. they probably just failed to predict the future, but they keep stopping just short of admitting http's biggest problem: when the server goes down, your uri can't be dereferenced anymore! + +(specifically i was reading https://www.w3.org/2001/tag/doc/URNsAndRegistries-50.xml which argues against urns because you can't dereference them) + +am i being too harsh on an editorial from 2001, sure, yeah, probably no one was seriously thinking of decentralized systems back then. if you just wanna obtain a resource from a given organization or whatever, it is generally a given that the org has its own domain name and can assign ids on that domain. but the whole thing falls apart when you need a global namespace that can be requested from multiple domains. this is *exactly* where urns are useful! like, naming things is in some way id! + +if we follow the logic of http maximalists from 2001, then we would not need the isbn or doi namespaces, we could just assign identifiers on an http hostname. a doi can be resolved using an http url so why not just use the url directly? + +well, that assumes persistence that simply isn't guaranteed. the doi foundation will tell you itself: https://www.doi.org/the-identifier/resources/factsheets/doi-system-and-persistent-urls + +> PURLs are all http and inherit both the strength and weakness of that approach + +it's those weaknesses that kept being ignored + diff --git a/unified.test.hugo/content/monologues/what-is-web/index.md b/unified.test.hugo/content/monologues/what-is-web/index.md new file mode 100644 index 0000000..0298818 --- /dev/null +++ b/unified.test.hugo/content/monologues/what-is-web/index.md @@ -0,0 +1,30 @@ ++++ +title = "what is web" +summary = "the many webs interpretation, what \"web\" means to me, and how do we build the \"social web\"" +date = "2024-09-26T11:57:00-06:00" +source = "https://matrix.to/#/!uHqAjmOtrLtidOiczC:matrix.org/$RwgyjnqW51n_VwkSwWXP3cewn-VLZ_20jIowiprYdSQ?via=matrix.org&via=mozilla.org&via=decentsocial.net" ++++ + +> How we move forward past these transparent takeover attempts is a conversation I have yet to see within the ActivityPub sphere, and perhaps that of itself is an answer to the question + +would it be correct or accurate to categorize this as a matter of governance? in that case, who are the constituents? imo the constituents are people who want to be social on the web, and software projects that let them do that, and whatever service providers enable the whole thing + +we define "social web" as "people who want to be social on the web", but this probably depends on what you consider "web", because we certainly already have many many ways to be social on the internet. there are a few definitions that could work, but at its core i think that "web" means "anything with links". + +in a more practical sense, it's "anything accessible by a web browser", although that definition is a bit circular. the most popular "web browsers", things like chrome and firefox let you browse the http and https webs. primarily using html documents or representations, so i think the "web" most people are familiar with can be classified as "http or https for the protocol, html for the primary data format". so something like "http(s)+html" or to pull from those acronyms the "hypertext web" + +then separately but partially overlapping you have the "semantic web" or "linked data web" that deals with semantic links between things that are more "data" than "document", kind of like the difference between the IANA media types for `text/*` versus `application/*` + +so idk, maybe it's a line in the sand, and certainly the concept of http gateways blurs it even more, but "web" to me is about publishing things that link to other things, in a way that most people can be expected to see them and make use of them and even link back. this makes things like atproto not really "web" until the moment they are (re)published through a gateway (either a web service or a web app) that makes them available over the "web" that most people can access with a "web browser" (currently the http family of protocols). in practice, the "web" part of atproto is https://bsky.app + +this line in the sand definition makes it clear that something like gemini is not part of "the" web that most people think about (the hypertext web) but is instead the "gemini web" that is browsable by a "gemini web browser", and so on for other protocols. + + + +it also goes a long way to explain why the semweb/ldweb has not seen as much adoption as some people would like — it is in actuality a different "web" than the "hypertext web", and it is more of a coincidence that hypertext browsers also have the capability to load semantic/ld resources over the http(s) protocols they share in common + +so conclusion. if we say "web" is primarily "hypertext web" then the question becomes "how can we communicate socially with/around hypertext documents or appviews?" which is a different question than "how can we develop a network protocol that lets us be social". if it were only a matter of the latter, we already have smtp/xmpp/etc. as other "social network protocols". and if a protocol were to be defined for the fediverse, it would also fall into that category of "social network protocols", with the distinction that several softwares in this network also publish your posts as "web resources", so they're not entirely removed from the "social web". they just can't claim a full mantle to it, because they don't give you full control over how you publish those resources to the web. \ No newline at end of file diff --git a/unified.test.hugo/content/search/_index.md b/unified.test.hugo/content/search/_index.md new file mode 100644 index 0000000..a7f481a --- /dev/null +++ b/unified.test.hugo/content/search/_index.md @@ -0,0 +1,3 @@ ++++ +title = "Search" ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/_dump/_index.md b/unified.test.hugo/content/wiki/_dump/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/_dump/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/_dump/concepts/stores-and-transports.md b/unified.test.hugo/content/wiki/_dump/concepts/stores-and-transports.md new file mode 100644 index 0000000..680e9c2 --- /dev/null +++ b/unified.test.hugo/content/wiki/_dump/concepts/stores-and-transports.md @@ -0,0 +1,13 @@ +data flows into the application from "stores", and flows out via "transports" + +### stores + +IMAP +AP C2S GET? +XMPP C2S??? + +### transports + +SMTP +XMPP +AP C2S POST? \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/_dump/email.md b/unified.test.hugo/content/wiki/_dump/email.md new file mode 100644 index 0000000..b83e485 --- /dev/null +++ b/unified.test.hugo/content/wiki/_dump/email.md @@ -0,0 +1,27 @@ ++++ +updated = "2021" ++++ +### Mailpile +- selfhosted mail archive? +- more of a webmail client? +- demo seems kinda slow :( +- uses imap/pop3 to download mail, optionally delete it from server +- uses its own http api instead of re-exposing imap UGH +- https://github.com/mailpile/Mailpile/wiki/Synchronizing-Mailpile-with-Thunderbird +- https://github.com/mailpile/Mailpile/wiki/Configuring-Linux-to-download-your-email +- https://github.com/mailpile/Mailpile/wiki/Mail-sources + +### Notmuch +- https://notmuchmail.org/ +- seems to be an email client with search caps +- idk if this is what i want +- https://github.com/johnnyutahh/search-based-email + +### OfflineIMAP +- http://www.offlineimap.org/ +- combine with notmuch? +- could also combine with mailpile? +- it seems like it just downloads to a folder idk + +### Just download it with thunderbird or something? +- idk \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/_dump/hackerwars.38.md b/unified.test.hugo/content/wiki/_dump/hackerwars.38.md new file mode 100644 index 0000000..67a1cd3 --- /dev/null +++ b/unified.test.hugo/content/wiki/_dump/hackerwars.38.md @@ -0,0 +1,221 @@ ++++ +draft = true ++++ + +## puzzles + +The First Puzzle: +98.151.11.252 - Tic Tac Toe +99.13.31.189 - `3` +131.209.236.188 - `Eyjafjallajökull` +38.184.207.244 - `12, 4` +134.202.106.252 - `24` +179.60.148.182 - `Area 51` +47.72.72.190 - `4` +177.222.33.107 - `Hacker Wars` +205.117.130.137 - `Too Many Secrets` +12.198.127.243 - Sudoku +[sends you to WHOIS 1] + +1.2.3.4 [WHOIS 1] - 2048 + +``` +$.ajax({ +type: "POST", +url: 'gotcha.php', +dataType: "json", +data: { +func: '2048', +type: 6 +}, +success: function(data){ +if(data.status == 'OK') { +result = $.parseJSON(data.msg); +$('#puzzle-header').html(result[0].header); +$('#puzzle-status').html(result[0].result); +$('#puzzle-next').html(result[0].next); +$('#puzzle-isSolved').attr('value', result +​ +[0].isSolved); +$('#puzzle-solve').hide(); +} +} +}) +``` +sends you to WHOIS 2 + +219.253.106.3 [Too Many Secrets] - `Stay Hungry, Stay Foolish` +175.136.25.16 - `Aramis` +101.33.53.239 - `62.5` +12.8.92.181 - `50` +190.177.124.74 [Lorem ipsum] - `5, 1, 94` +213.207.2.12 - Minesweeper +162.92.240.86 - `Phoebe, Milena, Naomy` +78.77.189.202 - `4, 3` +65.106.189.164 - `a, d, c` +164.36.19.95 - `3, 3, 9` +44.184.200.40 - `5, 2` +156.9.137.74 [Hangman] - `99+99/99` +186.43.119.219 - `49, 35` +143.114.166.104 - `Every player who buys premium is awesome` +185.42.143.179 - `9, 18` +179.196.168.131 - `To be or not to be` +188.85.245.142 - `Phoebe` +200.11.13.159 [WHOIS 2] - Turn the switches on + +``` +$.ajax({ +type: "POST", +url: 'gotcha.php', +dataType: "json", +data: { +func: 'lightsout' +}, +success: function(data){ +if(data.status == 'OK') { +result = $.parseJSON(data.msg); +$('#puzzle-header').html(result[0].header); +$('#puzzle-status').html(result[0].result); +$('#puzzle-next').html(result[0].next); +$('#puzzle-isSolved').attr('value', result + +[0].isSolved); +$('#puzzle-solve').hide(); +} +} +}) +``` + +8.22.72.164 - `penny` +94.236.84.16 - `Nishiyama Onsen Keiunkan` +53.83.66.249 - `Hack The Planet` +82.212.91.122 - `password123` +200.28.37.47 - `47` +127.73.175.172 - `SHOW NO REMORSE` +61.170.113.240 [WHOIS 3] - `1, 2, 3` +87.75.25.103 - `diamond, ruby, sapphire` +207.0.9.101 - `Kung Fury` +40.204.6.239 - `Morpheus` +240.93.247.103 [WHOIS 4] - The End... for now + +191.169.88.208 [Fsck you] - placeholder puzzle + +### ??? hidden puzzles + +[hasher 11, need cracker 11.1 to get in] +158.79.69.167 - `hacker` +25.25.200.137 - `LCM+L` +37.0.237.238 - `Burj Khalifa` +158.79.69.167 - `Satoshi Nakamoto` +13.14.243.214 - `SHA256` +54.215.105.98 - `10/11/2019` +[takes you back to WHOIS 4] + +### alt paths + +86.24.54.79 [WHOIS 3 -> Eduard Khil -> WHOIS 3] - `Despacito` + +52.6.13.235 [WHOIS 3 -> Gnirut -> WHOIS 2] - Turn the switches on (again) + +``` +$.ajax({ +type: "POST", +url: 'gotcha.php', +dataType: "json", +data: { +func: 'lightsout' +}, +success: function(data){ +if(data.status == 'OK') { +result = $.parseJSON(data.msg); +$('#puzzle-header').html(result[0].header); +$('#puzzle-status').html(result[0].result); +$('#puzzle-next').html(result[0].next); +$('#puzzle-isSolved').attr('value', result + +[0].isSolved); +$('#puzzle-solve').hide(); +} +} +}) +``` + + + +## cool shit + +44.133.241.160 - torrent 1,2,3 +61.170.113.240 - analyzer 3.0 +200.11.13.159 - spam 5.0, warez 5.0, miner 5.0 +188.85.245.142 - collector 5.0 +94.236.84.16 - collector 7.0 +86.24.54.79 - collector 10.0 +156.62.156.183 - hasher/firewall 10.0 +87.75.25.103 - hidder 10.0, antivirus 10.0, cracker 9.0, ssh 7.0 +207.0.9.101 - seeker 10.0, ddos 10.0 +40.204.6.239 - breaker 10.0, cracker 10.0 +240.93.247.103 - cracker 11.0, warez 10.0, miner 10.0 +130.216.37.220 - cracker 12.0 +78.192.143.228 - cracker 12.0, hasher 11.0, hidder 11.0, antivirus 12.0 + +37.0.237.238 - warez 14 +158.79.69.167 - hidder 15, antivirus 14 +13.14.243.214 - seeker 15 +54.215.105.98 - ftp 13, ssh 13, cracker 17, firewall 12 + +## me + +bank #757385614 +123.40.218.38 + +1wXjdkDA9V4kKtRQ1LCbCpiTHTLviAmbxd +X2ke7k3RB05YKa4zRIl5SlPFLykl4eIa1KGSdOwcc38um0igvBdWiUnewQScoUBA + +## banks + +bank #203344377 at 123.40.218.38 + +686206684 at 123.40.218.38 + + #485880455 on bank [123.40.218.38] + +## bitcoin + +1tKr4CjHeCMv0X69bxZG8j0BWfyOqKiiRs +iARby4xdWxXlOH7VdmRF3vVlu82hcnLzHi0NC8YqMKhd0vdJWtuMJgyAZXOvo95T + +1P8vEmxyBhldcmjjlgdYvg4MT908dQu +AUICn2EfwcjbSR4kwY3AgzCydsxO2UamqN2z7iyNeOp7sGgL5O6XQNyXlaKXLzn + +165PrvvXaznPBoRRXjwKQssIiOA2VopOhY +sNCi2fDCDf4lI3YBwKLVdJlUC26mgfg7X9pNuZHDYyQOLfWDZ5d0mFvQEWxVbvo3 + +## ips to hack? + +187.219.92.196 + +45.197.80.78 + +## meta caps + +cracker 50.7 +hasher 44.9 +firewall 30.5 + + + + + +``` +ips = document.getElementById("list").children; +output = "" + +for (var i = 0; i < ips.length; i++) { + ipElement = ips[i] + ip = ipElement.children[0].children[0].children[0].children[1].innerText + virus = ipElement.children[1].innerText + output += ip + "\n" +} + +console.log(output) +``` \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/_index.md b/unified.test.hugo/content/wiki/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/foobar2000.md b/unified.test.hugo/content/wiki/foobar2000.md new file mode 100644 index 0000000..1560c32 --- /dev/null +++ b/unified.test.hugo/content/wiki/foobar2000.md @@ -0,0 +1,19 @@ ++++ +updated = "2024-08-04" ++++ + +## "copy of repositories maintained by kode54" + +according to https://hydrogenaud.io/index.php/topic,123394.0.html you can go to https://foobar2000.xrea.jp/?Input+64bit#aada4e80 and get 64-bit compatible builds of some old 32-bit only plugins/decoders like USF support for N64 music. also supports dark mode + +### fixing foo_snesapu + + + +foobar >v2.0 before v2.2 preview 2024-06-24 has a bug where it will remove any dll that doesn't match plugin architecture, so it when installing the fb2k-component it will copy over the foo_snesapu.dll plugin but not its dependency snesapu.dll -- you will have to copy it manually to the install directory for foobar2000 (for windows this will be either `\AppData\Roaming\foobar2000-v2\user-components-x64\foo_snesapu\` for standard install, or `\profile\user-components-x64\foo_snesapu\` for portable install -- get the files out of the fb2k-component using an archive viewer) + +## recompiled plugins for x64 and dark mode support + +https://foobar.hyv.fi/ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/gaming/_index.md b/unified.test.hugo/content/wiki/gaming/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/gaming/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/gaming/gc.md b/unified.test.hugo/content/wiki/gaming/gc.md new file mode 100644 index 0000000..f1a7801 --- /dev/null +++ b/unified.test.hugo/content/wiki/gaming/gc.md @@ -0,0 +1,11 @@ ++++ +updated = "2024-08-03" ++++ + +tbh just play gamecube games on the [wii](../wii). it's easier to softmod and cheaper overall (have you seen the price of 480p component cables for the gamecube vs for the wii??????). nintendont + usb loader gx is a great experience too + +the only reason i can think of to invest in gamecube as a platform is if you want to use the game boy player? which... it would probably be better to use a gba consoleizer instead + +i guess the gamecube produces a (imo negligibly) better image (subjectively / to some people) but really it isn't anywhere near the difference between a wii and wii u (where the wii u produces a noticeably darker and muddier image for wii/vc games) -- and also the issue pretty much entirely stems from the filtering that the wii does + the aspect ratio it's rendering at. just disable deflicker + enable framebuffer rendering in usb loader gx to close any gaps between the two systems (and hardmodding the wii for hdmi output should be even less of a difference) + +so yeah unless you wanna use a gameboy player specifically then skip the gc and go straight for a wii \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/gaming/minecraft/_index.md b/unified.test.hugo/content/wiki/gaming/minecraft/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/gaming/minecraft/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/gaming/minecraft/server/_index.md b/unified.test.hugo/content/wiki/gaming/minecraft/server/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/gaming/minecraft/server/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/gaming/minecraft/server/multiverse.md b/unified.test.hugo/content/wiki/gaming/minecraft/server/multiverse.md new file mode 100644 index 0000000..f9f9a5c --- /dev/null +++ b/unified.test.hugo/content/wiki/gaming/minecraft/server/multiverse.md @@ -0,0 +1,83 @@ +# multiverse + +## skyblock in bukkit/spigot/paper + +prerequisites: +- multiverse-core +- multiverse-inventories +- multiverse-netherportals +- voidgen + +``` +/mvcreate world_skyblock NORMAL -g VoidGen:{structures:true,decoration:true,mobs:true} +/mvcreate world_skyblock_nether NORMAL -g VoidGen:{structures:true,decoration:true,mobs:true} +/mvcreate world_skyblock_the_end NORMAL -g VoidGen:{structures:true,decoration:true,mobs:true} +``` + +create a multiverse-inventories group to share player data + +``` +/mvinv group +create +# name the group something like "world_skyblock" +world_skyblock # add world +world_skyblock_nether # add world +world_skyblock_the_end # add world +@ # continue after adding all worlds +all # share all player data +@ # finish +``` + +go to the world and change settings + +``` +/mvtp world_skyblock +/gm c # go into creative, make a starter island +/mvsetspawn # set a reasonable spawn point +/mvmset respawnWorld world_skyblock # respawn in overworld +/mvmset diff hard +/mvmset allowflight false +/mvmset alias Skyblock +/mvmset color AQUA + +/mvtp world_skyblock_nether +/gm c # go into creative, make a starter island +/mvsetspawn # set a reasonable spawn point +/mvmset respawnWorld world_skyblock # respawn in overworld +/mvmset hidden true # hide non-overworld from mvlist +/mvmset diff hard +/mvmset allowflight false +/mvmset alias Skyblock +/mvmset color AQUA + +/mvtp world_skyblock_the_end +/gm c # go into creative, make a starter island +/mvsetspawn # set a reasonable spawn point +/mvmset respawnWorld world_skyblock # respawn in overworld +/mvmset hidden true # hide non-overworld from mvlist +/mvmset diff hard +/mvmset allowflight false +/mvmset alias Skyblock +/mvmset color AQUA +``` + +if you use essentialsx-chat: go to `plugins/Essentials/config.yml` and `chat.world-aliases` and define your aliases + +if you use essentialsx-spawn: set `respawn-listener-priority: lowest` so multiverse can handle respawns + +### caveats + +voidgen will generate water in ocean ruins, so if you want to play without water (ie getting rain in cauldrons) then this will be an easier way to get water + +voidgen will also not let you control which structures spawn, only all or nothing. you can get golden apples and regular apples from certain loot chests + +### todo + +- apples are dropping from spruce trees in skyblock +- /spawn in test world takes you to survival +- per-world warps (so you dont pollute the whole list) +- check /weather permissions in skyblock +- check /time permissions in skyblock +- check /seed permissions in skyblock + +i think a lot of perms are owner only but skyblock should remove them bc higher weight \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/gaming/n64.md b/unified.test.hugo/content/wiki/gaming/n64.md new file mode 100644 index 0000000..7e02a61 --- /dev/null +++ b/unified.test.hugo/content/wiki/gaming/n64.md @@ -0,0 +1,114 @@ ++++ +updated = "2024-07-31" ++++ + +## video output + +currently using an s-video cable from insurrection industries: https://insurrectionindustries.com/product/nintendo-s-video/ + +was previously using https://amzn.to/3SuywUe which is cheaper (only $10 instead of $25 plus shipping) and also worked just as well. i can't vouch for any specific cable because i've read reports of even the insurrection industries one possibly being bad, but you'll know if it's bad or not pretty soon. an earlier cable i was using which had both composite and s-video on the same cable would display a checkerboarding pattern over the signal + +### s-video distribution amplifier + +tried some passive splitters for s-video and they produced the checkerboarding pattern over the signal + +radioshack distribution amplifier https://amzn.to/3YyldWy - this works well and also allows for composite output at the same time as s-video. (my magnavox 20mt1331/17 crt tv only takes composite in). amazon has them out of stock but search for a RadioShack 1500320 1 in 4 out, maybe you can find elsewhere + +## display + +currently using the aforementioned magnavox 20mt1331/17 which works okay i guess. mine has some bowing at the bottom and used to have pretty bad overscan before i fiddled with the service menu and geometry. to get into the service menu, power the tv on and quickly press 062596 then MENU before it has a chance to load an RF channel + + + +### best display + +n64 outputs 15khz 240p and some games do 480i so whatever you use needs to support that which means a tv and not a monitor will be best. (crt monitors often do 31khz and do not support 480i so you will get an "out of sync range" error if you try to hook up to one of those via adapters to vga) + +cream of the crop is probably sony pvm 14l5 or 20l5? this even supports 480p so stuff like the wii might work on it as well with component output (which enables 480p) + +really anything will work fine, n64 was made with composite blurring in mind so even composite output looks *fine* from the n64. although s-video is a decent upgrade for clarity. this means you should probably be looking for a crt tv that at least takes in s-video if you want extra clarity. otherwise use s-video at least for capture... + +### best capture + +so yeah use a good s-video capture card. i have tried three + +- io-data gv-usb2: https://amzn.to/46KhFTz this one is good (probably best) usb capture card for gaming/240p but drivers are windows only. there are reverse engineered drivers for linux though! https://github.com/Isaac-Lozano/GV-USB2-Driver -- bit annoying to setup and enable/load every time you want to use it, also i have not gotten audio capture to work reliably, but it technically exists. + +- hauppauge usb-live2 610 (old version): https://amzn.to/3WI2K8S this one is also good (maybe not as good as the gvusb2 but good *enough*) usb capture card and supports 240p. it has coxenant cx23100 internals which are apparently also used in the diamond vc500 but i haven't tried that one specifically (same for avermedia c039 and august vgb100). the good thing about this usb capture card is that it works out of the box on linux for me. + +- blackmagic intensity pro / pro 4k: really good pcie capture that works in windows and linux, with a few issues in linux, mainly that getting it to work with obs studio is annoying because it doesn't work in the flatpak version, you need the native version. but the native version of obs studio in arch doesn't support browser sources. the solution i have is to use `obs-studio-tytan652` from the AUR. still a good device i guess, supports component as well via a breakout cable, and two rca pins (green/blue, so i think Y/Pb) can be adapted to s-video (Y/C). the quality is actually too good, as it's meant to be used with uncompressed capture of all kinds of tv signals. also because of it being a thing for tv, it doesn't support 480p. i got this as an upgrade over the hauppauge and it honestly is a sidegrade over the gvusb2 but the better option if you use linux (just install `decklink` from AUR and use a native obs studio build) + +people also say good things about the pinnacle 710 (and dazzle dvc100?) but i can't really vouch for either + +#### gvusb2 software setup + +https://iotku.pw/gvusb2-guide/ is a good resource but basically + +- go to https://www.iodata.jp/lib/software/g/1780.htm and download drivers -- some people recommend v1.11 but i am running the latest v1.14 and it's fine (edit: just checked while writing this and there's already a v1.15 that released today lol) + +ok so in obs or amarec or whatever open your video settings, this is what i use for "device setting" in windows + +- video input = "2/s-video" +- deinterlace = "weave ( off )" -- + +if you have a newer driver version keep the stuff in "advanced driver property" off except maybe "skype support (pls replug)" + +under "video decoder": + +- video standard = NTSC_M_J (even if you're recording NTSC, this brightens the image up and makes it look more like what you'd get on a CRT -- 7.5 IRE) + +under "video proc amp": + +- brightness = 128 +- contrast = 90 +- hue = 128 +- saturation = 128 +- sharpness = 40 + +then make sure to capture in 720x480 at 59.94fps (on older driver versions like 1.11 pick 29.97fps instead, then deinterlace with Retro in either amarec or obs) + +on arch linux i just install `gv-usb2-driver-dkms-git` from the AUR and it just works in obs studio after that + +in obs studio regardless of OS you want to apply retro deinterlacing and add a scaling filter to scale it from 720x480 to 640x480 bicubic (or bilinear if you want a slightly blurrier look that suits the n64 better) + +## flash carts + +summercart64 is what i have and it's cool. way cheaper than everdrive x7. + +- check the firmware on it by booting it up, if it's out of date then update it using the instructions at https://github.com/Polprzewodnikowy/SummerCart64 -- i didn't need to do this (yet) but the process is basically downloading sc64deployer and sc64-firmware + +- install the cr2032 battery into the holder such that the small pins bend upward and make contact with the top (positive side). the springy pins should be on the bottom (negative side) https://github.com/Polprzewodnikowy/SummerCart64/discussions/83 + +you will want to set up your microsd card with https://github.com/Polprzewodnikowy/N64FlashcartMenu + +when done your sd layout should look something like this: + +- /sc64menu.n64 +- /menu/config.ini +- /menu/boxart/* +- /menu/64ddipl/ + - /menu/64ddipl/NDDE0.n64 + - /menu/64ddipl/NDDJ2.n64 + - /menu/64ddipl/NDXJ0.n64 +- /menu/emulators/ + - /menu/emulators/neon64bu.rom + - /menu/emulators/sodium64.z64 + - /menu/emulators/gb.v64 + - /menu/emulators/gbc.v64 + +now load your roms and maybe saves on there. i've currently got mine in a `/roms/` folder but they can be loaded from anywhere. anything outside the above list is fair game. + +## hardmodding + +pixelfx n64digital obsoletes the old ultrahdmi? + +looks like there's a "pixelfx retro gem" which replaces the n64digital but doesn't support rgb output, only hdmi + +supposedly there's also the "n64advanced v2" which is open source on github but doesn't seem to be readily available + +- https://github.com/borti4938/n64adv2_pcb +- https://github.com/borti4938/n64adv2_fw + +https://www.reddit.com/r/n64/comments/1d6pzdm/n64_hdmi_2024_guide/ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/gaming/retroarch.md b/unified.test.hugo/content/wiki/gaming/retroarch.md new file mode 100644 index 0000000..1e67290 --- /dev/null +++ b/unified.test.hugo/content/wiki/gaming/retroarch.md @@ -0,0 +1,11 @@ +## n64 + +### shaders + +retro crisis n64 + +Slot Mask Height: 2x1 or 4x1... +: 1.00 + +LUT Colors: Trin.1 | Trin.2 | Nec Mult. | NTSC +: 1.00 (Trin.1) \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/gaming/wii.md b/unified.test.hugo/content/wiki/gaming/wii.md new file mode 100644 index 0000000..dfa5aef --- /dev/null +++ b/unified.test.hugo/content/wiki/gaming/wii.md @@ -0,0 +1,97 @@ ++++ +updated = "2024-08-03" ++++ + +## video output + +assuming no hard mods, the best you can get is to go through the component (YPbPr) signal chain in order to unlock 480p output. this is THE primary consideration when playing off of a wii, imo. there are a few games that only support 480i as well so that is another consideration. + +### display + +the "best you can do" is going to vary based on goals + +there's basically two "happy paths" here: + +- SD CRT TV that supports both 480i and 480p over component. This pretty much locks you into something high-end like a Sony PVM 14L5 or 20L5, but you get a setup that's not finicky and you also get lagfree gaming. + +- finding a 1440p IPS screen with HDMI input, and using something like an ElectronWarp https://electron-shepherd.com/collections/all/products/electronwarp or Mayflash Wii to HDMI https://amzn.to/4ft7Ddm -- this plugs right into the back and converts analog component into an hdmi output. couple that with a 1440p (300% or 3x integer scale) monitor that has a good upscaler/deinterlacer and low input lag, and you can get a way better experience than the LCD or plasma TVs of the era. + +things that don't work as well: + +- HD CRT TVs have horrible upscalers with lots of lag + +and then there's a finicky option: + +- PC CRT monitors. this locks you out of 480i which can be really annoying because not only do some games only run in 480i (and vc titles can run in 240p), the system menu will not show you anything until you blindly manage to switch it to 480p output. without doing this, you will just get an error like "out of sync range". so it's not enough to go from component to vga. + + + +i guess for upscaling/deinterlacing you could use something like an ossc or ossc pro or retrotink or whatever, to at least eliminate the 480i out of your analog chain and also have something easier to work with for any modern monitor/tv. + +### capture + +if doing component and nothing else, then get a component distribution amplifier like a calrad 937b. you can run it into a component capture card afterward, which... your only option pretty much ends up being the magewell pro capture hdmi and its breakout cable. yes that thing is $300 but it supports 240p over component so you won't have any issues with getting a signal out of the wii -- 240p/480i/480p should all work. + + + +if you convert from component YPbPr directly to VGA then you can look into VGA capture cards or also anything that accepts DVI-A should work too. i am told that the startech USB3HDCAP should work (but maybe not on linux?). a VGA splitter should also allow you to go into a PC CRT. + +if you convert from component YPbPr to HDMI or otherwise throw an ossc/etc at it, then you can easily capture HDMI these days using just about anything under the sun. (the avermedia bu113 live streamer cap 4k is like $99 at https://amzn.to/4fDLRn0 and does a great job from my experience -- only about 40ms latency in obs studio, no real quality loss, can handle 720x480@59.94Hz input just fine) you still have the option of going into a PC CRT with an HDMI to VGA adapter which is supposed to be lagless as well (as long as it doesn't scale content) + +### my setup + +wii -> component hd retrovision cables -> calrad 937b component distribution amp -> \[ magewell pro capture hdmi | sony vaio trinitron hmd-a100 via a YPbPr-to-VGA transcoder | mg16xu via an rca audio 1in4out switch \] + +alternatively: + +wii -> electronwarp wii2hdmi -> ezcoo splitter 1in2out -> \[ sony hmd-a100 via moread hdmi-to-vga dongle | avermedia bu113 capture card \] + +component costs: $423 ($123 without capture) +- retrovision $30 https://amzn.to/4dBenEd +- calrad ~$30 https://www.ebay.com/sch/i.html?_nkw=calrad+937b +- magewell pro capture $300 https://amzn.to/3YFfePY +- YPbPr to VGA transcoder $27 https://amzn.to/3WCh3up +- 2x component cable sets for interconnect $36 https://amzn.to/3WCV9qN or https://amzn.to/4cfCebz / https://amzn.to/3YDnzDB + +hdmi costs: $190 ($90 without capture) +- wii2hdmi $24 https://electron-shepherd.com/products/electronwarp +- ezcoo hdmi splitter $30 https://amzn.to/4diVNRr +- avermedia bu113 $100 https://amzn.to/3Acbb3l +- tendak adapter + gender changer $20 https://amzn.to/3SHpLq5 + https://amzn.to/46CqcI5 +- 2x hdmi cables ~$16 https://amzn.to/4fCdtsR + +so it would be overall cheaper to go through hdmi and probably more convenient paradoxically lol. even if your ultimate output is a pc crt. somehow a2d2a doesn't take a noticeable toll + +the last thing to mention is if you really want to avoid any 480i/240p signal hassles you probably should get an ossc or retrotink to deinterlace / linedouble to 640x480 progressive signal. yes this is like another hundred or three. such is the price of pc crt i guess. really makes you think if it would be worth just going for a high-end pvm that accepts 480p/480i/240p over component... \*glances at ebay prices\* nvm + +## softmodding + +https://wii.guide + +once you're homebrewed and installed your ios stuff then usb loader gx is a far superior way to play your games for both wii and gamecube. just make sure to use 480p patches, turn off the deflicker filter if you're not using a CRT, and highly consider using the framebuffer output instead of the stretched output. + +## hardmodding + +electronAVE obsoletes a lot of other things except maybe the Wii Dual? https://electron-shepherd.com/collections/all/products/electronave-kit + +personally idk if it's worth it though, if you want pure digital output you might as well emulate. also having hdmi out could make it harder to route your signal around -- for example i have an issue where my blackmagic intensity pro 4k doesn't support 480p at all. component only supports 480i and hdmi doesn't support less than 720p. + +## wifi + +wii only supports wifi b/g on 2.4ghz with wpa2 at most + +i knew about the wpa2 thing (not really an issue since wpa3 is so new) and i figured out the 2.4ghz thing (i guess 5ghz was also too new but also the wii u doesn't do 5ghz wifi either -- probably bc 5ghz is reserved for the gamepad communication) + +the thing i did not know about until i went searching for it is that apparently wifi n is also too new? i had my router in "n only" mode for efficiency reasons but had to change it back to auto b/g/n/(ax) -- that stopped the error 51330 from happening and i could connect to wifi again + +it will prompt you to check for an update (phrased as "perform an update") but if you do this you will softlock the wii since the nintendo servers seem to be down? + +## etc + +### hardware revisions + +supposedly the RVL40 is better for 480p but i have an older wii and it isn't bad so i wouldn't replace a wii i already have. i might spend more effort looking for a rvl40 though if i didn't already have one. also if you softmod (which you should) then you can enable "480p bug fix" in usb loader gx to get corrected output on older wiis \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/links/_dump.md b/unified.test.hugo/content/wiki/links/_dump.md new file mode 100644 index 0000000..0971c90 --- /dev/null +++ b/unified.test.hugo/content/wiki/links/_dump.md @@ -0,0 +1,53 @@ +### web + +minimum common web platform + +webfinger redirect in nginx config + +```nginx +location /.well-known/webfinger { + if ( $arg_resource = "acct:hello@yaakov.online" ) { + return 302 'https://cloudisland.nz/.well-known/webfinger/?resource=acct:yaakov@cloudisland.nz'; + } + + return 404; +} +``` + +mast logo + +openxri project + + + +indiekit, a nodejs server that helps static websites do indieweb stuff (is it like a cms?) + +### demetrification + +What Do Metrics Want? + +The quest to create a world without likes, retweets, and follower counts + +Will hiding likes on Instagram and Facebook improve mental health? + +### concert recording + + + + + +### varia + +V7MLIZ392DXQ4UC5GEMF + +### merch + + + + + +### music + + + + \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/links/_index.md b/unified.test.hugo/content/wiki/links/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/links/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/links/essays.md b/unified.test.hugo/content/wiki/links/essays.md new file mode 100644 index 0000000..5c7deab --- /dev/null +++ b/unified.test.hugo/content/wiki/links/essays.md @@ -0,0 +1,62 @@ ++++ +updated = "2018" ++++ + +# Essays + +## Have you considered the alternative? +https://homebrewserver.club/have-you-considered-the-alternative.html + +> There is a reason why we’re falling into this pattern of needing alternatives to the alternatives. And that is because… There are no alternatives. [...] what these alternatives all have in common is that they share the same model. A model that revolves around centralized services, vendor lock-in and marketing related surveillance, and all of that within a neoliberal context of the free market [...] The reason is that they have no choice within the economic system they choose to operate in. + +--- + +> In short, both Whatsapp and FacebookMessenger can afford to deploy end-to-end encryption for your messages because it won’t hurt their bottom line, which is making money based on the surveillance of your behavior and your social graph. Adding crypto thus merely patches your privacy worries, but not the threat to it. + +--- + +> the problem is not that federation doesn’t adapt, but rather that there are problems with its implementation for a very significant reason: software developers working on federated systems mostly work for free in their spare time or with little means [...] while Marlinspike seems to defend his product from a technological perspective, Gultsch’s counter argument moves back the discussion to the context of political economy. + +## Avoid News + + 1) News does not represent the real world [...] the highly visible misleads us. + + 2) News is irrelevant [...] It’s very difficult for us to recognize what’s relevant. It’s much easier to recognize what’s new [...] if something really important happens, you will hear about it, even if you try to live protected from the news in a cocoon + + 3) News limits understanding [...] It’s not “news facts” that are important, but the threads that connect them + + 4-5) News is toxic for your body/society [...] News consumers risk impairing their physical health [...] News leads to collective neurosis [...] **Psychological scars do not heal easily** + + 6) News massively increases cognitive errors [...] Our brains crave stories that “make sense” – even if they don’t correspond to reality + + 7) News inhibits thinking [...] **The passageway from working memory to long-term memory forms a bottleneck in our brain** [...] Because news disrupts concentration, it actively weakens comprehension + + 8) News changes the structure of your brain [...] The more news we consume, the more we are exercising the neural circuits devoted to skimming and multitasking while ignoring those used for reading and thinking deeply [...] Your attention is set on fast-breaking events, so you hunger for more data about them [...] [this] feeds compulsive information-seeking behavior (CISB) [and long term potentiation (LTP)] + + 9) News is a waste of time [...] Information is no longer a scarce commodity. But attention is. + + 10) News separates reputation from achievement [...] people become famous for reasons that have little relevance to our lives + + 11) News is produced by journalists [...] Fewer than ten percent of the news stories are original. Fewer than one percent are truly investigative + + 12) Reports and forecasts can be or are wrong [...] Incorrect forecast are not only useless, they are harmful + + 13) News is manipulative [...] News is the perfect Trojan horse. Few bits of news arrive without a hidden + agenda [...] It sets the public agenda + + 14) News makes us passive [...] **News stories are overwhelmingly about things you cannot influence** [...] it can lead to passivity and a sense of victimhood. The scientific term is learned helplessness + + 15) News gives us the illusion of caring [...] [it] delivers the illusion of care but doesn’t get us anywhere [...] we are not connected because we consume news + + 16) News kills creativity [...] Things we already know severely impact creativity [...] If you want to come up with old solutions, read news + + //Isn’t it inhumane not to care about Haiti? Your shtick feels pretty cold.// + + Is it inhumane not to care about horrific things happening on other planets? The point is: You can’t care about everything in the universe, on the earth, in your country, not even in your city. Nor should you. + + //Where is the compassion?// + + Let me state this even stronger: Caring without action is inhumane. It gives us the illusion of making the world a better place. Truth is, we do it for us. We revel in the marinade of caring. What does it change? It makes us feel good (humane if you like) but doesn’t help a thing. [...] Empathy – if it remains empathy – is useless. + +http://www.dobelli.com/en/essays/news-diet/ +https://web.archive.org/web/20180106154431/http://www.dobelli.com/en/essays/news-diet/ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/links/quotes.md b/unified.test.hugo/content/wiki/links/quotes.md new file mode 100644 index 0000000..7590952 --- /dev/null +++ b/unified.test.hugo/content/wiki/links/quotes.md @@ -0,0 +1,21 @@ ++++ +updated = "2018" ++++ + +# Quotes + +## Managers need private offices for "productivity" but put their workers in open offices + +https://arstechnica.com/science/2018/07/in-open-offices-workers-chat-70-less-are-less-productive-and-email-more/?comments=1&post=35658503#comment-35658503 + +> When they went to open office one of my friends said in the announcement meeting it was asked why managers and higher ups needed offices. Productivity was the answer. Didn't seem to phase them that the people actually doing the producing were going to be producing less. + +## "I watched an entire Flat Earth Convention for my research – here’s what I learnt" + +https://theconversation.com/i-watched-an-entire-flat-earth-convention-for-my-research-heres-what-i-learnt-95887 + +> While flat earthers seem to trust [...] scientific methods, what they don’t trust is scientists [...] those in power control what is considered to be correct [...] According to Foucault, there is therefore an intimate [...] relationship between power and knowledge. + +> With the increased voice afforded by social media, knowledge has been increasingly decentralised, and competing narratives have emerged. + +> one of the physicists pleaded with the audience to avoid trusting YouTube and bloggers. The audience and the panel of flat earthers took exception to this, noting that “now we’ve got the internet and mass communication … we’re not reliant on what the mainstream are telling us in newspapers, we can decide for ourselves”. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/optics/_index.md b/unified.test.hugo/content/wiki/optics/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/optics/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/optics/how-to-order-glasses-online.md b/unified.test.hugo/content/wiki/optics/how-to-order-glasses-online.md new file mode 100644 index 0000000..13de196 --- /dev/null +++ b/unified.test.hugo/content/wiki/optics/how-to-order-glasses-online.md @@ -0,0 +1,64 @@ ++++ +updated = "2018" ++++ +# How to order glasses online + +## My measurements + +SIZE = +- frame width: medium (135mm-139mm -- ~136mm) // 141mm? +- bridge width: small (17-18mm -- ~17mm) // 18mm +- lens width: medium (52-54mm -- ~53mm) // 52mm +- lens height: medium (33-40mm -- ~35mm) // 32mm?? +- temple arm: medium (135-144mm -- ~140mm) // 145mm? + +PD = +- Single: 65mm (64.5mm) +- Dual: ~32.5mm right / ~32.5mm left? 33/32? 32/33? + +PRESCRIPTION = Single Vision +``` + SPH CYL AXIS +OD -6.50 -0.75 30 +OS -5.75 -0.75 170 +``` +------------------------------ + +## NOTES: + +### Abbe numbers +- Abbe value measures color dispersion. +- Higher Abbe means less chromatic aberration. +- glass is the best, low-index plastics are close, polycarbonates suck +- Crown glass = 59 +- CR-39 Plastic = 58 +- Trivex = 43 +- Polycarbonate = 30 + +### Clarity, peripheral vision, chromatic aberration +- look for a high abbe value if you want + - more clarity, + - better peripheral vision, + - and less chroma aberration. +- consequently, the index actually doesn't matter for clarity; it only really matters for thickness! a high-index lens will typically lower the abbe value and therefore reduce clarity. + +### Aspheric lens +- aspheric designs will change curvature gradually, leading to flatter lens and better peripheral clarity. many high-index plastics might have aspheric designs to counteract the thicker edges. + +### Distortion +- i ordered one trivex and one 1.67 high-index from zenni but both glasses had distortion at edges. +- i think that's normal but i personally can't live with it, so i returned them and will be saving money to buy something with a better material. + - lenscrafters advertises this as "hd lenses", which is also a manufacturing process-based technique. if that's anything like what i did in amman, then an eye scan will be required. the digital scan of your eyes is used to carve out much more precise lenses up to 0.01D instead of 0.25D increments. + +### UV / Blue Light +- UV protection coating is kinda bullshit, the lens material will typically block <380nm anyway +- Blue light filters are even more bullshit, and can actively cause color shifts! + +------------------------------ + +## RESOURCES: + +- https://www.visioncareproducts.com/high-index-lens-materials-past-present-future/ +- http://www.mastereyeassociates.com/eyeglass-lens-materials +- http://www.trivexspecialist.com/blog/slimming-down-are-high-index-lenses-always-the-answer/ +- https://www.allaboutvision.com/lenses/how-to-choose.htm \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/photography.md b/unified.test.hugo/content/wiki/photography.md new file mode 100644 index 0000000..fa60d43 --- /dev/null +++ b/unified.test.hugo/content/wiki/photography.md @@ -0,0 +1,19 @@ ++++ +title = "Photography" +updated = "2019" ++++ +## "Beginner" vs "expert" is a false dichotomy + +There is no camera for "beginners". It doesn't make any sense to recommend a camera based on skill level at all. Instead, getting into photography should go something like this: + +### Self-discovery +Identify the area / subject matter you're interested in, and just start taking pictures! It doesn't matter if you only have a smartphone that only does auto. The important thing is to start taking pictures. Start gaining experience and get that sense of when something is photo-worthy, and how you want it to look. Start learning about framing and focus and other stuff like that. + +### Theory +Once you've got those basics understood, it's time to learn about how photography works. Get a camera with manual mode. Teach yourself about aperture, shutter speed, and sensitivity, then teach yourself how each of those settings affects the output of your camera. Internalize the effects that each parameter will have on the picture -- how will it affect brightness? noise? blur? etc. Start learning to tune your camera's settings for each scene. + +### Development +Find a camera that can take RAW photos. Learn how to develop those photos. Familiarize yourself with all the factors that go into outputting a finalized image -- exposure levels, color balance, sharpening and denoising filters, and so on. Pick a software and learn it. + +### Optional: Going pro / specializing +By this point you should have a thorough understanding of the types of pictures you want to take, how to actually take those pictures with your camera of choice, and how to develop the raw output into a pleasing image. This is the point where you can start looking into specialized equipment and gear that suits the niche you're most interested in -- landscape? architecture? street? still-life? portrait? event? If you have enough money or you can start making money from photography, then you can start looking at picking out gear that will help you take the photos you want. Pick out a good body (sensor size? ISO? resolution? autofocus?) then pick out some lenses (focal length? aperture?) and you should be able to take all the photos you want. diff --git a/unified.test.hugo/content/wiki/politics/_index.md b/unified.test.hugo/content/wiki/politics/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/politics/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/politics/fascism.md b/unified.test.hugo/content/wiki/politics/fascism.md new file mode 100644 index 0000000..ee4904e --- /dev/null +++ b/unified.test.hugo/content/wiki/politics/fascism.md @@ -0,0 +1,52 @@ ++++ +title = "Fascism" +updated = "2019" ++++ + + +## Definition +**Fascism** is a political ideology defined by the following: + +1. The myth of the **great nation**, meant to elicit pride in the Nation and its former accomplishments. +2. The myth of **degeneracy**, which is a scapegoat for all of the Nation's failings and the cause of its supposed decline. +3. The myth of **national rebirth**, i.e. returning the Nation to greatness, typically by "cleansing" the Nation of the aforementioned "degeneracy". + +# Related fundamental concepts you should be aware of + +**What is a nation?** A *nation* is a shared cultural or political identity. It is not strictly the same as a *government* (legal body), a *country* (geography), or an *ethnicity* (culture), although it may be defined along those lines. It is also not to be confused with a *state* (monopoly on power). + +**Social radix:** For fascists, national identity is the root of all society. + +## Characteristics + +### Third Positionism against liberalism and against socialism +Fascism positions itself as *against democracy* and *against Marxism*. It is anti-liberal and anti-socialist (especially anti-communist), and instead occupies the "Third Position". + +### Fetishization of order +Fascism is more dedicated to *order* rather than *justice*. All individuals are expected to have a duty to protect the Nation-State and uphold its interests and values. Any concept of "the greater good" beyond the national interest is mostly nonexistent. All that matters is preserving "law and order", i.e. preserving the superiority of your own nation above others. This focus on stability, discipline, hierarchy, and national pride permeates all of society. + +>Individuals simply [cannot] be relied on voluntarily to 'obey the law, pay their taxes and serve in war'. **No well-ordered society could want the people to be sovereign.** +> +>*Benito Mussolini* + +## Things that are fascism + +* Wanting to establish a national empire +* Wanting to conquer or subjugate other nations, or to make them subservient to your nation +* Believing that some nations are inferior to others +* Believing that certain peoples/cultures/lifestyles are bringing your nation down +* Eliminating rights of a targeted subgroup for above reasons +* Restricting entry or physically expelling a targeted subgroup for above reasons +* Murdering a targeted subgroup for above reasons + +## Things that are not fascism + +* A willingness to use violence +* A willingness to use violence in self-defense +* Defending a community against violence +* Having a government +* Having a government that does things +* Anything a government does +* Not letting someone give a speech +* Not letting someone organize in your community +* Not listening to someone trying to speak \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/politics/neoliberalism.md b/unified.test.hugo/content/wiki/politics/neoliberalism.md new file mode 100644 index 0000000..c392d75 --- /dev/null +++ b/unified.test.hugo/content/wiki/politics/neoliberalism.md @@ -0,0 +1,7 @@ ++++ +title = "Neoliberalism" ++++ + +neoliberalism is just largely a return to liberalism; the idea that govt's role is to help business, that markets can be used as a force for good https://en.wikipedia.org/wiki/Neoliberalism + +maybe best exemplified by thatcher, reagan, greenspan, clinton; the support of "free trade" agreements like NAFTA and TPP or organizations like the IMF or WTO; opposition to people like ralph nader in the 1970s; concepts like "the marketplace of ideas" or "soft power"; in short, everything is a market and the experts should decide the best policies to help the market \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/politics/policy.md b/unified.test.hugo/content/wiki/politics/policy.md new file mode 100644 index 0000000..93e9ad7 --- /dev/null +++ b/unified.test.hugo/content/wiki/politics/policy.md @@ -0,0 +1,15 @@ ++++ +updated = "2019" ++++ + +# Policy + +## 'It’s a miracle': Helsinki's radical solution to homelessness +Finland is the only EU country where homelessness is falling. Its secret? Giving people homes as soon as they need them – unconditionally + + +> “We had to get rid of the night shelters and short-term hostels we still had back then. They had a very long history in Finland, and everyone could see they were not getting people out of homelessness. We decided to reverse the assumptions.” + +> As in many countries, homelessness in Finland had long been tackled using a staircase model: you were supposed to move through different stages of temporary accommodation as you got your life back on track, with an apartment as the ultimate reward. + +> “We decided to make the housing unconditional,” says Kaakinen. “To say, look, you don’t need to solve your problems before you get a home. Instead, a home should be the secure foundation that makes it easier to solve your problems.” \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/politics/radicalization.md b/unified.test.hugo/content/wiki/politics/radicalization.md new file mode 100644 index 0000000..72355c8 --- /dev/null +++ b/unified.test.hugo/content/wiki/politics/radicalization.md @@ -0,0 +1,22 @@ ++++ +title = "Radicalization" +updated = "2018" ++++ + +## The three factors of radicalization + +>For radicalization to occur, there are three necessary ingredients, according to Kruglanski’s research. The first is the universal need to live a worthwhile life — to have significance. People usually satisfy this need through socially accepted means, “like working hard, having families, other kinds of achievements,” Kruglanski said. Radicals instead tend to place significance on their gender, religion or race. +> +>The second is “the narrative,” which gives someone permission to use violence. Kruglanski said the narrative is usually that there is an enemy attacking your group, and the radical must fight to gain or maintain respect, honor or glory. +> +>The third necessary component is the community, or the network of people who validate the narrative and the violence. + +-- ["The psychology of how someone becomes radicalized" (Angela Fritz, The Washington Post, 2018 Nov 1)](https://www.washingtonpost.com/science/2018/11/01/psychology-how-someone-becomes-radicalized/?noredirect=on&utm_term=.bb1c34780f0b) + +## Deradicalization tactics + +>Weilnboeck says one lesson successful facilitators have learned is to avoid engaging in debates about politics or religious doctrine with those they are trying to deradicalize. +> +>He says such debates usually fail to alter the belief system of a violent extremist, especially in the early stages of a deradicalization program, but will almost certainly foster distrust. + +-- ["The Dos And Don'ts Of Deradicalizing Violent Extremists" (Ron Synovitz, Radio Free Europe / Radio Liberty, 2015 Sep 6)](https://www.rferl.org/a/deradicalizing-violent-extremists-what-works-what-does-not-work/27229417.html) \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/politics/voluntarism.md b/unified.test.hugo/content/wiki/politics/voluntarism.md new file mode 100644 index 0000000..a894440 --- /dev/null +++ b/unified.test.hugo/content/wiki/politics/voluntarism.md @@ -0,0 +1,11 @@ ++++ +title = "Voluntarism" ++++ + +## criticisms + +pursuing pure voluntarism as an ideology (and not simply an ideal) tends to ignore the realities of power imbalances. If two people are inequal, then they can never come to a voluntary agreement -- the power of one will coerce the other, even if subconsciously. + +Consider whether one can "voluntarily" become a slave. Or, more relevant today, consider the wage labor system. Is it truly "voluntary" if your food, shelter, and very survival depends on such a "voluntary" arrangement? + +The cold reality is that voluntarism is merely idealism so long as any social class or hierarchy exists. Maybe some prefigurative politics are necessary, but you have to push for progress without 100% support or you'll wait forever. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/search/_index.md b/unified.test.hugo/content/wiki/search/_index.md new file mode 100644 index 0000000..a7f481a --- /dev/null +++ b/unified.test.hugo/content/wiki/search/_index.md @@ -0,0 +1,3 @@ ++++ +title = "Search" ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/sitemap/_index.md b/unified.test.hugo/content/wiki/sitemap/_index.md new file mode 100644 index 0000000..437bee0 --- /dev/null +++ b/unified.test.hugo/content/wiki/sitemap/_index.md @@ -0,0 +1,3 @@ ++++ +title = "sitemap" ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/!misc.md b/unified.test.hugo/content/wiki/tech/!misc.md new file mode 100644 index 0000000..a6ff085 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/!misc.md @@ -0,0 +1 @@ +prefer xml for trees, json(ld) for graphs? \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/_index.md b/unified.test.hugo/content/wiki/tech/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/communication.md b/unified.test.hugo/content/wiki/tech/communication.md new file mode 100644 index 0000000..82f0e8f --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/communication.md @@ -0,0 +1,36 @@ ++++ ++++ + +## Paradigms + +### 1-1 or 1-n + +### push or pull + +### relaying aka intermediaries + +## Separation of concerns + +### Publishing + +> "I want to share this with the world." + +For a resource to be visible to other people, it must first be published. Typically, resources are published at a location or with a specific identifier; people who wish to view that resource can then go to that location or search for that identifier using a lookup service in order to view the resource. Most commonly, resources are published on the World Wide Web, and they are found via their uniform resource location (URL). When you type, paste, or click a link in your Web browser, your browser will make a request to fetch that resource on your behalf, and the server responsible for that resource will respond with the resource. + +### Subscribing + +> "I want to see the things I am interested in." + +OK, so there are resources that we can access if they are published at a known location or with a known identifier. How do we know when there are new or updated resources? At the most basic level, you can manually check a resource to see if it has been updated; for example, you can check a website to see if there are any new pages. To make this manual checking process easier, publishers can generate a feed or stream of resources that can be subscribed to. When you subscribe to that feed, your feed reader will periodically check the feed for any changes; for example, a feed may be updated with the latest articles from a Web site, which your reader will then pull and show to you as an update. + +### Messaging + +> "I want to communicate directly with people." + +In some ways, messaging can be covered by having a publisher and a subscriber on each end of a conversation, but it usually makes more sense to deliver messages to your conversational partners directly rather than having them check for new messages on their own schedule. + +### Discussing + +> "I want to gather in a community or around a topic." + +Traditionally, this has been handled by forums, bulletin board systems, and groups. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/computers/_index.md b/unified.test.hugo/content/wiki/tech/computers/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/computers/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/computers/build-notes.md b/unified.test.hugo/content/wiki/tech/computers/build-notes.md new file mode 100644 index 0000000..699eb89 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/computers/build-notes.md @@ -0,0 +1,61 @@ ++++ +updated = "2018" ++++ +# Build Notes + +## ASUS Z170I Gaming +a mini-itx z170 board combo'd with an i5-6600k. + +### what to do with this board +- should i use it as a windows gaming machine? +- should i use it as a home server? + +right now i installed windows on a cheap nvme drive and have it powered by the evga 500bq; i bought a bitfenix prodigy for it so i guess it can be spec'd out for either use case thanks to that case's spaciousness. (whereas if i had gotten a ds380b it would've had some cooling issues, would've required me to buy an sfx psu, and wouldn't make for a good desktop at all -- so an expensive waste of money) + +## ASUS MAXIMUS VIII HERO +z170 atx motherboard that i bought as part of a combo with an i7-6700k. + +### observations +- one POST issue has been narrowed down to a weird interaction between thunderbolt support and igpu? specifically it seems to freeze (q code 60, as of latest testing) when both "igpu multi monitor" and "thunderbolt boot support" are enabled... and maybe some other thunderbolt options like usb or just thunderbolt in general, but i can't remember and i don't wanna retest, so i just disabled thunderbolt entirely. +- another POST issue (q code 22 / 55 / occasionally cc?) was happening when a certain stick of g.skill trident z rgb ddr4-3200 was inserted. i sent that kit off for rma, but i've read that perhaps asus motherboards can silently corrupt some earlier gskill trident z revisions. not sure about the validity of that statement but i guess i might wanna take it as an opportunity to sell them off and upgrade to 4x16gb idk + +## Supermicro X9DAE + +boy do i kinda hate this motherboard after all the problems it's given me and how meh supermicro's rma process has been + +### gotchas + +#### uefi boot usb must use usb2. +booting from uefi usb seemingly doesn't work, until you put the usb key into a **usb2** port. +the two rear usb3 ports **do not work** for this! + +#### lpddr3 is gaslighting me. +16x8gb samsung pc3L-12800R (lpddr3-1600 equivalent) would not work reliably... +...until it suddenly does, and then again suddenly doesn't. +i thought i had a dead stick because it wouldn't boot with all 16 filled. +then i thought it was misaligned cpu2 pins +then i thought it was cpu2 power delivery +then shuffling the sticks around made it somehow work... temporarily +clearing cmos made ALL the samsung ecc ram stop working +...but some standard corsair / kingston ddr3 ram works perfectly fine! +i still don't know if the ecc ram i bought is working, +or if the motherboard is incompatible, or what. +supermicro advertises 1.35v / 1.5v compatibility but +1.35v has not worked consistently for me at all + +#### hangs on BIOS if any connected drive has corrupted boot +i had an ssd connected with a windows 10 install that borked itself, +and that inadvertently caused the BIOS to become completely inaccessible +until i figured out that i needed to disconnect the disk... +the same thing happened when i left an install usb key plugged in??? + +### so many RMAs ughhhh + +1st rma was for not powering on when shorting the power pins, replaced. 2nd rma supposedly repaired a black screen issue / phantom overheat, and, well... it no longer trips the JOH1 header but it still has the black screen issue. after some amount of time the system hangs and the video output goes to "no signal". it seems to work for a few hours, then it doesn't work for like a full day, then it starts working again after you leave it alone for a while, ad nauseum. + +- is it the psu? +- is it the cpu1 pins? +- is it the ethernet? +- is it the ssd? + +~who even knows~ seems to be that evga nex750g power supply, because it's not happening with a new evga 500bq... also apparently you can test supermicro mobos without the cpu1/2 pins -- those are just used for delivering more power when needed. thanks to being told this by a rep, i was able to test more psus and discover this. so i guess now i need to buy a new/working psu with dual eps. ugh. also presumably the ram actually works, but i haven't tested all 16 sticks with a working psu. diff --git a/unified.test.hugo/content/wiki/tech/computers/graphviz.md b/unified.test.hugo/content/wiki/tech/computers/graphviz.md new file mode 100644 index 0000000..8ee9d14 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/computers/graphviz.md @@ -0,0 +1,192 @@ +``` +graph desktop { + label = "desktop" + rankdir = LR + + subgraph legend { + label = "Legend" + + legend_label [label = ""; xlabel = "Legend"; width = 0; height = 0] + unavailable [label = ""; xlabel = "unavailable"; width = 0.25; height = 0.25; shape = box; color = grey] + unused [label = ""; xlabel = "unused slot"; width = 0.25; height = 0.25; shape = box] + used [label = ""; xlabel = "used slot"; width = 0.25; height = 0.25; shape = box; color = "#333"; style = filled] + component [label = ""; xlabel = "component"; width = 0.25; height = 0.25; shape = box; color = grey; style = filled] + warning [label = ""; xlabel = "warning"; width = 0.25; height = 0.25; shape = box; color = orange; style = filled] + + legend_label -- unavailable [style = invis] + legend_label -- unused [style = invis] + legend_label -- used [style = invis] + legend_label -- component [style = invis] + legend_label -- warning [style = invis] + } + + node [ + shape = box + height = 0.5 + width = 1 + ] + + edge [ + penwidth = 1.25 + ] + + subgraph cluster_motherboard { + label = "Motherboard: Aorus MASTER rev1.2 (X570)" + + subgraph cluster_usb3 { + label = "USB headers" + + usb2_1 + usb2_2 + + usb3_1 + usb3_2 + + usbc_1 + } + + subgraph cluster_sata { + label = "SATA 3.0\nheaders" + + sata_1 + sata_2 + sata_3 + sata_4 + sata_5 + sata_6 + } + + subgraph cluster_nvme { + label = "3x PCIe 4.0 M.2 NVME" + + # The Aorus Master 1.2 has 3x NVME slots + nvme_1 + nvme_2 + nvme_3 + + # My NVME drives + nvme_drive_1 [label = "WD SN850 2TB PCIe 4.0"; width = 2.5; color = grey; style = filled] + nvme_drive_2 [label = "WD SN850 2TB PCIe 4.0"; width = 2.5; color = grey; style = filled] + nvme_drive_3 [label = "WD SN850 2TB PCIe 4.0"; width = 2.5; color = grey; style = filled] + + nvme_1 -- nvme_drive_1; nvme_1 [color = "#333"; style = filled; fontcolor = white] + nvme_2 -- nvme_drive_2; nvme_2 [color = "#333"; style = filled; fontcolor = white] + nvme_3 -- nvme_drive_3; nvme_3 [color = "#333"; style = filled; fontcolor = white] + + # Filling the 3rd NVME slot disables two SATA slots + sata_5 [color = grey; fontcolor = grey] + sata_6 [color = grey; fontcolor = grey] + sata_5 -- nvme_3 [color = orange] + sata_6 -- nvme_3 [color = orange] + } + + subgraph cluster_pcie { + label = "PCIe slots" + + subgraph pcie_cpu_lanes { + label = "PCIe slots from CPU lanes are linked." + rank = same + + pcie_x16_1 [label = "PCIe 4.0 x16 (running x16)"; width = 3] + pcie_x16_2 [label = "PCIe 4.0 x16 (running x8)"; width = 3; color = grey; fontcolor = grey] + # using the 8x slot reduces the 16x to 8x + pcie_x16_2 -- pcie_x16_1 [color = orange; tailport = n; headport = s] + } + pcie_x1 [label = "PCIe 4.0 x1 (running x1)"; width = 3] + pcie_x16_3 [label = "PCIe 4.0 x16 (running x4)"; width = 3] + + # graphics card 16x + asrock_5700xt [label = "AMD RX 5700 XT\n(AsROCK Challenger D OC 8GB)"; color = grey; style = filled] + pcie_x16_1 -- asrock_5700xt; pcie_x16_1 [color = "#333"; style = filled; fontcolor = white] + + # capture card 4x + bm_ip4k [label = "Blackmagic Intensity Pro 4K"; width = 3; color = grey; style = filled] + pcie_x16_3 -- bm_ip4k; pcie_x16_3 [color = "#333"; style = filled; fontcolor = white] + } + + subgraph cluster_cpu { + label = "AM4 socket" + + cpu [label = "AMD Ryzen 5950x"; width = 2; color = grey; style = filled] + } + + subgraph cluster_ram { + label = "DDR4 RAM slots" + + ram_1 + ram_2 + ram_3 + ram_4 + + # 128gb kit + vengeance_128gb [label = "128GB (4x32GB) DDR4-3600 C18\nCorsair Vengeance LPX"; width = 3.5; height = 2.75; color = grey; style = filled] + ram_1 -- vengeance_128gb; ram_1 [color = "#333"; style = filled; fontcolor = white] + ram_2 -- vengeance_128gb; ram_2 [color = "#333"; style = filled; fontcolor = white] + ram_3 -- vengeance_128gb; ram_3 [color = "#333"; style = filled; fontcolor = white] + ram_4 -- vengeance_128gb; ram_4 [color = "#333"; style = filled; fontcolor = white] + } + + } + + subgraph cluster_case { + label = "Case: CM HAF 932" + + subgraph cluster_front_bays { + label="5.25\" Front bays" + + # 6x front bays + bay_1 + bay_2 + bay_3 + bay_4 + bay_5 + bay_6 + + # Bay 1: USB 3.0 card reader + kingwin_bay_adapter [label = "Kingwin 5.25\" to 3.5\" adapter"; width = 3] + vantec_card_reader [label = "3.5\" USB 3.0 Card Reader\n(Vantec UGT-CR935)"; width = 3; color = grey; style = filled] + bay_1 -- kingwin_bay_adapter -- vantec_card_reader; bay_1 [color = "#333"; style = filled; fontcolor = white] + vantec_card_reader -- usb3_1 [tailport = n; headport = w]; usb3_1 [color = "#333"; style = filled; fontcolor = white] + + # Bay 2: SATA hotswap bays + syba_hotswap [label = "Syba 5.25\" Hotswap Bay"; width = 3; color = grey; style = filled] + bay_2 -- syba_hotswap; bay_2 [color = "#333"; style = filled; fontcolor = white] + syba_hotswap -- sata_1 [tailport = e; headport = w]; sata_1 [color = "#333"; style = filled; fontcolor = white] + syba_hotswap -- sata_2 [tailport = e; headport = w]; sata_2 [color = "#333"; style = filled; fontcolor = white] + syba_hotswap -- usb3_2 [tailport = e; headport = w]; usb3_2 [color = "#333"; style = filled; fontcolor = white] + + # Bay 3: DVD drive + asus_dvd [label = "ASUS DVD Drive 24x"; width = 3; color = grey; style = filled] + bay_3 -- asus_dvd; bay_3 [color = "#333"; style = filled; fontcolor = white] + asus_dvd -- sata_3 [tailport = e; headport = w]; sata_3 [color = "#333"; style = filled; fontcolor = white] + + # Bay 4: Kloud City drawer + kloud_city_1 [label = "Kloud City 5.25\" drawer"; width = 3; color = grey; style = filled] + bay_4 -- kloud_city_1; bay_4 [color = "#333"; style = filled; fontcolor = white] + + # Bays 5-6: Evercool Dual + evercool_dual [label = "Evercool Dual\n5.25\" to 3x 3.5 drives"; height = 1.25; width = 3] + bay_5 -- evercool_dual; bay_5 [color = "#333"; style = filled; fontcolor = white] + bay_6 -- evercool_dual; bay_6 [color = "#333"; style = filled; fontcolor = white] + } + + subgraph cluster_drive_sleds { + label = "Drive sleds" + + sled_1 + sled_2 + sled_3 + sled_4 + sled_5 + } + + subgraph cluster_cpu_clearance { + label = "CPU cooler\nclearance: 172mm" + + cpu_cooler [label = "Noctua NH-D15S"; width = 1.75 color = grey; style = filled] + } + + } + +} +``` \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/computers/linux-laptop.md b/unified.test.hugo/content/wiki/tech/computers/linux-laptop.md new file mode 100644 index 0000000..8486ad0 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/computers/linux-laptop.md @@ -0,0 +1,35 @@ ++++ +updated = "2019" ++++ +# Linux laptop +i'm using an asus zenbook infinity (ux301la-dh71t) for this. main challenges of laptops are being limited to 1 monitor, needing to set up hotkeys, and other such stuff. + +## WM/DE experiences/ratings + +### Good? +- Sway (pure Wayland, no big dependencies, but need to figure out how to supplement it with DE stuff like notification area, easily-configurable panel, notifications, audio settings, and a better menu than dmenu) (i ended up going with sway as my main environment, paired with waybar / mako / pavucontrol / rofi, and also screenshots with grim+slurp) +- XFCE + xfwm (no-nonsense traditionalism but bad tiling, so you need to use a different workflow based around a dockbar/panel instead of tiling and workspaces.) +- XFCE + i3-gaps (a good compromise between DE and WM, at least for X11) +- Deepin (pretty but idk if it's functional yet -- play around more with it) + +### Interesting +- Qtile (need to learn how to use it bc it seems decent, similar to sway/i3 but no idea how to open menus yet, unfortunately doesn't seem to be mouse-driven at all) + +### IDK +- bspwm / herbsluftwm (need config before opening?) + +### Not-so-good? +- Budgie (scaling a bit weird, and idk why but i don't really like the styling of it even though it's clean and makes sense) +- awesome (haven't been able to configure it how i want to with the title bars, but otherwise *seems* solid) + +### Eh... +- GNOME (too limited and boring) +- KDE (bad design) + +### Not good +- Openbox/Fluxbox (too much hardcoded stuff) +- Notion (too bare/ugly) + +### Broken +- way-cooler (failed to compile) +- liri-desktop (no input from mouse/keyboard) \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/computers/obs.md b/unified.test.hugo/content/wiki/tech/computers/obs.md new file mode 100644 index 0000000..a0090e4 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/computers/obs.md @@ -0,0 +1,18 @@ +## crt filter pipeline in obs studio + +source: 640x480 progressive signal (so deinterlaced with obs Retro or through amarectv plus automatic line-doubling) + +- [if capturing through amarec] Crop/Pad "Crop off Amarec window border" + - relative crop, 4px in each direction +- Scaling/Aspect ratio "Scale up for high-res effects" + - Point scale 3840x2880 (6x 480p) +- User-defined shader "Shader: TV CRT subpixel" [from obs-shaderfilter] + - width 1, height 3, horizontal/vertical gaps 1 +- Scaling/Aspect ratio "Scale back down to 4x (1280x960)" + - Bilinear scale 1280x960 +- User-defined shader "Shader: Bloom" [from obs-shaderfilter] + - amp factor 2.00, angle/radius steps at least 6 (but 20 is better) +- Image Mask/Blend "Scanlines mask" + - alpha mask (alpha channel) [image](/scanlines-mask-640x480.png) +- [Optional] User-defined shader "Shader: CRT curvature" [from obs-shaderfilter] + - adjust to taste. i was toying around with strength 16 and feathering 16 before turning it off \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/computers/zfs.md b/unified.test.hugo/content/wiki/tech/computers/zfs.md new file mode 100644 index 0000000..f237617 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/computers/zfs.md @@ -0,0 +1,7 @@ +## test dedup performance + +generally not a good idea to enable dedup unless you have a lot of similar vms or database backups or whatever, and have more RAM to spare than hard disk space + +``` +zdb -S poolName +``` \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/gorillaglass.md b/unified.test.hugo/content/wiki/tech/gorillaglass.md new file mode 100644 index 0000000..5fb2d65 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/gorillaglass.md @@ -0,0 +1,13 @@ ++++ +updated = "2018" ++++ +# Gorilla Glass + +Gorilla Glass is a brand of glass made by Corning and frequently used to manufacture smartphones. This page lists some of the details of each generation, such as chemical makeup, durability, scratch resistance, shatter resistance, and changes to these between generations. + +## Gorilla Glass 1 +## Gorilla Glass 2 +## Gorilla Glass 3 +## Gorilla Glass 4 +## Gorilla Glass 5 +## Gorilla Glass 6 \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/mastodon/_index.md b/unified.test.hugo/content/wiki/tech/mastodon/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/mastodon/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/mastodon/issue-tracker.md b/unified.test.hugo/content/wiki/tech/mastodon/issue-tracker.md new file mode 100644 index 0000000..d8b5a62 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/mastodon/issue-tracker.md @@ -0,0 +1,498 @@ ++++ +toc = true +autonumbering = true ++++ + +## (closeable) + +### (duplicates) + +### (maybe closeable?) + +- #813 split docker-compose deployment into "web" and "streaming" [i.e. separate image for streaming API -- is this relevant to current docker strategy?] +- #1298 add custom entries to Getting Started [the motivation was adding a link to code of conduct, although this could be more generally useful outside that context] +- #1306 timeline scroll jumps when new posts come in [addressed by slow mode?] + - #1774 timeline scroll jumps when posts are deleted +- #3283 composing a long post with overflow will cause jumping on typing +- #3369 ctrl+z after posting used to restore the text to the compose box, but now it does not +- #3858 allow pinning favourites column and user profile columns [half-fixed -- you can pin favs but you still can't pin user profiles] +- #4701 show private posts in hashtag search if you are authorized to see them [closed as "intentional" in #2440 but idk maybe it could be reconsidered] +- #4869 filters should apply to emoji [this was filed back when regex filters were a thing, and seems to have been shown to work even back then, so was not reproducable] [small caveat: could extract a feature request out of this for allowing filtering an emoji by its shortcode? but probably not needed] +- #5403 reblog `url` is sometimes null when it marked non-nullable [i think this isn't happening anymore] +- #5737 store metadata about relationship changes (when/why) [we have profile notes now so that probably works] +- #5896 allow mods to force hide all media from an account [is this the same as "force-mark as sensitive" or is it more like "reject media"?] +- #6033 postgres 10 has a long-running query on public timelines? [is this still relevant] +- #6064 remote suspensions do not always reach you for followers? [has this been fixed now? issue is from 2017] +- #6073 hashtag cloud on landing/about page [is this addressed by trending tags on explore page?] +- #6250 don't send email notifications if a notification is seen in an active session [isn't this done by default now? there's a setting to "always send"] +- #6321 "quiet hours" mode where notifications are not shown [this is done at the OS level] + +--- + +## (uncategorized) + +- #482 [retry limit for failed authentication] +- #1910 `/#hashtag` is not parsed as a hashtag (also `)#hashtag` and `_#test`) [because it could be a url fragment] +- #3166 boost/fav counts out of sync (due to being async) +- #3794 [someone is confused why replies are not fetched] +- #3964 filter out private posts if you can't see the full context + +### (needs verification) + +- #2650 disabling a notification type will cause that notification to be missed; re-enabling the notification type does not bring back the missing notifications during that period in which it was disabled +- #2777 browser notifications do not correctly handle mixed LTR + RTL +- #2826 drag and drop images from othe browser tab +- #2865 empty favourite notification +- #3040 registering an app and getting a user token might return data of previous user token? calling `/api/v1/accounts/verify_credentials` returned wrong user [they seem to be using the password grant, possibly this is related to that?] +- #3061 on post with multiple GIF attachments, going to next one will cause it to not animate +- #3473 hard refresh needed to see multiple pages of new posts? +- #3638 check if post is deleted when clicking reply button; if it is, then remove the post instead of allowing you to compose a reply +- #3680 support 3gpp media upload for conversion [seems to have started working at some point? or maybe reproduced?] +- #3703 if a mention cannot be processed, the whole job fails. maybe it shouldn't? +- #3742 opening a timeline with videos in it can be slow +- #3809 long-press to boost without confirmation (when confirmation modal is enabled for boosting) +- #3930 wrong import order for SCSS [maybe closeable? idk, needs clarification as well, what triggers this scss and so on] +- #3959 rake task `media:remove_remote` should not apply to posts that have been boosted locally +- #3996 sidekiq deadlocks when `:concurrency` > 1 +- #4118 repeatedly faving/unfaving will generate a ton of notifications +- #4236 Detect if desktop notifications are supported (hide settings for them if not) +- #4434 nonbreaking spaces in config/locales are not preserved when rendering HTML [where is this relevant?] +- #4573 some posts show up on profiles but not on home timeline [possibly related to #2614] +- #4755 more gender neutral language in i18n german translation +- #4809 browser notification for favourites does not show text of favourited post if an image is attached. but it does for mentions. so that should be consistent +- #4838 settings routes / uris are inconsistent with the parts that they link to +- #4887 Accept-Language header only supports en, not en-US +- #5468 unicode directional formatting sometimes messes with url linking, causing broken links +- #5476 importing following.csv sometimes leads to stuck follow requests for unlocked accounts (workaround: a manual unfollow/refollow fixes it) +- #5527 2fa code should show keypad 0-9 on mobile devices +- #5528 shortcode gets converted to emoji even without breaking whitespace +- #5583 skin color emoji sequence not getting emojified +- #5646 2-frame gifs do not respect delay on final frame +- #5658 remote gif avatar gets corrupted on docker instances +- #5707 wrong localization for zh-TW on relative short timestamp +- #5960 status creation fails on id collision in transaction +- #6070 discovering a post that wasn't federated can cause the counter to +1 mistakenly +- #6083 a certain video got stuck on the first frame +- #6113 favorite/boost counts take a while to update/refresh +- #6139 old accounts deleted manually should be cleaned up [do we have this as a rake task or tootctl cleanup command?] +- #6156 hide boosts from someone you follow, and you will not receive boost notifications from them +- #6208 if the timeline is full of filtered posts, it doesn't load more +- #6329 atom feeds have a CORS issue +- #6338 zwsp is wrongly included in URL parser but correctly removed by hashtag parser +- #6426 audit log breaks when statuses are deleted +- #6432 custom emojis with long shortcodes can break the emoji list in /admin/custom_emojis +- #6554 preview opengraph thumbnail for instance +- #6681 [can't change email more than once?] +- #6923 admin view of statuses doesn't show privacy scope [idk if this was ever fixed in a redesign] +- #6938 welcome email has poorly styled username@domain handle +- #6991 Net::LDAP simple method not supported +- #7025 german translation of 2fa challenge is unclear +- #7145 overscroll? [idk what this means] +- #7170 allow resolving a report "with note" even when no note is included +- #7174 bad ssl on websockets causes entire application to not render + +### (feature requests) + +- #34 backfill statuses on follow +- #116 communal blocklists +- #139 groups +- #208 custom nicknames +- #281 geotagging posts +- #309 quote + boost +- #512 stories [really more like twitter moments? or generic collections] +- #861 local-only posting +- #928 cryptographic verification of posts (specifically GPG signatures? it should be user-facing like github) +- #979 timelines/columns for selected instances [bubble timeline?] + - #3812 custom timeline with user-defined domains (also apply filters to public timelines) + - #3917 let admins define additional timelines including certain domains +- #983 custom audiences / arbitrary addressing (specifically, decide which servers to send your post to) + - #7135 mutuals-only posts +- #1133 Drafts +- #1162 Insert picture from URL [assuming this means download and reupload? although it would be more interesting to allow remote storage and simply embed it / use the remote url directly...] +- #1208 post to category / topic [like google+ collections] +- #1307 mods should be able to edit posts to add a cw +- #1353 option to show replies in public timelines +- #1405 Local account delegation [i.e. posting on behalf of another account? like tweetdeck team accounts?] +- #1539 mark posts as read (then clear the column) +- #1593 temporary block (expiring blocks just like expiring mutes) +- #1608 show timestamp of when post was favourited (in favourites column and in API) [same for bookmarks?] +- #1685 show status of filed reports or notify them when a report is actioned +- #1800 browse or show posts within a certain date range +- #2089 "Daily Digest" feature that shows only a selection or highlight of posts from certain users (instead of overloading your home timeline) + - #4451 Discovery / Catch-up timeline that shows posts you may have missed, or perhaps most boosted/faved, etc +- #2317 keep track of media attachments and allow re-using them in new posts [like misskey drive?] +- #3265 attach images to reports (in case users delete their statuses or set abusive avatars?) +- #3546 language filters should use a dropdown instead of checkboxes? should also support more languages +- #3664 Delete all your posts (or some subsets of your data) without deleting your entire account +- #3890 users should be able to override silences [perhaps like disabling twitter's "quality filter"?] +- #3945 mark undelivered mentions / provide feedback when posts are not delivered +- #4106 Support emoji reacts (reactions) on posts [keywords: EmojiReact, EmojiReaction] +- #4207 allow admins to set allowed languages in public timeline for logged-out users + - #5691 allow users to select their language on the landing page while logged out +- #4983 [original issue was about making posts unboostable, but was misunderstood to be about filtering out notifications for when a certain post is boosted] +- #5787 separate preference for "autoplay media" and "animate emoji" +- #6094 embed profiles or timelines +- #6122 tell the user when they are impacted by instance domain blocks +- #6332 show which local users follow a remote user in the moderation UI +- #6353 admin-configured limits on invites +- #6379 saved searches +- #6387 admin panel diagnostics page +- #6403 option to not convert GIF to video +- #6603 `media_only` on home timeline +- #6635 domain mute without hiding notifications +- #6912 downscale images on upload if they exceed the limit +- #6942 follow local public timelines from other instances [conceptually should be handled by groups instead?] +- #6958 tag avatar and/or header as sensitive/nsfw +- #6982 add accounts to lists without following them [bad idea imo] +- #7042 "View profile as" someone else +- #7066 "Force-unlisted" option for moderating profiles +- #7132 "Bunker mode" to make an account look deleted when it is really not [or possibly just hide the public profile?] +- #7169 upload subtitles with videos + +#### (more niche) + +- #547 "secure evidence" when admins ban users (instead of wiping all data) +- #4108 Notify me when someone I interact with changes their profile picture +- #5239 Licensing and attribution for custom emoji +- #5444 "emergency instructions" for when a user dies so they can tell admins what to do with their account +- #5657 option to show acct above your display name instead of below it +- #5675 choose the default tab for your profile +- #5714 maybe your posts should be cached offline in the web app's local storage so that if your instance goes offline you have a backup +- #5867 Support 360 panaroma photos +- #6067 notify when a hashtag is used +- #6084 user analytics +- #6090 RSS feed for all interactions on a post? +- #6350 choose the date format localization for timestamps +- #6569 SVG avatar support +- #6726 activity graph and/or calendar for browsing profiles' post history +- #6920 write your own translation of other people's posts +- #7014 add CSS classes based on hashtags, so admins can style certain tagged posts differently from others +- #7082 admin-configured hints for avatar/header image policies +- #7201 show which lists an account is in (from the timeline) + +### (meta) + +#### (clearly actionable) + +- #1404 OpenAPI documentation [but how to generate it?] +- #1487 show out-of-date warning for old servers [how can you tell?] +- #2222 require comments/reason on reports [worth mentioning we have categories now which seems partially relevant] +- #2668 let users point DNS at existing instance, allow multi-tenancy with custom domains +- #3618 reply filtering should hide posts starting with @mentions (even if it's first post in the thread) [basically mirroring twitter and the `.@reply` notation that was necessary in the past] +- #3785 silenced users should be able to DM admins and mods +- #4883 "embed" feature should support informed consent and opt-in to having your posts embedded +- #5781 refetch avatars (and other media?) after remove instance domain block with "reject media" checked +- #5797 prevent replying to someone without mentioning them +- #5883 allow pagination from oldest to newest [or discover the oldest post id somehow] +- #6136 API request limit should be higher -- 100 statuses? +- #6412 external "share" service at share.joinmastodon.org that redirects to your existing instance +- #6474 disable storage of IP addresses +- #6812 rename "local" timeline to something that makes it clear it is not geographically local +- #6828 separate "pinned posts" into separate tab on profiles + - #19657 combine pinned/featured {posts, hashtags, profiles} into one tab on profiles +- #6884 media usage numbers should be publicly shown? [or possibly to logged-in users, i would assume?] +- #6895 domain blocks with "reject media" should be explained clearly to users, because it looks like a bug currently +- #6899 a way to obtain media attachment cdn links again +- #6970 sensitive content toggle should be per-timeline instead of all-or-nothing. opting into sensitive content from followed users is not the same as opting into sensitive content from *everyone* +- #6976 allow logging in with username instead of email +- #7122 reason should be required on reports +- #7127 notify users when they are affected by moderation actions or decisions +- #10743 author and show hashtags outside of `content` + - #7250 [alternatively to above:] hide hashtags at the end of a post's `content` [though this can change meaning] +- #7274 show "post unavailable" placeholders whenever a status exists but is not visible (due to privacy or being deleted) + +#### (vague or inactionable) + +- #967 unique visual identity for niche instances (better customization or theming) +- #1049 better handling for unicode urls (punycode, idn, and so on) as well as schemes/protocols (steam: specifically?) and other encoding issues +- #3782 alternative sorting and aggregation algorithms for timelines (for example, epochs weighted by log(likes) + followers boosting) +- #3796 account aliases (particularly webfinger redirect?) +- #3819 better DM system +- #4870 new user experience +- #5380 make financial supporters visible [manually? integration with patreon/etc?] +- #5515 interest separation + account grouping [seems to be a split between "categories" and "unified timeline"?] +- #5553 urls should not be assumed 23 characters +- #5686 two stages of following -- unapproved and approved. send public posts to unapproved followers [could be handled with audiences instead?] +- #5723 granular post privacy (control whether post goes to public timelines, is available unauthenticated, local-only, etc) +- #5774 ability to change your instance domain (LOCAL_DOMAIN) +- #6192 scss stylesheets should have more color variables +- #6892 reserve usage of `#admin` tag for users who are actually admins [i don't think this is feasible, but if it were, you might want to have it be variable and admin-defined? but remote users exist, so...] +- #6945 disable DMs on an instance level [this makes no sense as-is, unless you have a "public only" mode that rejects anything not addressed to public?] +- #6957 default to not sending sensitive field when adding a status [idk what this means] +- #6992 rich preview cards don't have enough options? [idk what this issue is really about] +- #7114 admins/mods should be able to have a second email for moderation notifications +- #7155 temporarily cache following/follower lists +- #7164 `noindex` should apply to statuses even when boosted [but there's no way to apply it to only part of a page...] +- #7254 some kind of opt-in or out of "bot interactions" [this needs to be more meaningful imo] + +--- + +## Single-category issues + +### Admin UI + +- #146 admin ui for manually creating user accounts + +--- + +### Backend + +- #701 assume http? for bare domains [link `example.com` to `http://example.com`] +- #981 import posts (from csv, specifically?) [but could be from activitypub archive] +- #1781 customizable character limit / status max length (instead of hardcoding 500) +- #2478 allow setting multiple contact/representative accounts for your instance +- #3139 keep track of which users and domains are being widely blocked by local users +- #3811 automatically rake/prune inactive accounts and delete them +- #4296 greylist federation. instances are silenced by default until approved by the admin. +- #5972 Rename "always mark media as sensitive" to "Mark media as sensitive by default" [TODO: Low hanging fruit] +- #6007 button to generate archive exports on behalf of the user, then email them with a link to that archive +- #6031 Full-width japanese period gets included as part of path query in URLs (after the slash). this can break links +- #6351 URL renderer / linkifier adds empty span.invisible to the end of many links +- #6701 URL ending with period does not linkify the period, leading to a broken link +- #6825 empty status with CW should not convert CW to status +- #7056 automatically rake/prune old account headers + +#### specific to media + +- #5204 indicate the file size on failed uploads so that you can better tell why something went wrong +- #5619 Suport Alibaba Object Storage as an alternative to S3 +- #5729 Replace Paperclip with Shrine +- #6352 invalid PNG upload returns 500 Server Error instead of 400 Bad Request +- #6377 hfr video (240fps) transcoded to normal video (60fps), maybe there should be an option + +#### specific to search + +- #6287 search for multiple hashtags + +#### specific to signups and new accounts + +- #877 captcha, honeypot, ip limit, and other antispam measures for registering new accounts +- #951 max capacity for registered users (block registration when cap is reached) +- #2045 autogenerate default avatars per-user (specifically foxes?) +- #5647 add warning to registration form that username cannot be changed + +#### ActivityPub + +- #4640 activitypub property to signal when you opt out of search indexing (similar to robots.txt or robots meta tag in html) +- #4964 use a versioned json-ld @context [currently mastodon just uses the unversioned activitystreams context, but i'm not entirely sure what issues this may cause if any and why] +- #5500 human-readable errors on trying to post to activitypub inbox endpoint +- #6262 converted statuses should append Hashtags to the end of the status_content maybe? +- #6849 deletes are not retried after failure? +- #6878 do not fetch only the first `attributedTo` + +#### REST API + +- #2048 support Android Intent URIs when registering a client app [currently failing due to use of `#` in uri; workaround is to register custom scheme in android?] +- #5273 API response should include Relationship on each Notification, so that you can tell when a notification came from a follower/following/mutual [arguably you could embed the Relationship on the Account but that might be expensive] +- #5492 API for a client app to update its own registered information (such as `redirect_uris`) using an app token generated from the stored `client_id`+`client_secret` +- #6040 errors should have a non-localized string key to identify which specific error occurred (can be matched exactly) +- #6360 get only ids of accounts from followers/following? +- #6549 API to get ids of deleted statuses without streaming +- #7020 PATCH update_credentials should be replaced with PATCH settings/profile for more intuitive way of updating profile settings like display name, avatar, header image, etc. +- #7021 PUT api/v1/preferences to save new preferences, not just GET existing ones +- #7108 get all admins/mods + +#### Streaming API + +- #3049 websocket streaming api sometimes encodes payload sometimes doesn't [unlikely to be fixed, due to being a breaking change] +- #5971 add event for new PreviewCard? + +#### Security + +- #1149 automatically log you out, add checkbox to "stay logged in" +- #1181 do not set a cookie on logged-out users + +#### Standards and spec compliance + +- #673 RSS feed for your notifications +- #1384 support receiving Webmentions +- #2234 Support Micropub for authoring posts (as an alternative to `POST /api/v1/statuses`) +- #3165 Support Mastodon as an OAuth consumer (login by oauth to some other service / single sign-on / SSO?) ["Mastodon includes the omniauth gem ... it should be possible to support sign up through any OAuth service"] +- #4569 OAuth authorization code OOB flow should allow using an easier-to-type PIN code instead of a 64 digit hex code. twitter and imgur do this apparently +- #4800 Support Mastodon as an OpenID provider (OpenID Connect / OIDC? RFC 6749? IndieAuth is also mentioned) +- #5227 Support Atom feeds [previously supported only profiles, but even that was removed in favor of RSS only] + +--- + +### Deployment + +- #1068 offer a Snap/snapcraft package +- #1118 support Terraform from Hashicorp (or chef, or ansible, or puppet, or salt caps) +- #1328 Scalingo setup form should use human-friendly strings instead of plain AWS region names (e.g. `EU (Frankfurt)` instead of `eu-central-1`) +- #1528 /tmp directory fills up over time +- #3576 offer a Debian package + +--- + +### Filters + +- #18955 Revamp filters to cover more use cases + - #6078 Filters ignore username + - #6596 filter yourself in home timeline + +--- + +### Lists + +- #5938 backfill lists when adding new accounts to them +- #5978 Muting a user does not remove old posts from lists + +--- + +### Profiles + +- #609 hidden profiles [require auth? "bunker mode"?] +- #1040 custom backgrounds +- #2295 Forward chronological mode / sorting +- #3205 disable or opt out of having a media tab +- #4823 some languages like persian use different words for countable form and plural form, but only one string is used for both the count and for the "all posts" tab on profiles. + +--- + +### Web app + +- #380 multiple account management / account switcher (for tootdeck layout / advanced ui, this implies supporting columns per-account) +- #873 font size for larger text +- #1471 show account preview on hover +- #1955 hash acct/url and pick a distinct color to allow more easily identifying when an account is different or is a homograph and possibly impersonation +- #4647 when you hide media that isn't marked nsfw, it should stay hidden persistently (currently it is reshown on refresh) +- #6028 poor contrast on the CW and privacy toggles in the compose form +- #6034 clarify the difference between "desktop notifications" and "push notifications" toggles +- #6035 notification settings are messy and poorly laid out +- #6210 show when a boost was made, not just the original post timestamp +- #6407 show when there are unresolved reports +- #7860 show confirmation dialog before more things + - #3702 show confirmation dialog before posting + +#### specific to advanced UI + +- #2054 switching to advanced web UI should load "getting started" instead of a duplicate home/notifications/compose column [this seems to be done only sometimes?] +- #3771 customize the tab bar in the upper-left corner of advanced ui on desktop layout (currently hardcoded to getting started / local / federated / settings / log out) +- #4305 allow moving context column instead of having it on the far right +- #6440 Pin multiple columns of the same type +- #7017 columns should be drag-and-drop instead of rearranged by left/right buttons +- #7050 add workspaces to advanced ui, choose sets of columns to be visible together + +#### specific to authoring a post + +- #1174 empty CW in compose form should prompt for CW or use default text "content warning", instead of silently dropping the cw and posting a normal post +- #1765 allow replying inline within a column (like tweetdeck or twitter) +- #1860 Preview your post + - #4848 specifically, it is unclear which characters will be included / parsed as a hashtag or mention or URL +- #2365 copy hashtags on reply +- #3567 mention the booster when replying to a boost +- #3903 suggest a CW based on keywords in your post +- #5108 add a secondary publish button with a different scope (port from glitch-soc) + +#### specific to emoji + +- #717 option to use system emoji instead of EmojiOne +- #5592 option to not show emoji + +##### specific to authoring emoji + +- #1908 disambiguate emoji for country flags (maybe sort flags by continent region or geography?) [nightpool: "this is an upstream issue w/ emoji-data"] +- #5445 prevent suggesting emoji when typing emoticons (for example, typing `:-)` should not suggest `:slightly_smiling_face:` in emoji-mart) +- #5498 emoji shortcodes should inherit preferred skin color from emoji-mart +- #5808 shortcodes should always be converted to emoji, or perhaps only when selected manually + +#### specific to media + +- #921 `rich` OEmbed (e.g. for soundcloud) +- #1255 allow wider aspect ratios instead of zoom-cropping thumbnail [auto height instead of `object-fit: cover`?] +- #2034 when a modal is open, pause all animations in the background +- #6254 "reduce motion" should disable side-scrolling animation for preview of multiple images +- #6983 better handling of PeerTube embed/preview +- #7031 embed remote videos + +##### specific to authoring media + +- #3860 basic image editing (cropping, rotating, etc) in the web app before posting +- #6879 focal point is misleading. circled area is not in the center, nor is it fully inside the thumbnail crop. [possibly calculation or rendering of focal point may be bugged?] + +#### specific to notifications + +- #1483 group similar notifications (consecutive notifications of same type should be collapsed) +- #1868 collapse boost/fav notifications to one line only (and `text-overflow: ellipsis` for the rest) [TODO: low hanging fruit for trwnh/mastomods? or is the current "max height" mod good enough for this?] + +#### specific to onboarding + +- #2019 relaunch the onboarding tutorial at any time +- #3264 show instance info in onboarding tutorial (so that users are aware of rules/etc) +- #6867 choose your language filters after signup + +#### nonspecific + +##### accessibility + +- #1680 line height should be relative to font size, not absolute [TODO: low hanging fruit?] +- #3660 better contrast and visibility on button for closing image modals +- #3875 "edit profile" link should be easier to tap on mobile [TODO: low hanging fruit] +- #4508 better focus contrast / visibility for status action buttons [currently, there is a slight transparent background on focus but no prominent outline like other focused elements] [TODO: low hanging fruit] [side note: the video player has even worse contrast on focus, i legit could not tell it was focused] +- #4510 when you focus on a post and expand it, the focus should shift to the detailed status view instead of staying in the column +- #6152 larger click/touch target for adding account to list +- #6185 error toast notifications should show up closer to the source of the error, not in the lower left corner + +##### performance + +- #787 garbage collection for open webUI tabs (react redux / state management) +- #1379 switching columns on mobile should be optimized +- #1469 use SVG icons instead of web fonts +- #5504 components are re-rendered whenever redux state changes, due to `mapStateToProps` +- #6438 memory usage continues to grow as new items are loaded into timelines + +##### architecture + +- #4478 reload a single column or conversation without reloading the whole tab +- #7113 minimize the compose box on mobile + +##### bugs + +- #5160 fullscreen video on desktop safari doesn't work right [seemingly last reproduced in june 2022 on macos 12.4 + safari 15.5] + +##### unimplemented API features + +- #1900 clear one notification [i.e. implement `/api/v1/notifications/:id/dismiss`] +- #6702 role badges + +##### staying in-app + +- #739 edit profile in webUI instead of settings page +- #946 "back" button in header should not take you out of the web app (you should remain in-app) +- #1399 links to activitypub objects (posts/profiles) should stay in-app [i think this specifically calls out links in profile bios? that might be harder] + - #2136 links in posts (to other posts) should open those posts in-app + - #3185 links in bios (to other profiles) should open those profiles in-app + - #3982 links in bios (to hashtags) should open those hashtags in-app +- #3201 indicate that a language filter is active and allow temporarily activating language filters in-app (without going to settings) + +##### meta + +- #1249 use an icon for CW instead of literally `CW` +- #1850 Rename "Getting started" to something else (OP suggested "Home" but gargron instead suggests "menu" or "main menu") +- #1856 UI mockups for easier switching of columns? +- #2210 UI mockup for pre-rendering mentions as links, instead of showing the entire address in the compose box +- #3872 combine Getting Started + Compose into one column, since they're both always open? +- #4399 CW toggle and sensitive media toggle should be linked such that expanding a post expands the media with it, and collapsing a post should rehide the media + - #4689 CW and sensitive media should not be linked at all + - #6141 show a media indicator in the CW "show more" toggle +- #5727 UI mockup for two-column layout on tablets +- #5736 more layout adjustments. variable column width, variable font size, variable media thumbnail size +- #5958 quickly switch between lists in a pinned column, or allow pinning the main "Lists" list +- #6267 use typescript + +--- + + \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/openweb.md b/unified.test.hugo/content/wiki/tech/openweb.md new file mode 100644 index 0000000..6d26f66 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/openweb.md @@ -0,0 +1,26 @@ ++++ +updated = "2020" ++++ +# Open Web + +The open web is built on multiple technologies recommended by the W3C. This page is dedicated to taking notes about protocols and standards, and basic details of their implementation. + +{{}} + +## Static content + +Technologies that can be included in static HTML files, no backend server needed. Static site generators can generate these if the template supports them. + +### Microformats + +Microformats are used to define the Semantic Web, which aims to make machine-readable meta-content. http://microformats.org + +## Dynamic content + +### IndieWeb + +The goal of the IndieWeb project is to allow websites to be used as full-fledged substitutes for other services. The ideal indiewebsite would be able to self-host media content in multiple post types, serve as an authentication for logging into other services, and be used as a person's identity. Indieweb strategies include using your domain name as your identity, self-hosting your own data on that domain, syndicating copies of your content to silo services, and maintaining actually permanent permalinks. http://indieweb.org + +### ActivityPub + +ActivityPub is a federated social networking protocol that defines server-to-server and client-to-server interactions via ActivityStreams 2.0 and the Activity Vocab. It's basically email over JSON. Actors act on Objects that are sent and delivered via an Inbox and Outbox in various Collections. https://www.w3.org/TR/activitypub/ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/social.md b/unified.test.hugo/content/wiki/tech/social.md new file mode 100644 index 0000000..4bcf80d --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/social.md @@ -0,0 +1,57 @@ ++++ +updated = "2021" ++++ +## foundational concepts +- regular grammars, subject-verb-object, and the actor system +- addressing and identity +- centralization, authority, and the open-world system +- fetching vs delivery, and dealing with state +- authentication and authorization + +## real life and prior art +- physical building/mailing addresses and email +- phone numbers and sms +- the many im apps, attempted unification, and current fragmentation +- spec talk: smtp, irc, xmpp, activitypub, matrix, proprietary ReST APIs, and so on + +## introduction to activitypub +- activitystreams vocabulary +- web uri +- as2 serialization and json-ld +- inbox and outbox GET and POST +- cryptography, signatures, tokens for validation and access control + +## let's design a social network +- what's wrong with what we have now? +- what we can do better +- types of communication: 1-1 (chat or publish), closed/open group (room or wall) + +## my ideas +- mapping resources by uri, not just by https url, but also possibly by a urn resolving service? +- publish only what the user consents to. assume everything is private by default. including uris, in some cases. +- contact manager to map addresses to *people*. keep track of not only who has which address, but also *when* they had the address (in case the address changes!) + - id assignment should be on its own namespace and you should leave human-readable stuff for the url. url should resolve to id. +- Join a Group (for arbitrary delivery ingroup or serverside validation) vs Follow a Group (for its public postings, both Announce from group members but also directly authored by the Group actor itself) + - Follow a Service that will send you messages like a mailing list? + - maybe delivery-by-default isn't the best model for everything? maybe all you really need is cross-domain auth? + - n-way delivery is a nightmare anyway. better to deliver to Service then it redistributes to all participants (can use "context" to model rooms). this works like irc but with federated id and richer as2 vocab +- open registrations are a mistake. you are responsible for everyone that you provide service to, and every page published on your website +- Accept or Reject more things. let em know when side effects were processed. or use a signed Accept token during validation. or simply have both actors sign off on it. + +### other ideas + +- no-cost push messages = spam. being able to send you stuff is not something to be taken lightly. generally on the web, you pull stuff you're interested in (sub) that other people have made available (pub). assuming that everyone should be able to push stuff into your inbox is not a good idea. ultimate control for what you receive should be given to you, the recipient -- you should be able to refuse delivery of anything you don't want. with that said... push should be a permission or *capability* that you can grant to others, if you *trust* them. + +- related to push, is the ceding of the replies/comments section as out of your ultimate control. twitter for example fucked up when they made @ mentions deliver directly to someone. imo it would have been better to only see @mentions when you explicitly go searching for them (like hashtags). + +- another thing twitter did: full-text search. oh god it sucks so much when harassment mobs search for a specific term and then descend on anyone who uses it. rethink the boundaries of what should be considered "public" or "searchable". + +- assuming public by default. no. let the user determine what they want to *opt in* to publishing, not what they want to *opt out* of having visible. by default, nothing should be known about the user. + +> Copying and pasting made people look at what they shared, and think about it, at least for a moment. When the retweet button debuted, that friction diminished. Impulse superseded the at-least-minimal degree of thoughtfulness once baked into sharing. Before the retweet, Twitter was largely a convivial place. After, all hell broke loose — and spread. + +--[The Man Who Built The Retweet: “We Handed A Loaded Weapon To 4-Year-Olds”](https://www.buzzfeednews.com/article/alexkantrowitz/how-the-retweet-ruined-the-internet) + +> [S]ocial media has been overtaken by metrics, which are driven in large part by the vicious cycle of advertisers wanting to know which influencers are worth paying; and by toxic fan battles to make your favorite social media accounts gain followers and likes, and to downrank your favorites' rivals. + +--[Demetrification: improving social media by removing public like/follower/repost counts](https://boingboing.net/2019/09/12/flickrs-glory-days.html) \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/speakers.md b/unified.test.hugo/content/wiki/tech/speakers.md new file mode 100644 index 0000000..e9baeed --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/speakers.md @@ -0,0 +1,68 @@ ++++ +updated = "2024-09-22" ++++ + +idk if "tech" is the right place to put this but + +i was researching affordable-ish upgrades to my current desktop speakers (edifier r1280t which aren't amazing by any stretch but they were decent when i got them) + +hard requirement max 6 inches wide. preferably lower, closer to 5.5" or so, this would allow me to lower my pc display height a tiny bit when i place them sideways + +## frontrunners + +- neumi silk 4 ($150/pair) (5.5" wide) https://amzn.to/4e9iCaE +- micca rb42 ($149/pair) (4.9" wide) https://amzn.to/3TDztdI +- nht superzero 2.1 ($125/single so $250/pair?) (also 5.5" wide) https://amzn.to/3zx679R + + has good compiled objective data and comparisons sourced from high quality sources (audiosciencereview and erin's audio corner, mainly) + +neumi silk 4 vs micca rb42: https://www.spinorama.org/compare.html?speaker0=Neumi+Silk+4&origin0=ErinsAudioCorner&version0=eac&measurement=CEA2034&speaker1=Micca+RB42&origin1=ASR&version1=asr + +neumi silk 4 vs nht superzero 2.1: https://www.spinorama.org/compare.html?speaker0=Neumi+Silk+4&origin0=ErinsAudioCorner&version0=eac&measurement=CEA2034&speaker1=NHT+Super+Zero+2.1&origin1=ASR&version1=asr + +neumi silk 4: + +- pretty flat, 2.8db deviation +- (+) 4.7 tonality on a scale from -10 to +10 + - can be EQ'd to 5.87, add a subwoofer to get 7.39, sub+EQ = 8.28 +- (~) "neutral" response, less "flavorful" or "fun" +- (-) response drops pretty sharply after about 14k -- can get as low as -6db at 20k + +micca rb42: +- (~) "fun" due to more bass even if it is less clear than neumi silk 4 it generally extends further +- 4.49 tonality on a scale from -10 to +10 + - can be eq'd to 6.77 or add a sub for 6.49, or both for 8.63 + - (+) eq'd it gets better than the neumi silk 4 by almost a whole point +- also 2.8db deviation but not as flat or neutral throughout + - (+) but it also doesn't have the rolloff on the high end? + - (-~) somewhat scooped mids but it's like 2db or less once eq'd so not very apparent + - sharp highs and bright, will also distort if you go too loud + +nht superzero 2.1: + +- 3.4db deviation + - (+) less flat on average but seems to stay closer to within +-3db once you extend past 5khz +- 3.37 tonality, 5.0 eq, 6.7 sub, 8.1 eq+sub +- (-) price. $250/pair compared to neumi silk 4 $150/pair + +## other considerations + +- micca mb42x g2 has been described as "warm and rich" vs the original mb42x which was "bright and lean". anyway it's 5.8" wide and $100/pair. no data. https://amzn.to/3TykDor +- kanto yu passive 4" -- $180/pair and about 5.5" wide. https://amzn.to/47yAw4h + - 2.9db deviation, 3.37 tonality (5.58 eq, 6.29 sub, 8.2 eq+sub) + - wide dip at ~500hz, doesn't look pretty... even when eq'd it has a dip at 4k + - in general seems to have boosted mids but that can be eq'd out for something kinda "clear and neutral" +- psb alpha p3 -- $249/pair, 5.125" wide https://amzn.to/4eaLW0E + - supposedly better options for the price. could be good speakers but bad value + - (~) somewhat "dark" due to wide scoop in mids between 3.7k and 7.7k? + - (-) also SHARP dropoff after 16.5k (like -18db at 20k even when eq'd) + - 4.2db deviation, 3.29 tonality, 5.81 sub, 5.34 eq, 7.71 sub+eq + - really does seem like other speakers are better in same price range but idk it might have better response if you're into that sort of thing ("dark") +- dali spektor 1 -- https://amzn.to/3Bi5ba4 $350/pair idk the exact size but it seems to be not worth the price. even eq'd it dips around 4k and can't stay within +-3db very well. big treble boost when not eq'd (like +4.5db) +- dayton audio b40 -- https://amzn.to/4ewMv4B $50/pair, 5.5" wide, seems like a bargain if it's good but no data available to suggest it actually *is* good. no reviews on amazon, just a reddit post https://www.reddit.com/r/BudgetAudiophile/comments/1e5wjfl/a_quickish_review_of_the_dayton_b40s/ which describes them as "they definitely sound like $50, but like a really good $50". idk, skip. +- audioengine p4 https://amzn.to/4eQFlZh $249/pair 5.5" wide. random commenters describe it as dull and muddy, others say it's not that bad, the only thing that really stands out to me is that the proper reviews seem to be from 2009/2010 so it's very possible that better stuff has come out since. +- edifier p17 https://amzn.to/4eccDBV $140/pair 5" wide. no data. + +## conclusion + +idk i think it comes down to neumi silk 4 or micca rb42. rb42 seems like it could be better with eq+sub, and probably the "fun" sound would possibly be more enjoyable than the "flat"/"neutral" of the silk 4, but the neumi also doesn't distort like the micca. so even with that high-end rolloff i'm still leaning neumi. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/_index.md b/unified.test.hugo/content/wiki/tech/spec/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/Activity.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/Activity.md new file mode 100644 index 0000000..1e8aa4c --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/Activity.md @@ -0,0 +1,420 @@ +# Activity + +an Activity is just an object that has an `actor`. it represents an action that was performed. + +{{}} + +## activities in activitypub + +activities are meant to be POSTed to the outbox in C2S (by the Client), then if the Server is also a Federated Server, they get delivered to recipients' inboxes via POST to inbox (by the Federated Server) + +for C2S: if it has `actor` then do not wrap it in a Create when it gets POSTed to outbox. otherwise, per [[AP § 6.2.1 "Object creation without a Create Activity"](https://www.w3.org/TR/activitypub/#object-without-create)]: +- make a new `Create` to wrap the object in `object` +- copy over `to`/`cc`/`bto`/`bcc`/`audience` from the object to the activity. +- [not explicitly stated:] set `actor` on the activity equal to the current authorized user, then copy that over to `object.attributedTo` +- generate an `id` for both the `Create` and the `object`, unless it is transient [[how do we determine this? perhaps a client explicitly specifies `id=null`?]] +- return the `id` of the activity via the `Location` header + +for S2S: check `to`/`cc`/`bto`/`bcc`/`audience` on the activity. dereference any collections with a recursion limit (possibly n=1). add all discovered inboxes to a list. remove `bto`/`bcc`. POST to the list of discovered inboxes. + +some activity types have side-effects defined in the activitypub spec, sections 6 (c2S) and 7 (s2s) + +### (any Activity) + +if it has `actor` then do not wrap it in a Create when it gets POSTed to outbox + +- C2S: MUST assign `id` to the activity, ignoring anything that might be set by the Client, unless it is transient [[how to determine this?]] +- C2S: add it to the current actor's outbox [[if not transient?]] +- C2S: Return HTTP `201 Created`, `Location: ` +- S2S: warning, if it's an extension activity type then its side effects may not be understood. there may be fallback strategies to display `name`/`summary`/`content` + +### Create + +### Update + +### Delete + +### Add + +### Remove + +### Follow + +### Like + +### Block (C2S only) + +### Announce (S2S only) + +### Accept (S2S only) + +### Reject (S2S only) + +### Undo + +## activities in the fediverse + +in practice and in actuality, the "fediverse" largely does not conform to any of the 3 activitypub profiles. because c2s is not used, there are basically no Clients or Servers. and even on the s2s side, the side effects described by activitypub are not applied in any meaningful way. the *real* side effects vary per project. it can be argued that the fediverse is actually not built on activitypub, but rather, it is built on activitystreams 2.0 + linked data notifications. (it is a little-known fact that the `inbox` property in activitypub is actually `ldp:inbox` as defined by the linked data platform.) + +### mastodon + +supported activity types + +- Accept (accept a follow request) +- Add (adds hashtag or status to featured collection) +- Announce (reblog a status) +- Block (block an account) +- Create (create a message or status) +- Delete (delete account or status) +- Flag (report accounts and/or statuses) +- Follow (request to follow a local account) +- Like (favourite a status) +- Move (migrate an account's followers) +- Reject (reject follow request or remove follower) +- Remove (removes hashtag or status from featured collection) +- Undo (undoes some activities if possible) +- Update (update account info or edit a status) + +#### extended logic + +- **Accept** + - **Accept Follow** -- authorize a follow request + - (when relay is findable by `object` as follow_activity_id) + - (when `object` is uri of existing follow request) + - (when `object` is embedded Follow) + - **Accept Follow ``** +- **Add** + - (must have `target`) + - (`target` must be a `toot:featured` collection) + - (`object` must be inlined?) + - **Add Hashtag to `target`** -- feature a hashtag + - (takes `object.name` and removes prefix `#`) + - (creates FeaturedTag entity for the `actor`'s account) + - **Add `object` to `target`** -- pin a status + - (`object` must be transformable to status) + - (status must be authored by `actor`) + - (status must not already be pinned) +- **Announce** + - (must be related to local activity) + - (i.e. `actor` followed by local accounts) + - (or requested through relay) + - (or `object` refers to a status whose account is local) + - (`object` resolves to a status) + - **Announce `object`** -- creates a reblog of a status + - (stop if:) + - (no status) + - (status not boostable) + - (requested through relay) + - (find existing reblog or create) +- **Block** + - (`object` resolves to an account) + - (the resolved account exists and is local) + - **Block `object`** -- block an account + - (unfollow the `object`) + - (force `object` to unfollow you) + - (reject any follow requests from `object`) + - (create a block asynchronously) +- **Create** + - (dereference the `object`) + - **Create EncryptedMessage** -- creates an encrypted message + - (tries to find a device id) + - (extracts `messageType`, `cipherText`, `digest`, `messageFranking`) + - **Create `object`** -- creates a status + - (rejected if) + - (unsupported object type) + - (`object` is a string) + - (not in supported types) + - Note + - Question + - (not in converted types) + - Image + - Audio + - Video + - Article + - Page + - Event + - (or invalid origin) + - (or tombstone exists for `object` uri) + - (or not related to local activity) +- **Delete** + - (if `actor` matches `object`) + - **Delete `object`** -- delete your own account + - **Delete `object`** -- delete a status + - (create tombstone unless origin is invalid) + - (forward deletion if forwardable) + - (remove status from database and timelines) +- **Flag** + - (`object` array is resolved as accounts and statuses) + - (then filtered for local) + - **Flag `object`** -- report an account and/or statuses + - (foreach account get reported statuses) + - (create a report against the account w/ optional status ids and content) +- **Follow** + - (`object` must be a local account that exists) + - **Follow `object`** -- request to follow a local account + - (create or update follow request) + - (auto-reject if:) + - (`object` is blocking `actor`) + - (`object` is domain-blocking `actor`'s domain) + - (`object` has moved/redirected) + - (`object` is the instance actor) + - (send an Accept Follow if a follow already exists) + - (otherwise create a follow request) + - (if you are silenced or they are locked, send frq notification) + - (otherwise send Accept Follow and follow notification) +- **Like** + - (resolve status from `object`) + - **Like `object`** -- favourite a status + - (stop if:) + - (no status resolved) + - (status is not from a local account) + - (delete arrived first) + - (you already favourited this status) + - (create a favourite by `actor` for `object`) +- **Move** + - (`actor` must match `object` and resolve to account) + - (resolve `target` as account) + - **Move `object` to `target`** -- migrate your followers + - (stop if:) + - (no `target`) + - (`target` is suspended) + - (`target.alsoKnownAs` doesn't include `object`) + - (set a redirect) + - (async move followers from `object` to `target`) +- **Reject** + - **Reject Follow** -- reject a follow request or remove follower + - (when relay is findable by `object` as follow_activity_id) + - (when `object` is uri of existing follow request) + - (when `object` is uri of existing follow) + - (call UnfollowService for `actor`) + - (when `object` is embedded Follow) + - **Reject Follow `Follow.object`** +- **Remove** + - (must have `target`) + - (`target` must be a `toot:featured` collection) + - (`object` must be inlined?) + - **Remove Hashtag from `target`** -- unfeature a hashtag + - (takes `object.name` and removes prefix `#`) + - (deletes FeaturedTag entity for the `actor`'s account) + - **Remove `object` from `target`** -- unpin a status + - (`object` must be transformable to status) + - (status must be authored by `actor`) + - (destroy pin if existing pin found) +- **Undo** + - (`object` should be inlined or else it may not be handled) + - **Undo Announce** -- unreblog a status + - (stop if no `Announce.id`) + - (resolve `Announce.id` as status reblog) + - (call RemoveStatusService on status) + - **Undo Accept** -- unfollow an account [yes this is the assumption] + - (find follow by `object.object.id` and revoke it) + - **Undo Follow** + - (resolve `object.object` as account) + - (stop if not exists or not local) + - **Undo Follow ``** -- unfollow an account + - (`Undo.actor` unfollows `Follow.object` if following) + - **Undo Like** + - (resolve `object.object` as status) + - (stop if no status or if status is not local) + - **Undo Like ``** -- unfavourite a status + - (if `actor` has favourited the status:) + - (find a favourite on that status by that account) + - (destroy it) + - **Undo Block** + - (resolve `object.object` as account) + - (stop if not exists or not local) + - **Undo Block ``** --unblock an account + - (call UnblockService if `actor` is blocking `Block.object`) + - **Undo `object`** + - (try_undo_announce) + - (find reblogged status by `object` uri and `actor`) + - (if found, remove reblog and stop, else continue) + - (try_undo_accept) + - (do nothing, continue) [because Accept uri is not stored] + - (try_undo_follow) + - (find `actor` follow request/relation by `object` uri) + - (if found, destroy it and stop, else continue) + - (try_undo_like) + - (do nothing, continue) ["too costly", no index by Like uri] + - (try_undo_block) + - (find `actor` block by `object` uri) + - (if found, call UnblockService and stop, else continue) +- **Update** + - (dereference `object`) + - (if `object.type` in `Application Group Organization Person Service`) + - **Update `object`** -- update an account's info + - (stop if `actor.id` does not match `object.id`) + - (call ProcessAccountService) + - (else if `object.type` in `Note Question`) + - **Update `object`** -- edit a status + - (stop if invalid origin) + - (resolve `object` as status) + - (stop if no status) + - (call ProcessStatusUpdateService) + +### pixelfed + + + +(seems to require inlining in a lot of places? not 100% sure but that's what it looks like to me) + +- Add + - (must be inlined?) + - Add Story (not final) +- Create + - (requires `to` for some reason, so `cc` only will break) + - Create Question + - (a single `to` item will create a DM if no `cc`) + - Create Note.inReplyTo + - Create Note.attachment +- Follow + - Follow `object` +- Announce + - Announce `object` +- Accept + - Accept Follow (anything else will return immediately) +- Delete + - Delete `object` (if `object` == `actor` and is valid string uri) + - Delete [Person, Tombstone, Story] (???) + - Delete Person + - Delete Tombstone (???) + - Delete Story (not final) +- Like + - Like `object` +- Reject + - (does nothing) +- Undo + - (must be inlined) + - Undo Accept + - (does nothing) + - Undo Announce + - Undo Block + - (does nothing) + - Undo Follow + - Undo Like +- View + - View Story (not final) + - (also seems to get story id by whatever is after the last slash?) +- Story:Reaction (not final; undocumented extension) + - (`id` and `actor` must be valid urls) + - (`inReplyTo` and `to` must be local) + - (`object` must not resolve to Status) + - (seems to get story id by whatever is after the last slash?) +- Story:Reply (not final; undocumented extension) + - (`id` and `actor` must be valid urls) + - (`inReplyTo` and `to` must be local) + - (`object` must not resolve to Status) + - (seems to get story id by whatever is after the last slash?) +- Update (commented out) + +### misskey + + + +- Create +- Delete +- Update +- Read +- Undo +- Follow +- Accept +- Reject +- Add +- Remove +- Like | EmojiReaction | EmojiReact +- Announce +- Block +- Flag + + + +### pleroma + +ObjectValidator + +validate() + +- Block +- Undo +- Delete +- Create ChatMessage +- Create [Question Answer Audio Video Event Article Note Page] +- [Event Question Audio Video Article Note Page] + - Event + - Question + - Audio + - Video + - Article + - Note + - Page +- Update [Question Answer Audio Video Event Article Note Page] +- [Accept Reject Follow Update Like EmojiReact Announce] + - Accept + - Reject + - Follow + - Update + - Like + - EmojiReact + - Announce + - ChatMessage + - Answer +- [Add Remove] + +SideEffects + +handle() + +- Accept + - Accept Follow +- Reject + - Reject Follow +- Follow +- Block +- Update + - Update `object` + - Update `object` +- Like +- Create + - Create ChatMessage + - Create Question + - Create Answer + - Create [Audio Video Event Article Note Page] +- Announce +- Undo + - Undo Like + - Undo EmojiReact + - Undo Announce + - Undo Block +- EmojiReact +- Delete +- Add +- Remove + +Transmogrifier + +handle_incoming() + +- Flag +- Listen Audio +- Like._misskey_reaction +- Create [Question Answer ChatMessage Audio Video Event Article Note Page] +- [Like EmojiReact Announce Add Remove] + - (fetch `actor` and `object`) +- [Update Block Follow Accept Reject] + - (fetch `actor`) +- Delete + - (check if Create exists) +- Undo Follow +- Undo + - (get `object` by `id` and expand it) +- Move + +prepare_outgoing() + +- [Create Listen] +- Update `object` + - [Note Question Audio Video Event Article Page] +- Announce +- Accept -> Accept Follow +- Reject -> Reject Follow +- Answer -> Note \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/Collection.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/Collection.md new file mode 100644 index 0000000..94f2ba4 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/Collection.md @@ -0,0 +1,20 @@ ++++ ++++ + +A Collection is an Object that has `items` or `orderedItems` + +however, `orderedItems` is valid on both Collection and OrderedCollection! it is defined like this in the as2 context: + +```json +"orderedItems": { + "@id": "as:items", + "@type": "@id", + "@container": "@list" +} +``` + +so it is basically just an alias for `items` where it MUST be an array, and the array's order matters. (if it were `@container: set`, then it MUST be an array, but the array's order does not matter.) + +### tangent: a Collection may be ordered without being an OrderedCollection + +OrderedCollection is defined as strictly reverse chronological by ActivityPub. however, other orderings are valid on regular Collections. the use of the `orderedItems` term allows plain-JSON implementations to do exactly this. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/Create.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/Create.md new file mode 100644 index 0000000..d0add69 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/Create.md @@ -0,0 +1,14 @@ ++++ ++++ + +i have a hard time deciding what ought to be the correct behavior here. maybe activitypub should have just assumed everything is deliverable as-is, but only activities get side-effects? of course there's still a problem with id generation not being fully specified... https://github.com/w3c/activitypub/issues/438 + +something like "generate an id for the outermost object, overriding any pre-included id"? + +which is basically the current behavior and imo where the implicit-create is meant to be applied... basically normalizing everything to an activity (assuming Create by default) + +so without the implicit-create behavior, you would basically POST a note or whatever to your outbox in order to assign it an id, and it would be delivered as-is without the Create. the outbox wouldn't contain only activities, it would also contain objects. this kind of makes the Create itself redundant and unnecessary, i guess? or in other words, you need to define what Create means in terms other than id assignment. this is kind of a problem because right now, Create has "surprisingly few side effects" (read: basically none) + +otherwise you explicitly format every POST as a Create but you have unspecified behavior for id generation of the inner object + +maybe sending a Create C2S does nothing with the inner object, but the side effect should be to assign/register the object on the receiving S2S server? \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/Follow.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/Follow.md new file mode 100644 index 0000000..3476e80 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/Follow.md @@ -0,0 +1,46 @@ ++++ ++++ + +## what Follow is ideally like in theory + +- you send a Follow +- they send you an Accept Follow as a courtesy, and Add you to their `followers` +- you receive the Accept Follow and take it as a signal to Add them to your `following` (perhaps you can even show the Accept Follow as proof of this, if it was signed!) + +## what Follow is actually like in practice + +sharedInbox exists, and known follow relationships are used to calculate visibility on the receiving end (instead of relying on direct delivery). so now that Accept Follow actually matters... it's not just a courtesy anymore. + +because of this, Follows are realistically transient requests to update state. it is therefore enough to keep track of local state, then mutate state based on activities. + +### removing followers + +ideally, it should be possible to remove a follower without notifying them. notifying them could still be done as a courtesy, perhaps with Remove targeting your followers collection. + +in practice, mastodon first decided that they would send Undo Accept Follow, to undo the original acceptance of the follow request. this was soon after deemed to be too complex, and so mastodon settled upon sending a Reject Follow at any point after the original Accept Follow, which would be handled the same regardless of whether the Follow was ever accepted or not. the side effects of a Reject Follow in mastodon protocol are to destroy the follow request or follow relationship, with no regard to which one it actually is. + +## business logic + +if you receive an Accept/Reject Follow, check ONLY for the following: + +- actor +- type == Accept/Reject +- object.actor == (you) +- object.type == Follow +- object.object == actor + +in case of an Accept Follow, check that you have a local pending follow request. if you do not have a pending follow, then DO NOT process an incoming Accept Follow. + +in case of a Reject Follow at any time, destroy any existing follow relationship, regardless of whether it was previously Accepted or not. note that you may also receive an Undo Accept Follow by some implementations. this is discouraged but should be handled as well + +in either case, this is an idempotent action. the only id that matters is the outermost activity. if object is inlined, you don't need to check that object.id is local. the above is enough information to handle the activity. + +### resyncing follow state + +if you receive a Follow from someone you already Accepted, then send another Accept Follow to remind them. in practice, this usually means a state desync or database loss. + +### what happens if you ignore this guidance + +state desync, you think you removed a follower but you didn't. you send a post to sharedInbox and the remote server might end up showing it to someone you thought you removed successfully! and indeed, on your end, they were removed successfully. but the remote server doesn't know or care what your local state is -- it only cares for its own state. + + \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/_index.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/_index.md new file mode 100644 index 0000000..f448667 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/_index.md @@ -0,0 +1,18 @@ ++++ +title = "activitypub" ++++ + +shortcomings +: things that suck about the spec. could be improved by a new spec. + +confusion +: things that need clarification. could be improved by a rewrite. + +gotchas +: mistakes that implementations have made. could be improved by more guidance. + +ideas +: things that could reasonably be implemented + +extensions +: things not defined in activitypub proper \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/_json-ld.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/_json-ld.md new file mode 100644 index 0000000..42d30b1 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/_json-ld.md @@ -0,0 +1,366 @@ ++++ +autonumbering = true ++++ + +# everything you need to know about JSON-LD as far as activitypub is concerned + +{{}} + +## IRIs + +basically just URI+. the i stands for "internationalized" + +## the playground + + is a good way to get a better understanding of stuff + +## json-ld keywords + +there are [a lot](https://www.w3.org/TR/json-ld11/#syntax-tokens-and-keywords "no, seriously") but we only really care about @id and @context really (and sometimes @type) + +### @id + +the identifier for a json-ld node. by "node" we mean like a node on a graph. typically this is an iri, and dereferencing the iri should give us that node. + +### @context + +basically a way to map shorthand names ("terms") to a full iri, or sometimes to a keyword. you can also define iris or compact iris using a json object that represents the expanded definition. + +in short: +- terms (`foo`) map to iris (`https://example.com/foo`), compact iris (`ex:foo`), or keywords (`@foo`) +- iris (whether full like `https://example.com/foo` or compact like `ex:foo`) map to expanded definitions (a json object with only keywords inside) + +#### namespacing + +the benefit of the context definition is that we can namespace different json-ld terms based on which vocabulary they came from + +the activitystreams namespace (or base iri, if you will) is `https://www.w3.org/ns/activitystreams#` because this is what all activitystreams vocab terms begin with + +- consider the `actor` property, whose full iri is actually `https://www.w3.org/ns/activitystreams#actor` +- similarly, consider the `Public` collection, whose full iri is `https://www.w3.org/ns/activitystreams#Public` +- ...and so on + +we can also map some arbitrary string ("term") to the base iri. the activitystreams context by default uses `as` => `https://www.w3.org/ns/activitystreams#`. so instead of typing out the base iri every single time, we can instead type the *shorthand* prefix `as:`, or in other words, `as:actor` or `as:Public`, to get what is known as a "compact IRI" + +note once again the equivalencies: + +- `actor` == `as:actor` == `https://www.w3.org/ns/activitystreams#actor` +- `Public` == `as:Public` == `https://www.w3.org/ns/activitystreams#Public` +- ...and so on + +## the three ways to normalize you should be familiar with + +let's do expansion, compaction, flattening of the following example document: + +```json +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + { + "Hashtag": "as:Hashtag", + "toot": "https://joinmastodon.org/ns#", + "Emoji": "toot:Emoji" + } + ], + "id": "https://social.example/~alice/notes/1", + "type": "Note", + "content": "#HelloWorld :blobcatHug:", + "tag": [ + { + "type": "Hashtag", + "name": "#HelloWorld", + "href": "https://social.example/tags/HelloWorld" + }, + { + "type": "Emoji", + "name": "blobcatHug", + "icon": { + "type": "Image", + "mediaType": "image/png", + "url": "https://social.example/emojos/blobcatHug.png" + } + } + ] +} +``` + +and let's assume we only understand the following context: + +```json +{ + "@context": "https://www.w3.org/ns/activitystreams" +} +``` + +### expansion + +expansion works by taking the context and expanding every single term to its full iri form, and every single value into an array of objects with either a single @value (if the value before was a literal) or a single @id (if the value before was an iri) + +so if we expand the example document, we get this: + +```json +[ + { + "https://www.w3.org/ns/activitystreams#content": [ + { + "@value": "#HelloWorld :blobcatHug:" + } + ], + "@id": "https://social.example/~alice/notes/1", + "https://www.w3.org/ns/activitystreams#tag": [ + { + "https://www.w3.org/ns/activitystreams#href": [ + { + "@id": "https://social.example/tags/HelloWorld" + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@value": "#HelloWorld" + } + ], + "@type": [ + "https://www.w3.org/ns/activitystreams#Hashtag" + ] + }, + { + "https://www.w3.org/ns/activitystreams#icon": [ + { + "https://www.w3.org/ns/activitystreams#mediaType": [ + { + "@value": "image/png" + } + ], + "@type": [ + "https://www.w3.org/ns/activitystreams#Image" + ], + "https://www.w3.org/ns/activitystreams#url": [ + { + "@id": "https://social.example/emojos/blobcatHug.png" + } + ] + } + ], + "https://www.w3.org/ns/activitystreams#name": [ + { + "@value": "blobcatHug" + } + ], + "@type": [ + "https://joinmastodon.org/ns#Emoji" + ] + } + ], + "@type": [ + "https://www.w3.org/ns/activitystreams#Note" + ] + } +] +``` + +the point of expansion is to end up with a document that is **completely unambiguous** and doesn't need a @context -- see how everything is expressed purely in terms of keywords, literals, and iris? no shorthands are used, so you know exactly what each term represents. + +note that some nodes have an `@id` and some have a `@value`. if you see a value then that is just a raw value (often just a string, but could be a boolean or a number). if you see an id then that is a link to some other document or resource. + +### compaction + +compaction is similar to expansion but it keeps values collapsed. so again, you end up with full iris, but you don't have to deal with keywords everywhere other than @id (which sticks around bc any iri represents a node and not just a value) + +note that you can compact against a blank @context or supply your own @context. + +if you compact against a blank @context, you'll get everything as a full iri: + +```json +{ + "@id": "https://social.example/~alice/notes/1", + "@type": "https://www.w3.org/ns/activitystreams#Note", + "https://www.w3.org/ns/activitystreams#content": "#HelloWorld :blobcatHug:", + "https://www.w3.org/ns/activitystreams#tag": [ + { + "@type": "https://www.w3.org/ns/activitystreams#Hashtag", + "https://www.w3.org/ns/activitystreams#href": { + "@id": "https://social.example/tags/HelloWorld" + }, + "https://www.w3.org/ns/activitystreams#name": "#HelloWorld" + }, + { + "@type": "https://joinmastodon.org/ns#Emoji", + "https://www.w3.org/ns/activitystreams#icon": { + "@type": "https://www.w3.org/ns/activitystreams#Image", + "https://www.w3.org/ns/activitystreams#mediaType": "image/png", + "https://www.w3.org/ns/activitystreams#url": { + "@id": "https://social.example/emojos/blobcatHug.png" + } + }, + "https://www.w3.org/ns/activitystreams#name": "blobcatHug" + } + ] +} +``` + +but if you compact against whatever @context you understand, you will end up with shorthands for everything you understand and leave the full iris only for the stuff you *don't* understand. so again assuming we only understand the activitystreams context: + +```json +{ + "@context": "https://www.w3.org/ns/activitystreams", + "id": "https://social.example/~alice/notes/1", + "type": "Note", + "content": "#HelloWorld :blobcatHug:", + "tag": [ + { + "type": "as:Hashtag", + "href": "https://social.example/tags/HelloWorld", + "name": "#HelloWorld" + }, + { + "type": "https://joinmastodon.org/ns#Emoji", + "icon": { + "type": "Image", + "mediaType": "image/png", + "url": "https://social.example/emojos/blobcatHug.png" + }, + "name": "blobcatHug" + } + ] +} +``` + +note that this basically matches the input, **except** because we didn't compact against the extension vocab terms, we have a few namespaced terms to grapple with: + +- `as:Hashtag` is left in there because it's not actually part of the activitystreams namespace. it was a proposed extension, but the context document was never updated to include it. this is why pretty much all existing impls currently include it as an extension term in their supplied @context. + - note the `as:` namespace was maintained here because `as:` is defined within the activitystreams context document as a convenient shorthand for `https://www.w3.org/ns/activitystreams#` as discussed in [above sections](#namespacing) +- `https://joinmastodon.org/ns#Emoji` was left completely uncompacted because we didn't pass in the joinmastodon namespace at all when compacting +- note that `as:id` is just an alias for json-ld's @id keyword, and `as:type` is likewise just an alias for json-ld's @type keyword + +in summary, compaction is good for **simplifying the document based on what you know** -- worst case scenario, you have no @context and you can just parse for full iris (in a manner somewhat more efficient than parsing the expanded form). best case scenario, you have a @context that lets you parse for shorthand terms of your own choosing, and everything else is shortened only as much as possible (so you can generally ignore anything you don't understand, right?) + +### flattening + +similar to compaction, except you can flatten the document into a single @graph which contains a flat list of nodes. + +flattening against no @context: + +```json +{ + "@graph": [ + { + "@id": "_:b0", + "@type": "https://www.w3.org/ns/activitystreams#Hashtag", + "https://www.w3.org/ns/activitystreams#href": { + "@id": "https://social.example/tags/HelloWorld" + }, + "https://www.w3.org/ns/activitystreams#name": "#HelloWorld" + }, + { + "@id": "_:b1", + "@type": "https://joinmastodon.org/ns#Emoji", + "https://www.w3.org/ns/activitystreams#icon": { + "@id": "_:b2" + }, + "https://www.w3.org/ns/activitystreams#name": "blobcatHug" + }, + { + "@id": "_:b2", + "@type": "https://www.w3.org/ns/activitystreams#Image", + "https://www.w3.org/ns/activitystreams#mediaType": "image/png", + "https://www.w3.org/ns/activitystreams#url": { + "@id": "https://social.example/emojos/blobcatHug.png" + } + }, + { + "@id": "https://social.example/~alice/notes/1", + "@type": "https://www.w3.org/ns/activitystreams#Note", + "https://www.w3.org/ns/activitystreams#content": "#HelloWorld :blobcatHug:", + "https://www.w3.org/ns/activitystreams#tag": [ + { + "@id": "_:b0" + }, + { + "@id": "_:b1" + } + ] + } + ] +} +``` + +flattening against our understood @context of only activitystreams: + +```json +{ + "@context": "https://www.w3.org/ns/activitystreams", + "@graph": [ + { + "id": "_:b0", + "type": "as:Hashtag", + "href": "https://social.example/tags/HelloWorld", + "name": "#HelloWorld" + }, + { + "id": "_:b1", + "type": "https://joinmastodon.org/ns#Emoji", + "icon": "_:b2", + "name": "blobcatHug" + }, + { + "id": "_:b2", + "type": "Image", + "mediaType": "image/png", + "url": "https://social.example/emojos/blobcatHug.png" + }, + { + "id": "https://social.example/~alice/notes/1", + "type": "Note", + "content": "#HelloWorld :blobcatHug:", + "tag": [ + "_:b0", + "_:b1" + ] + } + ] +} +``` + +notice that the nodes that didn't have an id previously have now been assigned what is called a *blank node identifier* -- essentially an @id without a namespace and with a randomly generated identifier. + +the idea is that you can **parse the @graph and then filter that list by @id to obtain any relevant node** -- no worrying about nesting or otherwise having to deal with structure. for example, we receive `https://social.example/~alice/notes/1` and flatten it against our @context to get a list of nodes, which we filter for the given @id `https://social.example/~alice/notes/1`, and we can see that this node refers to `_:b0` and `_:b1` within the tag property + +## conclusion + +that's pretty much it tbh + +NOTE: activitystreams-core requires that for any serialized as2 document, + +- you MUST compact against the activitystreams @context +- you MAY compact against additional contexts +- you MUST NOT override the activitystreams context + +additionally if you encounter a document with `application/activity+json` mime-type then you MUST assume the activitystreams context if it is missing + +## further reading + +[JSON-LD 1.1 -- § 3.2 IRIs](https://www.w3.org/TR/json-ld11/#iris) + +> An IRI is defined in [RFC3987] as containing a scheme along with path and optional query and fragment segments. A relative IRI reference is an IRI that is relative to some other IRI. In JSON-LD, with exceptions that are as described below, all relative IRI references are resolved relative to the base IRI. + +> While it is a good practice for resource identifiers to be dereferenceable, sometimes this is not practical. In particular, note the [URN] scheme for Uniform Resource Names, such as UUID. An example UUID is urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6. + +[JSON-LD 1.1 -- § 3.1 The Context](https://www.w3.org/TR/json-ld11/#the-context) + +> Simply speaking, a context is used to map terms to IRIs. Terms are case sensitive and most valid strings that are not reserved JSON-LD keywords can be used as a term. Exceptions are the empty string "" and strings that have the form of a keyword (i.e., starting with "@" + +> Contexts can either be directly embedded into the document (an embedded context) or be referenced using a URL. Assuming the context document in the previous example can be retrieved at https://json-ld.org/contexts/person.jsonld, it can be referenced by adding a single line and allows a JSON-LD document to be expressed much more concisely + +[JSON-LD 1.1 -- § 5.1 Expanded Document Form](https://www.w3.org/TR/json-ld11/#expanded-document-form) + +> Expansion is the process of taking a JSON-LD document and applying a context such that all IRIs, types, and values are expanded so that the @context is no longer necessary. + +[JSON-LD 1.1 -- § 5.2 Compacted Document Form](https://www.w3.org/TR/json-ld11/#compacted-document-form) + +> Compaction is the process of applying a developer-supplied context to shorten IRIs to terms or compact IRIs and JSON-LD values expressed in expanded form to simple values such as strings or numbers. Often this makes it simpler to work with document as the data is expressed in application-specific terms. Compacted documents are also typically easier to read for humans. + +> The purpose of compaction is to apply the term definitions, vocabulary mapping, default language, and base IRI to an existing JSON-LD document to cause it to be represented in a form that is tailored to the use of the JSON-LD document directly as JSON. + +[JSON-LD 1.1 -- § 5.3 Flattened Document Form](https://www.w3.org/TR/json-ld11/#flattened-document-form) + +> Flattening collects all properties of a node in a single map and labels all blank nodes with blank node identifiers. This ensures a shape of the data and consequently may drastically simplify the code required to process JSON-LD in certain applications. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/_requirements.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/_requirements.md new file mode 100644 index 0000000..d48e110 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/_requirements.md @@ -0,0 +1,272 @@ ++++ +title = "understanding activitypub as a set of normative requirements and recommendations" +toc = true +autonumbering = true ++++ + +## what is activitypub + +in the simplest terms? "email for websites". you POST to inbox or outbox. the serialization of messages is activitystreams 2.0 (as2), and certain activities have defined side-effects when received in the inbox or outbox. client-to-server (c2s) uses the outbox, and server-to-server (s2s) uses the inbox. + +### theoretical foundation for activitypub + +- actor model. an actor is something that is programmed to behave in a certain way. +- message passing. the way actors communicate is to pass messages around, which are handled according to local procedures programmed into the actor. +- ontology. the nature of being. this is done with a resource description framework (RDF) where you have a set of statements (facts) about each resource. +- open world assumption. in logic systems, facts are not necessarily known by everyone. + +## activitystreams 2.0 as a foundation for activitypub + +AS2 documents represent resources and are described with properties. JSON-LD is used as a serialization of RDF. + +### requirements + +technical: + +- 2: empty arrays are explicitly set to `null` or excluded entirely +- 2: use UTF-8 +- 2.1: equivalent to JSON-LD compaction against `{"@context": "https://www.w3.org/ns/activitystreams"}` +- 2.1: do not override definitions from `https://www.w3.org/ns/activitystreams` +- 2.1: if `@context` is missing, assume or inject `https://www.w3.org/ns/activitystreams` +- 2.2: any international links (IRIs) should be converted to ascii (URIs) unless used as an `id` +- 2.3: datetimes use RFC3339, and use a "Z" if there is no timezone offset +- 4.1, 4.3, 4.4: if you use an extension type that overlaps with a core vocab type, do not exclude the core type from the `type` array [e.g. a vcard `Individual` should also explicitly be an as2 `Person`] +- 4.1: prefer as2 vocab when properties overlap [e.g. use as2 `name` instead of schema.org `name`] +- 4.2: Link `rel` must be valid in both RFC5988 and in HTML5 (registered or unregistered) +- 4.7: for language maps (`nameMap` /`summaryMap` / `contentMap`), every key is a well-formed BCP47 language tag, and every value is a string +- 4.7.2: properly handle bidirectional text +- 5: if you encounter something you don't understand, ignore it and continue processing as normal. do not stop or error. +- 5.1: if you want to support extensions, support compact iri expansion [i.e. `prefix:term` should be expanded according to the definition for `prefix`] for properties and `@id` values. +- 8.1: if using `application/activity+json; profile=""` then the list of profiles must be quoted [inside the double quotes]. `application/json` also still applies. +- 9.1: do not use deprecated as1 vocab. use as2 vocab. if you use other vocabs then also use as2 still. do not use json-ld algorithms other than compaction. use json-ld for extensions. + +non-technical / restatements: + +- 6, 7: tell your users when and why their personal info is needed/published. do not re-emit malicious input you consume [xss, etc] +- 9.2.1: conforming publishers make as2 documents following as2 serialization. consider privacy. consider security. +- 9.2.2: conforming consumers tolerate deprecated or obsolete as1 props. ignore props or types that aren't applicable to you. faithfully translate info when presenting on screen, in print, in audio, etc. consider privacy and security. +- B.2: `application/stream+json` or generic `application/json` is processed with old as1 rules. as2 only applies when using `application/activity+json` + + +### recommendations + +technical: + +- 1.2: do not use `displayName`, `verb`, `title`, or `objectType`. if encountered, process them using the deprecated AS1 syntax +- 2.1: include a `@context` property even if you don't process JSON-LD +- 2.2: do not use relative IRIs; plain json parsers have trouble with this +- 4.1, 4.3, 4.4: take care not to overlap or duplicate existing types +- 4.1.1: `name` is derived from user input. if not present, then `summary` should be plaintext and derived from user input, as well as being short enough to use as a reasonable text representation of the object +- 4.1.1: have a fallback strategy in case `name` and `summary` are missing or not available in your user's language or are too long +- 4.3: use vcard for describing Person, Group, Organization +- 4.6: if you wanna reconstruct a paged OrderedCollection, go to the first/last page and follow the next/prev links until all pages have been processed +- 4.6: OrderedCollection should use OrderedCollectionPage to maintain relative ordering +- 4.7.2: publishing bidirectional text should use explicit unicode control character or HTML +- 4.7.2: consumers should identify base direction of text +- 4.8: explicitly mark the language for natural language properties if the language is known (using either maps or default `@language` tag) +- 5: if you want to support extensions, use JSON-LD. define all extension term in `@context` +- 5.1: avoid compact IRIs except for property names and for types +- 5.2: if you use LD and reserialize an as2 document, preserve any properties/extensions you don't understand (by compacting against the original `@context` instead of your own) +- 8: consider `application/ld+json; profile="https://www.w3.org/ns/activitystreams"` as being equivalent to `application/activity+json` + +non-technical: + +- 6: limit sensitive personal info unless users "opt in" +- 6: do not store or share personal info unless users "opt in" +- 7: prevent spam and malicious content +- 7: do not publish malicious input from users +- 7: use rel=nofollow or convert links to plaintext to avoid SEO loopholes +- 7: be aware of spoofing attacks +- B: don't output AS1 unless you want to remain back-compatible +- B.9: avoid using `upstreamDuplicates` and `downstreamDuplicates` from AS1 +- B.10: if converting as1 to as2, treat `post` as `Create`, or if `target` is used, then treat it as `Add` + + +### optional + +- 2.1: @context extensions are allowed before compacting +- 2.1: using properties and values not defined in @context is fine but will likely be ignored by LD consumers +- 2.1: using http instead of https for the activitystreams uri +- 2.2: using uris instead of iris (since uris are valid iris) +- 2.3: omitting seconds from datetimes +- 4.1.1: not including `name` and `summary`, or having no explicit value in your current language, or being longer than appropriate for text representations +- 4.2: using Link `rel` that is not registered +- 4.6: using `OrderedCollection` to identify Collections whose items are ordered (since Collections may or may not be ordered) +- 4.6.1: using `OrderedCollectionPage` for collection pages whose items are ordered. using `startIndex` on these. +- 4.7.1: using `@language` inside `@context` to define default language. (this might not be understood by non-LD-aware consumers) +- 4.7.2: using bidirectional text. having the base direction change. wrapping additional control characters before display. +- 7: consider spam and malicious content +- 7: convert untrusted links to plaintext or add `rel=nofollow` +- 9.2.2: republish or present any consumed document in another format or presentation mechanism +- B.9: using `upstreamDuplicates` and `downstreamDuplicates` from AS1 + +## as2 vocab + +### requirements + +- 1: be able to serialize and deserialize all extended properties even if you don't understand them +- 1.1: all `xsd:datetime` MUST conform to rules in AS2 (RFC3339) +- 3: avoid using extensions that heavily overlap with or duplicate the as2 vocab +- Question: MUST NOT have both `anyOf` and `oneOf` +- name: MUST NOT include HTML markup +- duration: MUST be xsd:duration as defined by xmlschema (e.g. `P15D`, `PT2H`, etc) +- hreflang: MUST be a BCP47 language tag +- rel: MUST conform to both RFC5988 and HTML5 (cannot contain space, tab, LF, FF, CR, or comma) +- 5.1: remove `bto` and `bcc` before redistributing. they are part of the primary/secondary audience, but not disclosed to anyone else. +- Place: (non-normative) MUST support `name` `longitude` `latitude` `radius` `altitude` `accuracy` even if other mechanisms are used. [you don't have to use all of them but you have to support all of them] + +### recommendations + +- icon: has a square (1:1) aspect ratio and is suitable for presentation at small sizes +- 5.1: leave `to` and `cc` intact if redistributing an object +- 5.6: (non-normative) don't require parsing `name`/`summary`/`content` to determine notification, categorization, or linking. use vocab explicitly for this purpose [e.g. use `to` or `tag` instead of depending on text containing `@sally` or `#givingthanks`] +- 5.6: the primary audience in `to` receives notifications + +### optional + +- Question: use `anyOf` or `oneOf` to express possible answers +- type: multiple values can be specified +- actor: could be an indirect Link, could have multiple values +- content, name, summary: can use multiple language-tagged values in a map (`contentMap`, etc) +- 5.1: use `to`, `cc`, `bto`, `bcc` as explicit primary and secondary audiences. use `bto` and `bcc` for privately targeting. +- 5.2: reuse existing vocabularies for describing relationships, such as FOAF or Relationship vocabs, or create your own +- 5.3: (non-normative) using other mechanisms for describing locations other than `Place` +- 5.6: (non-normative) using microsyntaxes within `content`, `name`, `summary` +- 5.2.1: (non-normative) using `result` to include side effects of `Accept` +- 5.2.1: (non-normative) using `context` to relate activities back to a common reference point and efficiently group related activities together for display or analysis + + +## activitypub + +2.1 describes profiles for c2s "social API" and s2s "federation protocol". a conformant Client does all c2s, a conformant Server does all c2s, a conformant Federated Server does s2s + +activitypub follows as2-core and as2-vocab "core classes" of Object/Link/Activity/Collection/etc + +### requirements + +- 3.1: persistent distributed objects have unique global `id` +- 3.1: use `id` in s2s for persistent distributed objects +- 3.2: c2s Servers present AS2 in response to `application/ld+json; profile="https://www.w3.org/ns/activitystreams"` +- 3.3: Clients specify `Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"` +- 4.1: actors have `inbox` and `outbox` +- 4.1: dereferencing `sharedInbox` only includes Public activities +- 5: OrderedCollection is reverse chronological (newer items first) +- 5.1: `outbox` is an `OrderedCollection` +- 5.2: `inbox` is an `OrderedCollection` +- 5.2: Server deduplicates activities in inbox. (duplication might happen when an activity is addressed to a follower both implicitly via collection and explicitly via direct id.) dedupe by `id` and drop any existing activities +- 5.3: `followers` is `OrderedCollection` or `Collection` (if present) +- 5.4: `following` is `OrderedCollection` or `Collection` (if present) +- 5.5: `liked` is `OrderedCollection` or `Collection` (if present) +- 5.6: do not attempt to POST to `Public` +- 5.7: `likes` is `OrderedCollection` or `Collection` (if present) +- 5.8: `shares` is `OrderedCollection` or `Collection` (if present) +- 6: Clients discover your `outbox` and HTTP POST with `Content-Type: application/ld+json; profile="https://www.w3.org/ns/activitystreams"` using authentication with your credentials. the body is a single Activity or a single non-Activity object that will be wrapped in a Create +- 6: c2s Servers ignore any Client-provided `id` and generate their own +- 6: c2s Servers return 201 Created with `Location: ` header +- 6: c2s Servers remove `bto`/`bcc` before delivery but after calculating recipients for delivery +- 6: c2s Servers must add this Activity to the `outbox` collection [at least until side effects are processed] +- 6.1, 7.1.1: Clients be aware that Servers will only deliver to `to`, `cc`, `bto`, `bcc`, `audience` +- 6.1: Clients provide `object` for Create, Update, Delete, Follow, Add, Remove, Like, Block, Undo. provide `target` for Add, Remove. +- 6.2.1: wrap valid objects that aren't Activities in a Create. assign `id` to both the Object and the Create (unless transient). copy over `to`, `cc`, `bto`, `bcc`, `audience` from the wrapped object into the wrapping Create. return the id of the Create, not the object. [the object id is available via `object.id`] +- 6.3: c2s Update modifies the `object` if the actor has permission +- 6.10: c2s Undo has `Undo.actor` == `Undo.object.actor` +- 6.11: c2s Server that is also s2s Federated Server follows 7.1.1 outbox delivery +- 7: POST inbox has `Content-Type: application/ld+json; profile="https://www.w3.org/ns/activitystreams"` +- 7: GET has `Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"` +- 7: s2s Servers provide `object` for Create, Update, Delete, Follow, Add, Remove, Like, Block, Undo. provide `target` for Add, Remove. +- 7.1: s2s Servers that deliver to Collection MUST dereference the collection with the user's credentials [[how do they have this???]] and discover inboxes for each item in the collection. limit layers of indirection through additional Collections inside Collections +- 7.1: dedupe the final recipient list +- 7.1: exclude `actor` from the final list (i.e. don't deliver to yourself) +- 7.1.2: inbox forward to `to`, `cc`, `audience` iff first time seeing + value of `to`, `cc`, `audience` is a Collection owned by the server + `inReplyTo`, `object`, `target`, `tag` are owned by the server. don't pick up any new addressees outside of `to`, `cc`, `audience` +- 7.1.3: delivery to `sharedInbox` still delivers to `inbox` for actors that don't have a `sharedInbox` +- 7.3: ensure s2s Update is authorized to modify `object` (at minimum by applying same-origin check) +- 7.5, 7.7: Reject Follow MUST NOT add actor to followers collection + +### recommendations + +- 3: include activitystreams @context +- 3: validate anything you receive to avoid spoofing (exact mechanism is out-of-scope, but if it is resolvable then you can fetch the `id`) +- 3.1: use HTTPS `id` for public content +- 3.1: allocate `id` in actor's namespace +- 3.2: present AS2 in response to `application/activity+json` +- 3.2: authorization checks fail with an appropriate HTTP error code (at least 403 if private) +- 3.3: Clients warn users if editing will overwrite `source` +- 4: normalize `id` when entered in ui or login form. URIs are used directly, and if normalization fails, consider it invalid. dereference the actor URI once identified +- 4.1, 5.3, 5.4: actors have `following`, `followers` +- 4.1: `sharedInbox` is a publicly readable `OrderedCollection` containing Public addressed activities +- 5: don't use "last updated" timestamp to order items in an OrderedCollection (bc it changes too much) +- 5.1: unauthenticated requests to `outbox` return all Public posts +- 5.2: filter `inbox` according to requester permissions +- 5.2: if you don't support s2s Federated Server profile, then respond to POST inbox with 405 Not Allowed +- 5.6: plain JSON consumers, be aware of equivalence of Public, as:Public, etc +- 6: POST to outbox which doesn't support c2s Server should respond with 405 Not Allowed +- 6: respect HTTP caching for Clients and Servers +- 6.1: consider `actor`/`attributedTo` of `object`/`target`/`inReplyTo`/`tag[*]` for additional recipients. if you recurse through these, set a limit for recursion (without necessarily unpacking collections) +- 6.2: Create should copy `actor` to `object.attributedTo` +- 6.2: reconcile audiences on object and Create for initial distribution [although the object can be updated to have a different audience later] +- 6.2.1: return `Location: ` instead of id of object +- 6.3.1: c2s partial Update removes any property set to `null`. s2s Update is complete. +- 6.4: respond with 410 Gone if a Tombstone is presented, otherwise 404 +- 6.5: c2s Follow adds `Follow.object` to `Follow.actor.following` iff/when an Accept Follow is received +- 6.6, 6.7: c2s Add/Remove inserts/removes `object` to/from `target` unless `target` is not owned/authorized, or unless `object` is not allowed to be added/removed to `target` (at discretion of the c2s Server) +- 6.8: c2s Like adds `object` to `actor.liked` if present +- 6.9: c2s Block prevents `object` from interacting with any `object.attributedTo == Block.actor` or `actor == Block.actor` +- 6.9: c2s Block is not delivered to `object` +- 6.10: c2s Undo will undo any side effects (e.g. Like, Follow, Block) to the extent possible [e.g. Undo Like will remove the Like from the `likes` collection and decrement the `totalItems` counter] +- 6.10: don't use c2s Undo where an "inverse activity" exists, e.g. Create->Delete or Add->Remove +- 7: any persistent distributed activity SHOULD have an `id` +- 7: s2s Federated Servers interpret a `Content-Type` or `Accept` header of `application/activity+json` as equivalent to `application/ld+json; profile="https://www.w3.org/ns/activitystreams"` +- 7: respect HTTP caching for Federated Servers +- 7.1: s2s POST to inbox returns 405 Not Allowed if not an s2s Federated Server +- 7.1: use async for delivery +- 7.1: retry delivery after network failure +- 7.1: in inbox forwarding, recurse through `inReplyTo`, `object`, `target`, `tag` (with a max recursion limit) to look for "linked objects owned by the server" [this is presented in context of "getting updates that ... involve the recipient", but i can't see this being useful when we have explicit audience/addressing, except maybe for notification policies?] +- 7.2: s2s Create appears in `inbox` +- 7.3: s2s Update replaces copy of `id == object.id` with new repr +- 7.4: s2s Delete removes copy of `id == object.id` +- 7.5: s2s Follow generates either Accept/Reject Follow delivered to `actor`. upon [sending] Accept, add the `Follow.actor` to `actor.followers` collection +- 7.6: s2s Accept Follow (where the `Follow` is one you previously sent) adds `Accept.actor` to `Follow.actor.following` +- 7.8, 7.9: s2s Add/Remove adds/removes the `object` to/from `target` unless `target` isn't owned by you(r server) or unless `object` cannot be added/removed to `target` for some other reason (at receiver's discretion) +- 7.10: s2s Like gets added to `object.likes` if present +- 7.11: s2s Announce gets added to `object.shares` if present +- A: use internationalization tooling whenever possible [i.e. setting `@language` or using map properties if a language is defined or detected] +- B.2: (non-normative) Servers do not trust Client content, and Federated Servers do not trust other Federated Servers without verification or same-origin policy. be careful to verify attribution and write permissions. +- B.4: (non-normative) check how your URI handling library handles things like `file://` and consider whitelisting only `http`/`https`/etc as needed +- B.5: (non-normative) set a limit on recursion to avoid DoS +- B.7: (non-normative) implement protections against DoS from other Federated Servers, such as rate limiting. be especially careful whenever there are side effects to activities. do not overload other Federates Servers with activities (e.g. use exponential backoff strategy) +- B.8: (non-normative) rate limit Client submissions in order to prevent DoS of Server and also to ensure it does not propagate a DoS to Federated Servers +- B.9: (non-normative) limit the size of Collection pages when requested by Clients. Clients should also prepare to self-limit by e.g. timing out or erroring if they connect to a malicious Server that serves oversized collections +- B.11: (non-normative) omit `bto` and `bcc` when displaying objects even if not delivered + +### optional + +- 2.1: servers may implement either c2s or s2s individually +- 3: include additional `@context` other than activitystreams +- 3.1: omit `id` from transient objects +- 3.2: dereference `id` with HTTP GET +- 3.2: servers MAY use content negotiation +- 3.2: support other behaviors such as additional protocols or HTML response +- 3.2: require authorization, and implement your own rules on top of B.1 +- 3.2: use 404 Not Found to not leak existence of private objects without authorization +- 4: clients normalize provided `id` by assuming a default scheme, preferably `https` +- 4.1, 5.5: actors have `liked` +- 4.1: actors have `streams`, `preferredUsername`, `endpoints`, `endpoints.proxyUrl`, `endpoints.oauthAuthorizationEndpoint`, `endpoints.oauthTokenEndpoint`, `endpoints.provideClientKey`, `endpoints.signClientKey`, `endpoints.sharedInbox` +- 5.3, 5.4, 5.5, 5.7: filter `followers`, `following`, `liked`, `likes`, `shares` based on authenticated user or unauthenticated request +- 5.6: `sharedInbox` is for public and followers-only posts +- 5.7: objects have `likes` +- 5.8: objects have `shares` +- 6: interpret C2S `application/activity+json` as equivalent to C2S `application/ld+json; profile="https://www.w3.org/ns/activitystreams"` when used as `Accept` or `Content-Type` +- 6: activities POSTed to c2s outbox can contain embedded objects +- 6: c2s Servers carry out side effects, and the activity might appear later or disappear at any time from outbox +- 6.1: Clients MAY get inbox from additional recipients, MAY recurse through attached objects, MAY allow users to amend their addressing to include these recipients +- 6.4: c2s Server MAY take a `Delete` and replace the `object` with a `Tombstone` +- 6.12: (non-normative) support uploading media using some out-of-scope mechanism +- 7: s2s transient activities can omit `id` +- 7.1: limit indirection of Collection -> Actor to one layer +- 7.1.2: filter inbox forwarding delivery targets according to impl-specific rules like spam filtering +- 7.1.3: use `sharedInbox` to dedupe deliveries of Public activities or activities whose delivery will be determined by the receiving server +- 7.1.3: deliver Public activities to all known `sharedInbox` endpoints +- 7.3: apply same-origin check to `Update.id` and `Update.object.id` +- 7.4: replace `Delete.object` repr with a `Tombstone` +- 7.5: auto-generate Accept/Reject Follow, or require user input +- 7.5: do not send Reject Follow (though this might leave the server in an intermediate state) \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/actor.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/actor.md new file mode 100644 index 0000000..dab6697 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/actor.md @@ -0,0 +1,101 @@ ++++ ++++ +# Actor + +an actor is just something that has `inbox` and `outbox`. it represents an entity that can perform activities. + +{{}} + +## implementations + +### mastodon + +mastodon only understands Person / Group / Organization / Application / Service due to being overly strict -- [mastodon/mastodon#22322](https://github.com/mastodon/mastodon/issues/22322) + +### pleroma + +ostensibly pleroma is also limited in the same way? https://git.pleroma.social/pleroma/pleroma/-/blob/develop/lib/pleroma/constants.ex#L57 + +other references in code: + +- admin api param `actor_types` only takes Person Service Application https://git.pleroma.social/pleroma/pleroma/-/blob/develop/docs/development/API/admin_api.md#L25 + +- Pleroma.Object.Containment#get_actor filters against Person Service Application https://git.pleroma.social/pleroma/pleroma/-/blob/develop/lib/pleroma/object/containment.ex#L22 + +- Pleroma.Web.ActivityPub.ActivityPub#maybe_update_follow_information checks that user type against Person Service https://git.pleroma.social/pleroma/pleroma/-/blob/develop/lib/pleroma/web/activity_pub/activity_pub.ex#L1608 + +- SimplePolicy checks for Application Group Organization Person Service https://git.pleroma.social/pleroma/pleroma/-/blob/develop/lib/pleroma/web/activity_pub/mrf/simple_policy.ex#L230 + +- openapi spec schema defines enum Application Group Organization Person Service https://git.pleroma.social/pleroma/pleroma/-/blob/develop/lib/pleroma/web/api_spec/schemas/actor_type.ex#L11 + +### misskey + +the isActor check only validates if one of the five types + +the interface requires `inbox`, `outbox` so that's fine, it should just drop the `type` hardcoded check + +https://github.com/misskey-dev/misskey/blob/22ccb0fa716a84560c8599781647baaaeb8e80bd/packages/backend/src/core/activitypub/type.ts#L150-L176 + +```js +export const validActor = ['Person', 'Service', 'Group', 'Organization', 'Application']; + + +export const isActor = (object: IObject): object is IActor => + validActor.includes(getApType(object)); + + +export interface IActor extends IObject { + type: 'Person' | 'Service' | 'Organization' | 'Group' | 'Application'; + name?: string; + preferredUsername?: string; + manuallyApprovesFollowers?: boolean; + discoverable?: boolean; + inbox: string; + sharedInbox?: string; // 後方互換性のため + publicKey?: { + id: string; + publicKeyPem: string; + }; + followers?: string | ICollection | IOrderedCollection; + following?: string | ICollection | IOrderedCollection; + featured?: string | IOrderedCollection; + outbox: string | IOrderedCollection; + endpoints?: { + sharedInbox?: string; + }; + 'vcard:bday'?: string; + 'vcard:Address'?: string; +} +``` + +### gotosocial + +https://github.com/superseriousbusiness/gotosocial/blob/d445c60a26e7f51f6d742e992d15cb5fabe2100c/internal/federation/dereferencing/account.go#L412-L478 + +seems to have a switch-case for Application Group Organization Person Service, but the comment above dereferenceAccountable() says this only (currently?) works for Person Application Service + +### peertube + +https://github.com/Chocobozzz/PeerTube/blob/develop/shared/models/activitypub/activitypub-actor.ts + +seems to have required fields `type` `id` `following` `followers` `inbox` `outbox` `preferredUsername` `url` `name` `endpoints.sharedInbox` `summary` `attributedTo` `publicKey` `publicKey.id` `publicKey.owner` `publicKey.publicKeyPem` [whew that's a lot!] + +other code spots: + +https://github.com/Chocobozzz/PeerTube/blob/5070a9956052ed494077bb5e308eedd13e964799/server/helpers/custom-validators/activitypub/actor.ts + +sanitizeAndCheckActorObject() does the following: + +- actor exists +- id is valid AP url +- inbox is valid AP url +- preferredUsername is valid +- url is valid AP url +- publicKey is valid public key object +- endpoints is valid endpoints object +- either no outbox, or outbox is valid AP url +- either no following, or following is valid AP url +- either no followers, or followers is valid AP url +- set valid attributedTo +- set valid description [summary???] +- either type is not Group, or [if type is Group] then attributedTo has at least 1 item \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/audience.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/audience.md new file mode 100644 index 0000000..696db09 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/audience.md @@ -0,0 +1,81 @@ ++++ ++++ + +## what is an "audience" generally + +https://github.com/w3c/activitystreams/issues/18 + +> elf-pavlik: what we consider an audience? other people, groups, circles, lists of contacts … + +> jasnell: Any of these. This is intentionally left open. + +## `audience` used to be `scope` + +https://github.com/w3c/activitystreams/issues/300 + +> The `scope` indicates that the audience for the note is only members of the Organization. +> The `to` indicates specific people who should be actively notified. +> The `context` indicates a larger context within which the note exists. + +so at the very least we can surmise the following points: + +- “to” should actively notify specific actors + - implying that “cc” should passively notify specific actors? or not notify them, just deliver to them? +- “context” is as we already understand it, a purposeful grouping within which the object exists +- “scope” (later “audience”) is some kind of indication of something + +> To be clear: `scope` is not access control… it is closely related to `to`/`bto`/`cc`/`bcc` in that **a consuming implementation can use it to determine who it ought to display the content to**. So, for instance, given the note example above, a consuming implementation may include the note on the activity timeline of anyone associated with the ‘My Employer’ organization, but it would only activity notify two individuals listed by the to property. The `context` property, on the other hand, has absolutely nothing to do with audience targeting. The above note is essentially saying, “This is a note that was created in relation to A Project. Make the note available to anyone in the My Employer organization but specifically notify John and Sally” + +> `scope` is **advisory as to the publishers intent of whose attention they want to draw to the object**. A consuming application may use the scope/to/bto/cc/bcc to determine it’s access control policy if it wishes, but is not required to do so. + +> In the example, a consuming provider could still choose to allow `anyone` to see the note, but only **actively include the note on the activity streams of** people in the company. + +> `scope` could be renamed to `audience` + +https://github.com/w3c/activitystreams/issues/238#issuecomment-153408442 + +> In the AS2 vocabulary, there is a `scope` property that is used generally to identify the audience. **The targeting properties `to`, `bto`, `cc` and `bcc` indicate the audience subsets** within that identified scope. The `context` is really intended to allow objects and activities to be logically grouped. For instance, in an enterprise setting, the context may group activities by project while the scope would identify one or more teams for which the activity is considered relevant, while **the to/cc fields are used to indicate specific individuals to notify**. + +## synthesis time + +https://socialhub.activitypub.rocks/t/overlapping-taxonomies-and-the-audience-property/4229/11 + +i think the use of `audience` is basically “here’s everybody that can/should see this in a feed”. whereas `to` and `cc` are for notification policies (with `to` being intended to actively generate a notification). delivery happens for all of them, but after delivery, the consuming application needs to reconstruct possible intentions. + +BUT + +this doesn’t chime with the current usage by mastodon et al. with mastodon, [audience is generally ignored, only to and cc are considered](https://github.com/mastodon/mastodon/blob/1959365c2f410aa82874c5c05ab92c4eca4c4055/app/lib/activitypub/activity/create.rb#L139), and notifications are instead determined by the presence of a Mention in the tag array. (which imo shouldn’t generate a notification at all? you should be able to mention someone passively if desired.) + +so we have the intended ideal of audience being used for delivering to, well, audience… and to/cc for generating active/passive notifications. but instead, we have a situation where to/cc are used for delivering to an audience, and Mention tags are used for generating notifications (and audience is ignored). + +If we want to have a compatible migration path forward, then for now: + +- `to` should include anyone you want to notify +- `cc` should include everyone else you want to deliver to +- `audience` should include the sum total of both of these? (but if you want to support bto/bcc, then it realistically needs to be a private Collection) + - alternatively, `audience` should include any actors whose feeds / activity-streams should include this activity/object. (this still works out in practice to anyone mentioned, plus your followers, plus probably as:Public – which is likely the union of to and cc anyway) + +sample object/activity targeting for a basic (read: microblogging) use case: + +```yaml +content: "So here's what I have to say..." +inReplyTo: + - attributedTo: + content: "I said something." +to: [] # this should be interpreted as notifying john +cc: [as:Public, ] # this is interpreted as an "unlisted" post in mastodon parlance, and is necessary for delivery to mastodon currently +audience: [, as:Public, ] # this is interpreted as showing in john's home timeline, as well as your follower's home timelines, and also being accessible to anyone without authentication +``` + +so maybe the use of `audience` can address mastodon’s fears of showing “group” posts in home timelines? i know this is a big concern that mastodon brought up with their current groups PR, they very explicitly do not want group posts showing up in home timelines… perhaps some heuristic can be designed so that newer versions of mastodon can filter out posts from home timelines if someone is not included in `audience`? + +sample object/activity targeting for a more complex (read: forum/discussion) use case: + +```yaml +content: "synthesis time. i think the use of audience..." +context: +cc: [as:Public, ] +audience: [as:Public, , , ] +``` + +in this case because `` are not in `audience`, an updated/newer mastodon et al can know not to display this post in my followers’ home feeds. there’s still the sticking issue for mastodon in how they can get older, non-updated mastodon servers to drop the post, although i really think this is foolish, personally… you could still do it by using *only* `audience` and then older mastodon will drop the activity because it doesn’t understand the recipients. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/Link-as-qualified-indirect-reference.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/Link-as-qualified-indirect-reference.md new file mode 100644 index 0000000..e8f59c7 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/Link-as-qualified-indirect-reference.md @@ -0,0 +1,6 @@ ++++ ++++ + + + +what does it mean to address a Link? why are Link nodes allowed for collection paging properties...? \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/_index.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/accept-content-type.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/accept-content-type.md new file mode 100644 index 0000000..6b83a5d --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/accept-content-type.md @@ -0,0 +1,137 @@ ++++ +autonumbering = true ++++ + +# interpretation of request/response media types in as2/ap + +AS2-Core says + +> An Activity Streams Document is a JSON document whose root value is an Activity Streams Object of any type [...] and whose MIME media type is `application/activity+json` [...] Implementations SHOULD consider the `application/ld+json; profile="https://www.w3.org/ns/activitystreams"` media type as being equivalent to `application/activity+json`. + +AP says + +> POST requests (eg. to the inbox) MUST be made with a Content-Type of `application/ld+json; profile="https://www.w3.org/ns/activitystreams"` and GET requests with an Accept header of `application/ld+json; profile="https://www.w3.org/ns/activitystreams"`. Servers SHOULD interpret a Content-Type or Accept header of `application/activity+json` as equivalent + +> MUST present the ActivityStreams object representation in response to `application/ld+json; profile="https://www.w3.org/ns/activitystreams"`, and SHOULD also present the ActivityStreams representation in response to `application/activity+json` as well. The client MUST specify an Accept header with the `application/ld+json; profile="https://www.w3.org/ns/activitystreams"` media type in order to retrieve the activity + +basically as2 prefers activity+json while ap prefers ld+json with the activitystreams profile. ap is an extension to as2 so i guess ap takes precedence here... + +{{}} + +## conclusion A: request ld+json, respond activity+json? + +taken literally and strictly, i interpret it like so: + +- ap must request ld+json +- old as2 may request activity+json + +and on the response side: + +- return activity+json regardless of request type? since as2-core specifies that type for an "activity streams document" + - alternatively, return whatever type was requested. this is less likely to break expectations or otherwise false assumptions. + +## conclusion B: the semantics of json-ld profiles + +you could also interpret a semantic difference between the two? + +ld+json registration has 6 defined profiles: + +4 of these are the different forms of json-ld + +- `http://www.w3.org/ns/json-ld#expanded` to request or respond with data that has been expanded +- `http://www.w3.org/ns/json-ld#compacted` to request or respond with data that has been compacted +- `http://www.w3.org/ns/json-ld#flattened` to request or respond with data that has been flattened +- `http://www.w3.org/ns/json-ld#framed` to request or respond with data that has been framed + +there are also 2 utility profiles + +- `http://www.w3.org/ns/json-ld#frame` to request or respond with a frame (that can be applied to data) +- `http://www.w3.org/ns/json-ld#context` to request or respond with a context document + +so then, what is the activitystreams profile? it's not explicitly defined in either as2-core or in ap. but we can assume it has something to do with the extra restrictions and requirements that as2 adds on top of json-ld -- that the document must be compacted against the activitystreams context at minimum. + +### @context may be missing in activity+json? + +there's also this bit from as2-core: + +> When a JSON-LD enabled Activity Streams 2.0 implementation encounters a JSON document identified using the `application/activity+json` MIME media type, and that document does not contain a @context property whose value includes a reference to the normative Activity Streams 2.0 JSON-LD @context definition, the implementation MUST assume that the normative @context definition still applies. + +so basically ld-aware as2 implementations MUST inject the as2 context if it is missing from activity+json. but the reverse implication is what's interesting here -- activity+json means that context isn't required! + +also from as2-core: + +> Implementations producing Activity Streams 2.0 documents SHOULD include a @context property with a value that includes a reference to the normative Activity Streams 2.0 JSON-LD @context definition using the URL `https://www.w3.org/ns/activitystreams`. + +note that this is only a SHOULD. + +as2 author james snell explains further: + +> You can still use `application/ld+json` if you wish. The `application/activity+json` media type implies a very specific profile of JSON-LD -- that is, JSON-LD in compacted form using the normative context definition. When using `application/activity+json`, the context can be implicit if you're not using any extensions. + +further comments from the issue: + +> AS2 is not just JSON-LD, it's JSON-LD plus a number of additional constraints. The `application/activity+json` media type is used to indicate that those additional constraints are in effect. Yes, you can still treat it as straightforward JSON-LD, and yes, it's best if implementers make the @context explicit in order to maximize interoperability with existing JSON-LD stacks as well as performance, but when the document is served up as `application/activity+json`, there are certain assumptions that can be made. + +markus lanthaler concludes: + +>> Yes, you can still treat it as straightforward JSON-LD +> +> No, you can't if there's no explicit context. + +### supporting generic json-ld consumers is a choice + +it can be said that plain-json as2-native software may generate activity+json documents that are not compatible with json-ld. this gives as2 the dubious ability to be "json only". + +it can also be said that generic json-ld consumers may not recognize the activity+json type and may strictly require ld+json... although they shouldn't. but they might. + +so, the real problem is for generic json-ld software which has no idea what activitystreams is. to play nice with this kind of software, as2-core says you SHOULD include the as2 context. but this ends up being a choice because it's only a SHOULD and not a MUST. + +aside from that, the whole type debate is largely irrelevant for software which is activity-aware or activity-native (since you are recommended to treat the two as equivalent). + +## both are equivalent (and used in practice!) + +HOWEVER: in practice, you will probably need to be able to handle both types in both request+response + +impls that GET with activity+json: + +- ... + +impls that GET with ld+json: + +- ... + +impls that POST with activity+json: + +- mastodon + +impls that POST with ld+json: + +- pixelfed + +impls that return activity+json: + +- mastodon +- pleroma + +impls that return ld+json: + +- misskey +- pixelfed + +### QUIRK: multiple types + +ALSO NOTE: you may encounter multiple accept/content-type values. mastodon for example makes GET requests with `Accept: application/activity+json, application/ld+json` (in violation of the activitypub spec) or `Accept: application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams", text/html;q=0.1` (also in violation of activitypub). these are still valid by RFC 9110 "HTTP Semantics" `Accept:` header parsing rules. note that multiple types are separated by a comma (`,`) but you must not parse them in order; *you parse them by most specific type first*. + +> for example: +> `Accept: text/*, text/plain, text/plain;format=flowed, */*` +> [has] the following precedence: +> 1. text/plain;format=flowed +> 2. text/plain +> 3. text/* +> 4. \*/\* + +fwiw mastodon doesn't seem interested in changing this so you will have to Deal With It if you care about mastodon compat + +## see also + +- SocialWG: Media type for AS2 -- a discussion from when AS2 was being written. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/audience-and-addressing.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/audience-and-addressing.md new file mode 100644 index 0000000..8583f8c --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/audience-and-addressing.md @@ -0,0 +1,84 @@ +AS2-Vocab provides three properties for addressing certain audiences, and AP specifies that servers deliver to all three of these properties: + +to +: Identifies an entity considered to be part of the public primary audience of an Object + +cc +: Identifies an Object that is part of the public secondary audience of this Object. + +audience +: Identifies one or more entities that represent the total population of entities for which the object can considered to be relevant. + +There are also two properties for "private addressing", which are used for delivery but will be stripped before delivery. Consequently, they are not visible to consumers, and thus do not have to be interpreted. + +bto +: Identifies an Object that is part of the private primary audience of this Object. + +bcc +: Identifies one or more Objects that are part of the private secondary audience of this Object. + +## Spec guidance + +Per [AS2-Vocab 5.1 Audience Targeting](https://www.w3.org/TR/activitystreams-vocabulary/#audienceTargeting): + +
    + +Conceptually, every Object has both a Primary and Secondary audience. The Primary audience consists of those entities directly involved or owning the object. The Secondary audience consists of the collection of entities sharing an interest in the object but who might not be directly involved (e.g."followers"). + +For instance, suppose a social network of three individuals: Bob, Joe and Jane. Bob and Joe are each friends with Jane but are not friends with one another. Bob has chosen to "follow" activities for which Jane is directly involved. Jane shares a file with Joe. + +In this example, Jane and Joe are each directly involved in the file sharing activity and together make up the Primary Audience for that event. Bob, having an interest in activities involving Jane, is the Secondary Audience. Knowing this, a system that produces or consumes the activity can intelligently notify each person of the event. + +While there are means (based on the action type, actor, object and target of the activity) to infer the primary audience for many types of activities, heuristics do not work in every case and do not provide a means of identifying the secondary audience. The to, cc, bto and bcc properties MAY be used within an Object to explicitly identify the Primary and Secondary audiences. + +[...] + +Audience targeting information included within an Object only describes the intent of the object creator. With clear exception given to the appropriate handling of bto and bcc, this specification leaves it up to implementations to determine how the audience targeting information is used. + +
    + +There is also 5.1.1 about `audience` and `context` which is non-normative, but says this: + +
    + +Activities are rarely isolated events. Often, multiple individual activities will be performed around a similar context or audience. For instance, a collaborators working on a shared project might perform multiple related activities in the process of achieving some goal. Such activities can be logically grouped together using the context property, and scoped to a particular audience using the audience property. + +For instance, the following shows two related activities that share a common context and audience: + +
    + +## Issues and interpretations + +It is unclear what distinguishes "primary audience" from "secondary audience" from "audience". Delivery according to AP aside: When should a producer use to/cc/audience? What should a consumer do with to/cc/audience? + +The only wording used, normatively or not, is that: + +- [normative] the primary audience (`to`) is "directly involved" +- [non-normative] an object using `audience` is "scoped to a particular audience" + +Per Evan: [Audience is not for addressing; it's for defining the people it might be interesting to [...] The fact that it's called out in AP is a bug](https://github.com/evanp/onepage.pub/issues/91#issuecomment-1656844202). + +### My thoughts + +None of the wording above is clear or precise enough to establish a distinction, nor is there any practical difference between using to/cc/audience aside from implementation-specific rules and heuristics, such as: + +- Mastodon treating `cc: [Public, ...]` as "unlisted", a visibility scope which excludes the post from public timelines (which is itself a mastodon-specific UX abstraction). +- Many implementations ignoring `audience` entirely. + +For a compliant Server implementing C2S, there is no issue in delivering activities where the activity or the object contains an `audience`, although producing Clients should be aware that this will likely not be understood widely by consumers which generally expect only to/cc. + +#### Idea: Use `audience` to signal who can fetch an object via cross-domain authentication/authorization? + +Based on the (non-normative) wording for `audience` as being "scoped to a particular audience", we may interpret this as deciding who can fetch an object, even if it was not delivered to them with to/cc/bto/bcc? + +#### Idea: Use `to`/`cc` on activities, and `audience` on objects? + +Maybe prefer `to`/`cc` on activities since this will be used for delivery, and `audience` on the object? Caveats: the activity may need to be fetchable; the object may benefit from having primary/secondary audiences; + +#### Idea: Use `to` to signal intent to generate a notification, `cc` or `audience` to signal intent to not generate a notification? + +It is possible to notify someone differently based on whether they were in the primary or secondary audience. Primary audience may be interpreted as intent to generate a notification, whereas secondary audience may be interpreted as purely intent to deliver. + +#### Idea: AP Errata to remove requirement to deliver to `audience` + +This would drop `audience` to being optional metadata like `tag` or `inReplyTo`, and further enshrine only to/cc/bto/bcc as valid addressing properties. [Why, though?] \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/disambiguating-activity-by-shape-not-id.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/disambiguating-activity-by-shape-not-id.md new file mode 100644 index 0000000..8690872 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/disambiguating-activity-by-shape-not-id.md @@ -0,0 +1,21 @@ ++++ ++++ + +## what this affects + +whenever you embed a Follow, Block, Like, or some other activity where the original id isn't easily on hand, you can embed it as the `object` without an id. in such a case, the shape of the activity becomes semantically significant. + +for example, say you want to remove a follower. you typically do this with Reject Follow. but what do you do if you never stored the original Follow id? you embed it like so + +```yaml +id: +actor: +type: Reject +object: + - type: Follow # this has no id + object: +``` + +now ideally you probably *should* be storing the ids for everything... but eh, what can ya do. + + \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/note-vs-article.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/note-vs-article.md new file mode 100644 index 0000000..be2a863 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/note-vs-article.md @@ -0,0 +1,109 @@ ++++ ++++ + +# Note vs Article + +Discussion: + +in summary: + +> Note: Represents a short written work typically less than a single paragraph in length. + +> Article: represents any kind of multi-paragraph written work. + +but this is contradicted by as2/ap examples + +## the practical difference + +a Note will be displayed inline in Mastodon, but an Article will be converted to name/summary + url/id + +further recommendations for microblog compatibility: + +- a Note SHOULD still work with a plaintext fallback, as most html could be stripped +- a Note SHOULD NOT have a name/title, as this will be ignored + +if you don't care about Mastodon or similar microblogging impls then do whatever. some guidelines/thoughts below... + +## failed ideas for distinction + +### a "paragraph" + +perhaps a note could have no line breaks or only a single `

    ` tag, while an article does? well there's an example that directly contradicts this! ActivityPub example 4 uses two `

    ` tags inside a Note's content + +### titles + +some say a Note has no title but an Article does -- this is not strictly true in all cases, a Note can have a `name` (and AS2-Vocab example 43 does so) + +### formatting + +some say a Note has no formatting but an Article does -- this is not true at all, as Note can be HTML and is in fact assumed to be HTML by default (per AS2-Vocab definition of `mediaType`) + +### length + +perhaps a Note has some character limit and an Article doesn't -- but what is the limit? completely arbitrary. not worth making this distinction + +## what's left for distinction? + +### syndication + +an Article might be expected to be syndicated (think HTML `

    `) since it is a self-contained piece of content. whereas a Note might not be + + + +> The article element represents a complete, or self-contained, composition in a document, page, application, or site and that is, in principle, independently distributable or reusable, e.g. in syndication. This could be a forum post, a magazine or newspaper article, a blog entry, a user-submitted comment, an interactive widget or gadget, or any other independent item of content. +> +> Note: When used specifically with content to be redistributed in syndication, the article element is similar in purpose to the entry element in Atom. + +however this may imply that microblog posts should be sent out as Article? requires further thought + +### formality + +an Article is "published" in a formal context whereas a Note is presented in an informal context + +definitions for "article often stress that it is an independent unit of writing, and is often published. + +dictionary.com: + +> a written composition [...] forming an independent part of a [...] publication + +merriam-webster: + +> a distinct section of writing [...] often numbered + +> [a] composition [...] usually forming an independent part of a publication + +in other words a Note may be viewed in passing, while an Article is more persistent + +## indieweb perspective + +indieweb seems to take this view + +> post name/title [though discounted above] + +> non-trivial structure [akin to formality -- headings?] + +> plain text vs markup [basically the p-content vs e-content argument] + +## takeaway thoughts + +i would tend to assume everything is an article by default, with certain characteristics making it tend toward being a note instead + +for content: + +- no headings? +- no formatting? + +for metadata: + +- no `name`? +- no `id` (transient or anonymous objects)? + +but it's really that last one that seems most salient to me. consider an Article to be a top-level text container that can be referred to later since it forms an independent published unit of writing. consider a Note to be an anonymous text container to be embedded in other objects. in practical terms, a Note might be used for actor metadata, in which case it would have a `name` but still be a Note + +```yaml +type: Note +name: "Pronouns" +content: "they/them" +``` + +note that Note might still have an id, though... so really it's just a vague ill-defined "intention". for example, maybe use a Note for a "status update" in a chat/presence sense? like XMPP PEP. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/preferredUsername-format-not-specified.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/preferredUsername-format-not-specified.md new file mode 100644 index 0000000..be93473 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/preferredUsername-format-not-specified.md @@ -0,0 +1 @@ +`preferredUsername` is expected to map back into webfinger but there are additional length and character restrictions placed on top of it, and these vary between projects \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/public-addressing.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/public-addressing.md new file mode 100644 index 0000000..b4b283e --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/public-addressing.md @@ -0,0 +1,14 @@ ++++ ++++ + + + +the Public == as:Public thing doesn't actually work unless you redefine all the addressing properties from `@type: @id` to `@type: @vocab` (which may have other consequences?) but in any case, `Public` is defined in a way that it does nothing + +furthermore because `as` is defined as a prefix, you will NEVER encounter `https://www.w3.org/ns/activitystreams#Public` in a properly compacted document + +so the only correct way to do public addressing currently is `as:Public` + +## tangent: why are we doing pseudo-addressing anyway? + +why isn't this some other property or flag somewhere on the object? what is *really* being signaled by the public addressing? spec-wise, it's just that it's available to anyone without auth. so why not have some kinda `accessControl` property or `scope` or whatever, and have that explicitly be type:vocab, and define your scopes in there? \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/server-managed-collections.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/server-managed-collections.md new file mode 100644 index 0000000..0cc6dda --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/server-managed-collections.md @@ -0,0 +1,17 @@ +There are special collections that are managed by server side-effects, such as `followers` `following` `liked` on actors and possibly ~~`replies`~~, `likes`, `shares` on objects. In most cases, the side-effects are the only intended way of interacting with these collections; for example, a Follow results in an Accept Follow, which has the side effect of adding them to `followers` and them adding you to `following`; a Like has the side effect of you adding the object to `liked` and them adding your Like to `likes`; an Announce has the side effect of them adding the Announce to `shares`, and a small exception for `replies` which may be managed manually. + +But there's nothing in ActivityPub explicitly preventing a user from targeting their followers/following with an Add/Remove. In the case of a Remove, you can say that there is a legitimate use-case for this; perhaps you no longer wish to follow or be followed by a certain actor. However, for Add, it's a bit weirder -- you can Add an actor to your `followers` despite never receiving a Follow from them. You can add an actor to your `following` despite never receiving an Accept Follow from them. + +There is some language that can be interpreted along these lines, in 6.5 Follow + +> The Follow activity is used to subscribe to the activities of another actor. [...] The side effect of receiving this in an outbox is that the server SHOULD add the object to the actor's [following Collection](https://www.w3.org/TR/activitypub/#following) when and only if an Accept activity is subsequently received with this Follow activity as its object. + +and in 6.6/6.7 for Add/Remove: + +> the server SHOULD add the object to the collection specified in the target property, unless: [...] the object is not allowed to be added to the target collection for some other reason, at the receiving server's discretion. + +Taken together, we conclude that the logical `iff` regarding Accept Follow is the only way to add the other actor to your following. A C2S Add/Remove would not be allowed due to "discretion". + +Given this: how do we signal server management instead of actor management of these collections? My initial leaning would be to exclude `attributedTo` from the representation of these collections; in the absence of any attribution, it is assumed that the collection is owned by the server running at that origin / domain / hostname. (For S2S follower removal, this would have to be a special case handled similarly to Reject Follow being sent at any time after an Accept Follow, but that's a separate topic.) + +https://github.com/w3c/activitypub/issues/377 \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/tag-for-actual-taxonomy.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/tag-for-actual-taxonomy.md new file mode 100644 index 0000000..0a0e32b --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/confusion/tag-for-actual-taxonomy.md @@ -0,0 +1 @@ +in theory `tag` is for "association by reference". you reference other nodes, which can be either objects or links. but what's the best way to reference an arbitrary string? there is the unofficial extension of a `Hashtag` but this ends up getting used as a signal to show your tag alongside other posts that share the same tag. also the format of hashtags is a little weird -- no one can really agree on it. does it contain the hash sign? is it allowed to contain spaces? is it a subtype of Link, or a subtype of Object? should it or should it not appear in the content, since `tag` seems to be used to markup microsyntaxes? \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/context.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/context.md new file mode 100644 index 0000000..1c47622 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/context.md @@ -0,0 +1,75 @@ ++++ ++++ + +FEP-7888: Demystifying the context property + +## conceptual overview + +ActivityStreams Vocabulary defines the context property, but it is "intentionally vague". Unfortunately, this makes the definition so vague as to be practically useless. + +Aside from being "intentionally vague", the definition is also somewhat circular; it requires knowing what a context is and having some conceptual understanding of the notion of "context". However, we are given some guidance towards its "intended function", which is to group objects by some common purpose or origin. + +We might similarly use a `tag` for grouping objects and activities. Current fediverse projects often include a `Hashtag` (defined as an extension within the ActivityStreams namespace, but not actually adopted or defined formally). This `Hashtag` signals an intent to be included or discovered through a collection of objects bearing the same `Hashtag`, uniquely identified by its `name`. The maintenance of such collections is assumed to be the responsibility of the receiving server, although an `href` is provided for convenience, in order to browse the collection of tagged objects at the source. (This also makes the `Hashtag` a sub-type of `Link`.) + +The key property of such a tag is to signal a general, implicit association by reference. We might then consider a context to be an explicit association, but such an explicit association requires an explicit definition. + +Various dictionaries define context generally as something that helps you understand the situation. Following from this, the context should be something that helps you process the activity or object. Ignoring the context may lead to misunderstanding the activity or object; the object or activity exists *within* that context. + +Specific contexts can be thought of in several applications: + +- the "authoritative context" is a context in which some authority can be applied; +- the "conversational context" is a context which represents some conversation and possibly its history; +- the "originating context" is a context which represents some intended starting point that you might look at first. + +We might continue to articulate further types of contexts, but the general pattern that emerges is that a context exists to form a purposeful grouping, regardless of the specific purpose. For example, if we had the notion of a conversation, then we might reasonably say that someone owns this conversation and can apply their authority to it. Looking at some object or activity within this context is generally not recommended on its own; it is better to view the entire conversation or some page of it rather than viewing a singular message. + +The context may be presented using the following abstractions: + +- A "topic" in a forum presentation +- A "conversation" in a social networking presentation +- A "room" in a chatting or messaging presentation +- A "thread" in any of the above contexts (forum thread, social media thread, chat thread) + +Contexts may be nested within other contexts: + +- A forum topic/thread may be nested in a "forum" or "forum category", and may be nested in another parent forum as a sub-forum. +- A "wall" on a profile or group may contain conversations, which in turn may contain the top-level object and its comments +- A "guild" or "space" may contain multiple chat rooms with a common audience + +It is also possible to *not* have a context. Such objects exist only in the general context of their author (via `attributedTo`) and are otherwise self-sufficient. This can include: + +- An article published on a web site, particularly one meant to be accessible directly via a permalink + - A post in a blogging or microblogging environment, particularly one that does not represent a conversation, or where `inReplyTo` is meant only as a loose reference. +- An activity intended for or acting upon an object without a context + +## normative language + +The use of `context` SHOULD adhere to the following guidelines: + +- The `context` SHOULD have a purpose. Consider tags for looser references. +- The `context` SHOULD be resolvable. The resolved object or link should describe the context with at least the additional information needed to fully process the activity or object. + - The resolved `context` SHOULD be a Collection or a subtype. This Collection SHOULD contain the related items. + - The `context` MAY require authorization to resolve properly or fully, but SHOULD include an `attributedTo` property at minimum. + +When encountering an object with a `context`: + +- You MAY copy the `context` as-is, if you wish for your object to be included in the same context. +- You MAY set your own `context`, if you wish for your object to be in a separate context owned by you. +- You MAY remove the `context` entirely, if you wish for your object to exist on its own. + +In cases where you copy a context owned by someone else, you SHOULD send your activity to the owner of that context, defined via `context.attributedTo` if resolvable. You SHOULD NOT send your activity to anyone else, unless you implement a mechanism to allow third-party observers to verify that your object or activity is indeed a valid member of the referenced context. (A further FEP may follow up on this topic.) + +Upon receipt of such an activity referencing a context owned by you, you SHOULD distribute the object to the audience of the context, specified by `context.audience`, and possibly including `context.followers` if the context is itself an actor. This may be done with inbox forwarding or by delivering an Add activity. An Announce activity SHOULD NOT be used, as this would be interpreted as a reshare. (Verification mechanisms for inbox forwarding or Adding private objects is out-of-scope for this FEP.) You MAY drop certain activities not matching specific policies; for example, you might filter out spam, or implement a policy such that only certain actors (members, participants, etc.) are allowed to be included in the context. (Signaling which actors can participate is out-of-scope for this FEP and may be covered in a further FEP.) + +In cases where you copy an unresolvable context, or a context without an owner, you may deliver to an arbitrary audience as if there were no context. However, this is not recommended. Actors that receive such an activity or object with an unverifiable context SHOULD ignore this context, and SHOULD NOT associate the object with the declared context. + +### c2s + +The following algorithm may be used to create an object within a context collection: + +1. Create the `Collection` representing the context. Save the generated Collection `id` to be used in the next step. +2. Create the `Object` and specify the `context` as the `id` obtained in step 1. Set an appropriate `audience` or use `to`/`cc` to deliver the Create activity as-is. Save the returned Object or its `id` to be used in the next step. +3. Add the `Object` to the context `Collection`, using the response from step 2. You may wish to deliver this Add activity `to`/`cc` your intended recipients, especially if you did not deliver the Create Object from step 2. + + +## future directions: contexts as actors that can be followed and addressed \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/_index.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2-unofficial/Hashtag.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2-unofficial/Hashtag.md new file mode 100644 index 0000000..6ab6e41 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2-unofficial/Hashtag.md @@ -0,0 +1,33 @@ +### Hashtag {#hashtag} + +A sub-type of Link that refers to a `#topic`, typically used for associating the object with a collection of other objects sharing the same topic. + +#### Implementation details {#hashtag-implementation} + +

    Not officially part of the ActivityPub context definition, but still assumed to be included in the ActivityStreams `as:` namespace by most implementations (for historical reasons). Implementations should manually define `as:Hashtag` in their JSON-LD `@context`.

    + +The `href` typically links to a collection of all objects tagged with the same Hashtag. + +Consider the following Note: + +```json +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + { + "Hashtag": "as:Hashtag" + } + ], + + "id": "https://example.com/@alice/hello-world", + "type": "Note", + "content": "

    I am talking about a #topic

    ", + "tag": [ + { + "type": "Hashtag", + "name": "#topic", + "href": "https://example.com/tagged/topic" + } + ] +} +``` \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2-unofficial/_index.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2-unofficial/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2-unofficial/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2-unofficial/manuallyApprovesFollowers.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2-unofficial/manuallyApprovesFollowers.md new file mode 100644 index 0000000..97ea620 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2-unofficial/manuallyApprovesFollowers.md @@ -0,0 +1 @@ +boolean. if true, can be used as a hint that the actor will not immediately or automatically Accept your Follow. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2-unofficial/movedTo.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2-unofficial/movedTo.md new file mode 100644 index 0000000..361eaf4 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2-unofficial/movedTo.md @@ -0,0 +1,3 @@ +when using mastodon's definition of Move, indicates that the current account has migrated to the linked account. + +see [Move]({{}}) for more \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2-unofficial/sensitive.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2-unofficial/sensitive.md new file mode 100644 index 0000000..ed14d3e --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2-unofficial/sensitive.md @@ -0,0 +1,3 @@ +boolean. if true, indicates that the information contained within the object (content, etc) is considered "sensitive", in the sense that viewer discretion may be advised, e.g. "NSFW" material. + +when encountered, usually the assumption is that the object's content will be hidden or collapsed behind a warning of some sort. in mastodon, the `summary` will be used as the text of the warning, and the `content` will be hidden below it; furthermore, anything in `attachment` will be hidden behind a sensitive content click-through instead of being directly previewable. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2/Flag.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2/Flag.md new file mode 100644 index 0000000..b8b70a4 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2/Flag.md @@ -0,0 +1,35 @@ ++++ ++++ + +# Flag + +used for reports + +## sample payload + +### mastodon + +```http +POST /users/1/inbox HTTP/1.1 +Host: friends.grishka.me +Content-Type: application/activity+json + +{ + "@context": "https://www.w3.org/ns/activitystreams", + "id": "https://mastodon.social/ccb4f39a-506a-490e-9a8c-71831c7713a4", + "actor": "https://mastodon.social/actor", + "content": "Please disregard this report. I'm just testing report federation.", + "object": [ + "https://friends.grishka.me/users/1", + "https://friends.grishka.me/posts/380590" + ] +} +``` + +notes: +- it is sent to the reported account's `inbox` -- [ReportService#forward_to_origin!](https://github.com/mastodon/mastodon/blob/c4a429ed47e85a6bbf0d470a41cc2f64cf120c19/app/services/report_service.rb#L51) + - [arguably this should be sent to a `sharedInbox` if available? or an instance actor if detected somehow? idk] + - [mastodon uses the wrong content-type currently -- [mastodon/mastodon#22720](https://github.com/mastodon/mastodon/issues/22720)] +- the first item in `object` is the user +- additional items in `object` are attached statuses + - [shouldn't these be in `attachment` instead?] \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2/Move.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2/Move.md new file mode 100644 index 0000000..eb94a20 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2/Move.md @@ -0,0 +1,24 @@ ++++ ++++ + +# Move + +used for account migrations + +## sample payload + +### mastodon + + + +```json +{ + "@context": "https://www.w3.org/ns/activitystreams", + "id": "https://mastodon.example/users/username#moves/1", + "actor": "https://mastodon.example/users/username", + "type": "Move", + "object": "https://mastodon.example/users/username", + "target": "https://social.example/users/new_user" +} +``` + diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2/_index.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/as2/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/http-signatures.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/http-signatures.md new file mode 100644 index 0000000..7b86bcf --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/http-signatures.md @@ -0,0 +1,5 @@ +draft 8 cavage + +even in the updated HTTP Message Signatures which supercedes the old HTTP Signatures, the `keyId` resolution to get the actual key material is unspecced, it's up to app logic + +so you need to clearly specify somewhere such rules. like "keyId must point to a json-ld object with type sec:Key and must have sec:owner pointing to an activitypub actor" or something like that \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/toot/Emoji.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/toot/Emoji.md new file mode 100644 index 0000000..825175f --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/toot/Emoji.md @@ -0,0 +1,85 @@ +### Emoji {#emoji} + +See for more: + +A sub-type of Link that refers to a `:custom_emoji:`, typically used for replacing a plain-text substring with an inline image (by implementations that do not otherwise support arbitrary inline images). + +#### Implementation details {#emoji-implementation} + +Handling an Emoji is typically done by matching for the Emoji's `name` and replacing with an `` element where `src` is the `url` of the Emoji's `icon`. + +

    Note that this extension uses `icon` instead of `href`, but the same "search-and-replace" semantics apply, as with any microsyntax.

    + +Consider the following Note: + +```json +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + { + "toot": "http://joinmastodon.org/ns#", + "Emoji": "toot:Emoji" + } + ], + + "id": "https://example.com/@alice/hello-world", + "type": "Note", + "content": "

    Hello world :kappa:

    ", + "tag": [ + { + "id": "https://example.com/emoji/123", + "type": "Emoji", + "name": ":kappa:", + "icon": { + "type": "Image", + "mediaType": "image/png", + "url": "https://example.com/files/kappa.png" + } + } + ] +} +``` + +- We extract the natural-language properties of `name`, `summary`, and `content`. In this case, we have only `content` of `Hello world :kappa:`. +- We extract any elements from `tag` with a type of `Emoji`. In this case, we have only one, for `:kappa:`. +- We search for `Emoji.name` (`:kappa:`) within the identified `content` (`Hello world :kappa:`) and replace it with an inline image sourced from `Emoji.icon.url` (`https://example.com/files/kappa.png`), resulting in the final value for content being `

    Hello world

    `. + +Pseudocode might look something like this: + +```py +# Extract custom emojis from tag array +tags = Object.tag +Emojis = [tag for tag in tags where tag.type == "Emoji"] + +for Emoji in Emojis: + + # replace :emoji: microsyntax with an inline image (within name) + name = Object.name # may need to extract `name` from `nameMap` instead + name_matches = regex.match(substring = Emoji.name, text = name) + for match in name_matches: + search_and_replace( + text = name, + search = Emoji.name, + replace = f'' + ) + + # replace :emoji: microsyntax with an inline image (within summary) + summary = Object.summary # may need to extract `summary` from `summaryMap` instead + summary_matches = regex.match(substring = Emoji.name, text = summary) + for match in summary_matches: + search_and_replace( + text = summary, + search = Emoji.name, + replace = f'' + ) + + # replace :emoji: microsyntax with an inline image (within content) + content = Object.content # may need to extract `content` from `contentMap` instead + content_matches = regex.match(substring = Emoji.name, text = content) + for match in content_matches: + search_and_replace( + text = content, + search = Emoji.name, + replace = f'' + ) +``` \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/toot/_index.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/toot/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/extensions/toot/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/gotchas/_index.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/gotchas/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/gotchas/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/gotchas/orderedItems.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/gotchas/orderedItems.md new file mode 100644 index 0000000..412d653 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/gotchas/orderedItems.md @@ -0,0 +1,21 @@ +## DO NOT CONFUSE ITEMS AND ORDEREDITEMS + +`items` indicates that this is a Collection + +however, `orderedItems` is valid on both Collection and OrderedCollection! it is defined like this in the as2 context: + +```json +{ + "orderedItems": { + "@id": "as:items", + "@type": "@id", + "@container": "@list" + } +} +``` + +so it is basically just an alias for `items` where it MUST be an array, and the array's order matters. (if it were `@container: set`, then it MUST be an array, but the array's order does not matter.) + +### tangent: a Collection may be ordered without being an OrderedCollection + +OrderedCollection is defined as strictly reverse chronological by ActivityPub. however, other orderings are valid on regular Collections. the use of the `orderedItems` term allows plain-JSON implementations to do exactly this. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/gotchas/retroactive-Update.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/gotchas/retroactive-Update.md new file mode 100644 index 0000000..510f603 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/gotchas/retroactive-Update.md @@ -0,0 +1 @@ +mastodon, when editing a post, does not generate an Update activity in the outbox, but instead will silently and retroactively change the object of the Create \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/gotchas/validating-@context.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/gotchas/validating-@context.md new file mode 100644 index 0000000..d8db9de --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/gotchas/validating-@context.md @@ -0,0 +1,3 @@ +## DO NOT VALIDATE @CONTEXT IF YOU DO NOT UNDERSTAND JSON-LD + +you CANNOT check for the presence of `https://www.w3.org/ns/activitystreams` AT ALL -- the activitystreams context may be included within another context hosted elsewhere. or it may be excluded (although it SHOULD NOT). just ignore this property entirely if you don't understand it \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/gotchas/validating-id.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/gotchas/validating-id.md new file mode 100644 index 0000000..0a5f2a0 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/gotchas/validating-id.md @@ -0,0 +1,22 @@ +## DON'T BE STRICT ABOUT VALIDATING ID + +do NOT try to be overly strict about dereferencing IDs. some IDs may not be on your domain, or otherwise they may not be present at all, or they may be explicitly null. null or missing id indicates a transient activity. + +### example: Follow semantics + +Follows are realistically transient. it is therefore enough to: + +- keep track of local state +- mutate state based on activities + +if you receive an Accept/Reject Follow, check ONLY for the following: + +- actor +- type == Accept/Reject +- object.actor +- object.type == Follow +- object.object == actor + +if object is inlined, you don't need to check that object.id is local. the above is enough information, PROVIDED THAT you have a local pending follow request. if you do not have a pending follow, then DO NOT process an incoming Accept Follow. however, you may receive a Reject Follow at any time, indicating that you should destroy that follow relationship. note that you may also receive an Undo Accept Follow by some implementations. this is discouraged but should be handled as well + + \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/gotchas/validating-type.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/gotchas/validating-type.md new file mode 100644 index 0000000..690284a --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/gotchas/validating-type.md @@ -0,0 +1,32 @@ +## DO NOT CHECK TYPES DURING VALIDATION + +an Actor has an `inbox` and `outbox`. that's it. + +an Activity has an `actor`. that's it. + +a Collection has `items` or `orderedItems`. that's it. + +etc + +## DON'T PANIC WHEN YOU SEE A TYPE YOU DON'T UNDERSTAND + +say you understand tags of type Mention and Hashtag and Emoji. someone sends you a `tag` array with a raw Link. DON'T PANIC. the document is still valid. just filter out anything you don't understand, something like + +```python +UNDERSTOOD_TAG_TYPES = set("Mention", "Hashtag", "Emoji") +document = json.loads(...) +tags = document.get('tag', []) +tags = [ + tag + for tag in tags + if tag['type'] in UNDERSTOOD_TAG_TYPES +] +# do whatever you need to now +``` + +```javascript +const UNDERSTOOD_TAG_TYPES = new Set(["Mention", "Hashtag", "Emoji"]) +let document = ... +tags = document.tag.filter(tag => tag.type in UNDERSTOOD_TAG_TYPES) +// do whatever you need to now +``` \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/MAX_FOLLOWERS.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/MAX_FOLLOWERS.md new file mode 100644 index 0000000..e52d898 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/MAX_FOLLOWERS.md @@ -0,0 +1,3 @@ +https://github.com/mastodon/mastodon/issues/20089 + +max followers? mastodon has a MAX_FOLLOWS and MAX_FOLLOW_RATIO so why not MAX_FOLLOWERS? \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/Message.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/Message.md new file mode 100644 index 0000000..4170c4d --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/Message.md @@ -0,0 +1,45 @@ +# what if we had a Message type + +Message is an IntransitiveActivity? + +```yaml +id: https://alice.social/activities/1 +actor: https://alice.social +type: Message +to: https://bob.social +content: "hello bob" +``` + +representing rooms with context: + +```yaml +id: https://alice.social/activities/1 +actor: https://alice.social +type: Message +to: https://rooms.social/rooms/1/audience # inbox forwarding, probably +content: "hello room" +context: https://rooms.social/rooms/1 # verify inclusion how? +``` + +making the context into an actor: + +```yaml +id: https://alice.social/activities/1 +actor: https://alice.social +type: Message +to: # inbox forwarding, definitely + - https://rooms.social/rooms/1 # we need to deliver to the room actor + - https://rooms.social/rooms/1/followers # rooms.social or the room actor's client will forward to participants +content: "hello room" +context: https://rooms.social/rooms/1 +``` + +use of bto/bcc? + +```yaml +id: https://alice.social/activities/1 +actor: https://alice.social +type: Message +content: "hello room" # arguably only the content needs to be signed? no need for canonicalization +context: https://rooms.social/rooms/1 +``` \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/_index.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/closedBy.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/closedBy.md new file mode 100644 index 0000000..ef4f109 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/closedBy.md @@ -0,0 +1,20 @@ ++++ ++++ + + + +as:closed is defined as Object | Link | xsd:boolean | xsd:datetime + +the normative context explicitly types the value to a datetime + +solution: define `closedBy` as a term definition for as:closed but with `@type: @id` + +```json + "as": "https://www.w3.org/ns/activitystreams#", + // ... + "closedBy": { + "@id": "as:closed", + "@type": "@id" + }, + // ... +``` \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/do-not-inline.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/do-not-inline.md new file mode 100644 index 0000000..67a5c1c --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/do-not-inline.md @@ -0,0 +1,9 @@ +maybe objects shouldn't be inlined tho? spritely magenc golem ocappub etc etc etc + +```yaml +id: alice.example/54078934249073290847321094/activity/1 +actor: alice.example +type: Create +object: alice.example/54078934249073290847321094 # how to fetch this? +cc: [alice.example/followers, Public] +``` \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/exclude-followers.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/exclude-followers.md new file mode 100644 index 0000000..09df4c2 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/exclude-followers.md @@ -0,0 +1,13 @@ +## exclude your own followers? send to someone else's followers? send to a room? + +[tldr i should choose if i want my reply to go to my followers, or their followers, or just them, or all of the above, or whatever] + +1. alice makes a post and sends it to her followers or whatever. optionally it can be made available to the public? + +1. bob replies to alice, they send that to alice only, and *maybe* optionally to bob's followers. **this should be up to the user (bob).** + +1. alice can then choose to redistribute that reply. **this should be up to the recipient (alice)** and also **this should be made clear to the replier (bob)**. + +note that alice might allow bob's replies to be automatically redistributed, if alice trusts bob. + +- bob may not want his reply to be redistributed though? so there should be a way for bob to signal that bob is okay with alice forwarding bob's message to alice's followers. perhaps by explicitly addressing alice's followers? bob might also make his reply explicitly anonymous and transient by using id: null or not providing id. either way, **this should be an explicit decision** \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/jokes/Poke.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/jokes/Poke.md new file mode 100644 index 0000000..b2db37f --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/jokes/Poke.md @@ -0,0 +1 @@ +inspired by facebook pokes or by Yo. just sends a notification. transient, no id. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/jokes/_index.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/jokes/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/jokes/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/jokes/forum-signature.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/jokes/forum-signature.md new file mode 100644 index 0000000..a8e0ef1 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/jokes/forum-signature.md @@ -0,0 +1,5 @@ +https://mastodon.social/@trwnh/110252106080079481 + +maybe ive said this before but fedi should have forum signatures + +`signature` shouldn't mean proof of authorship by a keypair. it should mean a 460x120 image and about 1-3 lines of text \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/jokes/s2s-Block-reminder.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/jokes/s2s-Block-reminder.md new file mode 100644 index 0000000..90c12fc --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/jokes/s2s-Block-reminder.md @@ -0,0 +1,7 @@ +## Block/Mute reminders + +anytime someone muted tries to reply, you respond with an Ignore + +anytime someone blocked tries to interact, you respond with a Block + +what if you do this *every single time* they try to reply/interact \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/jokes/s2s-Ignore.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/jokes/s2s-Ignore.md new file mode 100644 index 0000000..d4dc60e --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/jokes/s2s-Ignore.md @@ -0,0 +1,3 @@ +## Federated mutes + +as2 has an Ignore type so you could theoretically federate out mutes in the same way that blocks are currently federated \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/map-Collection-onto-ldp-Container.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/map-Collection-onto-ldp-Container.md new file mode 100644 index 0000000..3351fb8 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/map-Collection-onto-ldp-Container.md @@ -0,0 +1 @@ +Collection mechanism is very similar to ldp:Container and i guess solid as well? can be backed by filesystem directory/folder and files. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/map-Follow-onto-WebSub.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/map-Follow-onto-WebSub.md new file mode 100644 index 0000000..a3d4791 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/map-Follow-onto-WebSub.md @@ -0,0 +1,3 @@ +if you turn everything into an actor, then Following that actor is like subscribing to a topic for that actor + +the actor's role is to programmatically forward or announce activities/objects related to that topic? \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/orderedAttachment.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/orderedAttachment.md new file mode 100644 index 0000000..1494f9d --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/orderedAttachment.md @@ -0,0 +1,45 @@ ++++ ++++ + + + +problem: sometimes you want to have attachments in a certain order, but `attachment` is an unordered set by default + +solution: define `orderedAttachment` similar to `orderedItems` + +```json +{ + "@context": [ + { + "orderedAttachment": { + "@id": "https://www.w3.org/ns/activitystreams#attachment", + "@type": "@id", + "@container": "@list" + } + }, + "https://www.w3.org/ns/activitystreams" + ] +} +``` + +you could maybe do the same for `orderedTag` but idk if that makes full sense bc `tag` is not really used for categorization so much... but if tumblr or a tumblr-like implementation wanted to order their tags then they have no way of doing so + +if you don't do this, you can technically do this instead + +```json +{ + "@context": "https://www.w3.org/ns/activitystreams", + "id": "https://example.com/object", + "type": "Note", + "content": "hello world, see attached in order", + "attachment": { + "@list": [ + "https://example.com/1", + "https://example.com/2", + "https://example.com/3" + ] + } +} +``` + +this is basically just having the expanded jsonld left as-is \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/s2s-Add-instead-of-Create.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/s2s-Add-instead-of-Create.md new file mode 100644 index 0000000..11ef072 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/s2s-Add-instead-of-Create.md @@ -0,0 +1,7 @@ +# federating a raw Create is not the same as properly managing a profile + +consider an unlisted youtube video, which doesn't appear in the uploads tab. how would you do the same on fedi? possibly by inventing some extension property that hides objects from "profiles"? but the real problem is that there actually isn't a profile at all -- the recipient is expected to keep track of and reconstruct your "profile" based on all known objects! + +instead: have an explicit profile Collection. Add stuff into it. when we federate social data we should explicitly be managing the expected presentation of that social data, in as generic a way as possible. + +related problem: constructing conversations based on a chain of `inReplyTo` instead of having an explicit collection (likely being used as `context`) -- actually the activitypub spec [doesn't specify side effects for inReplyTo]({{< relref "replies-have-no-side-effect" >}}) and for that matter neither does it specify use of context or a context-collection. these are both cases where the Add makes sense to send out explicitly. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/short-bio.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/short-bio.md new file mode 100644 index 0000000..b8e2c3b --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/ideas/short-bio.md @@ -0,0 +1 @@ +on actors that get converted to profiles/accounts, mastodon uses `summary` for bio, but we could use `content` for a "long bio" and reserve `summary` for a "short bio" \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/Article-not-html-article.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/Article-not-html-article.md new file mode 100644 index 0000000..3459381 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/Article-not-html-article.md @@ -0,0 +1,15 @@ +see [Note vs Article]({{}}) for more. but basically: + +in summary: + +> Note: Represents a short written work typically less than a single paragraph in length. + +> Article: represents any kind of multi-paragraph written work. + +but this is contradicted by as2/ap examples. + +the messy general consensus post-spec seems to be about "intention", but this is never defined. it is unclear what a `Note` is intended to be, and what an `Article` is intended to be, beyond very loosely and very vaguely tying such notions to app-specific abstractions or behavior. for example, Mastodon will show a Note more or less in full, but convert an Article to a title and url. + +it would have been better to define it similarly to HTML `
    ` perhaps? an independent unit of writing? one that is published and therefore might reasonably be syndicated? + +and maybe Note should have been forced plaintext. idk. at the very least the distinction should be better explained. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/Invite-extending-Offer.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/Invite-extending-Offer.md new file mode 100644 index 0000000..fb509bd --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/Invite-extending-Offer.md @@ -0,0 +1,5 @@ +Invite is a subtype of Offer, despite the grammar being inverted -- `John Offer Object to Sally` vs `John Invite Sally to Object` + +because Invite extends Offer, examples given for Invite therefore take the form `John Invite Object to Sally` which doesn't make sense. + +conclusion: Invite should not extend Offer. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/Mention-not-usefully-defined.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/Mention-not-usefully-defined.md new file mode 100644 index 0000000..2068a2f --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/Mention-not-usefully-defined.md @@ -0,0 +1,5 @@ +> Mention: A specialized Link that represents an @mention. + +this is an incredibly narrow definition and also one that is often useless. what's so special about an @mention? + +it would have been better to define it in terms of, idk, generating a notification or something? like a webmention? \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/Service-type-ambiguous.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/Service-type-ambiguous.md new file mode 100644 index 0000000..dbff542 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/Service-type-ambiguous.md @@ -0,0 +1,20 @@ +> Service: Represents a service of any kind. + +ok so... what are we supposed to do with this + +this is such an ambiguous definition and it doesn't deserve to exist. definitions of "service" according to dictionaries: + +- helping or doing work for someone +- routine maintenance +- the function of serving +- help, use, benefit +- religious ceremony or worship +- administrative division of govt/business +- articles with a particular use +- utility or facility +- material for a rope +- legal summons +- copulation +- ...and more + +so is as:Service supposed to cover any/all of these? that seems extremely unlikely. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/_index.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/attributedTo-ambiguous.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/attributedTo-ambiguous.md new file mode 100644 index 0000000..dbe5cfb --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/attributedTo-ambiguous.md @@ -0,0 +1,57 @@ +## the problem + +from https://www.w3.org/TR/activitystreams-vocabulary/#dfn-attributedto we have + +`attributedTo` +: Identifies one or more entities to which this object is attributed. The attributed entities might not be Actors. For instance, an object might be attributed to the completion of another activity. + +this definition is circular and therefore left ambiguous. + +from the oxford pocket dictionary of current english: + +**attributed** (verb) +: regard something as being caused by (someone or something).
    - ascribe a work or remark to (a particular author) + +in current usage, objects have `attributedTo` pointing to the actor that authored them or to the actor that "owns" the object (per https://w3id.org/fep/c7d3 which tries to describe this usage) + +a more useful usage would be to point from an Object to the Create activity that created it, or in the case of an Activity, to point from that Activity to some other Activity that caused it. current usage re: authorship should probably be migrated to a more appropriate property with better-fitting semantics, such as `creator` from dublin core or `author` from schema.org. + +http://purl.org/dc/terms/creator +: Creator. An entity responsible for making the resource. Recommended practice is to identify the creator with a URI. If this is not possible or feasible, a literal value that identifies the creator may be provided. + +http://purl.org/dc/elements/1.1/creator +: Creator. An entity primarily responsible for making the resource. Examples of a Creator include a person, an organization, or a service. Typically, the name of a Creator should be used to indicate the entity. + +https://schema.org/author +: The author of this content or rating. Please note that author is special in that HTML 5 provides a special mechanism for indicating authorship via the rel tag. That is equivalent to this and may be used interchangeably. Values expected to be one of these types: Organization, Person. Used on these types: CreativeWork, Rating + +so either reuse existing properties or come up with a new property/ies that encompass the sub-meanings of "attribution" better. + +## discussion + +erincandescent writes: https://socialhub.activitypub.rocks/t/fep-0391-special-collection-proofs/4165/15 + +> Ahh, attributedTo, my behated… +> +> We started with the author property from AS1.0. Somewhere along the way that got lost, then reintroduced as attributedTo, and the scope got widened so now anything can be attributedTo anything. attributedTo in what sense? Well right now everyone means what AS1.0 called “author” - what we started with - though they probably mean “publisher”, +> +> (What did AS1 implementations mean? That’s actually simultaneously more and less clear. What we today call Create(Note), AS1 would call post(note); there, publisher as the actor of the post activity as distinct from the author of the note makes more sense than it does with Create’s actor vs the note’s attributedTo) +> +> - +> +> Anyway, what I’m trying to get at is that in the road to the creation of AS2.0, there was an awful lot of semantic generalisation. Create is the result of squishing create, post and author together (yes there was also an author activity! no I don’t think anyone had a concrete use case for it or ever used it!). attributedTo is a generalisation of author +> +> Some of this makes sense: if we’re using attributedTo to strictly mean author, we’re probably using it wrong (if you imagine a properly rich implementation of AP by a news site, probably people would want to stuff the publication’s name into the attributedTo property for backwards compatibility, and add a new author property for the actual authors of the article); but you have to wonder how this useful generalisation got extended further to the point the Range of the property is now Link | Object. +> +> The result of this applied to the entirety of AS2 is a deeply, deeply unhelpful and implementer hostile situation where nearly every property applies to any object and can point at any object. + +starting from first principles i would honestly think it makes sense for an object to be "attributed to" the Create activity that created it, but no one uses it this way in practice. i respond: https://socialhub.activitypub.rocks/t/fep-0391-special-collection-proofs/4165/17 + +> We are definitely missing a “follow your nose” way of going from a `replies` or `followers` or `following` or `likes` or `shares` back to the object or actor they belong to. Less so for context, because you’d have to keep track of context URIs anyway. +> +> Maybe we can do this with attributedTo? Assuming that we say a Collection is “attributed” to an object, that is to say, the object resulted in the creation of the special collection, in the same way that the Create activity resulted in the creation of the object. It’s attributedTo all the way down. (I’m only half-joking!) +> +> If there’s anything to blame here, I’d point squarely toward the circular definition of the `attributedTo` property. At least with this thought experiment I’m being consistent with my interpretation of “attribution” == “resulting in creation of”. It’s simple causality. If you look up the definition of the word, that’s the sense you get: +> +> > **attributed** (verb) +> > regard something as being caused by (someone or something). diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/collections-underspecced.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/collections-underspecced.md new file mode 100644 index 0000000..d1c534b --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/collections-underspecced.md @@ -0,0 +1,34 @@ +# collections are kinda underspecced tbh + +loosely inspired by the submission of FEP-5bf0 Collection sorting and filtering + +## filtering + +you could pre-create collections that contain a subset of items, but there's no way to dynamically do server-side filtering; this has to be done client-side by downloading the entire collection and creating any useful indices + +## sorting + +OrderedCollection is mandated reverse-chronological but it should have been possible to specify the ordering + +taking schema.org/ItemList and schema.org/ListItem as prior art: + +- `ListItem.position` is the index +- `ItemList.itemListOrder` is the type of ordering + - `itemListOrderAscending` + - `itemListOrderDescending` + - `itemListUnordered` + +what might this imply is needed for activitypub? + +- `orderedBy`? + - what about multiple ordering criteria? SQL has `ORDER BY` + - actually, is a query language a good fit here? +- `reversed`? more like `order: Ascending` or `order: Descending`? + +## querying + +how do you tell if an arbitrary object is included in a collection or not? without iterating over the entire collection, that is. + +## constraining range + +how do you know what a collection contains? \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/extensibility-in-plain-json.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/extensibility-in-plain-json.md new file mode 100644 index 0000000..1eedaee --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/extensibility-in-plain-json.md @@ -0,0 +1,8 @@ +# extensibility for plain-json consumers is underconstrained + +the recommendation in the spec is to use JSON-LD for extensions, which leaves open the "best practices" on how might one expect to serialize and parse those extensions. + +my thoughts: + +- if you consider the mastodon protocol/profile, then you basically have to compact against the same context as them, because mastodon only understands shorthand terms that match their own definitions. +- a full IRI is the only unambiguous way to refer to the same thing. namespaces / prefixes are bad because you could have infinitely many ways of expressing the same thing \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/replies-have-no-side-effect.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/replies-have-no-side-effect.md new file mode 100644 index 0000000..d4bbe57 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/replies-have-no-side-effect.md @@ -0,0 +1,4 @@ + +`likes` and `shares` are defined in terms of side effects of `Like` and `Announce`, but there is no specified side effect for `Create` with `inReplyTo`. this implies manual management of the replies collection? + +https://github.com/w3c/activitypub/issues/374 \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/resource-vs-procedure-call.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/resource-vs-procedure-call.md new file mode 100644 index 0000000..eac7656 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/resource-vs-procedure-call.md @@ -0,0 +1,8 @@ ++++ ++++ + +> is there any idempotency in processing activities, either from a C2S or S2S perspective? I have seen it proposed (albeit semi-unseriously) that you could send multiple Follow or Like activities in order to represent a “super follow” or a “super like”. The only explicitly idempotent bit is the side effect of adding the object to an unordered Collection, which is technically a set and therefore theoretically can’t contain duplicates. A more “common usage” interpretation would hold that follows and likes should be idempotent, but there’s nothing actually establishing this one way or the other. The most naive implementation of, say, C2S or S2S Like, is to handle each Like separately if each activity uses a different id. It then follows that you could post 10 likes of the same object and subsequently undo 3 of those specific activities. And for what it’s worth, adding each activity to either a Collection or an OrderedCollection will not be deduplicated, because each of those activities has a different id. You’ll effectively need to add an implementation quirk that tries to dedupe activities by their shape rather than by their id, in which case… of what purpose is the id? Why bother looking up the original id at all? + +> I bring the previous paragraph/point as an example because I assume blocks are idempotent in “common usage”. If this is indeed the case, then perhaps this should be stated as explicit guidance, and all such “idempotent activities” should be identified clearly. But I can also foresee challenges in trying to establish a conclusive judgement on this. Look no further than Announce – on Twitter and Twitter-like systems, the “retweet” can only be performed once, but on Tumblr and Tumblr-like systems, the “reblog” can be performed any number of times, including in direct succession. Similar reasoning can be extended to pretty much any other activity type. In fact, if you treat all activities as generic posts or items in the “activity stream”, you might not care if someone does a Follow of the same person multiple times in a row. **There is a disconnect between each activity as a resource and each activity as a procedure call. I’m not entirely sure that this disconnect can be fully reconciled.** + +basically you are sending a resource and expecting it to be interpreted in such a way that it has side effects... but the side effects are underspecified. kinda makes you appreciate XRPC from atproto, huh \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/vcard-not-reused.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/vcard-not-reused.md new file mode 100644 index 0000000..62b4b2a --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/shortcomings/vcard-not-reused.md @@ -0,0 +1,3 @@ +activitystreams 2.0 defines some actor types like Person, Group, Organization + +these types should not have been defined at all. they should have reused the vcard properties. the semantics of the types have led to mistakes such as people looking at Group and assuming that it's a facebook-style group, when that's not the definition at all. \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/activitypub/tag.md b/unified.test.hugo/content/wiki/tech/spec/activitypub/tag.md new file mode 100644 index 0000000..fe3654d --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/activitypub/tag.md @@ -0,0 +1,301 @@ ++++ ++++ + +# Tags + +Tags are a property of Objects, stored in the `tag` array. + +From + +**URI:** https://www.w3.org/ns/activitystreams#tag +**Notes:** One or more "tags" that have been associated with an objects. A tag can be any kind of Object. The key difference between attachment and tag is that the former implies association by inclusion, while the latter implies associated by reference. +**Domain:** Object +**Range:** Object | Link + +{{}} + +## Tagging Links {#links} + +In practice, The primary usage of `tag` in most current implementations is to establish a microsyntax. Microsyntaxes are substrings of `name`, `summary`, and `content` that should be linked to or replaced by some rich entity. + +### Link {#link} + +Tagging a Link is not currently widely used, as most use-cases are covered by a more specific sub-type. + +#### Implementation details {#link-implementation} + +In theory, the `name` of a Link could be used to represent the inner text of an anchor link, and the other properties of the Link (`href`, `rel`, etc) would likewise map onto the anchor link. + +Consider the following Article: + +```json +{ + "@context": [ + "https://www.w3.org/ns/activitystreams" + ], + + "id": "https://social.trwnh.com/about", + "type": "Article", + "content": "

    My homepage is trwnh.com

    ", + "tag": [ + { + "type": "Link", + "name": "trwnh.com", + "href": "https://trwnh.com", + "rel": ["me"] + } + ] +} +``` + +For example, the Link in `tag` could be translated into `trwnh.com"`. A plain-text implementation could strip all HTML tags, resulting in a plain-text `content` (`My homepage is trwnh.com`). It could then safely reconstruct only the marked-up links within the tag metadata. In doing so, the plain-text implementation has removed the use of any element that is not supported, such as ``. + +##### FEP-e232: Object Links {object-links} + +FEP-e232 is an extension that proposes using `mediaType` to indicate when a Link refers specifically to an Object that can be fetched using ActivityPub. These Links to Objects are referred to as "object links". The `mediaType` is specified to be the Content-Type that MUST be used to fetch ActivityPub objects, per the ActivityPub spec. + +In Misskey, a quote is a post that embeds a copy of another post below it. Using FEP-e232, a Misskey quote may be represented like so: + +```json +{ + "@context": [ + "https://www.w3.org/ns/activitystreams" + ], + + "id": "https://example.com/@alice/statuses/1578798374936652608", + "type": "Note", + "content": "

    This post is pretty cool RE: https://trwnh.com/objects/e9c427d8-cef1-48bd-ab89-59a6df29673b

    ", + "tag": [ + { + "type": "Link", + "name": "RE: https://trwnh.com/objects/e9c427d8-cef1-48bd-ab89-59a6df29673b", + "href": "https://trwnh.com/objects/e9c427d8-cef1-48bd-ab89-59a6df29673b", + "mediaType": "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"", + "rel": ["https://misskey-hub.net/ns#_misskey_quote"] + } + ] +} +``` + +(It has also been proposed that Misskey quotes be defined by a different extension that specifies a Quote type (as a sub-type of Link) and a `quotes` collection to keep track of related activities in the same vein as the `likes` and `shares` collections. See for more details.) + +Other example microsyntaxes that could be represented by FEP-e232 include: + +- Wiki (`link to [[article]]`, where `[[article]]` is an object link to another Article in the wiki) +- Imageboard (`>>6513 reply to post`, where `>>6513` is an object link to another Note in the thread) +- Issue tracker (`Merge request #123 fixes bug #13 `, where `#123` and `#13` are object links to other entities in the project) + +General pseudocode may look something like this: + +```py +# Extract custom emojis from tag array +tags = Object.tag +REQUEST_TYPE = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' +RESPONSE_TYPE = 'application/activity+json' +ObjectLinks = [ + tag + for tag in tags + where tag.mediaType in set(REQUEST_TYPE, RESPONSE_TYPE) +] + +for Link in ObjectLinks: + + # The purpose of object links is to know that you can fetch an object with ActivityPub: + Object = http.GET( + Link.href, + headers={ + 'Accept': REQUEST_TYPE + } + ) + + # You can now process the object link in some way, + # for example by creating deep links to be resolved within the local application +``` + +The text of FEP-e232 may be found at + +### Mention {#mention} + +A sub-type of Link that refers to an `@mention`, typically used for Actors. In practice, the Mention may begin with other characters depending on the sub-type of the Actor. For example, some implementations [TODO: which?] may use `@person` for Person actors and `!group` for Group actors. + +#### Implementation details {#mention-implementation} + +The `href` typically links to the `id` of the actor being mentioned. + +Consider the following Note: + +```json +{ + "@context": [ + "https://www.w3.org/ns/activitystreams" + ], + + "id": "https://example.com/@alice/hello-world", + "type": "Note", + "content": "

    Hello @bob

    ", + "tag": [ + { + "type": "Mention", + "name": "@bob", + "href": "https://example.com/@bob" + } + ] +} +``` + +

    The following paragraph describes behavior necessary for Mastodon compatibility.

    + +In theory, this Mention tag is optional. In practice, Mastodon uses the presence of a Mention tag to determine when to send notifications, so it is not enough to include your primary recipients in the `to` field of your activity. You must also generate a Mention tag for them, *even if they are not actually mentioned anywhere in the text of `content`!* See for more information: (and other related issues) + +Mastodon also has other weird behavior regarding Mention tags. [TODO: figure out and compile a list of this implementation-specific behavior] + +### Hashtag {#hashtag} + +A sub-type of Link that refers to a `#topic`, typically used for associating the object with a collection of other objects sharing the same topic. + +#### Implementation details {#hashtag-implementation} + +

    Not officially part of the ActivityPub context definition, but still assumed to be included in the ActivityStreams `as:` namespace by most implementations (for historical reasons). Implementations should manually define `as:Hashtag` in their JSON-LD `@context`.

    + +The `href` typically links to a collection of all objects tagged with the same Hashtag. + +Consider the following Note: + +```json +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + { + "Hashtag": "as:Hashtag" + } + ], + + "id": "https://example.com/@alice/hello-world", + "type": "Note", + "content": "

    I am talking about a #topic

    ", + "tag": [ + { + "type": "Hashtag", + "name": "#topic", + "href": "https://example.com/tagged/topic" + } + ] +} +``` + +## Tagging Objects {#objects} + +In theory, you could tag an Object to show that it is somehow referentially associated with the current Object. + +An example application would be the Instagram or Facebook "tag a person in this image" feature, which might be implemented something like this: + +```json +{ + "id": "https://social.example/objects/e9c427d8-cef1-48bd-ab89-59a6df29673b", + "type": "Image", + "url": "https://cdn.social.example/1578798509203652608.jpg", + "tag": [ + "https://facebook.com/users/1" + ] +} +``` + +```json +{ + "id": "https://facebook.com/users/1", + "type": "Person", + "name": "Mark Zuckerberg" +} +``` + +However, it might be better to stick to using [Mentions](#mention) as defined above. + +Another example would be tagging a Note or an Article, but the semantic meaning of this is unclear, at least for most current social use-cases. + +### Emoji {#emoji} + +

    This is an extension type.

    + +See for more: + +An object node that refers to a `:custom_emoji:`, typically used for replacing a plain-text substring with an inline image (by implementations that do not otherwise support arbitrary inline images). + +#### Implementation details {#emoji-implementation} + +Handling an Emoji is typically done by matching for the Emoji's `name` and replacing with an `` element where `src` is the `url` of the Emoji's `icon`. + +

    Note that this extension uses `icon` instead of `href`, but the same "search-and-replace" semantics apply, as with any microsyntax.

    + +Consider the following Note: + +```json +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + { + "toot": "http://joinmastodon.org/ns#", + "Emoji": "toot:Emoji" + } + ], + + "id": "https://example.com/@alice/hello-world", + "type": "Note", + "content": "

    Hello world :kappa:

    ", + "tag": [ + { + "id": "https://example.com/emoji/123", + "type": "Emoji", + "name": ":kappa:", + "icon": { + "type": "Image", + "mediaType": "image/png", + "url": "https://example.com/files/kappa.png" + } + } + ] +} +``` + +- We extract the natural-language properties of `name`, `summary`, and `content`. In this case, we have only `content` of `Hello world :kappa:`. +- We extract any elements from `tag` with a type of `Emoji`. In this case, we have only one, for `:kappa:`. +- We search for `Emoji.name` (`:kappa:`) within the identified `content` (`Hello world :kappa:`) and replace it with an inline image sourced from `Emoji.icon.url` (`https://example.com/files/kappa.png`), resulting in the final value for content being `

    Hello world

    `. + +Pseudocode might look something like this: + +```py +# Extract custom emojis from tag array +tags = Object.tag +Emojis = [tag for tag in tags where tag.type == "Emoji"] + +for Emoji in Emojis: + + # replace :emoji: microsyntax with an inline image (within name) + name = Object.name # may need to extract `name` from `nameMap` instead + name_matches = regex.match(substring = Emoji.name, text = name) + for match in name_matches: + search_and_replace( + text = name, + search = Emoji.name, + replace = f'' + ) + + # replace :emoji: microsyntax with an inline image (within summary) + summary = Object.summary # may need to extract `summary` from `summaryMap` instead + summary_matches = regex.match(substring = Emoji.name, text = summary) + for match in summary_matches: + search_and_replace( + text = summary, + search = Emoji.name, + replace = f'' + ) + + # replace :emoji: microsyntax with an inline image (within content) + content = Object.content # may need to extract `content` from `contentMap` instead + content_matches = regex.match(substring = Emoji.name, text = content) + for match in content_matches: + search_and_replace( + text = content, + search = Emoji.name, + replace = f'' + ) +``` \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/email/_index.md b/unified.test.hugo/content/wiki/tech/spec/email/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/email/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/email/case-sensitivity.md b/unified.test.hugo/content/wiki/tech/spec/email/case-sensitivity.md new file mode 100644 index 0000000..13f68a2 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/email/case-sensitivity.md @@ -0,0 +1,30 @@ ++++ +title = "case sensitivity in email addresses" ++++ + +domain names are case-insensitive, but the local part of an email MAY be case sensitive, though it SHOULD NOT be case sensitive. + +https://www.reddit.com/r/todayilearned/comments/2r264r/comment/cnbuk7w/ + +> Way back when Compuserve and AOL were top-tier ISPs, maybe. Each of the RFCs supercedes the old ones. Even your source acknowledges this isn't the practice: +> +>> Interpretation of the local-part of an email address is dependent on the conventions and policies implemented in the mail server. For example, case sensitivity may distinguish mailboxes differing only in capitalization of characters of the local-part, although this is not very common.[6] +> +> Your source also goes on to talk about updates, like Google making their own additions with the extra dots and plus sign. +>> Gmail ignores all dots in the local-part for the purposes of determining account identity.[7] This prevents the creation of user accounts your.user.name or yourusername when the account your.username already exists. +> +> This may be misleading because the information about the email protocols has been updated, and the old protocols are no longer valid. +> - RFC 821 was the original (1982) email protocol, sure +case sensitive. +> - RFC 2821 (2001) makes 821 & others obsolete - still +case-sensitive. +> - RFC 5321 (2008) RFC 2821 is obsolete - perhaps, but no longer considered common +> +>> Mailbox = Local-part "@" ( Domain / address-literal ) +>> +>> Local-part = Dot-string / Quoted-string ; MAY be case-sensitive +> +> RFC 6530 (2012)- acknowledges this is a bad idea. +>> 10.1. Choices of Mailbox Names and Unicode Normalization +>> +>> It has long been the case that the email syntax permits choices about mailbox names that are unwise in practice, if one actually intends the mailboxes to be accessible to a broad range of senders. The most often cited examples involve the use of case-sensitivity and tricky quoting of embedded characters in mailbox local parts. These deliberately unusual constructions are permitted by the protocols, and servers are expected to support them. Although they can provide value in special cases, taking advantage of them is almost always bad practice unless the intent is to create some form of security by obscurity +> +> e-mail addresses WERE supposed to be case sensitive, but it was always a bad idea \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/openid/!overview.md b/unified.test.hugo/content/wiki/tech/spec/openid/!overview.md new file mode 100644 index 0000000..42a8487 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/openid/!overview.md @@ -0,0 +1,163 @@ ++++ ++++ + +ok let's dive in i guess + + + +here's what i could grasp + +## spec summary + +### openid connect core (OIDC-CORE) + +main points: + +- use oauth 2 to issue an **ID Token** +- use jwt to construct specific claims + - the `iss`uer is the url of the IdP host + - the `sub`ject is some unique identifier (uuid? etc) + - the `aud`ience MUST contain the `client_id` and MAY be an array with other values + - the `exp`iry is some unix timestamp (integer seconds since jan 1970) + - the `iat` (issued at) is also a unix timestamp + - the `auth_time` is a timestamp of when the user was authenticated + - required for `max_age` or when `auth_time` is marked as "essential claim" + - the `nonce` is a string that mitigates replay attacks. + - clients add this and you pass it back so they can verify + - required only if the client gives it to you, MUST be passed back as-is with no processing + - OPTIONAL: the `acr` (authentication class reference) indicates the "level"?? of the authentication. similar to `nist_auth_level` in openid 2.0? + - > Parties using this claim will need to agree upon the meanings of the values used, which may be context-specific + - so this is gonna require more in-depth investigation later + - OPTIONAL: the `amr` (authentication method reference) is an array of identifiers for which methods were used to authenticate -- password/otp/etc + - > The definition of particular values to be used in the amr Claim is beyond the scope of this specification + - so this is also gonna need investigation later + - OPTIONAL: the `azp` is the authorized party, this MUST contain the `client_id`. only needed when the `aud` is a single value that is *different*, but may be inclued even if it's the same. + - OPTIONAL: you MAY include other claims other than the standardized ones above, or per other standards +- use jws to sign the token (required) and jwe to encrypt the token (optional) + - sign, THEN encrypt, to produce a nested jwt as defined in the jwt spec + +example: client `s6BhdRkqt3` makes an authentication request `n-0S6_WzA2Mj`, and gets a response that user `24400320` on `https://server.example.com` was authenticated at `1311280970` and this claim expires in 1000 seconds + +```json +{ + // the authority + "iss": "https://server.example.com", + "sub": "24400320", + // the request + "aud": "s6BhdRkqt3", + "nonce": "n-0S6_WzA2Mj", + // timestamps and ranges + "auth_time": 1311280969, + "iat": 1311280970, + "exp": 1311281970, + // some extra info about the authn level + "acr": "urn:mace:incommon:iap:silver" +} +``` + +three flows defined as part of oauth 2: `response_type` == +- `code` for authorization code flow. code is returned from authorization endpoint, exchanged for token from token endpoint [best practice is to use this with PKCE] +- `id_token` or both `id_token token` for implicit flow. allows one round-trip, but inherently insecure [deprecated in oauth 2.1 even] +- hybrid flow? ask for some combo of `code` and at least one of `id_token` or `token`. + +also note that `token` is defined in oauth 2 but not? used for oidc? since no IdT is returned + +## putting it all together? + +per OIDC-DISCOVERY: webfinger? look for or query `rel` link `http://openid.net/specs/connect/1.0/issuer` and you obtain the host + +```json +{ + "subject": "acct:joe@example.com", // or the url "https://example.com/joe" could work. more than one way to get to this point, in theory. + "links": + [ + { + "rel": "http://openid.net/specs/connect/1.0/issuer", + "href": "https://server.example.com" // bingo. + } + ] +} +``` + +also per OIDC-DISCOVERY: obtain the openid configuration to get endpoints and relevant info + +```http +GET /.well-known/openid-configuration HTTP/1.1 +Host: server.example.com + +{ + "issuer": + "https://server.example.com", + "authorization_endpoint": + "https://server.example.com/connect/authorize", + "token_endpoint": + "https://server.example.com/connect/token", + "registration_endpoint": + "https://server.example.com/connect/register", + // ... +} +``` + +register your client with Dynamic Client Registration (OIDC-DCR) + +```http +POST /connect/register HTTP/1.1 +Content-Type: application/json +Accept: application/json +Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJ ... # may be obtained out-of-band or otherwise dropped if you want anyone to be able to register + +{ + // ... +} +``` + +make a GET request following the authcode flow. scopes defined in OIDC-CORE, along with their associated claims: + +- the `openid` scope grants standard claims like `sub` and must be present to validate the auth request +- the `profile` scope grants claims for + - `name` + - `family_name` + - `given_name` + - `middle_name` + - `nickname` + - `preferred_username` + - `profile` + - `picture` + - `website` + - `gender` + - `birthdate` + - `zoneinfo` + - `locale` + - `updated_at` +- the `email` scope grants claims for + - `email` + - `email_verified` +- the `address` scope grants claims for + - `address` +- the `phone` scope grants claims for + - `phone_number` + - `phone_number_verified` + +[TODO: are there any standards for granular scopes or for information not in this list? i see FHIR for health information registries, like `patient/*.* sens/ETH sens/PSY btg` to request access to all patient data with all methods, plus substance abuse and psychiatry data, while "breaking the glass" (the patient is unavailable, so log this in an audit log somewhere). so i'm guessing that i'm going to be firmly in extension territory here...] + +also per OIDC-PROMPT-CREATE you may add `prompt=create` to initiate a user registration? + +```http +GET /authorize? + response_type=code + &scope=openid%20profile%20email + &client_id=s6BhdRkqt3 + &state=af0ifjsldkj + &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb HTTP/1.1 +``` + +exchange your code for a user token + +```http +POST /token? + // ... +``` + +## drafts to consider (and their implications) + +per OID4VP (verifiable presentations, related to verifiable credentials): you may have client_id == redirect_uri or you may have iss == aud. this indicates a self-issued token. maybe the value is a DID? \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/openid/!scopes.md b/unified.test.hugo/content/wiki/tech/spec/openid/!scopes.md new file mode 100644 index 0000000..2d32573 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/openid/!scopes.md @@ -0,0 +1,9 @@ +https://mastodon.social/@trwnh/109799253222783029 + +diving back into openid specs to wrap my head around how this whole "identity provider" thing might work + +i have a webfinger server which is like step 1 for the intended flow -- ask webfinger for an account's link rel oidc issuer, then `GET /.well-known/openid-configuration` to find endpoints and other such info. the only real gap seems to be a major one: scope. there's no standardized definition for scope except for `profile` `email` `phone` and `address` as defined by OIDC-CORE... + +this is obviously not good enough for resource control, so it seems i might be firmly in extension territory + +i am not an expert here but my naive concept would be to replicate unix acls for directories and subdirectories? you can read this https uri and all children, or you can get write access. but i'd really like to do things in a more ocappy way if feasible \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/openid/_index.md b/unified.test.hugo/content/wiki/tech/spec/openid/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/openid/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/spec/webfinger.md b/unified.test.hugo/content/wiki/tech/spec/webfinger.md new file mode 100644 index 0000000..b3f542f --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/spec/webfinger.md @@ -0,0 +1,3 @@ ++++ ++++ + diff --git a/unified.test.hugo/content/wiki/tech/tutorials/_index.md b/unified.test.hugo/content/wiki/tech/tutorials/_index.md new file mode 100644 index 0000000..f7ba421 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/tutorials/_index.md @@ -0,0 +1,2 @@ ++++ ++++ \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/tutorials/att-bgw320-ipv6.md b/unified.test.hugo/content/wiki/tech/tutorials/att-bgw320-ipv6.md new file mode 100644 index 0000000..0965502 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/tutorials/att-bgw320-ipv6.md @@ -0,0 +1,8 @@ +# How to get IPv6 routing working for incoming traffic to your home servers behind an AT&T BGW320 modem + +Firewall > Firewall Advanced: + +- turn OFF "drop incoming ICMP Echo request to LAN" +- turn OFF "Reflexive ACL" + +more???? \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/tutorials/onhub-openwrt.md b/unified.test.hugo/content/wiki/tech/tutorials/onhub-openwrt.md new file mode 100644 index 0000000..46948ec --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/tutorials/onhub-openwrt.md @@ -0,0 +1,166 @@ +# installing openwrt on a tp-link google onhub + +was tracking this thread as it developed: + +anyway it happened, and it's at a point where it's basically usable and ~stable, will be officially supported in 23.05 i think + +## flashing + +wiki page: + +### steps i took + +prepare the install usb: + +- download the firmware and rename it openwrt.bin, and plug in a spare usb drive which showed up as /dev/sdg +- `sudo dd if=openwrt.bin of=/dev/sdg` + +prepare the hardware: + +- peel off the soft circular pad on the base of the router, unscrew the hex nut (1.5) and there will be a "developer mode" button somewhere below it (you can't see it but trust me it's there sorta). you'll need this in a bit + +boot sequence: + +- plug in the usb +- hold the reset button on the back (next to the ethernet and power) as you plug the power in. wait until the led ring blinks red (not orange), then you can let go. +- press the developer mode button you uncovered from behind the hex nut. fumble around a bit til you hear/feel it press down. the leds should blink purple for a bit and the speaker should beep twice, then the leds go blank as the device boots. press the developer mode button again after the beeps. you'll know it's done when the led ring lights up with multiple colors (rgb). + +flash: + +- connect ethernet to the lan port and to some other device like a laptop +- ping 192.168.1.1 to make sure it's online +- copy and write the firmware with scp and ssh + +```sh +scp -O openwrt.bin root@192.168.1.1:/tmp/ + +ssh root@192.168.1.1 -C "dd if=/dev/zero bs=512 seek=7552991 of=/dev/mmcblk0 count=33 && dd if=/tmp/openwrt.bin of=/dev/mmcblk0 bs=1M" +``` + +take out the usb because we're done, openwrt is installed. unplug power and put it back in. it should boot to the onboard storage (after blinking purple and beeping and then going multicolor rgb). brace yourself, because that was the easy part + +## configuring + +took me a hot minute to find this: + +### install web gui (if not already installed) + +what you specifically probably want to do is to get internet access and install the web gui. this should already be installed once 23.05 releases but on the snapshot i installed, it wasn't. so: + +```sh +ssh root@192.168.1.1 + +uci set network.lan.ipaddr="192.168.1.1" # if it's different than default +uci set network.lan.gateway="192.168.0.1" # whatever you use +uci set network.lan.dns="9.9.9.9" # or whatever you prefer + +uci commit +/etc/init.d/network restart +``` + +ssh will disconnect. reconnect at the new ip. + +now install luci: + +```sh +ssh root@192.168.1.1 + +opkg update +opkg install luci-ssl # for https. install `luci` if http is fine +``` + +### gui time + +the basics first: password, ssh limits, yknow. + +- system > system > general settings: set a hostname and some metadata and timezone +- system > administration: + - router password: set a good password + - ssh access: change the interface from "unspecified" (any) to `lan`. maybe also the port if you want. consider turning off password auth. + - ssh-keys: add ssh keys that you want to be able to login + - https access: optionally redirect http to https if you installed that earlier + +#### network + +network > interfaces: + +- i went to edit `lan` > dhcp server > general setup, and i changed the limit to 100 instead of 150. i *think* this maps the dhcp range to 101-200 if i understand correctly. + +network > wireless: + +- you can add the same ssid and security (wpa3/wpa2 mixed mode, most likely) to radio0 (2.4gz) and radio1 (5ghz). this doesn't actually seem to be enough for smart connection switching ("band steering"?) and i noticed pretty much all devices just stuck with 2.4ghz and never connected to 5ghz. + +- you could also say fuckit and use different ssids like "network-2g" and "network-5g". this seems less appealing, i'd rather properly figure out how to use the same ssid and get devices to prefer 5g + +- idk what radio2 is supposed to be for on the onhub. on the forum, there was some talk about some linksys router having a "third radio" for monitoring DFS, it wasn't meant to be connected to. but idk if this is the same kinda thing. i thought some routers had tri-band to use one of the bands as wireless backhaul in mesh situations. + +- set radio0 and radio1 to auto channel +- set radio1 width to 80mhz + +network > dhcp and dns > general settings: + +- change local server and local domain from `lan` to `local` (better browser support i think) + +network > dhcp and dns > advanced settings: + +- DNSSEC: turn it on + +network > dhcp and dns > hostnames + +- add mappings for stuff like `home.trwnh.com => 192.168.1.2` -- one mapping per hostname you want to resolve locally + +network > firewall > port forwards: + +- set up your port forwarding for home server apps that need it. stuff like `https = wan:443 => 192.168.1.2` + +#### some apps? + +this heavily depends on what you wanna do, if you wanna run homeserver stuff or whatnot. + +system > software + +stuff you might want: + +wpad-openssl +: fully featured wireless support. the default package (wpad-mbedtls) is stripped down and doesn't fully support roaming or mesh or other stuff you might want. + +dnmasq-full +: DNSSEC support? + +cli tools for easier ssh times: + +nano +: i don't really care for vi + +luci apps (gui stuff basically): + +luci-app-upnp +: configure upnp + +luci-app-attendedsysupgrade +: update openwrt from the web gui + +## problems left unsolved + +- same ssid for 2g/5g but preferring 5g, i.e. without getting stuck on 2g. (again: "band steering"?) + - it sort of works but idk if it actually works. stuff connects to 2g more often than i'd expect. what i did was set 2g power to 15db, leave it at 20mhz + +## mesh + +prereqs to install: ath10k (non-CT) qca988x firmware and driver + +- ath10k-firmware-qca988x +- kmod-ath10k + +you can now uninstall the old stuff (idk if you *have* to, but you can and i did) + +- ath10k-firmware-qca988x-ct +- kmod-ath10k-ct + +reboot. + +you should now be able to get your 802.11s interface working. i used radio2 in ac mode on channel 48 with 80mhz width. ymmv, but make sure the settings you choose are the same on all devices. + +same with the client wifi networks. use the same channels and everything + +for the wifi client stuff i had to use the lower channels bc the higher channels were giving me a driver error. `readlog -n 20 -f` \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/tutorials/postgres-upgrade.md b/unified.test.hugo/content/wiki/tech/tutorials/postgres-upgrade.md new file mode 100644 index 0000000..a05d1d0 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/tutorials/postgres-upgrade.md @@ -0,0 +1,114 @@ +# upgrading postgresql on arch (in case you fucked up) + +```sh +stop postgresql +stop akkoma # make sure nothing is trying to hit the database +``` + +## pg_upgrade will fail if you initdb with different params + +so i'd made a file-level backup at least + +```sh +sudo mv /var/lib/postgres/data /var/lib/postgres/olddata +``` + +i tried to + +``` +sudo mkdir /var/lib/postgres/data /var/lib/postgres/tmp +sudo chown postgres:postgres /var/lib/postgres/data /var/lib/postgres/tmp + +sudo -iu postgres +cd /var/lib/postgres/tmp +initdb -D /var/lib/postgres/data --locale=en_US.UTF-8 --encoding=UTF8 --data-checksums +``` + +this caused pg_upgrade to fail because the old data didn't have `--data-checksums` enabled + +## pg_dumpall will fail with extensions like rum + +ok so that didn't work, let's try the manual dump and reload. exit out of the postgres session and back to your user + +```sh +yay -S postgresql-old-upgrade +sudo rm -r /var/lib/postgres/data +sudo mkdir /var/lib/postgres/data +sudo chown -R postgres:postgres /var/lib/postgres/data + +sudo -iu postgres +initdb -D /var/lib/postgres/data +/opt/pgsql-14/bin/pg_ctl -D /var/lib/postgres/olddata/ start +``` + +the old version should be running now + +```sh +pg_dumpall -h /tmp -f /tmp/old_backup.sql +``` + +aaaaand this failed because of something to do with pg_rum + +## downgrading to get a good dump + +ok let's kill the old postgres + +```sh +sudo killall postgres +``` + +copy the old data over and set permissions + +```sh +sudo rm -r /var/lib/postgres/data +sudo cp -r /var/lib/postgres/olddata /var/lib/postgres/data +sudo chown -R postgres:postgres /var/lib/postgres/data +``` + +downgrade to the last version of postgres + +```sh +yay -S downgrade +sudo downgrade postgresql +start postgresql +``` + +dump + +```sh +pg_dumpall > /tmp/dumpall.sql +``` + +now we can upgrade again? + +```sh +stop postgresql +yay -S postgresql +yay -S pg_rum # do a clean build? +``` + +now we try to restore data + +``` +sudo rm -r /var/lib/postgres/data +sudo mkdir /var/lib/postgres/data +sudo chown -R postgres:postgres /var/lib/postgres/data + +sudo -Hu postgres initdb -D /var/lib/postgres/data --locale=en_US.UTF-8 --encoding=UTF8 --data-checksums + +start postgresql + +sudo -Hu postgres psql -f /tmp/dumpall.sql template1 +``` + +this worked for me + +## etc + +while you're here you might as well update and migrate akkoma if you're still running that? + +```sh +sudo -Hu akkoma MIX_ENV=prod mix deps.get +sudo -Hu akkoma MIX_ENV=prod mix ecto.migrate +start akkoma +``` \ No newline at end of file diff --git a/unified.test.hugo/content/wiki/tech/tutorials/sveltekit.md b/unified.test.hugo/content/wiki/tech/tutorials/sveltekit.md new file mode 100644 index 0000000..8cf84b2 --- /dev/null +++ b/unified.test.hugo/content/wiki/tech/tutorials/sveltekit.md @@ -0,0 +1,93 @@ ++++ ++++ + +# stuff i learned by me fucking around with sveltekit for a bit + +{{}} + +## prerequisites + +```sh +npm i -D @sveltejs/adapter-static # for static file output +npm i -D svelte-preprocess # to allow for + + + +
    +
    +

    ~a

    +

    i have approximate knowledge of many things. perpetual student. (nb/ace/they)

    +
    +
    +

    contact me

    +
    +
    Chat (XMPP)
    +
    a@trwnh.com
    +
    Mail (SMTP)
    +
    +
    Social (ActivityPub)
    +
    mastodon.social/@trwnh
    +
    +
    +
    +

    loosely categorized soup

    +
    +

    general stuff

    +

    you can probably find me around the web with the username "trwnh". it comes from my fleshform's legal name, "abdullah tarawneh"; just take the vowels out of the family name. 2014 they was so hipster. although nowadays "i" mostly just go by "a". historically i've had a really tough time with identity, so this is the best we're gonna get i guess. +

    + +
    +
    +

    concert/music/band stuff

    +

    i've used the names "obvious_humor"/"obvioushumor" for my vaguely music/band fandom stuff, and "birdsounds" for more creative stuff like my concert photography. both names are references to lyrics by Circa Survive, one of my favorite bands.

    +
    +
    + + Make your move, obvious humor
    + Desperate and respiratory plight
    + Always on, dressed to impress
    + I'll be the last one to find out why
    + Time takes its toll on us (this changes everything)
    + And I'd be a liar if I denied you at all
    + Oh, now that I know
    + This changes everything
    + I've been trading ideas with intriguing men, and I
    + I perceive an honest solution to all of your pride
    + [...]
    + I'm going home, but my own way
    + Going home on my own
    + I'm going home, but my own way
    + Going home on my own + +
    +
    + + Circa Survive, "The Great Golden Baby" -- Juturna (2005) + +
    +
    +
    +
    + + And it remains the only meaningful mistake
    + But you won't let go, you don't know how to
    + And every morning I begin my dreams when I'm awake
    + Empty bird sounds are reminders
    + You're not awake at all + +
    +
    + + Circa Survive, "Bird Sounds" -- Violent Waves (2012) + +
    +
    +

    links to some of my concert/music/band stuff

    +
      +
    • + birdsounds.media -- my concert photography. +
    • +
    • + youtube.com/@obvious_humor -- my concert videos. (also my de facto main youtube channel, but my youtube presence is really messy) +
    • +
    • + society6.com/trwnh -- on-demand custom merch printing service for my concert photos. (i haven't uploaded all my good photos there but there are a few. ask me if you'd like to buy a print of one of my other photos, and i can upload it.) +
    • +
    +
    +
    +

    gameing

    +

    most of my "gamer" stuff is under the name triggerofsol. the name came from boktai; in the first boktai game "boktai: the sun is in your hand", if you 100% s-rank and get all items you get "the highest title of the delegate of Sol the solar will -- Trigger of Sol". idk the boktai games are kinda quirky and left an impact on me during my formative years. vampires, norse mythology, magitek, post-apocalyptic absurdism, lotta good stuff in those games.

    +
    +
    +

    "So you're the Trigger of Sol? How embarrassing..."

    +
    +
    Sunflower Girl Zazie, in response to Solar Boy Django losing his Solar Gun "Gun del Sol" at the start of Boktai 2 and being unable to defeat a low-level skeleton
    +
    +

    links to gameing stuff

    + +
    +
    +

    i am consumed by a desire for learning

    +

    varied interests here. i went to college for biomedical engineering and computer science. i took cs for """fun""" but i suppose it ended up sorta working out, because i don't really plan to do anything bme-related in my academic or professional life.

    +

    particular areas of (current) interest:

    +
      +
    • the Web. not just the World Wide Web, but also the Semantic Web, Linked Data Web, Social Web, and all that jazz.
    • +
    • communication. protocols, paradigms, and so on. one of the things i've been working on recently-ish is a sort of "grand unified communications theory", where i take a look at the existing open protocols and map them onto the pure abstract paradigms of communication -- publishing, subscribing, discussing, messaging.
    • +
    • identifiers, particularly how to deal with root authority and delegation. resolving those identifiers in a decentralized and persistent way is something i wish i could find a solution to.
    • +
    • i'm learning a lot more about concepts like the actor model, message passing, object capabilities, verifiable claims, distributed systems, trust and authority, and way more.
    • +
    • ...but i also can do web dev and web design and stuff like that if i really had to. i don't really have anything noteworthy to show for it though.
    • +
    +

    look at this computer stuff

    +
      +
    • + git.trwnh.com -- personal stuff goes here +
    • +
    • + github.com/trwnh -- this is where pretty much everyone is forced to collaborate due to network effects, so that's where you can find my contributions i guess +
    • +
    • + SocialHub -- this is the forum where ActivityPub and the fediverse get discussed a lot +
    • +
    +
    +
    +
    +

    support me

    +

    look, i'm gonna level with ya. i need money to live. most of the stuff i do is what you might consider "socially useful" but also "generally unprofitable". given our capitalist society, my "value" is judged by the latter criteria rather than the former. you can skip past this section but consider maybe don't.

    +

    ways to support me

    +

    in order of most effective to least effective:

    +

    donate directly

    +

    here's how this one works: you can just give me money. i'll keep doing the stuff i do. this option is good if you already think the stuff i do is cool and worthwhile and valuable without me needing to convince you.

    +
      +
    • you can donate via stripe through that handy web form.
    • +
    • you can back me on liberapay.com/trwnh via bank, card, stripe or paypal. liberapay is a bit weird with how it processes payments, but you generally have an option to do "automatic renewal" or "manual renewal". you can do manual renewal and then cancel the subscription if you want to do a one-time payment.
    • +
    • you can also donate via paypal: tarawneh.abdullah@gmail.com if you prefer paypal for some reason. i'm not sure if that paypal.me link charges extra fees, so you might need to do it manually, and if so, make sure to select "friends and family" instead of "business".
    • +
    +

    hire me to do something for you

    +

    i can explain things and i can do websites. generally, i'm really really really good at thinking things through and analyzing them. i put stuff up on abdullahtarawneh.com last year and i kinda stalled due to a lot going on in my life and not much going on marketably. but maybe check out the following pages:

    +
      +
    • + Work -- the landing page i made that was intended to get people to hire me or contract me. not really happy with it at the moment, but still worth looking at. +
    • +
    • + Mastodon Documentation -- in particular, this one is something i'm way more proud of. take a look y'all. +
    • +
    +

    buy something from amazon and tell em i sent ya

    +

    can't say this is something i recommend doing, EXCEPT IF you were already going to buy something from amazon. the more expensive the better, since it's percentage-based. but don't go buying things using this referral link just because of me, y'hear?

    +

    https://amzn.to/2rydvvC

    +

    my pitch is basically this: if you can't avoid amazon and you're going to buy something from them regardless, then at least use my link so that they pay me a bit of the revenue and so that it slightly reduces their profits.

    +
    +
    +

    some questions you might have

    +

    "yo why is this website so plain"

    +

    i used to have a nicer-looking one-pager on here. at some point i decided i'd rather actually update my website with actual information instead of worrying about fitting things into some grand design. and for a one-pager, using a static site generator like hugo, which i usually use for this sort of thing... well, that's overkill, isn't it? i'd rather just dump some html in a text file and call it a day. maybe a touch of css, for legibility and a lil flair.

    +

    this style of website has other advantages too, y'know. it's lightweight and performs well on pretty much any device. and it respects people's defaults. some people like to change their fonts or font sizes, and i don't wanna get in the way of that. it's just text, after all. you should be able to read it on your own terms.

    +

    in any case, the main takeaway here is that anything worth doing is also worth doing poorly. it's better to actually do the thing instead of dreaming about how to perfect the thing and ending up with nothing at all.

    +
    +
    +

    things people have said about me

    +
      +
    • + it's scary how much you know. +
    • +
    • + you're the first person i've met that keeps a spreadsheet of their lightbulbs. +
    • +
    • + VERY MUCH not garbage [...] a worthwhile human +
    • +
    • + honestly, i trust your judgement more than i trust my own. +
    • +
    +
    +
    +

    done here? check out some other things if you want

    +
      +
    • + /wiki -- a place to dump my thoughts +
    • +
    • + tumblr -- i kinda don't use this anymore but idk where else to put this link on this page :x +
    • +
    • + no seriously i need money aaaa +
    • +
    +
    +
    + + + \ No newline at end of file diff --git a/unified.test.hugo/layouts/_default/list.html b/unified.test.hugo/layouts/_default/list.html new file mode 100644 index 0000000..5e41a41 --- /dev/null +++ b/unified.test.hugo/layouts/_default/list.html @@ -0,0 +1,34 @@ +{{ define "body" }} + +
    +
    +
    +

    {{.Title}}

    + {{ with (index .Site.Data.people "trwnh.com").a }} +

    {{ partial "mf2/h-card.html" . }}

    + {{ end }} +

    {{ .Summary }}

    +
    + {{ .Content }} +
    + +
    +
    +
    +
    +
    + {{ range .RegularPages }} +
    +

    + : {{.Title}}
    + {{ if isset .Params "summary" }} + {{.Summary}} + {{ end }} +

    +
    + {{ end }} +
    +
    +
    + +{{ end }} \ No newline at end of file diff --git a/unified.test.hugo/layouts/_default/raw-baseof.html b/unified.test.hugo/layouts/_default/raw-baseof.html new file mode 100644 index 0000000..a9f49d8 --- /dev/null +++ b/unified.test.hugo/layouts/_default/raw-baseof.html @@ -0,0 +1 @@ +{{.Content}} \ No newline at end of file diff --git a/unified.test.hugo/layouts/_default/single.html b/unified.test.hugo/layouts/_default/single.html new file mode 100644 index 0000000..687cb36 --- /dev/null +++ b/unified.test.hugo/layouts/_default/single.html @@ -0,0 +1,49 @@ +{{ define "body" }} + +
    +
    + +
    +
    + {{ .Content }} +
    +
    +
    +
    + +{{ end }} diff --git a/unified.test.hugo/layouts/index.json b/unified.test.hugo/layouts/index.json new file mode 100644 index 0000000..172e64c --- /dev/null +++ b/unified.test.hugo/layouts/index.json @@ -0,0 +1,8 @@ +{{- $.Scratch.Add "pagesIndex" slice -}} +{{- range $index, $page := .Site.RegularPages -}} + {{- if gt (len $page.Content) 0 -}} + {{- $pageData := (dict "title" (or $page.Title $page.File.LogicalName) "href" $page.Permalink "content" $page.Plain) -}} + {{- $.Scratch.Add "pagesIndex" $pageData -}} + {{- end -}} +{{- end -}} +{{- $.Scratch.Get "pagesIndex" | jsonify -}} \ No newline at end of file diff --git a/unified.test.hugo/layouts/partials/firstH1.html b/unified.test.hugo/layouts/partials/firstH1.html new file mode 100644 index 0000000..10df9d7 --- /dev/null +++ b/unified.test.hugo/layouts/partials/firstH1.html @@ -0,0 +1,16 @@ +{{ $firstH1 := + ( + substr + ( + delimit + ( + findRE + "^#{1} ([^{\n]+)" + .RawContent + 1 + ) + "" + ) + 2 + ) +}} \ No newline at end of file diff --git a/unified.test.hugo/layouts/partials/lastmod.html b/unified.test.hugo/layouts/partials/lastmod.html new file mode 100644 index 0000000..977ed19 --- /dev/null +++ b/unified.test.hugo/layouts/partials/lastmod.html @@ -0,0 +1,3 @@ +{{ if eq .Kind "page" }} +

    Last modified {{ or .Page.Params.updated (.Lastmod.UTC.Format "Mon Jan 2, 2006 at 15:04 MST") }}

    +{{ end }} \ No newline at end of file diff --git a/unified.test.hugo/layouts/partials/mf2/h-card.html b/unified.test.hugo/layouts/partials/mf2/h-card.html new file mode 100644 index 0000000..8abe551 --- /dev/null +++ b/unified.test.hugo/layouts/partials/mf2/h-card.html @@ -0,0 +1,9 @@ + + + + {{.name}} + + \ No newline at end of file diff --git a/unified.test.hugo/layouts/partials/paginator.html b/unified.test.hugo/layouts/partials/paginator.html new file mode 100644 index 0000000..e48721a --- /dev/null +++ b/unified.test.hugo/layouts/partials/paginator.html @@ -0,0 +1,16 @@ +
    +
    + {{ $paginator := .Paginate .RegularPages (or .Params.pagination.pagerSize 10)}} + {{ range $paginator.Pages }} +
    +

    + {{.Date.Format "2006-01-02"}}: + {{.Title}}
    + {{.Summary}} +

    +
    + {{ end }} +
    + + {{ template "_internal/pagination.html" . }} +
    \ No newline at end of file diff --git a/unified.test.hugo/layouts/partials/search/search-form.html b/unified.test.hugo/layouts/partials/search/search-form.html new file mode 100644 index 0000000..47c788e --- /dev/null +++ b/unified.test.hugo/layouts/partials/search/search-form.html @@ -0,0 +1,5 @@ +
    + + + +
    diff --git a/unified.test.hugo/layouts/partials/search/search-index.html b/unified.test.hugo/layouts/partials/search/search-index.html new file mode 100644 index 0000000..cefc741 --- /dev/null +++ b/unified.test.hugo/layouts/partials/search/search-index.html @@ -0,0 +1,3 @@ + +{{ $js := resources.Get "scripts/search.js" | minify | fingerprint }} + \ No newline at end of file diff --git a/unified.test.hugo/layouts/partials/seo.html b/unified.test.hugo/layouts/partials/seo.html new file mode 100644 index 0000000..9dcd22b --- /dev/null +++ b/unified.test.hugo/layouts/partials/seo.html @@ -0,0 +1,154 @@ +{{- $firstH1 := partial "firstH1.html" . }} +{{- $title := or .Title $firstH1 $.File.ContentBaseName }} + +{{- $cover := ($.Resources.ByType "image").GetMatch "{*opengraph*}" -}} +{{ $icon := resources.GetMatch (default "" .Site.Params.icon) -}} + +{{/*=== title ===*/}} +{{ "" | safeHTML }} +{{- with .Site.Title }} + +{{- end -}} +{{- if .IsHome}} +{{- with or .Params.name .Site.Title }} +{{ . }} + +{{- end }} +{{- else }} +{{ or .Params.name (print .Site.Title " | " $title) }} + +{{- end -}} + +{{/*=== description ===*/}} +{{- with or .Description .Summary .Site.Params.description }} + + +{{- end }} +{{ "" | safeHTML }} +{{- with .Permalink | absURL}} + + + + +{{- end -}} + +{{/*=== image ===*/}} +{{- $staticIcon := "icon.png" | absURL -}} +{{- with or $cover $icon }} +{{ "" | safeHTML }} + +{{- with .Width }} + +{{- end }} +{{- with .Height }} + +{{- end }} + + +{{- else }} +{{ "" | safeHTML }} + + + +{{- end -}} + +{{/*=== extra params? ===*/}} +{{- with .Params.audio }}{{ end }} +{{- with .Params.locale }}{{ end }} +{{- with .Params.videos }}{{- range . }} + +{{ end }}{{ end }} + +{{/*=== article ===*/}} +{{ with or .Params.author .Site.Params.author -}} +{{ "" | safeHTML }} + +{{- end }} + +{{ "" | safeHTML }} +{{ with .Date -}} + +{{ end -}} +{{ with .Lastmod -}} + +{{ end -}} + +{{/*=== section and keywords ===*/}} +{{- "" | safeHTML }} +{{ with.Params.category -}} + +{{- end -}} +{{- with .Params.tags }} + +{{- end -}} + +{{- if isset .Params "date" }} +{{ "" | safeHTML }} + + + +{{- else }} +{{ "" | safeHTML }} + + +{{- end -}} + +{{/* auxiliary info */}} +{{ "" | safeHTML }} +{{ with $icon }} + +{{- else -}} + +{{- end }} + + + +{{ with .OutputFormats.Get "RSS" -}} + +{{- end -}} + +{{/* robots */}} +{{ "" | safeHTML }} + + diff --git a/unified.test.hugo/layouts/partials/styles/external-links.html b/unified.test.hugo/layouts/partials/styles/external-links.html new file mode 100644 index 0000000..113d40f --- /dev/null +++ b/unified.test.hugo/layouts/partials/styles/external-links.html @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/unified.test.hugo/layouts/partials/wiki/breadcrumbs.html b/unified.test.hugo/layouts/partials/wiki/breadcrumbs.html new file mode 100644 index 0000000..29bce20 --- /dev/null +++ b/unified.test.hugo/layouts/partials/wiki/breadcrumbs.html @@ -0,0 +1,27 @@ + + + {{ define "breadcrumb" }} + {{ if .p1.Parent }} + {{ template "breadcrumb" (dict "p1" .p1.Parent "p2" .p2 ) }} + {{ else if not .p1.IsHome }} + {{ template "breadcrumb" (dict "p1" .p1.Site.Home "p2" .p2 ) }} + {{ end }} + + {{/* $header := substr (delimit (findRE "^#{1} ([^{\n]+)" .p1.RawContent 1) "") 2 */}} + + + {{ if eq .p1.Kind "page" }} + {{ .p1.File.LogicalName }} + {{ else }} + {{ or .p1.File.ContentBaseName .p1.Site.Title }} + {{ end }} + + + {{ end }} \ No newline at end of file diff --git a/unified.test.hugo/layouts/partials/wiki/site-footer.html b/unified.test.hugo/layouts/partials/wiki/site-footer.html new file mode 100644 index 0000000..27730f0 --- /dev/null +++ b/unified.test.hugo/layouts/partials/wiki/site-footer.html @@ -0,0 +1,7 @@ +
    +
    +
    + {{ partial "lastmod.html" . }} +
    +
    + diff --git a/unified.test.hugo/layouts/partials/wiki/site-header.html b/unified.test.hugo/layouts/partials/wiki/site-header.html new file mode 100644 index 0000000..fa15fed --- /dev/null +++ b/unified.test.hugo/layouts/partials/wiki/site-header.html @@ -0,0 +1,11 @@ + +
    +
    +
    \ No newline at end of file diff --git a/unified.test.hugo/layouts/search/list.html b/unified.test.hugo/layouts/search/list.html new file mode 100644 index 0000000..40ec74c --- /dev/null +++ b/unified.test.hugo/layouts/search/list.html @@ -0,0 +1,29 @@ +{{ define "head" }} + +{{ end }} +{{ define "body" }} + + {{ partial "wiki/site-header.html" .}} +
    +
    +
    +
    +

    for ""

    +
    +
    +
    +
    +
      + +
    +
    +
    +
    +
    + +
    + {{ partial "search/search-index.html" . }} + +{{ end }} \ No newline at end of file diff --git a/unified.test.hugo/layouts/shortcodes/mf2/h-cite.html b/unified.test.hugo/layouts/shortcodes/mf2/h-cite.html new file mode 100644 index 0000000..6aaca60 --- /dev/null +++ b/unified.test.hugo/layouts/shortcodes/mf2/h-cite.html @@ -0,0 +1,29 @@ +{{ $datapath := (split (.Get "author") "/") }} +{{ $author := .Site.Data.people }} +{{ range $datapath }} +{{ $author = index $author . }} +{{ end }} + +
    + {{ with $author }} + + {{ partial "mf2/h-card.html" . }} + + {{ end }} + {{ with .Inner }} +
    + {{.}} +
    + {{ end }} + + {{ with .Get "post-url" }} + + {{ with $.Get "post-name" }} + {{.}} + {{ else }} + [source] + {{ end }} + + {{ end }} + +
    \ No newline at end of file diff --git a/unified.test.hugo/layouts/shortcodes/toc.html b/unified.test.hugo/layouts/shortcodes/toc.html new file mode 100644 index 0000000..caa85a2 --- /dev/null +++ b/unified.test.hugo/layouts/shortcodes/toc.html @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/unified.test.hugo/layouts/sitemap/list.html b/unified.test.hugo/layouts/sitemap/list.html new file mode 100644 index 0000000..3c6b028 --- /dev/null +++ b/unified.test.hugo/layouts/sitemap/list.html @@ -0,0 +1,41 @@ +{{ define "main" }} +
    +
    +
    +

    {{.Title}}

    +

    alternate formats: [XML]

    +
    +
    +
    +
    +
    +
    +

    most recently updated

    +
    +
      + {{ range sort .Site.RegularPages ".Lastmod.UTC" "desc" }} +
    • + + {{.File.Path}} + +
      + {{ .Lastmod.UTC.Format "2006-01-02" }} +
    • + {{ end }} +
    +
    +
    +
    + +{{ end }} \ No newline at end of file diff --git a/unified.test.hugo/layouts/wiki/_markup/render-heading.html b/unified.test.hugo/layouts/wiki/_markup/render-heading.html new file mode 100644 index 0000000..1076ca4 --- /dev/null +++ b/unified.test.hugo/layouts/wiki/_markup/render-heading.html @@ -0,0 +1,6 @@ + + {{.Text | safeHTML}} + + [link] + + \ No newline at end of file diff --git a/unified.test.hugo/layouts/wiki/_markup/render-link.html b/unified.test.hugo/layouts/wiki/_markup/render-link.html new file mode 100644 index 0000000..ec352b7 --- /dev/null +++ b/unified.test.hugo/layouts/wiki/_markup/render-link.html @@ -0,0 +1,20 @@ +{{ $link := .Destination }} +{{ $isRemote := strings.HasPrefix $link "http" }} +{{- if not $isRemote -}} +{{ $url := urls.Parse .Destination }} +{{- if $url.Path -}} +{{ $fragment := "" }} +{{- with $url.Fragment }}{{ $fragment = printf "#%s" . }}{{ end -}} +{{- with .Page.GetPage $url.Path }}{{ $link = printf "%s%s" .RelPermalink $fragment }}{{ end }}{{ end -}} +{{- end -}} + + +{{- .Text | safeHTML -}} +{{ if $isRemote -}} + +{{- end -}} + \ No newline at end of file diff --git a/unified.test.hugo/layouts/wiki/list.html b/unified.test.hugo/layouts/wiki/list.html new file mode 100644 index 0000000..e89c5cb --- /dev/null +++ b/unified.test.hugo/layouts/wiki/list.html @@ -0,0 +1,56 @@ +{{ define "body" }} + + {{ $currentFolderName := or $.File.ContentBaseName "index" }} + {{ partial "wiki/site-header.html" .}} + {{ partial "wiki/breadcrumbs.html" .}} +
    +
    +
    +
    + {{ if .IsHome }} +

    {{.Site.Title}}

    + {{ else }} +

    {{or .Title .File.Dir}}

    + {{ end }} +
    +
    + {{.Content}} +
    + {{ with .Sections }} + + {{ end }} + {{ with .RegularPages }} + + {{ end }} +
    +
    +
    + +{{ end }} \ No newline at end of file diff --git a/unified.test.hugo/layouts/wiki/single.html b/unified.test.hugo/layouts/wiki/single.html new file mode 100644 index 0000000..e3976e1 --- /dev/null +++ b/unified.test.hugo/layouts/wiki/single.html @@ -0,0 +1,33 @@ +{{ define "body" }} + + {{ $currentFolderName := or $.File.ContentBaseName "index" }} + {{ partial "wiki/site-header.html" .}} + {{ partial "wiki/breadcrumbs.html" .}} +
    +
    + {{ with .Title}} + + {{ end }} + {{ if .Params.toc }} + + {{ end }} +
    +
    + {{ .Content }} +
    +
    +
    +
    + +{{ end }} \ No newline at end of file diff --git a/unified.test.hugo/static/.assets/icon.png b/unified.test.hugo/static/.assets/icon.png new file mode 100644 index 0000000..4d67cbb Binary files /dev/null and b/unified.test.hugo/static/.assets/icon.png differ diff --git a/unified.test.hugo/static/.assets/images/IMG_1270.JPG b/unified.test.hugo/static/.assets/images/IMG_1270.JPG new file mode 100644 index 0000000..3c09386 Binary files /dev/null and b/unified.test.hugo/static/.assets/images/IMG_1270.JPG differ diff --git a/unified.test.hugo/static/.assets/images/khalil.jpg b/unified.test.hugo/static/.assets/images/khalil.jpg new file mode 100644 index 0000000..fbc384c Binary files /dev/null and b/unified.test.hugo/static/.assets/images/khalil.jpg differ diff --git a/unified.test.hugo/static/.assets/images/letlive.jpg b/unified.test.hugo/static/.assets/images/letlive.jpg new file mode 100644 index 0000000..73a2bd9 Binary files /dev/null and b/unified.test.hugo/static/.assets/images/letlive.jpg differ diff --git a/unified.test.hugo/static/.assets/images/me.jpg b/unified.test.hugo/static/.assets/images/me.jpg new file mode 100644 index 0000000..d65e0b6 Binary files /dev/null and b/unified.test.hugo/static/.assets/images/me.jpg differ diff --git a/unified.test.hugo/static/.assets/images/study.jpg b/unified.test.hugo/static/.assets/images/study.jpg new file mode 100644 index 0000000..5794f7a Binary files /dev/null and b/unified.test.hugo/static/.assets/images/study.jpg differ diff --git a/unified.test.hugo/static/.assets/images/sunset-square-bg-blue.min.avif b/unified.test.hugo/static/.assets/images/sunset-square-bg-blue.min.avif new file mode 100644 index 0000000..0420750 Binary files /dev/null and b/unified.test.hugo/static/.assets/images/sunset-square-bg-blue.min.avif differ diff --git a/unified.test.hugo/static/.assets/images/sunset-square-bg-blue.min.jpg b/unified.test.hugo/static/.assets/images/sunset-square-bg-blue.min.jpg new file mode 100644 index 0000000..80d02c1 Binary files /dev/null and b/unified.test.hugo/static/.assets/images/sunset-square-bg-blue.min.jpg differ diff --git a/unified.test.hugo/static/.assets/images/sunset-square-bg.min.jpg b/unified.test.hugo/static/.assets/images/sunset-square-bg.min.jpg new file mode 100644 index 0000000..368d68f Binary files /dev/null and b/unified.test.hugo/static/.assets/images/sunset-square-bg.min.jpg differ diff --git a/unified.test.hugo/static/.assets/images/sunset-square.jpg b/unified.test.hugo/static/.assets/images/sunset-square.jpg new file mode 100644 index 0000000..4242859 Binary files /dev/null and b/unified.test.hugo/static/.assets/images/sunset-square.jpg differ diff --git a/unified.test.hugo/static/.assets/images/sunset-square.min.jpg b/unified.test.hugo/static/.assets/images/sunset-square.min.jpg new file mode 100644 index 0000000..d2df307 Binary files /dev/null and b/unified.test.hugo/static/.assets/images/sunset-square.min.jpg differ diff --git a/unified.test.hugo/static/.assets/images/sunset.jpg b/unified.test.hugo/static/.assets/images/sunset.jpg new file mode 100644 index 0000000..212e38e Binary files /dev/null and b/unified.test.hugo/static/.assets/images/sunset.jpg differ diff --git a/unified.test.hugo/static/.assets/images/sunset.min.jpg b/unified.test.hugo/static/.assets/images/sunset.min.jpg new file mode 100644 index 0000000..31763db Binary files /dev/null and b/unified.test.hugo/static/.assets/images/sunset.min.jpg differ diff --git a/unified.test.hugo/static/.assets/trwnh-192px.png b/unified.test.hugo/static/.assets/trwnh-192px.png new file mode 100644 index 0000000..4013254 Binary files /dev/null and b/unified.test.hugo/static/.assets/trwnh-192px.png differ diff --git a/unified.test.hugo/static/.well-known/host-meta.json b/unified.test.hugo/static/.well-known/host-meta.json new file mode 100644 index 0000000..8977b31 --- /dev/null +++ b/unified.test.hugo/static/.well-known/host-meta.json @@ -0,0 +1,12 @@ +{ + "links": [ + { + "rel": "urn:xmpp:alt-connections:xbosh", + "href": "https://trwnh.com:5281/http-bind" + }, + { + "rel": "urn:xmpp:alt-connections:websocket", + "href": "wss://trwnh.com:5281/xmpp-websocket" + } + ] +} diff --git a/unified.test.hugo/static/.well-known/host-meta.xrd b/unified.test.hugo/static/.well-known/host-meta.xrd new file mode 100644 index 0000000..3c3418e --- /dev/null +++ b/unified.test.hugo/static/.well-known/host-meta.xrd @@ -0,0 +1,7 @@ + + + + + diff --git a/unified.test.hugo/static/communication-diagram.png b/unified.test.hugo/static/communication-diagram.png new file mode 100644 index 0000000..4c9658f Binary files /dev/null and b/unified.test.hugo/static/communication-diagram.png differ diff --git a/unified.test.hugo/static/error/404.html b/unified.test.hugo/static/error/404.html new file mode 100644 index 0000000..8956492 --- /dev/null +++ b/unified.test.hugo/static/error/404.html @@ -0,0 +1,92 @@ + + + + + + + + 404 + + + + + + "404 computer hamsters not found." + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "404 computer hamsters + not found." + + + + + \ No newline at end of file diff --git a/unified.test.hugo/static/error/Error.png b/unified.test.hugo/static/error/Error.png new file mode 100644 index 0000000..2ddb843 Binary files /dev/null and b/unified.test.hugo/static/error/Error.png differ diff --git a/unified.test.hugo/static/error/I_am_Error.png b/unified.test.hugo/static/error/I_am_Error.png new file mode 100644 index 0000000..246a930 Binary files /dev/null and b/unified.test.hugo/static/error/I_am_Error.png differ diff --git a/unified.test.hugo/static/error/frack.min.min.svg b/unified.test.hugo/static/error/frack.min.min.svg new file mode 100644 index 0000000..39b224f --- /dev/null +++ b/unified.test.hugo/static/error/frack.min.min.svg @@ -0,0 +1 @@ +"404 computer hamstersnot found." \ No newline at end of file diff --git a/unified.test.hugo/static/error/frack.min.svg b/unified.test.hugo/static/error/frack.min.svg new file mode 100644 index 0000000..7c67d8b --- /dev/null +++ b/unified.test.hugo/static/error/frack.min.svg @@ -0,0 +1 @@ +"404 computer hamstersnot found." diff --git a/unified.test.hugo/static/error/frack.svg b/unified.test.hugo/static/error/frack.svg new file mode 100644 index 0000000..1020d56 --- /dev/null +++ b/unified.test.hugo/static/error/frack.svg @@ -0,0 +1,354 @@ + + + +"404 computer hamstersnot found." diff --git a/unified.test.hugo/static/error/index.html b/unified.test.hugo/static/error/index.html new file mode 100644 index 0000000..b049e25 --- /dev/null +++ b/unified.test.hugo/static/error/index.html @@ -0,0 +1,43 @@ + + + + + + I AM ERROR. + + + +
    +

    I AM ERROR.

    +
    + I AM ERROR. + + \ No newline at end of file diff --git a/unified.test.hugo/static/error/spm.woff b/unified.test.hugo/static/error/spm.woff new file mode 100644 index 0000000..254fa73 Binary files /dev/null and b/unified.test.hugo/static/error/spm.woff differ diff --git a/unified.test.hugo/static/error/zii.ttf b/unified.test.hugo/static/error/zii.ttf new file mode 100644 index 0000000..3f14506 Binary files /dev/null and b/unified.test.hugo/static/error/zii.ttf differ diff --git a/unified.test.hugo/static/index.2021.html b/unified.test.hugo/static/index.2021.html new file mode 100644 index 0000000..6d70450 --- /dev/null +++ b/unified.test.hugo/static/index.2021.html @@ -0,0 +1,86 @@ + + + + + +~trwnh + + + + + + + + + + + + + + +
    +

    hi i'm a

    +

    + smtp/xmpp: a@trwnh.com
    + please turn off omemo if you message me
    + activitypub: mastodon.social/@trwnh +

    +
    +
    +
    +

    creative

    +

    birdsounds.media

    +

    my photography side project

    +

    society6

    +

    buy prints and merch of my photography

    +

    youtube - obvious_humor

    +

    concert videos and other assorted junk

    +
    + +
    +

    gaming

    +

    twitch.tv/triggerofsol

    +

    retro game streaming when i get bored

    +

    youtube - trigger of sol

    +

    gaming clips and old stream vods

    +

    steam - triggerofsol

    +

    steamcommunity id

    +
    + +
    +

    professional

    +

    github

    +

    code repos shared with the public

    +

    abdullahtarawneh.com

    +

    i'm an information architect,
    please pay me

    +
    + +
    +

    support me

    +

    liberapay

    +

    sponsor me to do what i do

    +

    paypal

    +

    tip me with a one-time payment

    +

    amazon affiliate

    +

    if you shop on amazon via this link,
    i get a small percentage

    +
    + +
    + + + diff --git a/unified.test.hugo/static/index.2022.html b/unified.test.hugo/static/index.2022.html new file mode 100644 index 0000000..3e19294 --- /dev/null +++ b/unified.test.hugo/static/index.2022.html @@ -0,0 +1,192 @@ + + + + + +~trwnh + + + + + + + + + + + + + + +
    +
    + + + a picture i took of a sunset, but hue-shifted to be blue and purple + +
    +

    hi, i'm a.

    +

    i have approximate knowledge of many things. perpetual student. (nb/ace/they)

    +
    +
    +
    +
    +

    let's be friends.

    +
    +
    Chat (XMPP)
    +
    a@trwnh.com
    +

    send your message and don't worry about whether i add you as a contact. please turn OMEMO off.

    +
    Mail (SMTP)
    +
    a@trwnh.com
    +
    Social (AP)
    +
    mastodon.social/@trwnh
    +
    +
    +
    +
    +
    +

    sometimes i game.

    + +
    +
    +
    + +
    +
    +
    +

    i also contribute to open source software and work on the web.

    + +
    +
    +
    + +
    +
    + + + diff --git a/unified.test.hugo/static/index.html b/unified.test.hugo/static/index.html new file mode 100644 index 0000000..37ec1da --- /dev/null +++ b/unified.test.hugo/static/index.html @@ -0,0 +1,368 @@ + + + + + + + + ~a + + + + + + + + + + + + + + + + + + + + + + +
    +
    +

    ~a

    +

    i have approximate knowledge of many things. perpetual student. (nb/ace/they)

    +
    +
    +

    contact me

    +
    +
    Chat (XMPP)
    +
    a@trwnh.com
    +
    Mail (SMTP)
    +
    +
    Social (ActivityPub)
    +
    mastodon.social/@trwnh
    +
    +
    +
    +

    loosely categorized soup

    +
    +

    general stuff

    +

    you can probably find me around the web with the username "trwnh". it comes from my fleshform's legal name, "abdullah tarawneh"; just take the vowels out of the family name. 2014 they was so hipster. although nowadays "i" mostly just go by "a". historically i've had a really tough time with identity, so this is the best we're gonna get i guess. +

    + +
    +
    +

    concert/music/band stuff

    +

    i've used the names "obvious_humor"/"obvioushumor" for my vaguely music/band fandom stuff, and "birdsounds" for more creative stuff like my concert photography. both names are references to lyrics by Circa Survive, one of my favorite bands.

    +
    +
    + + Make your move, obvious humor
    + Desperate and respiratory plight
    + Always on, dressed to impress
    + I'll be the last one to find out why
    + Time takes its toll on us (this changes everything)
    + And I'd be a liar if I denied you at all
    + Oh, now that I know
    + This changes everything
    + I've been trading ideas with intriguing men, and I
    + I perceive an honest solution to all of your pride
    + [...]
    + I'm going home, but my own way
    + Going home on my own
    + I'm going home, but my own way
    + Going home on my own + +
    +
    + + Circa Survive, "The Great Golden Baby" -- Juturna (2005) + +
    +
    +
    +
    + + And it remains the only meaningful mistake
    + But you won't let go, you don't know how to
    + And every morning I begin my dreams when I'm awake
    + Empty bird sounds are reminders
    + You're not awake at all + +
    +
    + + Circa Survive, "Bird Sounds" -- Violent Waves (2012) + +
    +
    +

    links to some of my concert/music/band stuff

    +
      +
    • + birdsounds.media -- my concert photography. +
    • +
    • + youtube.com/@obvious_humor -- my concert videos. (also my de facto main youtube channel, but my youtube presence is really messy) +
    • +
    • + society6.com/trwnh -- on-demand custom merch printing service for my concert photos. (i haven't uploaded all my good photos there but there are a few. ask me if you'd like to buy a print of one of my other photos, and i can upload it.) +
    • +
    +
    +
    +

    gameing

    +

    most of my "gamer" stuff is under the name triggerofsol. the name came from boktai; in the first boktai game "boktai: the sun is in your hand", if you 100% s-rank and get all items you get "the highest title of the delegate of Sol the solar will -- Trigger of Sol". idk the boktai games are kinda quirky and left an impact on me during my formative years. vampires, norse mythology, magitek, post-apocalyptic absurdism, lotta good stuff in those games.

    +
    +
    +

    "So you're the Trigger of Sol? How embarrassing..."

    +
    +
    Sunflower Girl Zazie, in response to Solar Boy Django losing his Solar Gun "Gun del Sol" at the start of Boktai 2 and being unable to defeat a low-level skeleton
    +
    +

    links to gameing stuff

    + +
    +
    +

    i am consumed by a desire for learning

    +

    varied interests here. i went to college for biomedical engineering and computer science. i took cs for """fun""" but i suppose it ended up sorta working out, because i don't really plan to do anything bme-related in my academic or professional life.

    +

    particular areas of (current) interest:

    +
      +
    • the Web. not just the World Wide Web, but also the Semantic Web, Linked Data Web, Social Web, and all that jazz.
    • +
    • communication. protocols, paradigms, and so on. one of the things i've been working on recently-ish is a sort of "grand unified communications theory", where i take a look at the existing open protocols and map them onto the pure abstract paradigms of communication -- publishing, subscribing, discussing, messaging.
    • +
    • identifiers, particularly how to deal with root authority and delegation. resolving those identifiers in a decentralized and persistent way is something i wish i could find a solution to.
    • +
    • i'm learning a lot more about concepts like the actor model, message passing, object capabilities, verifiable claims, distributed systems, trust and authority, and way more.
    • +
    • ...but i also can do web dev and web design and stuff like that if i really had to. i don't really have anything noteworthy to show for it though.
    • +
    +

    look at this computer stuff

    +
      +
    • + git.trwnh.com -- personal stuff goes here +
    • +
    • + github.com/trwnh -- this is where pretty much everyone is forced to collaborate due to network effects, so that's where you can find my contributions i guess +
    • +
    • + SocialHub -- this is the forum where ActivityPub and the fediverse get discussed a lot +
    • +
    +
    +
    +
    +

    support me

    +

    look, i'm gonna level with ya. i need money to live. most of the stuff i do is what you might consider "socially useful" but also "generally unprofitable". given our capitalist society, my "value" is judged by the latter criteria rather than the former. you can skip past this section but consider maybe don't.

    +

    ways to support me

    +

    in order of most effective to least effective:

    +

    donate directly

    +

    here's how this one works: you can just give me money. i'll keep doing the stuff i do. this option is good if you already think the stuff i do is cool and worthwhile and valuable without me needing to convince you.

    +
      +
    • you can donate via stripe through that handy web form.
    • +
    • you can back me on liberapay.com/trwnh via bank, card, stripe or paypal. liberapay is a bit weird with how it processes payments, but you generally have an option to do "automatic renewal" or "manual renewal". you can do manual renewal and then cancel the subscription if you want to do a one-time payment.
    • +
    • you can also donate via paypal: tarawneh.abdullah@gmail.com if you prefer paypal for some reason. i'm not sure if that paypal.me link charges extra fees, so you might need to do it manually, and if so, make sure to select "friends and family" instead of "business".
    • +
    +

    hire me to do something for you

    +

    i can explain things and i can do websites. generally, i'm really really really good at thinking things through and analyzing them. i put stuff up on abdullahtarawneh.com last year and i kinda stalled due to a lot going on in my life and not much going on marketably. but maybe check out the following pages:

    +
      +
    • + Work -- the landing page i made that was intended to get people to hire me or contract me. not really happy with it at the moment, but still worth looking at. +
    • +
    • + Mastodon Documentation -- in particular, this one is something i'm way more proud of. take a look y'all. +
    • +
    +

    buy something from amazon and tell em i sent ya

    +

    can't say this is something i recommend doing, EXCEPT IF you were already going to buy something from amazon. the more expensive the better, since it's percentage-based. but don't go buying things using this referral link just because of me, y'hear?

    +

    https://amzn.to/2rydvvC

    +

    my pitch is basically this: if you can't avoid amazon and you're going to buy something from them regardless, then at least use my link so that they pay me a bit of the revenue and so that it slightly reduces their profits.

    +
    +
    +

    some questions you might have

    +

    "yo why is this website so plain"

    +

    i used to have a nicer-looking one-pager on here. at some point i decided i'd rather actually update my website with actual information instead of worrying about fitting things into some grand design. and for a one-pager, using a static site generator like hugo, which i usually use for this sort of thing... well, that's overkill, isn't it? i'd rather just dump some html in a text file and call it a day. maybe a touch of css, for legibility and a lil flair.

    +

    this style of website has other advantages too, y'know. it's lightweight and performs well on pretty much any device. and it respects people's defaults. some people like to change their fonts or font sizes, and i don't wanna get in the way of that. it's just text, after all. you should be able to read it on your own terms.

    +

    in any case, the main takeaway here is that anything worth doing is also worth doing poorly. it's better to actually do the thing instead of dreaming about how to perfect the thing and ending up with nothing at all.

    +
    +
    +

    things people have said about me

    +
      +
    • + it's scary how much you know. +
    • +
    • + you're the first person i've met that keeps a spreadsheet of their lightbulbs. +
    • +
    • + VERY MUCH not garbage [...] a worthwhile human +
    • +
    • + honestly, i trust your judgement more than i trust my own. +
    • +
    +
    +
    +

    done here? check out some other things if you want

    +
      +
    • + trwnh.com/wiki -- a place to dump my thoughts +
    • +
    • + tumblr -- i kinda don't use this anymore but idk where else to put this link on this page :x +
    • +
    • + no seriously i need money aaaa +
    • +
    +
    +
    + + + \ No newline at end of file diff --git a/unified.test.hugo/static/mastoFE-4.png b/unified.test.hugo/static/mastoFE-4.png new file mode 100644 index 0000000..b21c719 Binary files /dev/null and b/unified.test.hugo/static/mastoFE-4.png differ diff --git a/unified.test.hugo/static/samples/plumelogos.html b/unified.test.hugo/static/samples/plumelogos.html new file mode 100644 index 0000000..7705e4a --- /dev/null +++ b/unified.test.hugo/static/samples/plumelogos.html @@ -0,0 +1,106 @@ + + + + Plume SVG Logo Test + + + + + + +
    + + + + + +
    + +
    + + + + + +
    + +
    + + + + + +
    + + + diff --git a/unified.test.hugo/static/scanlines-mask-640x480.png b/unified.test.hugo/static/scanlines-mask-640x480.png new file mode 100644 index 0000000..5eae14d Binary files /dev/null and b/unified.test.hugo/static/scanlines-mask-640x480.png differ