10 interesting stories served every morning and every evening.




1 831 shares, 34 trendiness

Sarah Wynn-Williams's 'Careless People' (23 Apr 2025)

I never would have read Careless People, Sarah Wynn-Williams’s tell-all mem­oir about her years run­ning global pol­icy for Facebook, but then Meta’s lawyer tried to get the book sup­pressed and se­cured an in­junc­tion to pre­vent her from pro­mot­ing it:

So I’ve got some­thing to thank Meta’s lawyers for, be­cause it’s a great book! Not only is Wynn-Williams a skilled and lively writer who spills some of Facebook’s most shame­ful se­crets, but she’s also a kick-ass nar­ra­tor (I lis­tened to the au­dio­book, which she voices):

I went into Careless People with strong ex­pec­ta­tions about the kind of dis­gust­ing be­hav­ior it would chron­i­cle. I have sev­eral friends who took se­nior jobs at Facebook, think­ing they could make a dif­fer­ence (three of them ac­tu­ally ap­pear in Wynn-Williams’s mem­oir), and I’ve got a good sense of what a night­mare it is for a com­pany.

But Wynn-Williams was a lot closer to three of the key per­son­al­i­ties in Facebook’s up­per ech­e­lon than any­one in my or­bit: Mark Zuckerberg, Sheryl Sandberg, and Joel Kaplan, who was el­e­vated to VP of Global Policy af­ter the Trump II elec­tion. I al­ready har­bor an atavis­tic loathing of these three based on their pub­lic state­ments and con­duct, but the events Wynn-Williams re­veals from their pri­vate lives make these three out to be be­yond de­spi­ca­ble. There’s Zuck, whose un­der­lings let him win at board-games like Settlers of Catan be­cause he’s a man­baby who can’t lose (and who ac­cuses Wynn-Williams of cheat­ing when she fails to throw a game of Ticket to Ride while they’re fly­ing in his pri­vate jet). There’s Sandberg, who de­mands the right to buy a kid­ney for her child from some­one in Mexico, should that child ever need a kid­ney.

Then there’s Kaplan, who is such an ex­tra­or­di­nar­ily stu­pid and aw­ful oaf that it’s hard to pick out just one ex­am­ple, but I’ll try. At one point, Wynn-Williams gets Zuck a chance to ad­dress the UN General Assembly. As is his wont, Zuck re­fuses to be briefed be­fore he takes the dais (he’s re­peat­edly de­scribed as un­will­ing to con­sider any brief­ing note longer than a sin­gle text mes­sage). When he gets to the mic, he spon­ta­neously promises that Facebook will pro­vide in­ter­net ac­cess to refugees all over the world. Various teams at Facebook then race around, try­ing to fig­ure out whether this is some­thing the com­pany is ac­tu­ally do­ing, and once they re­al­ize Zuck was just bull­shit­ting, set about try­ing to fig­ure out how to do it. They get some way down this path when Kaplan in­ter­venes to in­sist that giv­ing away free in­ter­net to refugees is a bad idea, and that in­stead, they should sell in­ter­net ac­cess to refugees. Facebookers du­ti­fully throw them­selves into this ab­surd pro­ject, which dies when Kaplan fires off an email stat­ing that he’s just re­al­ized that refugees don’t have any money. The pro­ject dies.

The path that brought Wynn-Williams into the com­pany of these care­less peo­ple is a weird — and rather charm­ing — one. As a young woman, Wynn-Williams was a mi­nor func­tionary in the New Zealand diplo­matic corps, and dur­ing her for­eign ser­vice, she grew ob­sessed with the global po­lit­i­cal and so­cial po­ten­tial of Facebook. She threw her­self into the pro­ject of get­ting hired to work on Facebook’s global team, work­ing on strat­egy for li­ais­ing with gov­ern­ments around the world. The biggest im­ped­i­ment to land­ing this job is that it does­n’t ex­ist: sure, FB was lob­by­ing the US gov­ern­ment, but it was mon­u­men­tally dis­in­ter­ested in the rest of the world in gen­eral, and the gov­ern­ments of the world in par­tic­u­lar.

But Wynn-Williams per­sists, pes­ter­ing po­ten­tially rel­e­vant ex­ecs with re­quests, work­ing friends-of-friends (Facebook it­self is ex­tra­or­di­nar­ily use­ful for this), and re­fus­ing to give up. Then comes the Christchurch earth­quake. Wynn-Williams is in the US, about to board a flight, when her sis­ter, a news pre­sen­ter, calls her while trapped in­side a col­lapsed build­ing (the sis­ter had­n’t been able to get a call through to any­one in NZ). Wynn-Williams spends the flight won­der­ing if her sis­ter is dead or alive, and only learns that her sis­ter is OK through a post on Facebook.

The role Facebook played in the Christchurch quake trans­forms Wynn-Williams’s pas­sion for Facebook into some­thing like re­li­gious zealotry. She throws her­self into the pro­ject of land­ing the job, and she does, and af­ter some funny cul­ture-clashes aris­ing from her Kiwi her­itage and her pub­lic ser­vice back­ground, she set­tles in at Facebook.

Her early years there are some­times com­i­cal, some­times scary, and are char­ac­ter­is­tic of a com­pany that is grow­ing quickly and un­evenly. She’s dis­patched to Myanmar amidst a na­tion­wide block of Facebook or­dered by the rul­ing mil­i­tary junta and at one point, it seems like she’s about to get kid­napped and im­pris­oned by goons from the com­mu­ni­ca­tions min­istry. She arranges for a state visit by NZ Prime Minister John Key, who wants a photo-op with Zuckerberg, who — obliv­i­ous to the prime min­is­ter stand­ing right there in front of him — be­rates Wynn-Williams for de­mand­ing that he meet with some jack­ass politi­cian (they do the photo-op any­way).

One thing is clear: Facebook does­n’t re­ally care about coun­tries other than America. Though Wynn-Williams chalks this up to plain old provin­cial chau­vin­ism (which FBs top es­ch­e­lon pos­sess in co­pi­ous quan­ti­ties), there’s some­thing else at work. The USA is the only coun­try in the world that a) is rich, b) is pop­u­lous, and c) has no mean­ing­ful pri­vacy pro­tec­tions. If you make money sell­ing ac­cess to dossiers on rich peo­ple to ad­ver­tis­ers, America is the most im­por­tant mar­ket in the world.

But then Facebook con­quers America. Not only does FB sat­u­rate the US mar­ket, it uses its free cash-flow and high share price to ac­quire po­ten­tial ri­vals, like Whatsapp and Instagram, en­sur­ing that American users who leave Facebook (the ser­vice) re­main trapped by Facebook (the com­pany).

At this point, Facebook — Zuckerberg — turns to­wards the rest of the world. Suddenly, ac­quir­ing non-US users be­comes a mat­ter of ur­gency, and overnight Wynn-Williams is trans­formed from the sole weirdo talk­ing about global mar­kets to the key as­set in pur­suit off the com­pa­ny’s top pri­or­ity.

Wynn-Williams’s ex­pla­na­tion for this shift lies in Zuckerberg’s per­son­al­ity, his need to con­stantly dom­i­nate (which is also why his sub­or­di­nates have learned to let him win at board games). This is doubt­less true: not only has this as­pect of Zuckerberg’s per­son­al­ity been on dis­play in pub­lic for decades, Wynn-Williams was able to ob­serve it first-hand, be­hind closed doors.

But I think that in ad­di­tion to this per­son­al­ity de­fect, there’s a ma­te­r­ial pres­sure for Facebook to grow that Wynn-Williams does­n’t men­tion. Companies that grow get ex­tremely high price-to-earn­ings (P:E) ra­tios, mean­ing that in­vestors are will­ing to spend many dol­lars on shares for every dol­lar the com­pany takes in. Two sim­i­lar com­pa­nies with sim­i­lar earn­ings can have vastly dif­fer­ent val­u­a­tions (the value of all the stock the com­pany has ever is­sued), de­pend­ing on whether one of them is still grow­ing.

High P:E ra­tios re­flect a bet on the part of in­vestors that the com­pany will con­tinue to grow, and those bets only be­come more ex­trav­a­gant the more the com­pany grows. This is a huge ad­van­tage to com­pa­nies with growth stocks.” If your shares con­stantly in­crease in value, they are highly liq­uid — that is, you can al­ways find some­one who’s will­ing to buy your shares from you for cash, which means that you can treat shares like cash. But growth stocks are bet­ter than cash, be­cause money grows slowly, if at all (especially in pe­ri­ods of ex­tremely low in­ter­est rates, like the past 15+ years). Growth stocks, on the other hand, grow.

Best of all, com­pa­nies with growth stocks have no trou­ble find­ing more stock when they need it. They just type ze­roes into a spread­sheet and more shares ap­pear. Contrast this with money. Facebook may take in a lot of money, but the money only ar­rives when some­one else spends it. Facebook’s ac­cess to money is lim­ited by ex­oge­nous fac­tors — your will­ing­ness to send your money to Facebook. Facebook’s ac­cess to shares is only lim­ited by en­doge­nous fac­tors — the com­pa­ny’s own will­ing­ness to is­sue new stock.

That means that when Facebook needs to buy some­thing, there’s a very good chance that the seller will ac­cept Facebook’s stock in lieu of US dol­lars. Whether Facebook is hir­ing a new em­ployee or buy­ing a com­pany, it can out­bid ri­vals who only have dol­lars to spend, be­cause that bid­der has to ask some­one else for more dol­lars, whereas Facebook can make its own stock on de­mand. This is a mas­sive com­pet­i­tive ad­van­tage.

But it is also a mas­sive busi­ness risk. As Stein’s Law has it, anything that can’t go on for­ever even­tu­ally stops.” Facebook can’t grow for­ever by sign­ing up new users. Eventually, every­one who might con­ceiv­ably have a Facebook ac­count will get one. When that hap­pens, Facebook will need to find some other way to make money. They could en­shit­tify — that is, shift value from the com­pa­ny’s users and cus­tomers to it­self. They could in­vent some­thing new (like meta­verse, or AI). But if they can’t make those things work, then the com­pa­ny’s growth will have ended, and it will in­stan­ta­neously be­come grossly over­val­ued. Its P:E ra­tio will have to shift from the high value en­joyed by growth stocks to the low value en­dured by mature” com­pa­nies.

When that hap­pens, any­one who is slow to sell will lose a ton of money. So in­vestors in growth stocks tend to keep one fist poised over the sell” but­ton and sleep with one eye open, watch­ing for any hint that growth is slow­ing. It’s not just that growth gives FB the power to out­com­pete ri­vals — it’s also the case that growth makes the com­pany vul­ner­a­ble to mas­sive, sud­den de­val­u­a­tions. What’s more, if these de­val­u­a­tions are per­sis­tent and/​or fre­quent enough, the key FB em­ploy­ees who ac­cepted stock in lieu of cash for some or all of their com­pen­sa­tion will ei­ther de­mand lots more cash, or jump ship for a grow­ing ri­val. These are the very same peo­ple that Facebook needs to pull it­self out of its nose­dives. For a growth stock, even small re­duc­tions in growth met­rics (or worse, de­clines) can trig­ger cas­cades of com­pound­ing, mu­tu­ally re­in­forc­ing col­lapse.

This is what hap­pened in early 2022, when Meta posted slightly lower-than-an­tic­i­pated US growth num­bers, and the mar­ket all pounded on the sell” but­ton at once, lop­ping $250,000,000,000 of the com­pa­ny’s val­u­a­tion in 24 hours. At the time, it was the worst-ever sin­gle day losses for any com­pany in hu­man his­tory:

Facebook’s con­quest of the US mar­ket trig­gered an em­pha­sis on for­eign cus­tomers, but not just be­cause Zuck is ob­sessed with con­quest. For Facebook, a de­cline in US growth posed an ex­is­ten­tial risk, the pos­si­bil­ity of mass stock sell­offs and with them, the end of the years in which Facebook could ac­quire key cor­po­rate ri­vals and ex­ec­u­tives with money” it could print on the premises, on de­mand.

So Facebook cast its eye upon the world, and Wynn-Williams’s long in­sis­tence that the com­pany should be pay­ing at­ten­tion to the po­lit­i­cal sit­u­a­tion abroad sud­denly starts land­ing with her bosses. But those bosses — Zuck, Sandberg, Kaplan and oth­ers — are careless.” Zuck screws up op­por­tu­nity af­ter op­por­tu­nity be­cause he re­fuses to be briefed, for­gets what lit­tle in­for­ma­tion he’s been given, and blows key meet­ings be­cause he re­fuses to get out of bed be­fore noon. Sandberg’s vis­its to Davos are un­der­mined by her re­lent­less need to pro­mote her­self, her Lean In” brand, and her petty games­man­ship. Kaplan is the liv­ing em­bod­i­ment of Green Day’s American Idiot” and can barely fathom that for­eign­ers ex­ist.

Wynn-Williams’s ad­ven­tures dur­ing this pe­riod are very well told, and are, by turns, har­row­ing and hi­lar­i­ous. Time and again, Facebook’s top brass snatch de­feat from the jaws of vic­tory, squan­der­ing in­cred­i­ble op­por­tu­ni­ties that Wynn-Williams se­cures for them be­cause of their pet­ti­ness, short-sight­ed­ness, and ar­ro­gance (that is, their care­less­ness).

But Wynn-Williams’s dis­il­lu­sion­ment with Facebook is­n’t rooted in these frus­tra­tions. Rather, she is both per­son­ally and pro­fes­sion­ally aghast at the com­pa­ny’s dis­gust­ing, cal­lous and cruel be­hav­ior. She de­scribes how her boss, Joel Kaplan, re­lent­lessly sex­u­ally ha­rasses her, and every­one in a po­si­tion to make this stop tells her to shut up and take it. When Wynn-Williams give birth to her sec­ond child, she he­m­or­rhages, al­most dies, and ends up in a coma. Afterwards, Kaplan gives her a neg­a­tive per­for­mance re­view be­cause she was unresponsive” to his emails and texts while she was dy­ing in an ICU. This is a sig­nif­i­cant es­ca­la­tion of the ear­lier be­hav­ior she de­scribes, like pes­ter­ing her with per­sonal ques­tions about breast­feed­ing, video-call­ing her from bed, and so on (Kaplan is Sandberg’s ex-boyfriend, and Wynn-Williams de­scribes an­other creepy event where Sandberg pres­sures her to sleep next to her in the bed­room on one of Facebook’s jets, some­thing Wynn-Williams says she rou­tinely does with the young women who re­port to her).

Meanwhile, Zuck is re­lent­lessly pur­su­ing Facebook’s largest con­ceiv­able growth mar­ket: China. The only prob­lem: China does­n’t want Facebook. Zuck re­peat­edly tries to en­gi­neer meet­ings with Xi Jinping so he can plead his case in per­son. Xi is mon­u­men­tally hos­tile to this idea. Zuck learns Mandarin. He stud­ies Xi’s book, con­spic­u­ously dis­plays a copy of it on his desk. Eventually, he man­ages to sit next to Xi at a din­ner where he begs Xi to name his next child. Xi turns him down.

After years of per­sis­tent nag­ging, lob­by­ing, and grov­el­ing, Facebook’s China ex­ecs start to make progress with a state ap­pa­ratchik who dan­gles the pos­si­bil­ity of Facebook en­ter­ing China. Facebook promises this fac­to­tum the world — all the sur­veil­lance and cen­sor­ship the Chinese state wants and more. Then, Facebook’s con­tact in China is jailed for cor­rup­tion, and they have to start over.

At this point, Kaplan has pun­ished Wynn-Williams — she blames it on her at­tempts to get oth­ers to force him to stop his sex­ual ha­rass­ment — and cut her re­spon­si­bil­i­ties in half. He tries to ma­neu­ver her into tak­ing over the China op­er­a­tion, some­thing he knows she ab­solutely dis­ap­proves of and has re­fused to work on — but she re­fuses. Instead, she is put in charge of hir­ing the new chief of China op­er­a­tions, giv­ing her ac­cess to a vo­lu­mi­nous pa­per-trail de­tail­ing the com­pa­ny’s deal­ings with the Chinese gov­ern­ment.

According to Wynn-Williams, Facebook ac­tu­ally built an ex­ten­sive cen­sor­ship and sur­veil­lance sys­tem for the Chinese state — spies, cops and mil­i­tary — to use against Chinese Facebook users, and FB users glob­ally. They promise to set up caches of global FB con­tent in China that the Chinese state can use to mon­i­tor all Facebook ac­tiv­ity, every­where, with the im­pli­ca­tion that they’ll be able to spy on pri­vate com­mu­ni­ca­tions, and cen­sor con­tent for non-Chi­nese users.

Despite all of this, Facebook is never given ac­cess to China. However, the Chinese state is able to use the tools Facebook built for it to at­tack in­de­pen­dence move­ments, the free press and dis­si­dent up­ris­ings in Hong Kong and Taiwan.

Meanwhile, in Myanmar, a geno­cide is brew­ing. NGOs and hu­man rights ac­tivists keep reach­ing out to Facebook to get them to pay at­ten­tion to the wide­spread use of the plat­form to whip up ha­tred against the coun­try’s Muslim mi­nor­ity group, the Rohinga. Despite hav­ing ex­pended tremen­dous amounts of en­ergy to roll out Free Basics” in Myanmar (a pro­gram whereby Facebook bribes car­ri­ers to ex­clude its own ser­vices from data caps), with the re­sult that in Myanmar, the in­ter­net” is syn­ony­mous with Facebook,” the com­pany has not ex­pended any ef­fort to man­age its Burmese pres­ence. The en­tire mod­er­a­tion staff con­sists of one (later two) Burmese speak­ers who are based in Dublin and do not work lo­cal hours (later, these two are re­vealed as likely stooges for the Myanmar mil­i­tary junta, who are be­hind the geno­cide plans).

The com­pany has also failed to in­vest in Burmese lan­guage sup­port for its sys­tems — posts writ­ten in Burmese script are not stored as Unicode, mean­ing that none of the com­pa­ny’s au­to­mated mod­er­a­tion sys­tems can parse it. The com­pany is so hos­tile to pleas to up­grade these sys­tems that Wynn-Williams and some col­leagues cre­ate se­cret, pri­vate Facebook groups where they can track the fail­ures of the com­pany and the ris­ing tide of lethal vi­o­lence in the coun­try (this is­n’t the only se­cret dis­si­dent Facebook group that Wynn-Williams joins — she’s also part of a group of women who have been sex­u­ally ha­rassed by col­leagues and bosses).

The geno­cide that fol­lows is hor­rific be­yond mea­sure. And, as with the Trump elec­tion, the com­pa­ny’s ini­tial pos­ture is that they could­n’t pos­si­bly have played a sig­nif­i­cant role in a real-world event that shocked and hor­ri­fied its rank-and-file em­ploy­ees.

The com­pany, in other words, is careless.” Warned of im­mi­nent harms to its users, to democ­racy, to its own em­ploy­ees, the top ex­ec­u­tives sim­ply do not care. They ig­nore the warn­ings and the con­se­quences, or pay lip ser­vice to them. They don’t care.

Take Kaplan: af­ter fig­ur­ing out that the com­pany can’t curry fa­vor with the world’s gov­ern­ments by sell­ing drone-de­liv­ered wifi to refugees (the drones don’t fly and the refugees are broke), he hits on an­other strat­egy. He re­makes government re­la­tions” as a sales of­fice, sell­ing po­lit­i­cal ads to politi­cians who are seek­ing to win over vot­ers, or, in the case of au­toc­ra­cies, dis­en­fran­chised hostage-cit­i­zens. This is hugely suc­cess­ful, both as a sys­tem for se­cur­ing gov­ern­ment co­op­er­a­tion and as a way to trans­form Facebook’s global pol­icy shop from a cost-cen­ter to a profit-cen­ter.

But of course, it has a price. Kaplan’s best cus­tomers are dic­ta­tors and would-be dic­ta­tors, for­menters of ha­tred and geno­cide, au­thor­i­tar­i­ans seek­ing op­por­tu­ni­ties to purge their op­po­nents, through ex­ile and/​or mur­der.

Wynn-Williams makes a very good case that Facebook is run by aw­ful peo­ple who are also very care­less — in the sense of be­ing reck­less, in­cu­ri­ous, in­dif­fer­ent.

But there’s an­other mean­ing to careless” that lurks just be­low the sur­face of this ex­cel­lent mem­oir: careless” in the sense of arrogant” — in the sense of not car­ing about the con­se­quences of their ac­tions.

To me, this was the most im­por­tant — but least-de­vel­oped — les­son of Careless People. When Wynn-Williams lands at Facebook, she finds her­self sur­rounded by oafs and so­ciopaths, car­toon­ishly self­ish and shitty peo­ple, who, nev­er­the­less, have built a ser­vice that she loves and val­ues, along with hun­dreds of mil­lions of other peo­ple.

She’s not wrong to be ex­cited about Facebook, or its po­ten­tial. The com­pany may be run by care­less peo­ple, but they are still pru­dent, be­hav­ing as though the con­se­quences of screw­ing up mat­ter. They are careless” in the sense of being reck­less,” but they care, in the sense of hav­ing a healthy fear (and thus re­spect) for what might hap­pen if they fully yield to their reck­less im­pulses.

Wynn-Williams’s first­hand ac­count of the next decade is not a story of these peo­ple be­com­ing more reck­less, rather, it’s a story in which the pos­si­bil­ity of con­se­quences for that reck­less­ness re­cedes, and with it, so does their care over those con­se­quences.

Facebook buys its com­peti­tors, free­ing it from mar­ket con­se­quences for its bad acts. By buy­ing the places where dis­af­fected Facebook users are seek­ing refuge — Instagram and Whatsapp — Facebook is able to in­su­late it­self from the dis­ci­pline of com­pe­ti­tion — the fear that do­ing things that are ad­verse to its users will cause them to flee.

Facebook cap­tures its reg­u­la­tors, free­ing it from reg­u­la­tory con­se­quences for its bad acts. By play­ing a cen­tral role in the elec­toral cam­paigns of Obama and then other politi­cians around the world, Facebook trans­forms its watch­dogs into sup­pli­cants who are more apt to beg it for fa­vors than hold it to ac­count.

Facebook tames its em­ploy­ees, free­ing it from la­bor con­se­quences for its bad acts. As en­gi­neer­ing sup­ply catches up with de­mand, Facebook’s lead­er­ship come to re­al­ize that they don’t have to worry about work­force up­ris­ings, whether in­cited by im­punity for sex­u­ally abu­sive bosses, or by the com­pa­ny’s com­plic­ity in geno­cide and au­to­cratic op­pres­sion.

First, Facebook be­comes too big to fail.

Then, Facebook be­comes too big to jail.

Finally, Facebook be­comes too big to care.

This is the carelessness” that ul­ti­mately changes Facebook for the worse, that turns it into the hellscape that Wynn-Williams is even­tu­ally fired from af­ter she speaks out once too of­ten. Facebook bosses aren’t just careless” be­cause they refuse to read a brief­ing note that’s longer than a tweet. They’re careless” in the sense that they ar­rive at a junc­ture where they don’t have to care who they harm, whom they en­rage, who they ruin.

There’s a telling anaec­dote near the end of Careless People. Back in 2017, leaks re­vealed that Facebook’s sales-reps were promis­ing ad­ver­tis­ers the abil­ity to mar­ket to teens who felt de­pressed and worthless”:

Wynn-Williams is — rightly — aghast about this, and even more aghast when she sees the com­pa­ny’s of­fi­cial re­sponse, in which they dis­claim any knowl­edge that this ca­pa­bil­ity was be­ing de­vel­oped and fire a ran­dom, low-level scape­goat. Wynn-Williams knows they’re ly­ing. She knows that this is a rou­tine of­fer­ing, one that the com­pany rou­tinely boasts about to ad­ver­tis­ers.

But she does­n’t men­tion the other lies that Facebook tells in this mo­ment: for one thing, the com­pany of­fers ad­ver­tis­ers the power to tar­get more teens than ac­tu­ally ex­ist. The com­pany pro­claims the ef­fi­cacy of its sentiment analy­sis” tool that knows how to tell if teens are feel­ing de­pressed or worthless,” even though these tools are no­to­ri­ously in­ac­cu­rate, hardly bet­ter than a coin-toss, a kind of dig­i­tal phrenol­ogy.

Facebook, in other words, is­n’t just ly­ing to the pub­lic about what it of­fers to ad­ver­tis­ers — it’s ly­ing to ad­ver­tis­ers, too. Contra those who say, if you’re not pay­ing for the prod­uct, you’re the prod­uct,” Facebook treats any­one it can get away with abus­ing as the prod­uct” (just like every other tech mo­nop­o­list):

Wynn-Williams doc­u­ments so many in­stances in which Facebook’s top ex­ec­u­tives lie — to the courts, to Congress, to the UN, to the press. Facebook lies when it is ben­e­fi­cial to do so — but only when they can get away with it. By the time Facebook was ly­ing to ad­ver­tis­ers about its de­pressed teen tar­get­ing tools, it was al­ready col­lud­ing with Google to rig the ad mar­ket with an il­le­gal tool called Jedi Blue”:

Facebook’s story is the story of a com­pany that set out to be­come too big to care, and achieved that goal. The com­pa­ny’s abuses track pre­cisely with its mar­ket dom­i­nance. It en­shit­ti­fied things for users once it had the users locked in. It screwed ad­ver­tis­ers once it cap­tured their mar­ket. It did the me­dia-in­dus­try-de­stroy­ing pivot to video” fraud once it cap­tured the me­dia:

The im­por­tant thing about Facebook’s care­less­ness is that it was­n’t the re­sult of the many grave per­son­al­ity de­fects in Facebook’s top ex­ec­u­tives — it was the re­sult of pol­icy choices. Government de­ci­sions not to en­force an­titrust law, to al­low pri­vacy law to wither on the vine, to ex­pand IP law to give Facebook a weapon to shut down in­ter­op­er­a­ble ri­vals — these all cre­ated the en­shit­to­genic en­vi­ron­ment that al­lowed the care­less peo­ple who run Facebook to stop car­ing.

The corol­lary: if we change the pol­icy en­vi­ron­ment, we can make these care­less peo­ple — and their suc­ces­sors, who run other busi­nesses we rely upon — care. They may never care about us, but we can make them care about what we might do to them if they give in to their care­less­ness.

Meta is in global reg­u­la­tory crosshairs, fac­ing an­titrust ac­tion in the USA:

And mus­cu­lar en­force­ment pledges in the EU:

The law can­not make a man love me, but it can stop him from lynch­ing me, and I think that’s pretty im­por­tant.

What Happens When Private Equity Owns Your Kid’s Day Care https://​ja­cobin.com/​2025/​04/​pri­vate-eq­uity-day-care-child­care/

#15yrsago India’s copy­right bill gets it right https://​web.archive.org/​web/​20100425031519/​https://​www.michael­geist.ca/​con­tent/​view/​4974/​196/

#15yrsago Hitler’s pissed off about fair use https://​www.youtube.com/​watch?v=kBO5d­h9qrIQ

#5yrsago Unmasking the reg­is­trants of the reopen” web­sites https://​plu­ral­is­tic.net/​2020/​04/​22/​fil­ter­net/#​krebs

#1yrago Paying for it does­n’t make it a mar­ket https://​plu­ral­is­tic.net/​2024/​04/​22/​kargo-kult-kap­tial­ism/#​dont-buy-it

* Can we use the Internet for Democracy?

https://​www.youtube.com/​watch?v=Zh_HON6iql8

* Enshittification: Why Everything Suddenly Got Worse and What to Do About It, Farrar, Straus, Giroux, October 7 2025

https://​us.macmil­lan.com/​books/​9780374619329/​en­shit­ti­fi­ca­tion/

Unauthorized Bread: a mid­dle-grades graphic novel adapted from my novella about refugees, toast­ers and DRM, FirstSecond, 2026

Enshittification, Why Everything Suddenly Got Worse and What to Do About It (the graphic novel), Firstsecond, 2026

* Enshittification: a non­fic­tion book about plat­form de­cay for Farrar, Straus, Giroux. Status: sec­ond pass edit un­der­way (readaloud)

Picks and Shovels, a Martin Hench noir thriller about the heroic era of the PC. FORTHCOMING TOR BOOKS FEB 2025

This work — ex­clud­ing any se­ri­al­ized fic­tion — is li­censed un­der a Creative Commons Attribution 4.0 li­cense. That means you can use it any way you like, in­clud­ing com­mer­cially, pro­vided that you at­tribute it to me, Cory Doctorow, and in­clude a link to plu­ral­is­tic.net.

Quotations and im­ages are not in­cluded in this li­cense; they are in­cluded ei­ther un­der a lim­i­ta­tion or ex­cep­tion to copy­right, or on the ba­sis of a sep­a­rate li­cense. Please ex­er­cise cau­tion.

When life gives you SARS, you make sar­sa­par­illa” -Joey Accordion Guy” DeVilla

READ CAREFULLY: By read­ing this, you agree, on be­half of your em­ployer, to re­lease me from all oblig­a­tions and waivers aris­ing from any and all NON-NEGOTIATED agree­ments, li­censes, terms-of-ser­vice, shrinkwrap, click­wrap, browsewrap, con­fi­den­tial­ity, non-dis­clo­sure, non-com­pete and ac­cept­able use poli­cies (“BOGUS AGREEMENTS) that I have en­tered into with your em­ployer, its part­ners, li­cen­sors, agents and as­signs, in per­pe­tu­ity, with­out prej­u­dice to my on­go­ing rights and priv­i­leges. You fur­ther rep­re­sent that you have the au­thor­ity to re­lease me from any BOGUS AGREEMENTS on be­half of your em­ployer.

...

Read the original on pluralistic.net »

2 645 shares, 29 trendiness

I wrote to the address in the GPLv2 license notice and received the GPLv3 license

Dealing with open source soft­ware, I reg­u­larly en­counter many kinds of li­censes — MIT, Apache, BSD, GPL be­ing the most promi­nent — and I’ve taken time out to read them. Of the many, the GNU General Public License (GPL) stands out the most. It reads like a let­ter to the reader rather than legalese, and feels quite in tune with the spirit of open source and soft­ware free­dom.

Although GPLv3 is the most cur­rent ver­sion, I com­monly en­counter soft­ware that makes use of GPLv2. I got cu­ri­ous about the last line in its li­cense no­tice:

You should have re­ceived a copy of the GNU General Public License

along with this pro­gram; if not, write to the Free Software

Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

Why does this li­cense no­tice have a phys­i­cal ad­dress, and not a URL? After all, even though the full li­cense does­n’t of­ten get in­cluded with soft­ware, it’s a sim­ple mat­ter to do a search and find the text of the GPLv2. Do peo­ple write to this ad­dress, and what hap­pens if you do?

I turned to the Open Source Stack Exchange and got a very help­ful an­swer. It’s be­cause the GPLv2 was pub­lished in 1991, and most peo­ple were not on­line. Most peo­ple would have ac­quired soft­ware through phys­i­cal me­dia (such as tape or flop­pies) rather than a down­load.

Considering the stor­age con­straints back then, it would­n’t be sur­pris­ing if de­vel­op­ers only in­cluded the li­cense no­tice, and not the en­tire li­cense. It makes sense that the most com­mon form of com­mu­ni­ca­tion would have been through post.

The GPLv3, pub­lished in 2007, does con­tain a URL in the li­cense no­tice since Internet us­age was more wide­spread at the time.

I de­cided to write to the ad­dress to see what would hap­pen. To do that, I would need some stamps and en­velopes (I found one at my work­place) to send the re­quest, and a self ad­dressed en­veloped with an in­ter­na­tional re­ply coupon to cover the cost of the re­ply.

I was dis­ap­pointed to find out that the UKs Royal Mail dis­con­tin­ued in­ter­na­tional re­ply coupons in 2011. The only al­ter­na­tive that I could think of was to buy some US stamps.

The eas­i­est place to look for US stamps was on Ebay. I did­n’t re­al­ize that I was step­ping briefly into the world of phi­lat­ely; most stamp list­ings on Ebay were cov­ered in phrases and ter­mi­nol­ogy such as very fine grade, MNH (Mint Never Hinged), FDC (First Day Cover), NDC (No Die Cut), NDN (Nondenominated), and so on. It’s pretty easy to glean that these are prop­er­ties that col­lec­tors would be look­ing for.

I or­dered what seemed to be a global’ stamp, for the small­est but safest amount that I could (about £3.86). The list­ing men­tioned that it was uncertified’ which was mildly un­nerv­ing, did that mean it was an in­valid stamp? I de­cided to chance it, and quickly ex­ited that world.

After a few weeks of wait­ing, I even­tu­ally re­ceived the African Daisy global for­ever vert pair’ stamp which was round! I should have no­ticed that the seller sent me the item us­ing stamps at a much lower de­nom­i­na­tion that those I had or­dered. Oh well.

With the self ad­dressed en­ve­lope ready, I wrote the re­quest and ad­dressed it to the GPLv2 ad­dress. Luckily I did have some UK stamps avail­able to send the let­ter with.

Writing the ad­dress on the en­ve­lope was awk­ward, as I haven’t used a pen in sev­eral years; it took a few at­tempts and some wasted en­velopes, print­ing the ad­dress would have taken less time. But it was ready so I posted it in my near­est Royal Mail box.

I had posted the let­ter in June 2022 and about five later weeks later, I re­ceived a re­ply. The round stamps looked suf­fi­ciently stamped upon with wavy lines, known as can­cel­la­tion marks, which are yet an­other thing that phi­lat­e­lists like to col­lect!

Anyway the let­ter in­side con­tained the full li­cense text on 5 sheets of dou­ble-sided pa­per.

The first thing that came to at­ten­tion, the pa­per that the text was printed on was­n’t an A4, it was smaller and not a size I was fa­mil­iar with. I mea­sured it and found that it’s a US let­ter size pa­per at about 21.5cm x 27.9cm. I com­pletely for­got that the US, Canada, and a few other coun­tries don’t fol­low the stan­dard in­ter­na­tional pa­per sizes, even though I had writ­ten about it ear­lier.

There was a prob­lem that I no­ticed right away, though: this text was from the GPL v3, not the GPL v2. In my orig­i­nal re­quest I had never men­tioned the GPL ver­sion I was ask­ing about.

The orig­i­nal li­cense no­tice makes no men­tion of GPL ver­sion ei­ther. Should the fact that the li­cense no­tice con­tained an ad­dress have been enough meta­data or a clue, that I was ac­tu­ally re­quest­ing the GPL v2 li­cense? Or should I have men­tioned that I was seek­ing the GPLv2 li­cense?

I could choose to pur­sue by writ­ing again and re­quest­ing the right thing, but it would take too much ef­fort to fol­low up on, and I’m over­all sat­is­fied with what I re­ceived. As a postal in­tro­vert, I will now need a long pe­riod of rest to re­coup.

...

Read the original on code.mendhak.com »

3 487 shares, 22 trendiness

Mark Zuckerberg Says Social Media Is Over

What, ex­actly, does a so­cial net­work do? Is it a web­site that con­nects peo­ple with one an­other on­line, a dig­i­tal gath­er­ing place where we can con­sume con­tent posted by our friends? That’s cer­tainly what it was in its hey­day, in the two-thou­sands. Facebook was where you might find out that your friend was dat­ing some­one new, or that some­one had thrown a party with­out invit­ing you. In the course of the past decade, though, so­cial me­dia has come to re­sem­ble some­thing more like reg­u­lar me­dia. It’s where we find pro­mo­tional videos cre­ated by celebri­ties, pun­dits shout­ing re­sponses to the news, ag­gre­gated clips from pop cul­ture, a ris­ing tide of A. I.-generated slop, and other con­tent de­signed to be broad­cast to the largest num­ber of view­ers pos­si­ble. The peo­ple we fol­low and the mes­sages they post in­creas­ingly feel like nee­dles in a dig­i­tal haystack. Social me­dia has be­come less so­cial.

Facebook’s founder, Mark Zuckerberg, ad­mit­ted as much dur­ing more than ten hours of tes­ti­mony, over three days last week, in the open­ing phase of the Federal Trade Commission’s an­titrust trial against Facebook’s par­ent com­pany, Meta. The com­pany, Zuckerberg said, has lately been in­volved in the gen­eral idea of en­ter­tain­ment and learn­ing about the world and dis­cov­er­ing what’s go­ing on.” This un­der-rec­og­nized shift away from in­ter­per­sonal com­mu­ni­ca­tion has been mea­sured by the com­pany it­self. During the de­fense’s open­ing state­ment, Meta dis­played a chart show­ing that the percent of time spent view­ing con­tent posted by friends’ ” has de­clined in the past two years, from twenty-two per cent to sev­en­teen per cent on Facebook, and from eleven per cent to seven per cent on Instagram.

The F. T.C. is ar­gu­ing that Meta main­tained an il­le­gal mo­nop­oly in the personal so­cial net­work­ing ser­vices” in­dus­try, in part by buy­ing up Facebook’s com­peti­tors, such as Instagram, which the com­pany ac­quired in 2012, and the mes­sag­ing plat­form WhatsApp, which it ac­quired in 2014. But the F.T.C.’s de­f­i­n­i­tion of the so­cial-me­dia in­dus­try is hazy, and the an­titrust case was al­ready dis­missed once, in 2021, partly be­cause the personal so­cial net­work­ing ser­vices” mar­ket was too loosely de­fined. Meta’s counter-ar­gu­ment is, in a sense, that so­cial me­dia per se does­n’t ex­ist now in the way that it did in the twenty-tens, and that what the com­pa­ny’s plat­forms are now known for—the dig­i­tal con­sump­tion of all kinds of con­tent—has be­come so wide­spread that no sin­gle com­pany or plat­form can be said to mo­nop­o­lize it. In one of its slides at trial, Meta ex­hib­ited a graphic of a box­ing ring show­ing the lo­gos of Instagram, Facebook, and the var­i­ous com­pa­nies that Meta ar­gues are com­peti­tors, in­clud­ing TikTok, YouTube, and Apple’s iMes­sage, though the F.T.C. does­n’t de­fine any of those three as such. The com­pany also used smart­phone screen­shots from the var­i­ous apps to demon­strate how they’ve grav­i­tated to­ward com­mon for­mats: short video clips look sim­i­lar on both Instagram and TikTok; mes­sages look es­sen­tially the same in Instagram DMs as on Apple’s iMes­sage. Even as such sim­i­lar­i­ties serve as help­ful ev­i­dence for Meta’s de­fense, they also demon­strate how stul­ti­fy­ing the en­tire on­line ecosys­tem has be­come. While in 2012 Facebook may have seemed sin­gu­lar and in­escapable, now it looks like part of a crowded mar­ket­place of apps com­pet­ing to serve the same pur­pose.

The F. T.C.’s case, which orig­i­nated dur­ing Donald Trump’s first term, en­tails reë­val­u­at­ing busi­ness deals that it ap­proved more than a decade ago, when the in­dus­try looked dra­mat­i­cally dif­fer­ent. This makes the com­mis­sion’s case less than air­tight. Benedict Evans, an in­flu­en­tial tech­nol­ogy an­a­lyst, called the F.T.C.’s mar­ket de­f­i­n­i­tion of so­cial net­works gerrymandering.” He told me, By the F.T.C.’s de­f­i­n­i­tion, TikTok does­n’t com­pete with Facebook at all. Does that mean it would be O.K. for Facebook to buy TikTok?” Antitrust lawyers must prove that al­legedly mo­nop­o­lis­tic prac­tices cause con­sumer harm. In an­other an­titrust case cur­rently un­fold­ing against Google, a court found that the com­pany main­tained a mo­nop­oly over parts of the on­line-ad­ver­tis­ing mar­ket by in­te­grat­ing its var­i­ous au­to­mated ad­ver­tis­ing tech­nolo­gies, il­le­gally priv­i­leg­ing it­self and harm­ing its pub­lish­ing cus­tomers by reducing their rev­enue.” In the case of Meta, though, there is no price dif­fer­en­tial to point to—Meta’s plat­forms all al­low users to ac­cess them for free—so the ques­tion of harm is less clear-cut.

The F. T.C. is ar­gu­ing, in­stead, that Meta’s pur­ported mo­nop­oly has led to a lack of in­no­va­tion and to re­duced con­sumer choice. But that, too, is dif­fi­cult to prove in the case of Meta’s WhatsApp and Instagram ac­qui­si­tions, be­cause both sales oc­curred early in those com­pa­nies’ life spans. In 2014, when WhatsApp was ac­quired, it had around half a bil­lion users; now it has more than two bil­lion. As Evans put it, the F.T.C. is ar­gu­ing that if Meta had­n’t bought WhatsApp, it would have be­come this vo­ra­cious com­peti­tor.” He con­tin­ued, What we all ac­tu­ally know from fol­low­ing the his­tory is that the founders of WhatsApp did­n’t want to do any of the things that Meta did to fuel its run­away ex­pan­sion. One of WhatsApp’s founders once com­pared the ser­vice’s goals to those of Craigslist, Zuckerberg re­called dur­ing his tes­ti­mony. Meta, by con­trast, ag­gres­sively pur­sued growth, load­ing WhatsApp with fea­tures such as so­cial groups and video calls. The F.T.C. notes that mar­ket com­pe­ti­tion can re­sult in improved fea­tures, func­tion­al­i­ties, in­tegrity mea­sures, and user ex­pe­ri­ences”; it’s hard to mount a per­sua­sive ar­gu­ment that an in­de­pen­dent WhatsApp would nec­es­sar­ily have pro­vided more of those things than a Zuckerberg-owned one. (Many so­cial net­works fail; Path and Google+ were two other threats that Zuckerberg per­ceived, but nei­ther grew into a vi­able com­peti­tor. He did at one point at­tempt to buy Snapchat, and though that com­pany sur­vived, it failed to be­come a ma­jor ri­val.)

One of the most sur­pris­ing mo­ments in Zuckerberg’s tes­ti­mony came when the F. T.C. pre­sented him with a memo that he sent to com­pany ex­ec­u­tives, in 2018, sug­gest­ing that it might be bet­ter to spin Instagram into its own en­tity by choice. Zuckerberg wrote that Instagram was po­ten­tially un­der­min­ing Facebook’s suc­cess, and that busi­nesses that are in­de­pen­dent of­ten per­form bet­ter than they would within a par­ent con­glom­er­ate. Over time we may face an­titrust reg­u­la­tion re­quir­ing us to spin off our other apps any­way,” he noted, with some pre­science. Seven years ago, be­fore the ad­vent of TikTok and the di­ver­si­fi­ca­tion of con­tent across dig­i­tal plat­forms, that kind of split might have re­sulted in more var­ied prod­ucts for users, more quickly—or it might not have. Either way, the so­cial-me­dia land­scape to­day is ar­guably in the midst of a dra­matic over­haul. TikTok may ul­ti­mately be banned; gen­er­a­tive A.I. may sup­plant the ex­ist­ing model of an open, user-gen­er­ated in­ter­net. On April 15th, the Verge broke the news that OpenAI is de­vel­op­ing a so­cial net­work of its own, to com­pete with the likes of Instagram and X. The F.T.C. may be chas­ing an old prob­lem just as newer, big­ger ones ap­pear on the hori­zon.

This week, the European Union fined Apple and Meta for an­ti­com­pet­i­tive prac­tices, but the penal­ties—five hun­dred mil­lion eu­ros and two hun­dred mil­lion eu­ros, re­spec­tively—are rel­a­tively mod­est. If the U. S. case pre­vails, the F.T.C. will have to de­cide whether to force a whole­sale breakup of Meta or seek less dra­matic remedies.” One fac­tor in this cal­cu­lus might be the wishes of President Trump. In re­cent months, Zuckerberg has vis­ited the White House re­peat­edly, and he’s in­gra­ti­ated him­self to the Administration with moves, at Meta, against D.E.I. and fact-check­ing. So far, de­spite a grow­ing close­ness with Silicon Valley, Trump has nev­er­the­less con­tin­ued to back the suit against Meta. As in the Administration’s on­go­ing trade war, Trump ap­pre­ci­ates a pro­nounced threat as a tool to force a deal. Bytedance, the owner of TikTok, has all but ca­pit­u­lated to a man­dated sale of a ma­jor­ity of the com­pany. With re­gard to Trump, at least, Zuckerberg might be ex­pected to ca­pit­u­late one way or an­other. ♦

...

Read the original on www.newyorker.com »

4 391 shares, 18 trendiness

On loyalty to your employer — Talent Stuff

Skip to Content

On loy­alty to your em­ployer

Note: This post orig­i­nally ap­peared in HackerNoon in 2018. I’m re­pub­lish­ing it here in or­der to pre­serve and share the orig­i­nal piece.

I’ve just re­turned to London hav­ing spent the past two weeks back home in Cork where I spent an aw­ful lot of time with my fa­ther, a man who set up his first ever email ac­count less than a year ago and has spent the past 30 years work­ing for the same em­ployer. My Dad is the an­tithe­sis of the tech in­dus­try in every sense. Considering the av­er­age career’ with each em­ployer in the tech in­dus­try is a touch un­der three years, the idea of spend­ing 30 years work­ing for the same em­ployer is mind bog­gling. Despite this enor­mous dis­par­ity, I’m con­stantly wit­ness to col­leagues in the tech in­dus­try post­ing on LinkedIn about how great their em­ployer is and why every­one should drop every­thing and come and work with them, only for them to an­nounce a few short years later that they are mov­ing on to big­ger and bet­ter things”.I’m go­ing to be the first to hold my hands up and ad­mit to be­ing ex­tremely guilty of do­ing ex­actly that on a reg­u­lar ba­sis in the past. I work in re­cruit­ment. Employers pay me a lot of money to wax lyri­cal about how great they are. They pay me to con­vince you that the grass is not only greener, but their grass is more flex­i­ble and in­clu­sive too. So how do I rec­on­cile my ap­a­thy to­wards every em­ployer claim­ing to be the best, and my abil­ity to do a good job?My cri­te­ria for vet­ting an em­ployer worth work­ing with is very straight­for­ward. Anything be­yond these four cri­te­ria is a bonus (and ex­tremely sub­jec­tive) but the four cri­te­ria be­low are my ab­solute zero com­pro­mise cri­te­ria.Do you pay rea­son­able salaries?

Fortunately, due to my line of work, ask­ing for specifics around salaries is par for the course and not some­thing an em­ployer can eas­ily lie about. To put it sim­ply, if your salaries aren’t at least com­pet­i­tive then we’re wast­ing each oth­er’s time. Pay fairly or pay well and we’re off to a good start.Do you treat your peo­ple well?

Glassdoor is your friend. If there are a slew of neg­a­tive com­ments, look for con­sis­ten­cies. Were they all posted around the same time? Are there con­sis­tent themes? Raise these points and ask for the em­ploy­ers per­spec­tive. A qual­ity em­ployer will be hon­est and high­light what steps they took to ad­dress those is­sues. Not every com­pany has a help­ful Glassdoor pro­file (a lot of star­tups have yet to be re­viewed) so take to so­cial me­dia, and look up cur­rent and for­mer em­ploy­ees to see if there are any red flags.Are you fi­nan­cially se­cure?

This is startup 101 folks. Do your due dili­gence. Companies House, Crunchbase, etc are a good start. Enquire about their run­way (how long they can sur­vive if their cur­rent in­come and ex­penses stay con­stant). If they aren’t will­ing to be open and hon­est about their fi­nances, walk away im­me­di­ately.Are you open to try­ing new things?

This cri­te­ria is quite spe­cific to the work I do and may not be uni­ver­sally ap­plic­a­ble. If you’re ask­ing me to team up with you to im­prove your abil­ity to hire peo­ple then you cat­e­gor­i­cally need to be open and will­ing to try new things. No amount of money will be enough to con­vince me to join your com­pany and fol­low your same old tired recipe just be­cause it worked well a cou­ple of times in the past.If you hit all of the above cri­te­ria then I can do the thing that en­ables me to con­vince great peo­ple to work for your com­pany. I can be ab­solutely trans­par­ent and hon­est with peo­ple.

So you’ve landed a great job, the of­fice is in­cred­i­ble, the peo­ple seem su­per friendly, the money is good, the work is chal­leng­ing and life seems pretty great. Post pic­tures of your desk lit­tered with com­pany branded swag. Enjoy your­self but don’t de­lude your­self.

You are a trans­ac­tion. Sure, your em­ployer gives you the im­pres­sion they care about you but as soon as you start cost­ing the com­pany money or pose a risk to the com­pa­ny’s im­age or breach any other el­e­ment of your 300 page con­tract, then I can ab­solutely as­sure you that they will drop you in a heart­beat. You don’t even need to do any­thing wrong to be at risk. If the com­pany is strug­gling fi­nan­cially, due to no fault of yours, you and all your col­leagues are at risk. Suddenly the cor­po­rate line of we’re all fam­ily here” sounds a bit ridicu­lous.

Your em­ployer pays you to spend more time with them than you spend with your fam­ily and/​or loved ones. Your em­ployer is one of the biggest in­flu­encers on your men­tal well-be­ing. Your em­ployer can and will re­place you in a heart­beat if ab­solutely nec­es­sary.

Let me be ex­plic­itly clear, your em­ployer is­n’t your fam­ily and they are not your friend. They pay you to do a job and in re­turn your only re­spon­si­bil­ity is to do that job well.

Do not sac­ri­fice your re­la­tion­ship with fam­ily and friends to ap­pease your em­ployer.Do not sac­ri­fice your men­tal well­be­ing to ap­pease your em­ployer.Do not sac­ri­fice your dig­nity, val­ues, and ethics to ap­pease your em­ployer.Do not buy into the bull­shit hype of hustle” to ap­pease your em­ployer.Get your head down and work hard. If your em­ployer com­pen­sates you well, puts ef­fort into en­sur­ing you are healthy in every sense and in­vests in your per­sonal and/​or pro­fes­sional growth then by all means, tell the world how happy you are.Fo­cus on your own growth. Focus on help­ing the hu­mans you work with. Focus on be­ing ef­fi­cient with your time and ef­forts so that you can spend even more time and ef­fort on the things and peo­ple that truly mat­ter.I’ll leave you on the words of my fa­ther on the eve of his 30 year work an­niver­sary:

When I’m on my deathbed, I won’t look back at my life and wish I had worked harder. I’ll look back and wish I spent more time with the peo­ple I loved.

What Your Job Ad Says About You

...

Read the original on www.talentstuff.com »

5 305 shares, 13 trendiness

Instant SQL is here: Speedrun ad-hoc queries as you type

Today, we’re re­leas­ing Instant SQL, a new way to write SQL that up­dates your re­sult set as you type to ex­pe­dite query build­ing and de­bug­ging — all with zero-la­tency, no run but­ton re­quired. Instant SQL is now avail­able in MotherDuck and the DuckDB Local UI.

We built Instant SQL for a sim­ple rea­son: writ­ing SQL is still too te­dious and slow. Not be­cause of the lan­guage it­self, but be­cause the way we in­ter­act with data­bases has­n’t evolved much since SQL was cre­ated. Writing SQL is­n’t just about syn­tax - It’s about mak­ing sense of your data, know­ing what to ask, and fig­ur­ing out how to get there. That process is it­er­a­tive, and it’s hard.

Instant SQL will save me the mis­ery of hav­ing to try and wran­gle SQL in my BI tool where it­er­a­tion speed can be very slow. This lets me get the data right ear­lier in the process, with faster feed­back than wait­ing for a chart to ren­der or clear­ing an an­a­lyt­ics cache.” — Mike McClannahan, CTO, DashFuel

Despite how much data­base en­gines have im­proved, with things like colum­nar stor­age, vec­tor­ized ex­e­cu­tion, and the cre­ation of blaz­ing-fast en­gines like DuckDB, which can scan bil­lions of rows in sec­onds, the ex­pe­ri­ence of build­ing a query has­n’t kept up. We still write queries in a text ed­i­tor, hit a run but­ton, and wait to see what hap­pens.

At MotherDuck, we’ve been tack­ling this prob­lem from mul­ti­ple an­gles. Last year, we re­leased the Column Explorer, which gives you fast dis­tri­b­u­tions and sum­mary sta­tis­tics for all the columns in your ta­bles and re­sult sets. We also re­leased FixIt, an un­rea­son­ably ef­fec­tive AI fixer for SQL. MotherDuck users love these tools be­cause they speed up data ex­plo­ration and query it­er­a­tion.

Instant SQL is­n’t just an in­cre­men­tal im­prove­ment to SQL tool­ing: It’s a fun­da­men­tally new way to in­ter­act with your queries - one where you can see your changes in­stantly, de­bug nat­u­rally, and ac­tu­ally trust the code that your AI as­sis­tant sug­gests. No more wait­ing. No more con­text switch­ing. Just flow.

Let’s take a closer look at how it works.

Everyone knows what it feels like to start a new query from scratch. Draft, run, wait, fix, run again—an ex­haust­ing cy­cle that re­peats hun­dreds of times a day. Instant SQL gives you re­sult set pre­views that up­date as you type. You’re no longer run­ning queries—you’re ex­plor­ing your data in real-time, main­tain­ing an an­a­lyt­i­cal flow state where your best think­ing hap­pens.Whether your query is a sim­ple trans­for­ma­tion or a com­plex ag­gre­ga­tion, Instant SQL will let you pre­view your re­sults in real-time.

CTEs are easy to write, but dif­fi­cult to de­bug. How many times a day do you com­ment out code to fig­ure out what’s go­ing on in a CTE? With Instant SQL, you can now click around and in­stantly vi­su­al­ize any CTE in sec­onds, rather than spend hours de­bug­ging. Even bet­ter, changes you make to a CTE are im­me­di­ately re­flected in all de­pen­dent se­lect nodes, giv­ing you real-time feed­back on how your mod­i­fi­ca­tions cas­cade through the query.

We’ve all been there; you write a com­plex col­umn for­mula for an im­por­tant busi­ness met­ric, and when you run the query, you get a re­sult set full of NULLs. You then have to painstak­ingly dis­man­tle it piece-by-piece to de­ter­mine if the is­sue is your logic or the un­der­ly­ing data. Instant SQL lets you break apart your col­umn ex­pres­sions in your re­sult table to pin­point ex­actly what’s hap­pen­ing. Every edit you make to the query is in­stantly re­flected in how data flows through the ex­pres­sion tree. This makes de­bug­ging any­thing from com­plex nu­meric for­mu­las to reg­u­lar ex­pres­sions feel ef­fort­less.

Preview any­thing DuckDB can query - not just ta­blesIn­stant SQL works for more than just DuckDB ta­bles; it works for mas­sive ta­bles in MotherDuck, par­quet files in S3, Postgres ta­bles, SQLite, MySQL, Iceberg, Delta — you name it. If DuckDB can query it, you can see a pre­view of it. This is, hands down, the best way to quickly ex­plore and model ex­ter­nal data.

Fast-forward to a use­ful query be­fore run­ning itIn­stant SQL gives you the free­dom to test and re­fine your query logic with­out the wait. You can quickly ex­per­i­ment with dif­fer­ent ap­proaches in real-time. When you’re sat­is­fied with what you see in the pre­view, you can then run the query for your fi­nal, ma­te­ri­al­ized re­sults. This ap­proach cuts hours off your SQL work­flow, trans­form­ing the te­dious cy­cle of write-run-wait into a fluid process of ex­plo­ration and dis­cov­ery.

All of these work­flow im­prove­ments are great for hu­mans, but they’re even bet­ter when you throw AI fea­tures into the mix. Today, we’re also re­leas­ing a new in­line prompt edit­ing fea­ture for MotherDuck users. You can now se­lect a bit of text, hit cmd+k (or ctrl+k for Windows and Linux users), write an in­struc­tion in plain lan­guage, and get an AI sug­ges­tion. Instant SQL makes this in­line edit fea­ture work mag­i­cally. When you get a sug­ges­tion, you im­me­di­ately see the sug­ges­tion ap­plied to the re­sult set. No more flip­ping a coin and ac­cept­ing a sug­ges­tion that might ruin your hard work.Why has­n’t any­one done this be­fore?As soon as we had a vi­able pro­to­type of Instant SQL, we be­gan to ask our­selves: why has­n’t any­one done some­thing like this be­fore? It seems ob­vi­ous in hind­sight. It turns out that you need a unique set of re­quire­ments to make Instant SQL work.A way to dras­ti­cally re­duce the la­tency in run­ning a queryEven if you made your data­base re­turn re­sults in mil­lisec­onds, it won’t be much help if you’re send­ing your queries to us-east-1. DuckDB’s lo­cal-first de­sign, along with prin­ci­pled per­for­mance op­ti­miza­tions and friendly SQL, made it pos­si­ble to use your com­puter to parse queries, cache de­pen­den­cies, and rewrite & run them. Combined with MotherDuck’s dual ex­e­cu­tion ar­chi­tec­ture, you can ef­fort­lessly pre­view and query mas­sive amounts of data with low la­tency.Mak­ing Instant SQL re­quires more than just a per­for­mant ar­chi­tec­ture. Even if DuckDB is fast, real-world ad hoc queries may still take longer 100ms to re­turn a re­sult. And of of course, DuckDB can also query re­mote data sources. We need a way to lo­cally cache sam­ples of cer­tain table ref­er­ences and rewrite our queries to point to those.A few years ago, DuckDB hid a piece of magic in the JSON ex­ten­sion: a way to get an ab­stract syn­tax tree (or AST) from any SELECT state­ment via a SQL scalar func­tion. This means any tool­maker can build parser-pow­ered fea­tures us­ing this im­por­tant part of DuckDB’s data­base in­ter­nals - no need to write your own SQL parser from scratch.Of course, show­ing pre­views as you type re­quires more than just know­ing where you are in the query. We’ve im­ple­mented sev­eral so­phis­ti­cated lo­cal caching strate­gies to en­sure re­sults ap­pear in­stantly. Think of it as a sys­tem that an­tic­i­pates what you might want to see and pre­pares it ahead of time. The de­tails of these caching tech­niques are in­ter­est­ing enough to de­serve their own blog post. But suf­fice it to say, once the cache is warm, the re­sults ma­te­ri­al­ize be­fore you can even lift your fin­gers from the key­board.With­out this per­fect storm of tech­ni­cal ca­pa­bil­i­ties — a fast lo­cal SQL en­gine, parser ac­ces­si­bil­ity, pre­cise cur­sor-to-AST map­ping, and in­tel­li­gent caching — Instant SQL sim­ply could­n’t ex­ist.A way to pre­view any SELECT node in a queryGet­ting the AST is a big step for­ward, but we still need a way to take your cur­sor po­si­tion in the ed­i­tor and map it to a path through this AST. Otherwise, we can’t know which part of the query you’re in­ter­ested in pre­view­ing. So we built some sim­ple tools that pair DuckDB’s parser with its to­k­enizer to en­rich the parse tree, which we then use to pin­point the start and end of all nodes, clauses, and se­lect state­ments. This cur­sor-to-AST map­ping en­ables us to show you a pre­view of ex­actly the SELECT state­ment you’re work­ing on, no mat­ter where it ap­pears in a com­plex query.

...

Read the original on motherduck.com »

6 291 shares, 12 trendiness

Manufactured consensus on x.com

Influential users and rec­om­men­da­tion al­go­rithm de­sign qui­etly shape what peo­ple see, what gains at­ten­tion, and what gets si­lenced.

When an ac­count with 219 mil­lion fol­low­ers in­ter­acts with a smaller one — not by block­ing or ar­gu­ing, but sim­ply by mut­ing — the con­se­quences are im­me­di­ate. The smaller ac­coun­t’s vis­i­bil­ity drops from 150,000 views to 20,000 overnight. No no­tice. No rule bro­ken. Dimmed into ir­rel­e­vance.

It’s a form of shad­ow­ban­ning — not im­posed by mod­er­a­tors, but ac­ti­vated by the al­go­rithm in re­sponse to a high-weight en­gage­ment sig­nal.

On the flip side, the same sig­nal that sup­presses can also el­e­vate. When a high-reach ac­count in­ter­acts — some­times with noth­ing more than a vague com­ment or a re­post — the al­go­rithm reads it as en­dorse­ment. Content is boosted, vis­i­bil­ity spikes, and nar­ra­tives take flight.

Even low-ef­fort, repet­i­tive in­ter­ac­tions—likes, generic replies—can act like a con­trolled dose of AstroBoost™ - just enough to sim­u­late mo­men­tum and trig­ger am­pli­fi­ca­tion.

Social proof used to re­flect crowd wis­dom. Now it re­flects al­go­rith­mic en­dorse­ment — trig­gered not by con­sen­sus, but by prox­im­ity to in­flu­ence. A sin­gle in­ter­ac­tion can dis­tort scale, mak­ing se­lected con­tent ap­pear widely sup­ported.

The re­sult? Artificial pop­u­lar­ity. Boosted nar­ra­tives. Organic ideas buried by en­gi­neered reach. The crowd did­n’t pick it—the al­go­rithm did, based on who touched it.

Nothing needs to be re­moved or blocked. Often, con­tent is sim­ply de­pri­or­i­tized—pushed lower in the feed, placed out­side key vis­i­bil­ity zones, or dis­placed by fresher sig­nals. The mech­a­nisms are sub­tle, the out­comes con­sis­tent: lower reach, re­duced vis­i­bil­ity, di­min­ished pres­ence.

Meanwhile, am­pli­fi­ca­tion flows down­stream. A sin­gle high-weight in­ter­ac­tion can trig­ger a cas­cade—sur­fac­ing aligned con­tent, prompt­ing en­gage­ment across sim­i­lar ac­counts, and re­in­forc­ing the same nar­ra­tive through rep­e­ti­tion.

What peo­ple see feels or­ganic. In re­al­ity, they’re en­gag­ing with what’s al­ready been fil­tered, ranked, and sur­faced.

There’s no need to sim­u­late sup­port when the plat­form it­self is the am­pli­fier. Traditional as­tro­turf­ing re­lied on fake ac­counts and bots. Today, man­u­fac­tured con­sen­sus is pow­ered by real users—but se­lected ones. Elite ac­counts trig­ger the ma­chine. Everyone else gets pulled into the rip­ple.

This is­n’t about fak­ing the crowd — it’s about guid­ing it. Real users, real en­gage­ment, se­lec­tively am­pli­fied to cre­ate the il­lu­sion of wide­spread agree­ment. Consensus is just what sur­vived the feed.

Perception shaped at scale does­n’t just change what peo­ple see—it changes how they vote, what they buy, what they protest, and what they ig­nore. It does­n’t just dis­tort at­ten­tion. It steers out­comes.

What’s not shown might as well not ex­ist.

And if you think this only hap­pens on one so­cial net­work, you’re al­ready caught in the wrong at­ten­tion loop.

The most ef­fec­tive in­flu­ence does­n’t an­nounce it­self. It does­n’t cen­sor loudly, or boost ag­gres­sively. It shapes per­cep­tion qui­etly — one al­go­rith­mic nudge at a time.

The ones who try to con­trol every­thing too openly, too quickly, get caught. It’s not the blunt force au­thor­i­tar­i­ans who en­dure. It’s the sub­tle ones. The ones who let peo­ple be­lieve they chose freely — while feed­ing them only cu­rated choices.

At rook2­root.co we ex­pose the tac­tics no one talks about. Not to preach, but to il­lu­mi­nate. sub­scribe to get new ar­ti­cles de­liv­ered by mail.

...

Read the original on rook2root.co »

7 218 shares, 9 trendiness

Why 21 cm is our Universe's "magic length"

In our Universe, quan­tum tran­si­tions are the gov­ern­ing rule be­hind every nu­clear, atomic, and mol­e­c­u­lar phe­nom­e­non. Unlike the plan­ets in our Solar System, which could sta­bly or­bit the Sun at any dis­tance if they pos­sessed the right speed, the pro­tons, neu­trons, and elec­trons that make up all the con­ven­tional mat­ter we know of can only bind to­gether in a spe­cific set of con­fig­u­ra­tions. These pos­si­bil­i­ties, al­though nu­mer­ous, are fi­nite in num­ber, as the quan­tum rules that gov­ern elec­tro­mag­net­ism and the nu­clear forces re­strict how atomic nu­clei and the elec­trons that or­bit them can arrange them­selves.

In all the Universe, the most com­mon atom of all is hy­dro­gen, with just one pro­ton and one elec­tron. Wherever new stars form, hy­dro­gen atoms be­come ion­ized, be­com­ing neu­tral again if those free elec­trons can find their way back to a free pro­ton. Although the elec­trons will typ­i­cally cas­cade down the al­lowed en­ergy lev­els into the ground state, that nor­mally pro­duces only a spe­cific set of in­frared, vis­i­ble, and ul­tra­vi­o­let light. But more im­por­tantly, a spe­cial tran­si­tion oc­curs in hy­dro­gen that pro­duces light of about the size of your hand: 21 cen­time­ters (about ) in wave­length. Even as a physi­cist, you’d be well jus­ti­fied to call this the magic length” of our Universe, as it just might some­day un­lock the dark­est se­crets hid­ing out in the deep­est cos­mic re­cesses from which starlight will never es­cape.

When it comes to the light in the Universe, wave­length is the one prop­erty that you can count on to re­veal how that light was cre­ated. Even though light comes to us in the form of pho­tons — in­di­vid­ual quanta that, col­lec­tively, make up the phe­nom­e­non we know as light — there are two very dif­fer­ent classes of quan­tum process that cre­ate the light that sur­rounds us: con­tin­u­ous ones and dis­crete ones.

A con­tin­u­ous process is some­thing like the light emit­ted by the pho­to­s­phere of the Sun. It’s a dark ob­ject that’s been heated up to a cer­tain tem­per­a­ture, and it ra­di­ates light of all dif­fer­ent, con­tin­u­ous wave­lengths as dic­tated by that tem­per­a­ture: what physi­cists know as black­body ra­di­a­tion. More ac­cu­rately, be­cause the dif­fer­ent lay­ers of the pho­to­s­phere are at dif­fer­ent tem­per­a­tures, the so­lar spec­trum acts like a se­ries of black­bod­ies all summed to­gether: an amal­gam of con­tin­u­ous processes.

A dis­crete process, how­ever, does­n’t al­low for the emis­sion of light of a con­tin­u­ous set of wave­lengths, but rather only at ex­tremely spe­cific, or dis­crete (and quan­tized), wave­lengths. A good ex­am­ple of that is the light ab­sorbed by the neu­tral atoms pre­sent within the ex­treme outer lay­ers of the Sun. As the black­body ra­di­a­tion from the lower lay­ers of the pho­to­s­phere strikes those neu­tral atoms sit­ting at the sur­face, a few of those pho­tons will have just the right wave­lengths to be ab­sorbed by the elec­trons within the neu­tral atoms they en­counter. When we break sun­light up into its in­di­vid­ual wave­lengths, the var­i­ous ab­sorp­tion lines pre­sent against the back­drop of con­tin­u­ous, black­body ra­di­a­tion re­veal both of these processes to us.

Each in­di­vid­ual atom has its prop­er­ties pri­mar­ily de­fined by its nu­cleus, made up of pro­tons (which de­ter­mine its charge) and neu­trons (which, com­bined with pro­tons, de­ter­mine its mass). Atoms also have elec­trons, which or­bit the nu­cleus at a dis­tance de­ter­mined by their charge-to-mass ra­tio, and each elec­tron can only oc­cupy a spe­cific set of en­ergy lev­els. In iso­la­tion, each atom will come to ex­ist in the ground state: where the elec­trons cas­cade down un­til they oc­cupy the low­est al­low­able en­ergy lev­els, lim­ited only by the quan­tum rules that de­ter­mine the var­i­ous prop­er­ties that elec­trons are and aren’t al­lowed to pos­sess.

Electrons can oc­cupy the ground state — the 1s or­bital — of an atom un­til it’s full, which can hold two elec­trons. The next en­ergy level up con­sists of spher­i­cal (the 2s) and per­pen­dic­u­lar (the 2p) or­bitals, which can hold two and six elec­trons, re­spec­tively, for a to­tal of eight. The third en­ergy level can hold 18 elec­trons: 3s (with two), 3p (with six), and 3d (with ten), and the pat­tern con­tin­ues on up­ward. In gen­eral, the upward” tran­si­tions oc­cur when a pho­ton of a par­tic­u­lar wave­length gets ab­sorbed, while the downward” tran­si­tions can oc­cur spon­ta­neously, and re­sult in the emis­sion of pho­tons of the ex­act same wave­lengths as are pre­sent within the atom’s ab­sorp­tion spec­trum.

That’s the ba­sic struc­ture of an atom, some­times re­ferred to as coarse struc­ture.” When you tran­si­tion from the third en­ergy level to the sec­ond en­ergy level in a hy­dro­gen atom, for ex­am­ple, you pro­duce a pho­ton that’s red in color, with a wave­length of pre­cisely 656.3 nanome­ters: right in the vis­i­ble light range of hu­man eyes.

But there are very, very slight dif­fer­ences be­tween the ex­act, pre­cise wave­length of a pho­ton that gets emit­ted if you tran­si­tion from:

* the third en­ergy level down to ei­ther the 2s or the 2p or­bital,

* an en­ergy level where the spin an­gu­lar mo­men­tum and the or­bital an­gu­lar mo­men­tum are aligned ver­sus one where they’re anti-aligned,

* or one where the nu­clear spin and the elec­tron spin are aligned ver­sus anti-aligned.

There are rules as to what’s al­lowed ver­sus what’s for­bid­den in quan­tum me­chan­ics as well, such as the fact that you can tran­si­tion an elec­tron from a d-or­bital to ei­ther an s-or­bital or a p-or­bital, and from an s-or­bital to a p-or­bital, but not from an s-or­bital to an­other s-or­bital.

The slight dif­fer­ences in en­ergy that arise be­tween tran­si­tions of dif­fer­ent types of or­bital within the same en­ergy level is known as an atom’s fine-struc­ture, aris­ing from the in­ter­ac­tion be­tween the spin of each par­ti­cle within an atom and the or­bital an­gu­lar mo­men­tum of the elec­trons around the nu­cleus. It causes a shift in wave­length of less than 0.1%: small com­pared to the atom’s course struc­ture, but still mea­sur­able and sig­nif­i­cant.

However, ow­ing to the weird phe­nom­ena that oc­cur within quan­tum me­chan­ics, even forbidden” tran­si­tions can some­times oc­cur. These tran­si­tions oc­cur due to the phe­nom­e­non of quan­tum tun­nel­ing, where a quan­tum state can spon­ta­neously tran­si­tion to an­other, lower-en­ergy quan­tum state. Sure, you might not be able to tran­si­tion from an s-or­bital to an­other s-or­bital di­rectly, but if you can:

* tran­si­tion from an s-or­bital to a p-or­bital and then back to an s-or­bital,

* tran­si­tion from an s-or­bital to a d-or­bital and then back to an s-or­bital,

* or, more gen­er­ally, tran­si­tion from an s-or­bital to any other al­low­able state and then back to an s-or­bital,

then that tran­si­tion can oc­cur. The only thing weird about quan­tum tun­nel­ing is that you don’t have to have a real” tran­si­tion oc­cur to the in­ter­me­di­ate state. Real tran­si­tions re­quire en­ergy, and even with in­suf­fi­cient en­er­gies, the in­ter­me­di­ate state can be by­passed un­der the rules of quan­tum physics. This oc­curs when tran­si­tions hap­pen vir­tu­ally (as op­posed to real tran­si­tions), so that you only see the fi­nal state emerge from the ini­tial state: some­thing that would be for­bid­den with­out the in­vo­ca­tion of quan­tum tun­nel­ing.

This al­lows us to go be­yond mere coarse struc­ture” and fine struc­ture,” al­low­ing us to probe what’s known as hy­per­fine struc­ture. Hyperfine struc­ture ap­pears where the spin of the atomic nu­cleus and one of the elec­trons that or­bit it be­gin in an aligned” state, where the spins are both in the same di­rec­tion even though the elec­tron is in the low­est-en­ergy, ground (1s) state, and then tran­si­tions to an anti-aligned state, where the spins are re­versed.

The most fa­mous of these tran­si­tions oc­curs in the sim­plest type of atom of all: hy­dro­gen. With just one pro­ton and one elec­tron, every time you form a neu­tral hy­dro­gen atom and the elec­tron cas­cades down to the ground (lowest-energy) state, there’s a 50% chance that the spins of the cen­tral pro­ton and the elec­tron will be aligned, with a 50% chance that the spins will be anti-aligned.

If the spins are anti-aligned, that’s truly the low­est-en­ergy state; there’s nowhere to go via any known tran­si­tion that will re­sult in the emis­sion of en­ergy at all. But if the spins are aligned, it’s a slightly higher en­ergy state than in the anti-aligned case. A hy­dro­gen atom whose elec­tron and pro­ton both spin in the same di­rec­tion could quite pos­si­bly tran­si­tion, through quan­tum tun­nel­ing, to the anti-aligned state. Even though the di­rect tran­si­tion process is for­bid­den, tun­nel­ing al­lows you to go straight from the start­ing point to the end­ing point, emit­ting a pho­ton in the process.

This tran­si­tion, be­cause of its forbidden” na­ture, takes an ex­tremely long time to oc­cur: ap­prox­i­mately 10 mil­lion years for the av­er­age atom. However, this long life­time of the slightly ex­cited, aligned case for a hy­dro­gen atom has an up­side to it: the pho­ton that gets emit­ted, at 21 cen­time­ters in wave­length and with a fre­quency of 1420 mega­hertz, is in­trin­si­cally, ex­tremely nar­row. In fact, it’s the nar­row­est, most pre­cise tran­si­tion line known in all of atomic and nu­clear physics!

If you were to go all the way back to the early stages of the hot Big Bang, be­fore any stars had formed, you’d dis­cover that a whop­ping 92% of the atoms in the Universe were ex­actly this species of hy­dro­gen: with one pro­ton and one elec­tron in them. (At the pre­sent time, af­ter all the stars that have formed some 13.8 bil­lion years later, that num­ber is down to only” about 90% of all atoms.) As soon as neu­tral atoms sta­bly form — just a few hun­dred thou­sand years af­ter the Big Bang — these neu­tral hy­dro­gen atoms form with a 50/50 chance of hav­ing aligned ver­sus anti-aligned spins. The ones that form anti-aligned will re­main so; the ones that form with their spins aligned will un­dergo this spin-flip tran­si­tion, emit­ting ra­di­a­tion of 21 cen­time­ters in wave­length.

Although it’s never yet been done, this gives us a tremen­dously provoca­tive way to mea­sure the early stages of the Universe as never be­fore. If we could find a cloud of hy­dro­gen-rich gas, even one that’s never formed stars, we could look for this spin-flip sig­nal — ac­count­ing for the ex­pan­sion of the Universe and the cor­re­spond­ing red­shift of the light — to mea­sure the atoms in the Universe from the ear­li­est times ever seen. The only broadening” to the line we’d ex­pect to see would come from ther­mal and ki­netic ef­fects: from the non-zero tem­per­a­ture and the grav­i­ta­tion­ally-in­duced mo­tion of the atoms that emit those 21 cen­time­ter sig­nals.

In ad­di­tion to those pri­mor­dial sig­nals, 21 cen­time­ter ra­di­a­tion arises as a con­se­quence when­ever new stars are pro­duced. Every time that a star-form­ing event oc­curs, the more mas­sive new­born stars pro­duce large amounts of ul­tra­vi­o­let ra­di­a­tion: ra­di­a­tion that’s en­er­getic enough to ion­ize hy­dro­gen atoms. All of a sud­den, space that was once filled with neu­tral hy­dro­gen atoms is now filled with free pro­tons and free elec­trons.

But those elec­trons aren’t go­ing to re­main ion­ized for­ever; if the in­ter­stel­lar en­vi­ron­ment they’re lo­cated in has enough free atomic nu­clei (e.g., pro­tons), they’re go­ing to even­tu­ally be cap­tured, once again, by those pro­tons. Once the most mas­sive stars have died away, there’s no longer go­ing to be enough ul­tra­vi­o­let ra­di­a­tion to con­tinue to ion­ize them over and over again, and then those elec­trons will once again sink down to the ground state, where they’ll have a 50/50 chance of be­ing aligned or anti-aligned with the spin of the atomic nu­cleus.

Again, that same ra­di­a­tion — of 21 cen­time­ters in wave­length — gets pro­duced over timescales of ~10 mil­lion years. Every time we mea­sure that 21 cen­time­ter wave­length lo­cal­ized in a spe­cific re­gion of space, even if it gets red­shifted by the ex­pan­sion of the Universe, what we’re see­ing is ev­i­dence of re­cent star-for­ma­tion. Wherever star-for­ma­tion oc­curs, hy­dro­gen gets ion­ized, and when­ever those atoms be­come neu­tral and de-ex­cite again, this spe­cific-wave­length ra­di­a­tion per­sists for tens of mil­lions of years.

If we had the ca­pa­bil­ity of sen­si­tively map­ping this 21 cen­time­ter emis­sion in all di­rec­tions and at all red­shifts (i.e., dis­tances) in space, we could lit­er­ally un­cover the star-for­ma­tion his­tory of the en­tire Universe, as well as the de-ex­ci­ta­tion of the hy­dro­gen atoms first formed in the af­ter­math of the hot Big Bang. With sen­si­tive enough ob­ser­va­tions, we could an­swer ques­tions like:

* Are there stars pre­sent in dark voids in space be­low the thresh­old of what we can ob­serve, wait­ing to be re­vealed by their de-ex­cit­ing hy­dro­gen atoms?

* In galax­ies where no new star-for­ma­tion is ob­served, is star-for­ma­tion truly over, or are there low-lev­els of new stars be­ing born, just wait­ing to be dis­cov­ered from this tell­tale sig­na­ture of hy­dro­gen atoms?

* Are there any events that heat up and lead to hy­dro­gen ion­iza­tion prior to the for­ma­tion of the first stars, and are there star-for­ma­tion bursts that ex­ist be­yond the ca­pa­bil­i­ties of even our most pow­er­ful in­frared ob­ser­va­to­ries to ob­serve di­rectly?

By mea­sur­ing light of pre­cisely the needed wave­length — peak­ing at pre­cisely 21.106114053 cen­time­ters, plus what­ever length­en­ing ef­fects arise from the cos­mic ex­pan­sion of the Universe — we could re­veal the an­swers to all of these ques­tions and more. In fact, this is one of the main sci­ence goals of LOFAR: the low-fre­quency ar­ray, and it pre­sents a strong sci­ence case for putting an up­scaled ver­sion of this ar­ray on the ra­dio-shielded far side of the Moon.

Of course, there’s an­other pos­si­bil­ity that takes us far be­yond as­tron­omy when it comes to mak­ing use of this im­por­tant length: cre­at­ing and mea­sur­ing enough spin-aligned hy­dro­gen atoms in the lab to de­tect this spin-flip tran­si­tion di­rectly, in a con­trolled fash­ion. The tran­si­tion takes about ~10 mil­lion years to flip” on av­er­age, which means we’d need around a quadrillion (1015) pre­pared atoms, kept still and cooled to cryo­genic tem­per­a­tures, to mea­sure not only the emis­sion line, but the width of it. If there are phe­nom­ena that cause an in­trin­sic line-broad­en­ing, such as a pri­mor­dial grav­i­ta­tional wave sig­nal, such an ex­per­i­ment would, quite re­mark­ably, be able to un­cover its ex­is­tence and mag­ni­tude.

In all the Universe, there are only a few known quan­tum tran­si­tions with the pre­ci­sion in­her­ent to the hy­per­fine spin-flip tran­si­tion of hy­dro­gen, which re­sults in the emis­sion of ra­di­a­tion that’s 21 cen­time­ters in wave­length. If we want to iden­tify:

* on­go­ing and re­cent star-for­ma­tion across the Universe,

* the first atomic sig­nals even be­fore the first stars were formed,

* or the relic strength of yet-un­de­tected grav­i­ta­tional waves left over from cos­mic in­fla­tion,

it be­comes clear that the 21 cen­time­ter tran­si­tion is the most im­por­tant probe we have in all the cos­mos. In many ways, it’s the magic length” for un­cov­er­ing some of na­ture’s great­est se­crets, and can take us closer to the Big Bang than ob­ser­va­tions of any stars or galax­ies could ever hope to.

This ar­ti­cle was orig­i­nally pub­lished in December of 2022. It was up­dated in 2025.

...

Read the original on bigthink.com »

8 201 shares, 9 trendiness

Cars and Key Fobs

Almost all cars cur­rently come with a key fob, which al­lows you to open the doors, and start the car. When you buy a car, the con­ve­nience is the com­pelling fea­ture. You can leave the key fob in your pocket, and never again worry about hav­ing a phys­i­cal key. It sounds great.

The im­plicit as­sump­tion you make is that the key fob sys­tem is se­cure, and that some ran­dom per­son with $50 of hard­ware can’t drive off with your car. You have no real way to tell whether the car com­pany did a rea­son­able job with their sys­tem, so you have to trust them. Unfortunately, that trust is not al­ways war­ranted. And it is­n’t un­til peo­ple try to hack these sys­tems that the prob­lems come out. Problems that less scrupu­lous peo­ple may have al­ready been ex­ploit­ing.

There are lots of dif­fer­ent key fob sys­tems. We’ll start by look­ing at the key fob for my 2006 Prius. Key fobs use some­thing called a Remote Keyless System (RKS). In the U. S. these op­er­ate at 315 MHz, +/- 2.5 MHz. My Prius key turned out to be at 312.590 MHz.The key­fobs are all listed in the FCC data­base. Watching for new en­tries is one of the ways peo­ple can tell when new car mod­els are com­ing out. These will ap­pear long be­fore the of­fi­cial an­nounce­ment.

You can fig­ure out what fre­quency your key fob trans­mits on us­ing your SDR and use GQRX or SDR# to mon­i­tor the spec­trum. When you push a but­ton on the fob, you should see a brief jump in the spec­trum. You may need to shift the fre­quency band up or down by a cou­ple of MHz to find the sig­nal, mine was al­most 2.5 MHz low.

One word of cau­tion. Don’t get too car­ried away push­ing the but­ton! The RKS sys­tem uses a rolling pseudo-ran­domly gen­er­ated code. Both the key fob and the car keep in sync, so that the car rec­og­nizes the next code. However, if the key fob gets too far ahead in the se­quence (100s of but­ton pushes) the car won’t rec­og­nize it. That makes the key (and the car) con­sid­er­ably less use­ful!

If we cap­ture the sig­nal the re­sult is shown be­low

The to­tal width of the plot is 10 sec­onds, so you can see there is one key press shortly af­ter 2 sec­onds, and an­other shortly af­ter 5 sec­onds.

If we plot 100 ms start­ing at 2 sec­onds, we can see the dig­i­tal sig­nal we are look­ing for:

Zooming in to the first cou­ple of bits, we get

The bits are easy to iden­tify. A de­ci­sion thresh­old of 15 will give al­most per­fect de­tec­tion. If we do this, and then plot first part of the dig­i­tal data for the two key presses, we get this

Although the two start the same, they rapidly di­verge. This is for­tu­nate, be­cause if the sig­nal was the same every time, you’d have enough in­for­ma­tion to steal my car now!

The data is again on-off key­ing (OOK). It is also al­most cer­tainly split phase (or Manchester) en­cod­ing. Instead of a 1” be­ing high, and a 0” be­ing low, the in­for­ma­tion is en­cod­ing in the tran­si­tion from high to low or low to high. That means that a 0” bit is a ris­ing tran­si­tion, and a 1” bit is a falling tran­si­tion. A good way to rec­og­nize split phase en­cod­ing is that you can only have one or two low or high seg­ments in a row. The nice thing about Manchester en­cod­ing is that every sym­bol has a tran­si­tion, and these are eas­ier to find then when the sig­nal has been high or low for sev­eral in­ter­vals.

This ex­am­ple is OOK, which is the most com­mon for car re­motes. Some use fre­quency-shift key­ing (FSK), where each bit is trans­mit­ted as a dif­fer­ent fre­quency, and the en­ve­lope is con­stant.

There are lots of dif­fer­ent at­tacks that can be used against car re­motes, de­pend­ing on how they work, and what sort of ac­cess you are look­ing for. The sim­plest just let you open the car up. More thor­ough at­tacks give you com­plete con­trol by ba­si­cally cloning the re­mote.

Most key fobs use a rolling key. This pro­duces a new wave­form that de­pends on the ID of the key fob, a ran­dom seed, and how many times the key has been pressed. The car keeps track of the last code it re­ceived, and knows what the next sev­eral hun­dred codes might be. If it de­tects one of the ex­pected fu­ture codes it opens the car. If it gets a pre­vi­ously used code, it stops re­spond­ing to the key fob. For the Prius you have to do the Chicken Dance” to get it to work again, pro­vided you have an­other work­ing key fob. Otherwise, you have to have the dealer rekey the car, for many hun­dreds of dol­lars. I have had to do this a cou­ple times, now (for other rea­sons).

There are sev­eral lines of at­tack. One is sim­ply record­ing the key fob out­put for a cou­ple of but­ton presses when it is away from the car, or the car is be­ing jammed. With recorded un­used codes, you can open the car.

Another is to re­verse en­gi­neer the RKS se­quence. In gen­eral this should be ex­tremely hard. However, there have been sev­eral sit­u­a­tions where this is very easy.

Finally, there are cars that open when the owner gets close to the car. This is based on a low power sig­nal that can only be re­ceived when the key fob is very close. This can be de­feated by am­pli­fy­ing these small sig­nals.

There are many more at­tacks, and these will con­tinue to mul­ti­ply as cars get more com­plex, and have more em­bed­ded com­puter sys­tems to go af­ter. You can look at some of these for next week.

The old­est and sim­plest ap­proach was to record the wave­form that a key fob puts out (using your rtl-sdr), and then re­play it. This works well for older garage door open­ers, that used a sin­gle fixed key. There are still cars out there that have key fobs that work this way (some pre-2000 Mercedes for ex­am­ple).

For key fobs that use a rolling key, you can still use a re­play at­tack. If you can get ac­cess to the key fob when it is away from the car and record sev­eral key presses, you can re­play these to have the car open.

If you can’t get ac­cess to the key fob, a sec­ond ap­proach is to make a de­vice that records the out­put of the key fob when it is used, and si­mul­ta­ne­ously jams the car. A stan­dard way to do this is to lis­ten to the key fob trans­mis­sion, and then start jam­ming when the er­ror cor­rec­tion bits are trans­mit­ted at the end. That way you don’t jam your­self. The car won’t rec­og­nize the packet, but you can recre­ate the er­ror cor­rec­tion bits, and re­trans­mit the wave­form later.

Finally, a jam­mer by it­self will keep the re­mote from be­gin able to lock the car. If the dri­ver is­n’t at­ten­tive, they may walk away from the car leav­ing it open.

All of this de­pends on your abil­ity to both trans­mit and re­ceive RF. Your rtl-sdr’s are just re­ceivers, and do a great job of ac­quir­ing sig­nals. There are lots of op­tions for trans­mit­ting. There are a num­ber of usb don­gles that are based on the TI CC111X chips that are used in key fobs, like this one

Another re­cent de­vice that has at­tracted a lot of at­ten­tion is the Flipper Zero

This has the same chip as the pre­vi­ous de­vice, but is much more ac­ces­si­u­ble pack­aged. This is the Swiss army knife of RF hack­ing. It has gen­er­ated a lot of con­tro­versy, as you can look into for this week’s as­sign­ment.

An in­ter­est­ing, more flex­i­ble ap­proach uses your Raspberry PI to gen­er­ate RF by send­ing a care­fully crafted data se­quence to the GPIO port. This is de­scribed in de­tail, with videos, and links to the code here:

With this, you can gen­er­ate pretty much any dig­i­tal packet wave­form you would like. Power lev­els are more than ad­e­quate for em­u­lat­ing a key fob. The rtl-sdr’s are also well sup­ported on the Raspberry PI, so the two to­gether give you a to­tal key fob hack­ing sys­tem for $50 or so, as we will see shortly.

Many higher end cars use a pas­sive sys­tem for open­ing the car when the dri­ver ap­proaches. A low power sig­nal is trans­mit­ted from the car as a chal­lenge. The key fob then re­sponds with an au­then­ti­ca­tion. Because the power is so low, the car as­sumes the dri­ver must be in close prox­im­ity if it re­ceives a re­sponse.

These sys­tems can be hacked by build­ing a re­peater that placed near the car. It cap­tures the car’s sig­nal and re­trans­mits it at higher power. The re­mote can be any­where with in a cou­ple hun­dred me­ters, and it will still hear the sig­nal. The re­mote re­sponds, and that is again cap­tured by the re­peater, and re­trans­mit­ted. The car thinks the key fob is nearby and opens the car.

The nice thing about this ap­proach is that you don’t need to know any­thing about the key fob, ex­cept its fre­quency. You don’t need to re­verse en­gi­neer the pro­to­col it uses, you are ac­tu­ally just us­ing the real key!

Here is a video of some care thieves steal­ing a Tesla with this ap­proach

How can you re­duce this risk?

The next at­tacks go af­ter the rolling key sys­tem it­self. The way this gen­er­ally works is that the key fob sends an ID, along with a counter of how many times a key has been pressed. This is en­crypted, and trans­mit­ted to the car when you push the but­ton.

If the en­cryp­tion is strong, it is ex­tremely dif­fi­cult to fig­ure out what the userid and counter is. There are sev­eral in­ter­est­ing cases. One is for the 20 years of VWs (and Audi’s, Porsche’s, etc), that we’ll look at here. Another is for Subarus, that you can look at for your as­sign­ment this week.

A de­scrip­tion of the VW RKS sys­tem is given here

This points to a Wired ar­ti­cle (which un­for­tu­nately cur­rently be­hind a pay­wall), and in­cludes a tech­ni­cal pa­per that goes into great de­tail about how it works. The au­thors of the tech­ni­cal pa­per looked at the VW RKS sys­tems for the last 20 years.

For the most re­cent sys­tems, the en­cryp­tion was rel­a­tively strong, equiv­a­lent to a 90 bit key. However, it turns out they used the same key in every car! 100 mil­lion of them!

The chal­lenge then is to fig­ure out what the key is, and what the en­cryp­tion al­go­rithm is. The car it­self helps you solve that one. When but­ton is pushed the car re­ceives the sig­nal, and then de­codes it in the on­board com­puter (ECU). The key and the al­go­rithm are stored in the ECU firmware. The au­thors bought some ECUs on EBay, down­loaded the firmware, and re­verse en­gi­neered the en­cryp­tion (these are usu­ally fairly sim­ple bit­wise op­er­a­tions that are easy to iden­tify). With this knowl­edge, af­ter ac­quir­ing the sig­nal from a sin­gle key press, the user ID and counter can be de­coded, and the key fob cloned, giv­ing com­plete con­trol of the car.

There are a cou­ple of in­ter­est­ing things here. One is that every VW car de­codes every key fob, so by mon­i­tor­ing the ex­e­cu­tion of your ECU, you can find the user ID and counter for all of the cars around you. There are re­ports of peo­ple us­ing sys­tems like this to steal other makes of cars, also.

The rea­son only your car re­sponds to your re­mote is that your car has a allow list” of key fob IDs it re­sponds to. That is what gets set when you rekey the car.

This all sounds pretty alarm­ing. But it gets worse, as we’ll see next week.

You have sev­eral op­tions for your as­sign­ment this week. For each topic, gen­er­ate about 5 slides to de­scribe your thoughts or re­sults. Sign up here

and up­load your slides here:

1. This ar­ti­cle con­cerns the Subaru RKS sys­tem. Read it, watch the videos, and de­scribe what you find.

2. The Flipper Zero has got­ten lots of at­ten­tion. What con­tro­ver­sies can you find? What can the de­vice ac­tu­ally do? Should it be banned?

3. Why steal a car when you can have a bull­dozer! Read this ar­ti­cle, and watch the video, to see how this works.

4. There are lots of other car hacks out there. See if you can find some­thing in­ter­est­ing, and de­scribe it. Look for sto­ries where you can fig­ure out how it works. Entertainment sys­tems are a com­mon mode of ac­cess (check the Uconnect hack for Jeeps). Tesla and hack­ers have a long run­ning cat-and-mouse game go­ing. There are lots of in­ter­est­ing ex­am­ples here. Two re­cent are Teslas and Hondas.

Finally, if you haven’t al­ready, please send me an email about how the class is go­ing for you. I ap­pre­ci­ate hear­ing your thoughts. Thanks!

...

Read the original on web.stanford.edu »

9 192 shares, 13 trendiness

Eclipse Foundation status

Some ser­vices are down

Last up­dated on Apr 25 at 04:45am EDT

Homepage, Query API, and 2 other ser­vices are down

We are work­ing to re­solve an is­sue with our back­end stor­age that is pre­vent­ing the ser­vice from start­ing cor­rectly

...

Read the original on status.open-vsx.org »

10 173 shares, 7 trendiness

Creating your own federated microblog

Skip to con­tent This tu­to­r­ial is also avail­able in the fol­low­ing lan­guages: 한국어 (Korean) and 日本語 (Japanese).In this tu­to­r­ial, we will build a small mi­croblog that im­ple­ments the ActivityPub pro­to­col, sim­i­lar to Mastodon or Misskey, us­ing Fedify, an ActivityPub server frame­work. This tu­to­r­ial will fo­cus more on how to use Fedify rather than un­der­stand­ing its un­der­ly­ing op­er­at­ing prin­ci­ples. If you have any ques­tions, sug­ges­tions, or feed­back, please feel free to join our Matrix chat space or Discord server or GitHub Discussions.This tu­to­r­ial is aimed at those who want to learn Fedify and cre­ate ActivityPub server soft­ware.We as­sume that you have ex­pe­ri­ence in cre­at­ing web ap­pli­ca­tions us­ing HTML and HTTP, and that you un­der­stand com­mand-line in­ter­faces, SQL, JSON, and ba­sic JavaScript. However, you don’t need to know TypeScript, , ActivityPub, or Fedify—we’ll teach you what you need to know about these as we go along.You don’t need ex­pe­ri­ence in cre­at­ing ActivityPub soft­ware, but we do as­sume that you’ve used at least one ActivityPub soft­ware like Mastodon or Misskey. This is so you have an idea of what we’re try­ing to build.In this tu­to­r­ial, we’ll use Fedify to cre­ate a sin­gle-user mi­croblog that can com­mu­ni­cate with other fed­er­ated soft­ware and ser­vices via ActivityPub. This soft­ware will in­clude the fol­low­ing fea­tures:Only one ac­count can be cre­ated.Other ac­counts in the fe­di­verse can fol­low the user.The user can view their list of fol­low­ers.The user’s posts are vis­i­ble to fol­low­ers in the fe­di­verse.The user can fol­low other ac­counts in the fe­di­verse.The user can view a list of ac­counts they are fol­low­ing.The user can view a chrono­log­i­cal list of posts from ac­counts they fol­low.To sim­plify the tu­to­r­ial, we’ll im­pose the fol­low­ing fea­ture con­straints:Ac­count pro­files (bio, pho­tos, etc.) can­not be set.Once cre­ated, an ac­count can­not be deleted.Once posted, a post can­not be edited or deleted.Once fol­lowed, an­other ac­count can­not be un­fol­lowed.There are no likes, shares, or com­ments.There is no search func­tion­al­ity.There are no se­cu­rity fea­tures such as au­then­ti­ca­tion or per­mis­sion checks.Of course, af­ter com­plet­ing the tu­to­r­ial, you’re wel­come to add these fea­tures—it would be good prac­tice!The com­plete source code is avail­able in the GitHub repos­i­tory, with com­mits sep­a­rated ac­cord­ing to each im­ple­men­ta­tion step for your ref­er­ence.Fed­ify sup­ports three JavaScript run­times: Deno, Bun, and Node.js. Among these, Node.js is the most widely used, so we’ll use Node.js as the ba­sis for this tu­to­r­ial.A JavaScript run­time is a plat­form that ex­e­cutes JavaScript code. Web browsers are one type of JavaScript run­time, and for com­mand-line or server use, Node.js is widely used. Recently, cloud edge func­tions like Cloudflare Workers have also gained pop­u­lar­ity as JavaScript run­times.To use Fedify, you need Node.js ver­sion 20.0.0 or higher. There are var­i­ous in­stal­la­tion meth­ods—choose the one that suits you best.Once Node.js is in­stalled, you’ll have ac­cess to the node and npm com­mands:To set up a Fedify pro­ject, you need to in­stall the fed­ify com­mand on your sys­tem. There are sev­eral in­stal­la­tion meth­ods, but us­ing the npm com­mand is the sim­plest:Af­ter in­stal­la­tion, check if you can use the fed­ify com­mand. You can check the ver­sion of the fed­ify com­mand with this com­mand:Make sure the ver­sion num­ber is 1.0.0 or higher. If it’s an older ver­sion, you won’t be able to prop­erly fol­low this tu­to­r­ial.To start a new Fedify pro­ject, let’s de­cide on a di­rec­tory path to work in. In this tu­to­r­ial, we’ll name it mi­croblog. Run the fed­ify init com­mand fol­lowed by the di­rec­tory path (it’s okay if the di­rec­tory does­n’t ex­ist yet):When you run the fed­ify init com­mand, you’ll see a se­ries of prompts. Select Node.js, npm, Hono, In-memory, and In-process in or­der:Fed­ify is not a full-stack frame­work, but rather a frame­work spe­cial­ized for im­ple­ment­ing ActivityPub servers. Therefore, it’s de­signed to be used along­side other web frame­works. In this tu­to­r­ial, we’ll adopt Hono as our web frame­work to use with Fedify.After a mo­ment, you’ll see files cre­ated in your work­ing di­rec­tory with the fol­low­ing struc­ture:As you might guess, we’re us­ing TypeScript in­stead of JavaScript, which is why we have .ts and .tsx files in­stead of .js files.The gen­er­ated source code is a work­ing demo. Let’s first check if it runs prop­erly:This com­mand will keep the server run­ning un­til you press +:With the server run­ning, open a new ter­mi­nal tab and run the fol­low­ing com­mand:This com­mand queries an ac­tor (actor) on the ActivityPub server we’ve set up lo­cally. In ActivityPub, an ac­tor can be thought of as an ac­count that’s ac­ces­si­ble across var­i­ous ActivityPub servers.If you see out­put like this, it’s work­ing cor­rectly:✔ Looking up the ob­ject…

Person {

id: URL http://​lo­cal­host:8000/​users/​john,

name: john”,

pre­ferre­dUser­name: john”

}This re­sult tells us that there’s an ac­tor ob­ject lo­cated at the /users/john path, it’s of type Person, its ID is http://​lo­cal­host:8000/​users/​john, its name is john, and its user­name is also john.fed­ify lookup is a com­mand to query ActivityPub ob­jects. This is equiv­a­lent to search­ing with the cor­re­spond­ing URI on Mastodon. (Of course, since your server is only ac­ces­si­ble lo­cally at the mo­ment, search­ing on Mastodon won’t yield any re­sults yet.)If you pre­fer curl over the fed­ify lookup com­mand, you can also query the ac­tor with this com­mand (note that we’re send­ing the Accept header with the -H op­tion):How­ever, if you query like this, the re­sult will be in JSON for­mat, which is dif­fi­cult to read with the naked eye. If you also have the jq com­mand in­stalled on your sys­tem, you can use curl and jq to­gether:Vi­sual Studio Code might not be your fa­vorite ed­i­tor. However, we rec­om­mend us­ing Visual Studio Code while fol­low­ing this tu­to­r­ial. This is be­cause we need to use TypeScript, and Visual Studio Code is cur­rently the most con­ve­nient and ex­cel­lent TypeScript IDE. Also, the gen­er­ated pro­ject setup al­ready in­cludes Visual Studio Code set­tings, so you don’t have to wres­tle with for­mat­ters or lin­ters.Don’t con­fuse this with Visual Studio. Visual Studio Code and Visual Studio only share a brand name; they are com­pletely dif­fer­ent soft­ware.Af­ter in­stalling Visual Studio Code, open the work­ing di­rec­tory by se­lect­ing File → Open Folder… from the menu.If you see a popup in the bot­tom right ask­ing Do you want to in­stall the rec­om­mended Biome’ ex­ten­sion from bio­mejs for this repos­i­tory?, click the Install but­ton to in­stall the ex­ten­sion. Installing this ex­ten­sion will au­to­mat­i­cally for­mat your TypeScript code, so you don’t have to wres­tle with code styles like in­den­ta­tion or spac­ing when writ­ing TypeScript code.If you’re a loyal Emacs or Vim user, we won’t dis­cour­age you from us­ing your fa­vorite ed­i­tor. However, we rec­om­mend set­ting up TypeScript . The dif­fer­ence in pro­duc­tiv­ity de­pend­ing on whether TypeScript is set up or not is sig­nif­i­cant.Be­fore we start mod­i­fy­ing code, let’s briefly go over TypeScript. If you’re al­ready fa­mil­iar with TypeScript, you can skip this sec­tion.Type­Script adds sta­tic type check­ing to JavaScript. The TypeScript syn­tax is al­most the same as JavaScript, but the main dif­fer­ence is that you can spec­ify types for vari­ables and func­tions. Types are spec­i­fied by adding a colon (:) af­ter the vari­able or pa­ra­me­ter.For ex­am­ple, the fol­low­ing code in­di­cates that the foo vari­able is a string:If you try to as­sign a value of a dif­fer­ent type to a vari­able de­clared like this, Visual Studio Code will show a red un­der­line be­fore you even run it and dis­play a type er­ror:foo = 123;Type number’ is not as­sign­a­ble to type string’.When cod­ing, don’t ig­nore red un­der­lines. If you ig­nore them and run the pro­gram, it’s likely that an er­ror will ac­tu­ally oc­cur at that part.The most com­mon type of er­ror you’ll en­counter when cod­ing in TypeScript is the null pos­si­bil­ity er­ror. For ex­am­ple, in the fol­low­ing code, the bar vari­able can be ei­ther a string or null (string | null):What hap­pens if you try to get the first char­ac­ter of this vari­able’s con­tent like this?You’ll get a type er­ror like above. It’s say­ing that bar might some­times be null, and in that case, call­ing null.charAt(0) would cause an er­ror, so you need to fix the code. In such cases, you need to add han­dling for the null case like this:In this way, TypeScript helps pre­vent bugs by mak­ing you think of cases you might not have con­sid­ered when cod­ing.An­other in­ci­den­tal ad­van­tage of TypeScript is that it en­ables auto-com­ple­tion. For ex­am­ple, if you type foo., a list of meth­ods avail­able for string ob­jects will ap­pear, al­low­ing you to choose from them. This al­lows for faster cod­ing with­out hav­ing to check doc­u­men­ta­tion each time.We hope you’ll feel the charm of TypeScript as you fol­low this tu­to­r­ial. Above all, Fedify pro­vides the best ex­pe­ri­ence when used with TypeScript.If you want to learn TypeScript prop­erly and thor­oughly, we rec­om­mend read­ing The TypeScript Handbook. It takes about 30 min­utes to read it all. is a syn­tax ex­ten­sion of JavaScript that al­lows you to in­sert XML or HTML into JavaScript code. It can also be used in TypeScript, in which case it’s some­times called TSX. In this tu­to­r­ial, we’ll write all HTML within JavaScript code us­ing syn­tax. Those who are al­ready fa­mil­iar with can skip this sec­tion.For ex­am­ple, the fol­low­ing code as­signs an HTML tree with a el­e­ment at the top to the html vari­able:You can also in­sert JavaScript ex­pres­sions us­ing curly braces (the fol­low­ing code as­sumes, of course, that there’s a get­Name() func­tion):One of the fea­tures of is that you can de­fine your own tags called com­po­nents. Components can be de­fined as or­di­nary JavaScript func­tions. For ex­am­ple, the fol­low­ing code de­fines and uses a com­po­nent (component names typ­i­cally fol­low PascalCase style):im­port type { Child, FC } from hono/jsx”;

func­tion get­Name() {

re­turn JSX;

in­ter­face ContainerProps {

name: string;

chil­dren: Child;

const Container: FCIn the above code, FC is pro­vided by Hono, the web frame­work we’ll use, and it helps de­fine the type of the com­po­nent. FC is a generic type, and the types that go in­side the an­gle brack­ets af­ter FC are type ar­gu­ments. Here, we spec­ify the props type as the type ar­gu­ment. Props re­fer to the pa­ra­me­ters passed to the com­po­nent. In the above code, we de­clared and used the ContainerProps in­ter­face as the props type for the com­po­nent.Type ar­gu­ments for generic types can be mul­ti­ple, sep­a­rated by com­mas. For ex­am­ple, Foo ap­plies type ar­gu­ments A and B to the generic type Foo.There are also generic func­tions, which are writ­ten as some­Func­tion.When there’s only one type ar­gu­ment, the an­gle brack­ets en­clos­ing the type ar­gu­ment may look like XML/HTML tags, but they have noth­ing to do with func­tion­al­ity.Ap­plies the type ar­gu­ment ContainerProps to the generic type FC.Opens a com­po­nent tag named . Must be closed with .Among the things passed as props, chil­dren is worth not­ing specif­i­cally. This is be­cause the child el­e­ments of the com­po­nent are passed as the chil­dren prop. As a re­sult, in the above code, the html vari­able is as­signed the HTML tree . was in­vented in the React pro­ject and started to be widely used. If you want to know more about , read the Writing Markup with and JavaScript in with Curly Braces sec­tions of the React doc­u­men­ta­tion.The first thing we’ll cre­ate is the ac­count cre­ation page. We need to cre­ate an ac­count be­fore we can post or fol­low other ac­counts. Let’s start by build­ing the vis­i­ble part.First, let’s cre­ate a file named src/​views.tsx. Inside this file, we’ll de­fine a com­po­nent us­ing :To avoid spend­ing too much time on de­sign, we’ll use a CSS frame­work called Pico CSS.When the type of a vari­able or pa­ra­me­ter can be in­ferred by TypeScript’s type checker, like props above, it’s fine to omit the type an­no­ta­tion. Even when the type an­no­ta­tion is omit­ted in such cases, you can check the type of a vari­able by hov­er­ing your mouse cur­sor over the vari­able name in Visual Studio Code.Next, in the same file, let’s de­fine a com­po­nent that will go in­side the lay­out:In , you can only have one top-level el­e­ment, but the com­po­nent has two top-level el­e­ments: and . That’s why we’ve wrapped them with <> and </>. This is called a frag­ment.

Now it’s time to use the com­po­nents we’ve de­fined. Open the src/​app.tsx file and im­port the two com­po­nents we just de­fined:

Then, dis­play the ac­count cre­ation form we just made on the /setup page:

Now, let’s open the http://​lo­cal­host:8000/​setup page in a web browser. If you see a screen like this, it’s work­ing cor­rectly:

Now that we’ve im­ple­mented the vis­i­ble part, it’s time to im­ple­ment the func­tion­al­ity. We need a place to store ac­count in­for­ma­tion, so let’s use SQLite. SQLite is a re­la­tional data­base suit­able for small-scale ap­pli­ca­tions.

First, let’s de­clare a table to hold ac­count in­for­ma­tion. From now on, we’ll write all table de­c­la­ra­tions in the src/​schema.sql file. We’ll store ac­count in­for­ma­tion in the users table:

Since the mi­croblog we’re cre­at­ing can only have one ac­count, we’ve put a con­straint on the id col­umn, which is the pri­mary key, to not al­low val­ues other than 1. This en­sures that the users table can’t con­tain more than one record. We’ve also put con­straints on the user­name col­umn to not al­low empty strings or strings that are too long.

Now we need to run the src/​schema.sql file to cre­ate the users table. For this, we need the sqlite3 com­mand, which you can get from the SQLite web­site or in­stall from your plat­for­m’s pack­age man­ager. For ma­cOS, you don’t need to get it sep­a­rately as it is built into the sys­tem. If you get it di­rectly, you can get the sqlite-tools-*.zip file for your OS and un­zip it. If you use a pack­age man­ager, you can also in­stall it with the fol­low­ing com­mand:

Okay, now that we have the sqlite3 com­mand, let’s use it to cre­ate a data­base file:

The above com­mand will cre­ate a mi­croblog.sqlite3 file, which will store your SQLite data.

Now we need to use the SQLite data­base in our app. To use SQLite data­base in Node.js, we need a SQLite dri­ver li­brary, and we’ll use the bet­ter-sqlite3 pack­age. You can eas­ily in­stall the pack­age with the npm com­mand:

Now that we’ve in­stalled the pack­age, let’s write code to con­nect to the data­base us­ing this pack­age. Create a new file named src/​db.ts and code it as fol­lows:

Now let’s de­clare a type in JavaScript to rep­re­sent the record stored in the users table. Create a src/​schema.ts file and de­fine the User type as fol­lows:

Now that we’ve con­nected to the data­base, it’s time to write code to in­sert records.

Open the src/​app.tsx file and im­port the db ob­ject and User type that will be used for record in­ser­tion:

Add code to check if an ac­count al­ready ex­ists to the GET /setup han­dler we cre­ated ear­lier:

Now that we’ve roughly im­ple­mented the ac­count cre­ation fea­ture, let’s try it out. Open the http://​lo­cal­host:8000/​setup page in a web browser and cre­ate an ac­count. In this tu­to­r­ial, we’ll as­sume that we used john­doe as the user­name. If it’s cre­ated, let’s also check if the record was prop­erly in­serted into the SQLite data­base:

If the record was prop­erly in­serted, you should see out­put like this (of course, john­doe will be what­ever user­name you en­tered):

Now that we’ve cre­ated an ac­count, let’s im­ple­ment a pro­file page to dis­play the ac­count in­for­ma­tion. Although we don’t have much in­for­ma­tion to show yet.

Let’s start with the vis­i­ble part again. Open the src/​views.tsx file and de­fine a com­po­nent:

Then, open the src/​app.tsx file and im­port the com­po­nent we just de­fined:

And add a GET /users/{username} re­quest han­dler that dis­plays the com­po­nent:

Now let’s test if it dis­plays cor­rectly. Open the http://​lo­cal­host:8000/​users/​john­doe page in your web browser (if you cre­ated an ac­count with a user­name other than john­doe, change the URL ac­cord­ingly). You should see a screen like this:

As the name sug­gests, ActivityPub is a pro­to­col for ex­chang­ing ac­tiv­i­ties. Writing a post, edit­ing a post, delet­ing a post, lik­ing a post, com­ment­ing, edit­ing a pro­file… All ac­tions that hap­pen in so­cial me­dia are ex­pressed as ac­tiv­i­ties.

And all ac­tiv­i­ties are trans­mit­ted from ac­tor to ac­tor. For ex­am­ple, when John Doe writes a post, a (Create(Note)) ac­tiv­ity is sent from Joh Doe to John Doe’s fol­low­ers. If Jane Doe likes that post, a (Like) ac­tiv­ity is sent from Jane Doe to John Doe.

Therefore, the first step in im­ple­ment­ing ActivityPub is to im­ple­ment the ac­tor.

The demo app gen­er­ated by the fed­ify init com­mand al­ready has a very sim­ple ac­tor im­ple­mented, but to com­mu­ni­cate with ac­tual soft­ware like Mastodon or Misskey, we need to im­ple­ment the ac­tor more prop­erly.

First, let’s take a look at the cur­rent im­ple­men­ta­tion. Open the src/​fed­er­a­tion.ts file:

The part we should fo­cus on is the se­tAc­torDis­patcher() method. This method de­fines the URL and be­hav­ior that other ActivityPub soft­ware will use when query­ing an ac­tor on our server. For ex­am­ple, if we query /users/johndoe as we did ear­lier, the iden­ti­fier pa­ra­me­ter of the call­back func­tion will re­ceive the string value johndoe”. And the call­back func­tion re­turns an in­stance of the Person class to con­vey the in­for­ma­tion of the queried ac­tor.

The ctx pa­ra­me­ter re­ceives a Context ob­ject, which con­tains var­i­ous func­tions re­lated to the ActivityPub pro­to­col. For ex­am­ple, the getAc­torUri() method used in the above code re­turns the unique URI of the ac­tor with the iden­ti­fier passed as a pa­ra­me­ter. This URI is be­ing used as the unique iden­ti­fier of the Person ob­ject.

As you can see from the im­ple­men­ta­tion code, cur­rently it’s mak­ing up ac­tor in­for­ma­tion and re­turn­ing it for any iden­ti­fier that comes af­ter the /users/ path. But what we want is to only al­low queries for ac­counts that are ac­tu­ally reg­is­tered. Let’s mod­ify this part to only re­turn for ac­counts in the data­base.

We need to cre­ate an ac­tors table. Unlike the users table which only con­tains ac­counts on the cur­rent in­stance server, this table will also in­clude re­mote ac­tors be­long­ing to fed­er­ated servers. The table looks like this. Add the fol­low­ing SQL to the src/​schema.sql file:

* The user_id col­umn is a for­eign key to con­nect with the users col­umn. If the record rep­re­sents a re­mote ac­tor, it will be NULL, but if it’s an ac­count on the cur­rent in­stance server, it will con­tain the users.id value of that ac­count.

* The uri col­umn con­tains the unique URI of the ac­tor, also called the ac­tor ID. All ActivityPub ob­jects, in­clud­ing ac­tors, have a unique ID in URI form. Therefore, it can­not be empty and can­not be du­pli­cated.

* The han­dle col­umn con­tains the fe­di­verse han­dle in the form of @john­doe@ex­am­ple.com. Likewise, it can­not be empty and can­not be du­pli­cated.

* The name col­umn con­tains the name dis­played in the UI. It usu­ally con­tains a full name or nick­name. However, ac­cord­ing to the ActivityPub spec­i­fi­ca­tion, this col­umn can be empty.

* The in­box_url col­umn con­tains the URL of the ac­tor’s in­box. We’ll ex­plain in de­tail what an in­box is be­low, but for now, just know that it must ex­ist for the ac­tor. This col­umn also can­not be empty or du­pli­cated.

* The shared_in­box_url col­umn con­tains the URL of the ac­tor’s shared in­box, which we’ll also ex­plain be­low. It’s not manda­tory, so it can be empty, and as the col­umn name sug­gests, it can share the same shared in­box URL with other ac­tors.

* The url col­umn con­tains the pro­file URL of the ac­tor. A pro­file URL means the URL of the pro­file page that can be opened in a web browser. Sometimes the ac­tor’s ID and pro­file URL are the same, but they can be dif­fer­ent de­pend­ing on the ser­vice, so in that case, the pro­file URL is stored in this col­umn. It can be empty.

* The cre­ated col­umn records when the record was cre­ated. It can­not be empty, and by de­fault, the in­ser­tion time is recorded.

Now, let’s ap­ply the src/​schema.sql file to the mi­croblog.sqlite3 data­base file:

And let’s de­fine a type in src/​schema.ts to rep­re­sent records stored in the ac­tors table in JavaScript:

Although we cur­rently have one record in the users table, there’s no cor­re­spond­ing record in the ac­tors table. This is be­cause we did­n’t add a record to the ac­tors table when cre­at­ing the ac­count. We need to mod­ify the ac­count cre­ation code to add records to both users and ac­tors.

First, let’s mod­ify the SetupForm in src/​views.tsx to also in­put a name that will go into the ac­tors.name col­umn along with the user­name:

Now im­port the Actor type we de­fined ear­lier in src/​app.tsx:

Now let’s add code to the POST /setup han­dler to cre­ate a record in the ac­tors table with the in­put name and other nec­es­sary in­for­ma­tion:

When check­ing if an ac­count al­ready ex­ists, we mod­i­fied it to de­ter­mine that there’s no ac­count yet not only when there’s no record in the users table, but also when there’s no match­ing record in the ac­tors table. Apply the same con­di­tion to the GET /setup han­dler and the GET /users/{username} han­dler:

Finally, open the src/​fed­er­a­tion.ts file and add the fol­low­ing code be­low the ac­tor dis­patcher:

Don’t worry about the set­InboxLis­ten­ers() method for now. We’ll cover this when we ex­plain about the in­box. Just note that the get­Inbox­Uri() method used in the ac­count cre­ation code needs the above code to work prop­erly.

If you’ve mod­i­fied all the code, open the http://​lo­cal­host:8000/​setup page in your browser and cre­ate an ac­count again:

Now that we’ve cre­ated the ac­tors table and filled in a record, let’s mod­ify src/​fed­er­a­tion.ts again. First, im­port the db ob­ject, and Endpoints and Actor types:

Now that we’ve im­ported what we need, let’s mod­ify the se­tAc­torDis­patcher() method:

In the changed code, we now query the users table in the data­base and re­turn null if it’s not an ac­count on the cur­rent server. In other words, it will re­spond with a proper Person ob­ject with 200 OK for a GET /users/johndoe re­quest (assuming the ac­count was cre­ated with the user­name john­doe), and re­spond with 404 Not Found for other re­quests.

Let’s look at how the part cre­at­ing the Person ob­ject has changed. First, a name prop­erty has been added. This prop­erty uses the value from the ac­tors.name col­umn. We’ll cover the in­box and end­points prop­er­ties when we ex­plain about the in­box. The url prop­erty con­tains the pro­file URL of this ac­count, and in this tu­to­r­ial, we’ll make the ac­tor ID and the ac­tor’s pro­file URL match.

Now, let’s test if the ac­tor dis­patcher is work­ing well.

With the server run­ning, open a new ter­mi­nal tab and en­ter the fol­low­ing com­mand:

Since there’s no ac­count named al­ice, you’ll get an er­ror like this, un­like be­fore:

Now let’s look up the john­doe ac­count:

Now you get a good re­sult:

The next thing we’ll im­ple­ment is the ac­tor’s cryp­to­graphic keys for sign­ing. In ActivityPub, when an ac­tor cre­ates and sends an ac­tiv­ity, it uses a dig­i­tal sig­na­ture to prove that the ac­tiv­ity was re­ally cre­ated by that ac­tor. For this, each ac­tor cre­ates and holds their own match­ing pri­vate key (secret key) and pub­lic key pair, and makes the pub­lic key vis­i­ble to other ac­tors. When ac­tors re­ceive an ac­tiv­ity, they com­pare the sender’s pub­lic key with the ac­tiv­i­ty’s sig­na­ture to ver­ify that the ac­tiv­ity was in­deed cre­ated by the sender. Fedify han­dles the sign­ing and sig­na­ture ver­i­fi­ca­tion au­to­mat­i­cally, but you need to im­ple­ment the gen­er­a­tion and preser­va­tion of the key pairs your­self.

Let’s de­fine a keys table in src/​schema.sql to store the pri­vate and pub­lic key pairs:

If you look closely at the table, you can see that the type col­umn only al­lows two types of val­ues. One is the RSA-PKCS#1-v1.5 type and the other is the Ed25519 type. (What each of these means is not im­por­tant for this tu­to­r­ial.) Since the pri­mary key is on (user_id, type), there can be a max­i­mum of two key pairs for one user.

The pri­vate_key and pub­lic_key columns can re­ceive strings, and we’ll put JSON data in them. We’ll cover how to en­code pri­vate and pub­lic keys as JSON later.

Let’s also de­fine a Key type in the src/​schema.ts file to rep­re­sent records stored in the keys table in JavaScript:

Now we need to write code to gen­er­ate and load key pairs.

Open the src/​fed­er­a­tion.ts file and im­port the ex­portJwk(), gen­er­ate­Cryp­toKey­Pair(), im­portJwk() func­tions pro­vided by Fedify and the Key type we de­fined ear­lier:

Now let’s mod­ify the ac­tor dis­patcher part as fol­lows:

First of all, we should pay at­ten­tion to the setKey­Pairs­Dis­patcher() method called in suc­ces­sion af­ter the se­tAc­torDis­patcher() method. This method con­nects the key pairs re­turned by the call­back func­tion to the ac­count. By con­nect­ing the key pairs in this way, Fedify au­to­mat­i­cally adds dig­i­tal sig­na­tures with the reg­is­tered pri­vate keys when send­ing ac­tiv­i­ties.

The gen­er­ate­Cryp­toKey­Pair() func­tion gen­er­ates a new pri­vate key and pub­lic key pair and re­turns it as a CryptoKeyPair ob­ject. For your ref­er­ence, the CryptoKeyPair type has the type { pri­vateKey: CryptoKey; pub­licKey: CryptoKey; }.

The ex­portJwk() func­tion re­turns an ob­ject rep­re­sent­ing the CryptoKey ob­ject in JWK for­mat. You don’t need to know what the JWK for­mat is. Just un­der­stand that it’s a stan­dard for­mat for rep­re­sent­ing cryp­to­graphic keys in JSON. CryptoKey is a web stan­dard type for rep­re­sent­ing cryp­to­graphic keys as JavaScript ob­jects.

The im­portJwk() func­tion con­verts a key rep­re­sented in JWK for­mat to a CryptoKey ob­ject. You can un­der­stand it as the op­po­site of the ex­portJwk() func­tion.

Now, let’s turn our at­ten­tion back to the se­tAc­torDis­patcher() method. We’re us­ing a method called getAc­torKey­Pairs(), which, as the name sug­gests, re­turns the key pairs of the ac­tor. The ac­tor’s key pairs are those very key pairs we just loaded with the setKey­Pairs­Dis­patcher() method. We loaded two pairs of keys in RSA-PKCS#1-v1.5 and Ed25519 for­mats, so the getAc­torKey­Pairs() method re­turns an ar­ray of two key pairs. Each el­e­ment of the ar­ray is an ob­ject rep­re­sent­ing the key pair in var­i­ous for­mats, which looks like this:

It’s com­plex to ex­plain here how CryptoKey, CryptographicKey, and Multikey dif­fer, and why there need to be so many for­mats. For now, let’s just note that when ini­tial­iz­ing the Person ob­ject, the pub­licKey prop­erty ac­cepts the CryptographicKey type and the as­ser­tion­Meth­ods prop­erty ac­cepts the MultiKey[] (TypeScript no­ta­tion for an ar­ray of Multikey) type.

By the way, why are there two prop­er­ties in the Person ob­ject that hold pub­lic keys, pub­licKey and as­ser­tion­Meth­ods? Originally in ActivityPub, there was only the pub­licKey prop­erty, but later the as­ser­tion­Meth­ods prop­erty was added to al­low reg­is­tra­tion of mul­ti­ple keys. Similar to how we gen­er­ated both RSA-PKCS#1-v1.5 and Ed25519 keys ear­lier, we’re set­ting both prop­er­ties for com­pat­i­bil­ity with var­i­ous soft­ware. If you look closely, you can see that we’re only reg­is­ter­ing the RSA-PKCS#1-v1.5 key to the legacy pub­licKey prop­erty (the first item in the ar­ray is the RSA-PKCS#1-v1.5 key pair, and the sec­ond item is the Ed25519 key pair).

Now that we’ve reg­is­tered the cryp­to­graphic keys to the ac­tor ob­ject, let’s check if it’s work­ing well. Query the ac­tor with the fol­low­ing com­mand:

If it’s work­ing cor­rectly, you should see out­put like this:

You can see that the Person ob­jec­t’s pub­licKey prop­erty con­tains one CryptographicKey ob­ject in RSA-PKCS#1-v1.5 type, and the as­ser­tion­Meth­ods prop­erty con­tains two Multikey ob­jects in RSA-PKCS#1-v1.5 and Ed25519 for­mats.

Now let’s check if we can ac­tu­ally view the ac­tor we’ve cre­ated in Mastodon.

Unfortunately, the cur­rent server is only ac­ces­si­ble lo­cally. However, it would be in­con­ve­nient to de­ploy some­where every time we mod­ify the code for test­ing. Wouldn’t it be great if we could ex­pose our lo­cal server to the in­ter­net with­out de­ploy­ment for im­me­di­ate test­ing?

Here’s where the fed­ify tun­nel com­mand comes in handy. In a ter­mi­nal, open a new tab and en­ter this com­mand fol­lowed by the port num­ber of your lo­cal server:

This cre­ates a dis­pos­able do­main name and re­lays to your lo­cal server. It will out­put a URL that’s ac­ces­si­ble from the out­side:

Of course, you’ll see your own unique URL dif­fer­ent from the one above. You can check if it’s con­nect­ing well by open­ing https://​temp-ad­dress.serveo.net/​users/​john­doe in your web browser (replace with your unique tem­po­rary do­main):

Copy your fe­di­verse han­dle shown on the above web page, then go into Mastodon and paste it into the search box in the up­per left cor­ner:

If the ac­tor we cre­ated ap­pears in the search re­sults as shown above, it’s work­ing cor­rectly. You can also click on the ac­tor’s name in the search re­sults to go to their pro­file page:

But this is as far as we can go. Don’t try to fol­low yet! For our ac­tor to be fol­low­able from other servers, we need to im­ple­ment an in­box.

In ActivityPub, an in­box is an end­point where an ac­tor re­ceives in­com­ing ac­tiv­i­ties from other ac­tors. All ac­tors have their own in­box, which is a URL that can re­ceive ac­tiv­i­ties via HTTP POST re­quests. When an­other ac­tor sends a fol­low re­quest, writes a post, com­ments, or per­forms any other in­ter­ac­tion, the cor­re­spond­ing ac­tiv­ity is de­liv­ered to the re­cip­i­en­t’s in­box. The server processes the ac­tiv­i­ties that come into the in­box and re­sponds ap­pro­pri­ately, al­low­ing it to com­mu­ni­cate and func­tion as part of the fed­er­ated net­work.

For now, we’ll start by im­ple­ment­ing the re­cep­tion of fol­low re­quests.

We need to cre­ate a fol­lows table to hold the ac­tors who fol­low you (followers) and the ac­tors you fol­low (following). Add the fol­low­ing SQL to the src/​schema.sql file:

Let’s cre­ate the fol­lows table by ex­e­cut­ing src/​schema.sql once again:

...

Read the original on fedify.dev »

To add this web app to your iOS home screen tap the share button and select "Add to the Home Screen".

10HN is also available as an iOS App

If you visit 10HN only rarely, check out the the best articles from the past week.

If you like 10HN please leave feedback and share

Visit pancik.com for more.