

A warning for the segment of the left demanding these unaccountable Silicon Valley oligarchs have the final say over speech… You are spreading reactionary views, ones held by only the most extreme members of the right wing: even most libertarian-capitalists don’t think monopolists should have complete latitude like this. Not to speak of the way that Facebook and Twitter effectively operate as part of the public square now
Wolff’s post highlighted an Indypendent story on the recent strike by workers at the Hunts Point Produce Market and in his caption he approvingly noted, “US political winds are shifting left. Key example is Hunts Point food market for New York City. First labor union strike since 1986: strong, solid, supported by socialists and much public opinion. Victorious and widely celebrated.” … When Wolff’s Facebook followers went to click on the article, they were redirected. When they went to share it, they received this notice:
Facebook Blocks Sharing of the Indypendent’s Coverage of Hunts Point Produce Market Strike
Shortly after sunrise on Jan. 15, FBI agents descended with guns drawn on a squat, red-brick apartment complex here, broke open the door of one of the units and threw in a stun grenade, prompting the frightened property manager to call 911.
https://www.washingtonpost.com/nation/2021/02/14/fbi-arrest-left-wing-violence/
Inside the apartment, furnished with little besides books and a sign declaring “THE REVOLUTION IS NOT A PARTY,” the agents found their target: a 33-year-old U.S. Army veteran and self-described “hardcore leftist” who had posted a flier on social media threatening to attack “armed racist mobs WITH EVERY CALIBER AVAILABLE.”
The man, Daniel Baker, hardly fit the profile of those who had been expected to cause trouble in the run-up to President Biden’s inauguration. After a mob of Donald Trump supporters invaded the U.S. Capitol on Jan. 6 in hopes of preventing Biden from taking office, the FBI had warned that far-right extremists were plotting armed marches in Tallahassee and other state capitals, as well as in D.C.
But Baker represents the flip side of that threat: As a far-right extremist movement wages an assault on American government and institutions, experts say an unpredictable battle is brewing, fueling potentially legitimate threats of violence from the opposite fringe of the political spectrum.
…
Baker’s friends said he had a bombastic social media presence that he stepped up to match inflammatory right-wing rhetoric. … The FBI agents who had been monitoring Baker’s social media posts since October described him as being on a “path toward radicalization.” … On Jan. 25, U.S. Magistrate Judge Michael J. Frank agreed that Baker posed a potential threat and ordered him held without bond, writing that the former soldier had “repeatedly endorsed violent means to advance the political beliefs that he espouses.”
The corporate establishment media is doing their job and continuing to manufacture consent for a new PATRIOT act, this time aimed (more so) at crushing internal dissent. One thing to note in the language the Democrats have used around this—they never say right wing “extremism,” it’s always just “domestic extremism.” Considering that fascism and capitalism are totally compatible, and some might argue neoliberalism is quite similar to fascism, it should be no surprise that the “right wing extremism” is being used (again, if anyone recalls the 90s) as a pretense for passing laws that are squarely aimed at the dissident and socialist left.
Unfortunately the mainstream “left” have been subject to an unhinged propaganda campaign over the last five years, and consists in reality of mainly conservatives if not outright reactionaries at this point, many of whom are cheering on these developments instead of recoiling in horror as they ought to.
January 6th is the new 9/11, only with far less justification. The state and its media organs have convinced the mainstream left to demand draconian prison sentences for people essentially charged with trespassing (using laws the left once correctly decried as criminalizing protest!), to call for strengthening the police state, to demand expansion of unconstitutional domestic surveillance programs, to demand that private actors censor on behalf of the state (as if a public-private partnership to sidestep the Constitution is justifiable, and worse using extreme right wing capitalist-libertarian views on free speech rights that in earlier times were only held by reactionary nutjobs like Pat Buchanan and Moral Majority types), to live in fear that their neighbors are extremists who would eat their children and murder them in their sleep for being good liberals were it not for the fear of an all powerful state apparatus of violence keeping them civilized…
Probably doesn’t count as a recipe (not enough for me to bother putting it on my website properly), but eh.
Drain the beans, throw them in a pot, mix the rest of the ingredients together in a measuring cup and allow to stand for five minutes (maybe it’s placebo, but maybe it develops the garlic flavor a bit), pour over the beans, simmer on medium-low for ten minutes, and you’re done. Works great to just eat or as a taco filling.
I used to be a tea drinker, from age nineteen until sometime in my mids 20s, when I was seduced by the ease of just tossing some grounds and water into a machine and clicking brew to make some coffee, and just stopped drinking tea entirely for far too many years. I made the occasional attempt to grab a couple of tins and get back into it, but just always fell back to the ease of the coffee machine.
Eventually I got one of those fancy normal person 45-hour-a-week desk jobs, and had to wake up at normal person hours… and the extra ten minutes needed to steep tea instead of making enough coffee to give myself caffeine poisoning on a daily basis was just too much. So I just gave up entirely on trying to get back into tea for far too long. The thought of having to spend ten entire minutes heating up some water and steeping a pot of tea was just too much because mornings were absolute misery.
During the summer of 2018, I finally realized what I was doing to myself, and how many of my problems with irritability in the morning, constant exhaustion, being unable to get moving before the entire day was gone on the weekends, and taking hours to get ready when on the road and needing to go places to actually enjoy my brief mini-vacations had a common cause: drinking too much damn caffeine! I ordered a few packets of loose leaf tea, put the evil machine away, and forced myself to start drinking tea again.
The first months were rough: the amount of caffeine I had been consuming was pretty obscene, so I was even more exhausted and found focusing difficult. But eventually I made it through, and it’s been incredible. My resting heart rate is lower, I went from needing three or four 6oz cups of coffee just to not hate existence and be minimally awake to being able to grab a couple cups of tea and get moving (and nowadays, don’t even need caffeine in the morning at all, for the first time in over a decade), and when I’m on the road I can grab a half cup of coffee and be ready to go go go and enjoy life.
And less than three years later, here I am with fourteen tins of tea again, just like in 2004/2005, and I finally feel like me again. I won’t claim to be a connoisseur now though, I just drink boring black teas (nothing like a hearty cup of Assam) because I still don’t have the patience to properly make green tea aside from the occasional cup of gunpowder green tea (very forgiving), and Oolongs are generally too expensive for me now (I know you can steep them over and over, but I’m still a bit lazy and I don’t find them so much better than it justifies the prices nowadays). But it’s something.
I’ve been asked to post some content. Have some content.
No one said it would be good content.
Greetings,
At the press conference Friday morning, our mayor passionately stated:
The Raleigh City Council supports our police chief … We have her back now, and we support her.
Raleigh Mayor holds press conference after a week of protests in the city
The council member code of conduct states:
Members should never attempt to express an opinion on an issue as the position of the city unless the full council has endorsed that position.
CODE OF CONDUCT FOR THE RALEIGH CITY COUNCIL
However, there is no public record of a meeting, motion, vote, or resolution wherein the council declared their support for the police chief. Based upon this it appears that our Mayor violated the council code of conduct, and if the the rules of the council are to mean anything can and should be sanctioned for it. It is hypocritical for the mayor to consistently note when members of the public violate decorum, and to gavel at other members of the council when she deems them in violation, only to go on and do so herself with such a bold affirmation very publicly during a politically tense moment with public confidence in RPD low (an understatement, I suspect). If this is just a misunderstanding, a vote on a resolution of support for our police chief should be held so that each council member enters their view into the public record.
Even after the events of this weekend, the RPD continues to astound with its brazen attacks on their fellow citizens. Friday we learned that the RPD instructed the Wake County Sheriff to serve a warrant unrelated to the RPD’s jurisdiction (certainly not worthy of rousing officers in the middle of the night over) against Conrad James (whose event drew an astounding crowd of three), in the dead of night because he “had caused a nuisance”: merely knocking on the front door of a police station asking that officers pass a list of his demands for reform onward to their chief officer, afterward even having a polite chat with the police chief that happened to make for a diffusing news piece that was nothing but glowing for the police chief and the RPD (the citizen heard! the chief opening her heart and pledging to seek a more perfect justice!).
And then the RPD went on to openly surveil him (speaking his name as a target over public radio bands) during the peaceful marches Friday night, and furthermore openly followed him back to his home as he left well before curfew.
These are clear acts of retribution on the part of RPD that they have openly admitted to intended to have a chilling effect on speech, and for what? Mere participation in a moment of protest? Mild criticism of the police department? Should I be afraid of a knock on my door at three in the morning for sending these letters? Is the RPD running background checks on everyone who called into the meeting Thursday evening in case they have some outstanding warrant or unpaid citation they could be harassed over? Which of us will they next descend upon in the dead of night in their attempt to intimidate the city into silence? There is no going back from this precipice: the mayor and police chief must go, no more of this “if immediate demands are not met” nonsense.
Furthermore, while the curfew may have been legal and justified the first night, at this point it is very clearly unconstitutional on a number of grounds, and grows more problematic with each passing day. The NC ACLU has noted its concern with very similar curfews imposed in Greensboro and High Point, and by the criteria listed in their June 1st article it is clear Raleigh’s curfew fails to pass muster.
This is the latest declaration from our mayor that impinges upon our basic right to free expression, showing a pattern of either fundamental misunderstanding of or outright contempt for the basic law of our land. That upon reflection her only regret is not putting a curfew into place with even less justification makes it feel like contempt is the likelier of the two.
Does the city council really stand for this: For tear gassing peaceful protesters (including at least one member of the city council)? For banally violating the basic civil liberties of Raleigh’s citizens? For allowing the police to terrorize and take vengeance upon anyone who dares question them?
I thought I was cynical, but every day this year is a surprise,
To the mayor,
I see you are still in office. Do you not understand how responsibility works? Especially after Sunday where RPD launched chemical weapons into a peaceful crowd with no provocation (spreading an outright lie to justify it), proceeded to antagonize the crowd for hours by repeatedly tear gassing them, escalating the situation until the crowd erupted in anger. Officers launching flash bang grenades at the owner of Ruby Deluxe was a nice touch too.
There were hours where the crowd was cohesive enough that the police could have declared an unlawful gathering and ended it Sunday before rioting started (or, you know, the RPD could simply have not antagonized the crowd in the first place): the blame falls squarely on your shoulders as the Mayor for this absolutely bungled response and I think proves the point of the protesters. Your police force picked a fight with the citizens they are sworn to protect, and outright terrorized the city Sunday.
Compare to last night when RPD showed restraint and at least kept their jackbooted thug contingent out of sight, giving the protesters room and allowing them time to peacefully disperse. I do hope the council reconsiders the curfew soon however: it will certainly be unequally enforced if it goes on long enough, and there will almost surely be an incident that inflames tensions again.
In addition to to your resignation and the termination of the chief of police, the city council must move forward and kill the half-assed police “oversight” board (where the oversight is the oversight) and replace it with one that has subpoena power, as our marginalized communities have been demanding for years now. It might be time to reconsider your position that “Sometimes, when you make nobody happy, maybe that is the best solution” and consider that listening to the citizens you represent and protecting them from brutalization at the hands of law enforcement is the best solution, and is your duty. Law enforcement is a job: if they don’t like having to respect citizens, good riddance. Citizens can’t choose the color of their skin!
Reinstating CACs until an alternative is researched would be a good show of faith too, although since the rest of the council except for Mr. Cox are also opposed to them I admit that’s a stretch. Just know you’re all unlikely to be re-elected unless you actually do something about this and really begin to LISTEN to marginalized communities instead of paying them lip service and waiting for them to be gentrified out of existence.
If you don’t understand why you as the mayor must resign over this, I leave you with a tale of inverted responsibility courtesy of Kierkegaard:
Although everyone wants to rule, no one wants to have responsibility. It is still fresh in our memory that a French statesman, when offered a portfolio the second time, declared that he would accept it but on the condition that the secretary of state be made responsible. It is well known that the king in France is not responsible, but the prime minister is; the prime minister does not wish to be responsible but wants to be prime minister provided that the secretary of state will be responsible; ultimately it ends, of course, with the watchmen or street commissioners becoming responsible. Would not this inverted story of responsibility be an appropriate subject for Aristophanes!
I know you were looking for a cushy prestige gig to capstone your career where you didn’t actually have to lead as it’s clear you have no leadership ability in you, but that’s not how this year turned out. Resign and allow someone competent to take your place before Raleigh goes down in service of your vanity.
To the mayor,
Resign, now. You have no legitimacy after allowing the police to brutalize a peaceful protest last night and trigger rioting.
The chief of police and wake county sheriff need to go too. What did you think would happen when the police showed up fully jackbooted in riot gear off the bat? Do you not understand the message that sends? That they followed up by lobbing chemical weapons at peaceful protesters made it deafeningly loud: we are an occupying force, and you are the occupied. You are in charge of that force, and are ultimately responsible for last night.
You went on to blame outside agitators: I hate to break it to you, but the agitators took their uniforms off and quietly went back to their homes in our communities last night.
You’ve made it clear through your many tone deaf comments (remember when you endorsed Bloomberg, making it clear that you’re fine with monstrous policing that brutalizes marginalized communities as long as the tax base increases?) that you are only the mayor of upper class white Raleigh. Disbanding the CACs because the underclass used them to complain about being tread upon, creating a joke of a police advisory board with no teeth as a giant “fuck you” to the communities suffering from state violence, even continuing to push forward on the stadium project (made possible only by Trump’s “opportunity zones” which were created specifically to destroy minority communities!) even as the COVID-19 crisis began. But you created a few special parking zones! Mission accomplished! You’re a joke.
You’ve made it clear you view the majority of Raleigh as an annoyance, and wish to silence their pleas for a better life as they are ground underheel (until they are silenced forever: dispossessed by gentrification courtesy of your friends in the construction industry).
—
And did those feet in ancient times
Walk bare upon these lonely streets like mine?
Does God watch us from that penthouse high above
His children down below who live on air and love?
I was very excited on June 19th to hear that the Maine legislature had passed LD 1083, which would have finally implemented ranked voting for Presidential elections. But then thanks to some technicality the Senate had to pass it a second time, failed to do so, and adjourned for the session. So close, yet infinitely far away.
I’ve been waiting for ranked voting for at least the Presidential vote since I was fifteen (Ralph Nader, Indecision 2000, and an excellent American Government teacher all happened in the same year and ruined me), and it’s maddening how something so sensible is perpetually impossible to implement.
Imagine being able to vote for the party you really want to win with a middling mainstream candidate as your backup: instead of having to weigh how many people will never speak to you again because you voted "wrong", and violating everything you believe in so the slightly less shitty party can win (and the all-knowing politicos then using the lack of third party votes as self-fulfilling proof that no one supports major political change).
I’m hoping once one state successfully uses ranked voting for a general election it’ll spread to the rest quickly—it feels like shutting down the bullshit argument that voters are too stupid to count to three or four is the last significant propaganda barrier to breach. But it looks like we’re gonna have to wait at least another Presidential election cycle to prove the naysayers wrong :-\
My ancient (but still perfectly reliable and awesome) LaserJet 6MP has had a problem for a yearish now… one of the clips that keep the rear exit tray closed finally fatigued and snapped. Replacement bits are expensive enough that it’s not really worth replacing, and it’s not feasible to repair in place. Problem is, the rear tray needs to be closed for paper to feed to the exit tray on the top, and if it’s not quite closed, paper just tangles itself in the rollers and causes a nice little jam. So I’ve had a stack of DVDs jammed between the printer and my subwoofer on the same shelf this entire time…
Finally got fed up with this arrangement and used my other printer to make clips to keep the tray closed. Not very exciting, but hey… better living through technology.
A few summers ago, I was lucky enough to exist in the right time and place to be able to regularly play TEMPEST. The summer wasn’t meant to last — the realities of aging vector hardware in a busy bar led to TEMPEST disappearing a few shorts months later.
Attempting to simulate a spinner with a keyboard or gamepad with MAME is an exercise in futile suffering, so what’s a TEMPEST addict that can use a drill and knows how to plug wires into things and measure to do?
Why, build a very weird mouse in essence, which I did last September. This was a pretty easy project: I just grabbed a TurboTwist 2 spinner (an ultimarc spintrak would probably work equivalently), the mouse encoder board for it, a few buttons, and stuffed it all in a reasonably sized project box from the craft store.
I used a bit of openscad to make a template and ended up giving the box a light sanding and a few coats of spray paint that I had lying around.
I set MAME to interpret the third mouse button as both coin and start, so it’s all self contained for TEMPEST. It plays great after calibrating the turn count and making sure to totally disable mouse acceleration for the spinner.
It’s been a few years since my reprap’s journey began, and I think it has reached the conclusion, before a total overhaul and replacement of the frame (3.0?).
I replaced the 45° rear frame brackets with slightly better ones (used a bit off-label — I’m just bolting the frame part to a table) that mount to where I had originally intended the supports to go, decided to see if the hype was real and swapped my worn out three year old belts for real, live Gates GT2 belts, replaced the original y-axis mounts that made it impossible to remove the y-axis without getting under the printer with metal brackets that are accessible from the top, and swapped the y-axis parts for the Wilson II y-axis.
This resulted in some slight improvements in print quality (mainly in y, since the original belt was really worn out and there was a ton of backlash… not helped by my super misaligned belt line), but nothing major. Worth the effort if only for the y-axis not being awkwardly mounted and impossible to remove, and the control board being in a better position.
At this point it’s clear that the 2020 frame is too flimsy for a printer of this size… as such, I’m planning to design a new frame inspired by the Prusa i3 MK3 Bear Frame Rebuild, but in openscad instead of a proprietary cad program that doesn’t run on GNU/Linux (still debating continuing hacking on the pre-MK2 community version of the Prusa i3 or just re-forking the mainline Prusa i3 MK3).
A quick and probably meaningless rough history of changes to the machine, that I want to expand into a page on my actual website eventually (more naval gazing?):
To all zero of my readers,
Ages ago, I disabled comments on my journal because I posted approximately never and the few comments I did get were always spam so it was just some extra noise for me to deal with. You could always comment if you logged in using openid… maybe a good filter once upon a time, but it feels like that never really caught on and fizzled out over the years (maybe there will be a resurgence now that ActivityPub is catching on).
Since I am posting regularly again (albeit as mindless sharing of links I find interesting), I figured I’d give opening comments in general another shot. You still have to provide your name and email address, and the first comment is always moderated as a trivial spam filter. After I’ve approved your email address, you can post away all you’d like. I am a bit wary of enabling proprietary SaaS like akismet, so that’s not enabled yet… hopefully deleting spam from the moderation queue doesn’t become a huge pain.
I guess that’s that.
Thanks to moving to a provider that supports it, HCoop now has IPv6 support. After a bit of work on domtool, all member domains (including my journal here!) now have IPv6 enabled automatically.
We’re not doing anything too fancy (everyone shares one address for now, unfortunately our upstream provider has a weird implementation and we only get 16 IPv6 addresses per server right now), but it feels pretty cool to see the "6" in my menu bar from IPvQ.
We also finally implemented PHP 7.2 support, just in the nick of time.
2018 update.
To all zero of my readers,
Actually writing things seems to be something I can’t muster up the will to do.
So I hacked up an rss plugin for wordpress last year to repost excepts from my tt-rss shared feed, but have left the posts it generates private. Since it’s OK if not ideal, I’m just gonna set the plugin to post publicly for now to see if it works out, and maybe as motivation to hurry up and finish tweaking the format, or writing a fresh plugin from scratch that only does what I need.
For now it will post every time I update my shared feed from tt-rss; I am leaning toward modifying it so that it collects all posts and makes a single daily entry, but I’ll see how this works first.
I previously wrote David Price after learning of HR 676‘s reintroduction this year, and received no response (not even a paltry form letter sent by an intern). Since the issue is back on the table, I decided to give it another shot. Feel free to borrow some of my ideas.
Representative Price,
I am writing you a second time about HR 676, the Expanded and Improved Medicare For All Act [0] which your colleague John Conyers is yet again introducing, and to request that you cosponsor the legislation.
As you are likely aware, Senator Sanders has announced plans to introduce either a Medicare for All or Public Option in the Senate in the coming weeks. With the collapse (and moreso with the grumblings of revival) of the AHCA efforts, it is my opinion that the time is ripe for Democrats to show that they are still capable of pushing for social progress, instead of merely defending the status quo as seems to be their way in recent years.
My hope is that strong support for HR676 in the House will result in a Senate version, instead of a watered-down Public Option that is, purely from a financial perspective, doomed to failure as it would be forced to take on the sickest citizens and would not have the needed clout to effectively manage costs.
Although I was unable to take off of work to attend any of your recent Town Halls, I was glad to read [1] that several of my fellow constituents asked about your stance on single-payer and called upon you to support Medicare for All. I was, however, disappointed hearing that your response was not one of support, but a declaration it was off limits for another 20 years.
A progressive party cannot progress society if they lack forward thinking ideals and goals. I fear that the democratic party has now become a conservative party, fiercely defending the status quo, attacking progressive politics, and having the mere appearance of progressiveness relative only to the republican party now that it has devolved into a regressive party of neofascists.
Although it is true we still need to defend and expand basic access to healthcare, and perhaps the bill would be dead on arrival this session, I still believe your party supporting it would go a long way toward repairing your tarnished image with the public, possibly ensuring strong wins in the House and the ability to push positive legislation come 2019.
There is also the human cost — at a time when the majority of your constituents support a single-payer system, when insurance company profits are bolstered by the private-industry bailout of the ACA, when real health care costs are unaffordable for far too many despite nominally having insurance — you ask us to suffer and die destitute upon the streets for twenty more years before even considering the idea that profit and human health are incompatible?
Economic reality supports single-payer sooner than later as well — all resources expended enhancing the intrinsically broken for-profit healthcare industry instead of building up a public not-for-profit one is wasted, and with each year the population grows and ages, and the problem of building a public system sufficient for all becomes that much more financially disruptive; perhaps insurmountable.
We simply do not have time as a society to delay more than another four years (and even that is too long, but your party decided against single-payer when there was a chance, and I suspect the current President wouldn’t be amenable to signing such a bill). If the discussion is not started now, the prospects for passage in time to save the country from a public health crisis not seen since the 19th century seem dim.
I end my plea with a warning — I suspect you are aware of the strong support for Sanders during the 2016 primary in your district, and the growing disaffection with status-quo democrats. A failure to take a stand for something so popular reinforces the perception that your party no longer cares to represent the common citizen.
I am already leaning toward lending material support to any more progressive primary challenger for your seat, and your refusal to make a stand with HR676 will certainly seal that decision. The North Carolina Green Party also may very well have ballot access in 2018 (emboldened by a recent 11th circuit ruling [2] they have now filed to overturn our ballot access laws as unconstitutional [3]), so you may no longer rest easy, assured that your gerrymandered constituency will re-elect you without challenge.
Best Regards,
Clinton Ebadi
[0] https://www.congress.gov/bill/115th-congress/house-bill/676]
[1] http://carycitizen.com/2017/03/07/david-price-talks-health-care-budget-cuts-in-cary-town-hall/
[2] http://www.ajc.com/news/state–regional-govt–politics/court-upholds-ruling-for-third-party-presidential-candidates/hKV5eClapgz7Tgj3k6OK6N/
[3] http://ballot-access.org/2017/02/24/green-party-and-constitution-party-file-ballot-access-case-in-north-carolina/
Good news for the Netherlands:
The big winner of Wednesday’s election – and now the largest party of the Dutch left for the first time – was GreenLeft, headed by 30-year-old Jesse Klaver, hailed by his enthusiastic supporters as the “Jessiah”.
…
Sometimes compared to Canada’s youthful prime minister, Justin Trudeau, Klaver – who has a Moroccan father and a mother of Indonesian descent – said on polling day that the left’s answer to the far right’s rise in Europe was to stand up for its ideals.
“What I would say to all my leftwing friends in Europe: don’t try to fake the populace,” he said.
“Stand for your principles. Be straight. Be pro-refugee. Be pro-European. We’re gaining momentum in the polls. And I think that’s the message we have to send to Europe. You can stop populism.”
The Netherlands’ youngest ever party leader, Klaver built a strong following on social media through small Meetup events after taking over GreenLeft’s leadership in May 2015.
Where were these people when the Democrats scuttled socialized healthcare and gave us the capitalist abomination that is the ACA?
I think they were busy calling me a communist for suggesting that for-profit enterprise was intrinsically incompatible with a universally required service like “preventing people from dying on the streets.” But economic eugenics is ok — those poor undesirables really should have had a better lineage if they wanted healthcare after all — until the petit-privileged classes find out they too get to die on the streets as inequality rises.
And yet they still fight for their privileged capitalist healthcare (we just want the leeches to die, not proper middle class wage slaves, get it?) instead of fighting for something that would be unassailable when the forces of regression rise to attack again.
The CCFL backlight on my six year old monitor started having problems cold starting this week and I need my monitor to live so a new one was ordered. This was surprisingly cheap, QHD, and the included stand rotates which is neat for pdfs and viewing a ton of code at once (actual readable size here, could knock it down one point of I got around to getting new glasses). A few hours later I realized I could also play pinball on it… how did I live before?
Thom Tillis is a total asshole and should probably go fuck himself. His current views represent a disdain for democracy and education and I hope that he loses re-election and is banished from the public sphere for all of time when his seat comes up.
Here is a letter I wrote to him on the topic of the DeVos nomination after hearing he was on the fence and wanted the input of his constituents. Not that I thought it would do anything — I’ve far too good an education to think something like lobbying your representatives will result in representation, unless that lobbying comes with cash money or a promise of a lavish consulting gig later.
Greetings,
I recently read in the Charlotte Observer that you were seeking the input of North Carolina citizens in order to make your decision on the confirmation of DeVos for Secretary of Education. Since you asked — here’s my two cents:
Our public education system has been under attack by regressive anti-intellectual forces for decades, and her appointment represents their ultimate victory in their quest to build a compliant, uneducated populace. It would be a great tragedy to see our public education system completely dismantled for a system of second-rate charter schools (as can be seen from the many scandals with poor performance, grade inflation, and outright noncompliance with state education standards here in North Carolina), wherein only the privileged few may receive a good education while the rest languish in ignorance and the resulting lack of economic and social opportunity. It could very well result in the dissolution of the already tenuous social fabric itself in ten or twenty years time when the children of today take the helm of society. Now is the time to rebuild our failing system, not to encourage it to completely fail.
As representative democracy is based upon an informed and educated electorate, this would represent a great tragedy and an acceleration of our descent into status as a failed democracy. I exhort you to vote against her confirmation.
One thing that bothers me about Democrats and their self-praise in regards to voting rights is that they have done more than the Republicans to suppress ballot access by third parties. Not that the Republicans haven’t done their fair share (it benefits both ol’ boys after all). There’s some good news on that front today: The 11th Circuit of Appeals upheld that Georgia’s Egregious and Unconstitutional Ballot Access Laws Are Indeed Unconstitutional:
The one-sentence ruling, by a unanimous three-judge panel of the 11th U.S. Circuit Court of Appeals, adopted the “well-reasoned opinion” issued last March by U.S. District Judge Richard Story in Atlanta. Story had significantly lowered the number of signatures required for third-party candidates to petition to get on Georgia’s presidential ballot — from tens of thousands [approximately 51k] to 7,500.
The ruling has a nice side-effect in that it lifts restrictions in Florida as well that curiously enough went unenforced from 2011 until August of 2016, just in time to keep “…Gloria La Riva, Evan McMullin, and Thomas Hoefling off the Florida ballot, with no warning.”
Georgia appears to be planning an appeal; my hope is that the Supreme Court will take up the case and strike down absurd ballot access restrictions across the country so that we can have freer elections in 2018. I mean, who cares if you can vote, if you have no options at the ballot box?
I have a seemingly trivial task at hand: automagically repost things on the ol’ weblog from my public tt-rss atom feed. Just an excerpt and maybe a relevant picture, nothing too difficult.
I’ve been fighting it on and off again for years, recently finding cybersyn which worked but has its own bugs (like not aggregating anything without a valid thumbnail and filling my media library with gigantic stls from planet reprap. Still, it was the only one that actually fetched feeds with any reliability.
But to get excerpts and some other things I’ve had to hack it up… and have come to realization that I too must write another half-assed aggregation plugin. Or convince the cybersyn folks to add some filters to make it easier to munge things. Unfortunately that doesn’t fix things like it using php’s built in horror show of an xml parser (so I end up with feeds entitled “Article Title – Source Name” and there’s nothing I can do about — it’s just blindly catenating the title
in <entry>
and <source>
, and the source comes last so that’s that without major surgery…
Running tests with my hacked up plugin set to post privately also reveals a social issue: I can easily share more than a full page of links in between real posts (if I actually journalled into the abyss… which I might be now). Thinking there should be some kind of squashing (e.g. everything posted in a 3h window gets thrown into one post). Or maybe not, tracking posts would be more annoying then. Trying not to think too hard about it and just get something minimal running soon.
Last week, the Montgomery County Council approved a bill that would have made it the first jurisdiction in Maryland — and the second in the region after Washington, D.C., to mandate a $15-per-hour base pay by 2020.
…
Del. Derek E. Davis (D-Prince George’s), the chairman of the House Economic Matters Committee, has introduced a bill that would put the General Assembly in charge of setting minimum wage even for cities and counties.
Davis said the bill would help improve the business climate in Maryland by making wage and benefit rules more predictable and consistent, noting that Montgomery and Prince George’s counties current have their own minimum-wage laws in place, and Baltimore considered a $15 base wage last summer.
“We’re not a collection of 24 individual fiefdoms,” Davis said “We have to work together as a state so we can attract and retain businesses, keep a healthy, strong economy, and not put our jobs at risk.”
Who needs Republicans when you have Democrats like these. It’s not like a higher minimum wage is a majoritarian viewpoint or anything like that…
This post brought to you by me finally overcoming extreme procrastination and general laziness and implementing fastcgi php support in domtool. Yep, we were spawning an independent php-cgi for each request…
January 25th
A national physicians group today hailed the reintroduction of a federal bill that would upgrade the Medicare program and swiftly expand it to cover the entire population, saying it’s the only workable and equitable way to move forward in U.S. health care.
The Expanded and Improved Medicare for All Act, H.R. 676, introduced last night by Rep. John Conyers Jr., D-Mich., ranking member of the Judiciary Committee, with 51 other House members, would replace today’s welter of private health insurance companies with a single, streamlined public agency that would pay all medical claims, much like traditional Medicare works for seniors today.
And yet, not a peep from the so-called “Real Media”. Shocking. This broke January 20th, and aside from an open letter published by Ralph Nader, some press releases from physicians groups, and a few recent endorsements from labor unions the supposedly Liberal Media hasn’t made a peep. How can anyone fight for something they don’t know exists?
I’ve put together a note on the Frobenius property for weak factorisaion systems and it’s relation to models of type theory. Awodey and Warren described a way of obtaining a model of type theory with identity types from a model category structure/weak factorisation system. However, in absence of axioms for other type formers (specifically, Π-types), one is required to put an additional restriction on the weak factorisation system, in order to model identity elimination in an arbitrary context/with arbitrary parameters; specifically, it is required that cofibrations are stable under pullbacks along fibrations. In presence of Π-types, however, this is not necessary, as I tried to explain in the note.
It’s almost alive!
This post is intended to be a short summary of my SoC project, as well as my recent trip to Darcs sprint.
I am finishing up this post on the train back from the Autumn 2015 Darcs sprint. Today (Sept 20, Sun) was a very fun day full of darcs chatting and coding. By the end of the day we’ve heard a number of presentations
DataKinds
are used in the darcs codebase;I have spent this summer hacking on DarcsDen as part of the Google Summer of Code program.
My basic goal was to create a "local" version of darcsden. It was not a trivial task to install darcsden (and probably installation is still not very easy!). It uses a third-party software like Redis and CouchDB. During my coding process I modifed darcsden such that it now can be a good choice for local (or lightweight single user) darcs UI. The local darcsden version can be used without any databases, tracking the repositories in the local file system. This way darcsden can be used by a developer on her local computer, like darcsum, (for working with/comparing repositories) as well as a replacement for darcsweb/cgit — a single user web front for darcs repositories.
Besides that a user of a local version can use darcsden’s interactive UI for recording new patches, as well as a command-line tool den
for a quick way of browsing the repositories.
Installing darcsden-local is currently not as easy as I want to it be, but I hope that soon you will be able to install it just by running cabal install darcsden
or brew install darcsden
. As for now, one could do the following:
darcs get --lazy http://hub.darcs.net/co-dan/darcsden-local
cabal install .
or stack install
This should install the darcsden binary and all the related css/js files. You can start darcsden by running darcsden --local
. If you open your web browser you should see a list of repositories in the current directory.
However, you might have repositories scattered all over the place, and scanning your whole system for darcs repositories is just inefficient. For this purposes darcs keeps a list of repositories in a file inside your ~/.darcs
directory. You can manage that list either by hand, or using the command-line den
tool:
den $PATH
— add $PATH to the list of repositories in ~/.darcs/darcsden_repos
(if it’s not already present there), start darcsden server in the background and launch the browser pointing to $PATH;den
— the same as den .
;den --add $PATH
— add $PATH to the list of repositories in ~/.darcs/darcsden_repos
;den --remove $PATH
— remove $PATH from the list of repositories in ~/.darcs/darcsden_repos
.In order to further customize darcsden, one can tweak the configuration file located at ~/.darcs/darcsden.conf
. Apart from the usual darcsden settings one may pay attention to the following variables:
homeDir
(default .
), points to the "root" directory with repositories. If the list file ~/.darcs/darcsden_repos
is not present darcsden will recursively search repositories in that directoryunLocal
, pwLocal
: the username and the password of the "local" userThe user/password credentials are required for editing the repositories and recording new patches. However, the den
binary should automatically pick them up from the config file and log you in.
Once you are logged in, and you have unrecorded changes in the repository, you can use darcsden UI to record a new patch.
DarcsDen record
Below you can see an example of recording and merging patches from a branch.
DarcsDen merge
Darsden allows you to create forks/branches of your repositories, and it keeps track of the patch dependencies in your branches.
More "internal" changes:
den
tool utilizes it to log the user in automatically.During the sprint I hacked together some code for viewing suspended patches along the regular ones. The next step would be to have a similar interface for managing the suspended patches.
We have also discussed the possibility of adding rewrite rules implementing short-cut fusion for the directed types in Darcs. In order to see if it’s really worth it we would have to bring back to life the benchmarking suite (or at least check on it!).
It was a really exciting weekend for me and I was delighted to meet some of my IRC friends. As it turns out, it is a small world and despite being from different parts of it we have a bunch of common IRL friends, professors. As the French would (probably not) say, très bien. The next darcs sprint will probably be in January, and probably in Europe, again.
I am editing this post from IRILL, where the darcs sprint is taking place
One of the things that I particularly like about the Darcs codebase is that you can see that the developers were not shy about using intermediate-slash-advanced Haskell/GHC features to help achieving type safety. You can see GADTs, associated types, phantom types, existential types actively used.
In this post I would like to discuss the representation of patches and the use of type witnesses in darcs.
This post is intended for people interested in patch theory and its implementation in darcs. A passing familiarity with patches, contexts, inverses, etc is useful, but not required, as we restate some basic definitions in this section.
A primitive patch is a basic unit in patch theory. It constitutes an atomic change in the repository. The definition of a primitive patch may vary, but usually the following changes are considered primitive patches:
n
in a file in the repositoryEvery primitive patch has a pre-context and a post-context. Roughly, you can think of a pre-context as the full state of the repository before the change was made, and of the post-context as the full state of the repository after the change was applied. We write (x)-A->(y)
for a patch A
with a pre-context x
and a post-context y
.
If a primitive patch A
has a pre-context a
, a post-context o
, and a primitive patch B
has a pre-context o
, a post-context b
, then we can combine two patches to obtain a sequential patch AB
with the pre-context a
and the post-context b
.
Every primitive patch (x)-A->(y)
has an inverse (y)-A^{-1}->(x)
, such that (x)-A->(y)-A^{-1}->(x)
is equivalent to the identity patch (x)-1->(x)
.
In the next sections we will see how those things are implemented in darcs.
A primitive patch, which constitutes a single fine grained change, can be represented as a (G)ADT:
data Prim where
Move :: FileName -> FileName -> Prim
RmFile :: FileName -> Prim
AddFile :: FileName -> Prim
Hunk :: FileName -> Int -> ByteString -> ByteString -> Prim
RmDir :: FileName -> Prim
…
We can represent complex patches as sequences of primitive patches:
data Patch where
NilP :: Patch
PrimP :: Prim -> Patch
SeqP :: Patch -> Patch -> Patch
This seems reasonable enough. But if we implement our patch theory this way we seem to be missing something — patches have (pre- and post-) contexts. Having contexs allows us to enforce patch composition on the level of type system. Consider the following definition, which uses phantom types as type witnesses for contexts.
data Prim x y where
Move :: FileName -> FileName -> Prim x y
RmFile :: FileName -> Prim x y
AddFile :: FileName -> Prim x y
Hunk :: FileName -> Int -> ByteString -> ByteString -> Prim x y
RmDir :: FileName -> Prim x y
…
data Patch x y where
NilP :: Patch x x
PrimP :: Prim x y -> Patch x y
SeqP :: Patch x y -> Patch y z -> Patch x z
We call the types with witnesses representing pre- and post-contexts directed types. Intuitively, the directed type D x y
has a “direction” from x
to y
, written as (x)->(y)
. The Prim
datatype looks pretty much like the type actually used in Darcs. The Patch
datatype, however, is completely artificial. We will see in the next sections how Darcs really models complex patches.
Two particularly useful directed types used in darcs are directed lists: forwards lists of the type FL a x y
and reverse lists RL a x y
. Forward lists “go” from the head to the tail; reverse lists “go” from the tail to the head. The lists are polymorphic over a
just like regular lists.
data FL a x y where
NilFL :: FL a x x {- The empty list stays at (x) -}
(:>:) :: a x y -> FL a y z -> FL a x z
infixr 5 :>:
For myself, I visualise forward lists like this:
(x) —a—> (y) —b—> (z) ——Nil——> (z)
a :: Patch x y
b :: Patch y z
(a :>: b :>: NilFL) :: FL Patch x z
The reverse lists are “going” from tail to head1
data RL a x y where
NilRL :: RL a x x
(:<:) :: RL a x y -> a y z -> RL a x z
infixl 5 :<:
(Mnemonically, the the head is always “greater” than the tail)
The reason I used the word “go” inside quotation marks so far is the following. Reverse lists and forward lists represent the same concept: a sequence of patches (or a sequence of directed things for that matter). They only differ in the associativity of the elements. Forward lists associate to the right, but reverse lists associate to the left.
p = Move "foo" "bar"
-- [[(x) --Nil--> (x) -p-> (y)] -id-> (y)] -p^{-1}-> (x)
example :: RL Patch x x
example = NilRL :<: p :<: Identity :<: inverse p
-- (x) -p-> [(y) -p^{-1}-> (x) --Nil--> (x)]
example2 :: FL Patch x x
example2 = p :>: inverse p :>: NilFL
The right-associated/reverse lists provide easy access to the last element of the sequence; the left-associated/forward lists provide easy access to the first element of the sequence. Therefore, if we view a repository as a directed sequence of patches, right-associated lists are useful for operations that work on the “latest” patches in the repository (such as record/unrecord), and left-associated lists are useful for commands that scan the repository from the beginning (like clone).
We can reassociate the lists easily, and verify that the two representations are isomoprhic:2
reverseRL :: RL a wX wY -> FL a wX wY
reverseRL = r NilFL
-- the type signature of r basically gives us an invariant
-- wZ is slowly "decreasing" reaching the point where
-- wZ = wX; at that point the first argument is of type FL a wX wY
where r :: FL a wZ wY -> RL a wX wZ -> FL a wX wY
r a NilRL = a
r a (xs :<: x) = r (x :>: a) xs
For example,
-- [[(x) --Nil--> (x) -p-> (y1)] -q-> (y2)] -r-> (z)
Turns into
-- (x) -p-> [(y1) -q-> (y2) -r-> [(z) --Nil--> (z)]]
Exercise: write a function reverseFL :: FL a wX wY -> RL a wX wY
We can write a lot of directed analogues of familiar list functions. For example, here is a directed append:
infixl 5 +<+
(+<+) :: RL a wX wY -> RL a wY wZ -> RL a wX wZ
xs +<+ NilRL = xs
xs +<+ (ys :<: y) = (xs +<+ ys) :<: y
Exercise: write directed append for forward lists: (+>+) :: FL a wX wY -> FL a wY wZ -> FL a wX wZ
So we wrote a bunch of standard list functions for directed lists; what about some of the other functions? Can we, for example, implement filter
for directed lists. Can it look like filterFL :: (a wX wY -> Bool) -> FL a wX wY
? Well, we can try writing
filterFL :: (a wX wY -> Bool) -> FL a wX wY
filterFL p NilFL = NilFL
filterFL p (x :>: xs) | p x = filterFL p xs
| otherwise = x :>: filterFL p xs
However, under closer scrutiny we realize that it does not typecheck! In the second clause of filterFL we have the following information:
x :: a x y, xs :: FL a y z
filterFL xs :: FL a y z
Thus, in the first case (in which p x
holds) we try to return something of the type FL a wY wZ
, when FL a wX wZ
was expected. It is clear that generally we can do this only if x :: a wX wX
, i.e. wY = wX
. But a simple predicate of the type p :: a wX wZ -> Bool
won’t tell us anything about that. We need an additional type witness in our system telling us that if p x
holds, then x :: a wX wX
. For that purpose we introdue the EqCheck datatype.
data EqCheck wX wY where
IsEq :: EqCheck wX wX
NotEq :: EqCheck wX wY
then the type of a predicate would be
type Pred a = forall wX wY. a wX wY -> EqCheck wX wY
If (p x) = IsEq
, then the typechecker will know that x :: a wX wX
. We can then finally write
filterFL :: Pred a -> FL a wX wY -> FL a wX wY
filterFL p NilFL = NilFL
filterFL p (x :>: xs) | IsEq <- p x = filterFL p xs
| otherwise = x :>: filterFL p xs
EqCheck
is used this way in the darcs source code to e.g., filter our internal patches. Sometimes darcs stores information — like suspended patches — in the so called internal patches. Every patch type implements the internal patch checker (code slightly adapted):
-- |Provides a hook for flagging whether a patch is "internal" to the repo
-- and therefore shouldn't be referred to externally, e.g. by inclusion in tags.
-- Note that despite the name, every patch type has to implement it, but for
-- normal (non-internal) types the default implementation is fine.
-- Currently only used for rebase internal patches.
class MaybeInternal p where
-- | @maybe (const NotEq) (fmap isInternal patchInternalChecker) p@
-- returns 'IsEq' if @p@ is internal, and 'NotEq' otherwise.
-- The two-level structure is purely for efficiency: 'Nothing' and 'Just (InternalChecker (const NotEq))' are
-- semantically identical, but 'Nothing' allows clients to avoid traversing an entire list.
-- The patch type is passed as an 'FL' because that's how the internals of named patches are stored.
patchInternalChecker :: Maybe (forall wX wY . FL p wX wY -> EqCheck wX wY)
patchInternalChecker = Nothing
When the user runs darcs tag
in the repository, darcs creates a dummy patch that explicitly depends on all the previous patches — apart from the internal ones of course. Thus, the tag
command uses the following function (slightly adapted):
filterNonInternal :: MaybeInternal p => PatchSet p wX wY -> PatchSet p wX wY
filterNonInternal =
case patchInternalChecker of
Nothing -> id
Just f -> \l -> PatchSet (filterRL (f . patchcontents . hopefully) (unPatchSet l))
where a PatchSet
is the list of PatchInfoAnd
patches — patches together with the meta-information.
It is worth noting that EqCheck x y
is isomorphic Maybe (x :~: y)
, but the propositional equality datatype has only been added to base since 4.7.0.0. In the future versions darcs will probably switch to using Data.Type.Equality
.
We’ve briefly touched upon patch representation in darcs and talked about directed types and directed programming.
A good if a bit outdated reference is Jason Dagit’s master thesis (specifically the bits from chapter 4). The wiki is currently lacking in material, but I hope to improve the situation eventually.
Next time we will probably discuss either directed pairs and their use in darcs, or sealed datatypes, or both.
My 600W 24V DC power supply arrived from mouser, along with my hobbed bolts and the NEMA14 motors for the dual extruder.
I’m wiring up the DC side of the power supply to use 12 awg wire and female disconnects for now. I’ve got the main board supply, a separate line for the heatbeds, and a third set that will be wired in voltage regulator to give me a couple of amps of 12V power for the fans.
And, yeah, heatbeds. The Wilson y-axis can be stretched to 400mm, and I figured it was worth a shot going all the way. I wanted at least 300mm in the x-axis as well, and I found 200x300mm heatbeds (cheaper than one 300mmx300mm) and a conveniently sized 16″x12″ piece of glass at Home Depot. Worst case, it proves to be too large and I have to downgrade to 200mmx300mm (keeping the second heatbed ready for The Future). This might seem a wee bit insane, but, after having used the TAZ 4, less than 300mmx300mmx250mm seemed underwhelming.
For the controller, I got an Azteeg X3 Pro because it has dual heatbed MOSFETs and support for up to five extruders as a bonus. At the outset, I decided to sink some of the savings over buying a printer into dual extrusion, and wanted to leave open the possibility of at least triple later on… and the X3 Pro wasn’t much more than a RUMBA with steppers aaaand it came with eight stepper drivers (useful in their own right), was fully soldered, and, hey… a triple nozzle extruder plus a single hexagon in the next couple of years or something doesn’t seem too crazy does it?
Not much I can do now until my nuts and bolts come Monday or Tuesday. I have very boring things to say about crimping wire harnesses too.
So I printed the parts for a three dee printer on a TAZ 4 my friend graciously let me borrow, and I may have actually spent weeks going over the BOM a few times … and ended up hitting order on a few too many websites. Packages started trickling in yesterday…
This is going to be … interesting.
Darcs is a patch-centric version control system. In Darcs, there is no “correct” linear history of a repository – rather, there is a poset of patches. That means that most of the time you are pushing and pulling changes you can cherry-pick patches without a problem. However, in some cases you cannot perform a pull (or some other operation on the repository) smoothly. Sometimes it is necessary to rewrite the “history” – i.e. modify a patch that is a dependency of one or more other patches. For those cases darcs rebase
comes in handy. To put it in the words of the implementor “Rebase is a workaround for cases where commutation doesn’t do enough”.
A repository can change it’s state from rebase-in-progress back to normal if there are no suspended patches left. However, be aware that you cannot unsuspend a patch1 if you have unrecorded changes in the repository. In light of this, I suggest recording a temporary patch with current changes
darcs record -am DRAFT
You can suspend that patch at the beginning of your rebase process and apply it at the end.
darcs rebase
is an operation (or, rather, a family of operations) that allows one to make changes “deep down” in the repository history. One of the crucial things that allows for rebase
to work is the fact that since darcs 2.10 patches can be suspended. When one performs any of the darcs rebase
commands, the repository moves to a special rebase-in-progress state. In this state repository contains a pristine, a set of patches, a working copy, and — in addition to all the usual stuff — a set of suspended patches. Suspended patches are not active in the repository — that is, they are not applied.
Let’s go over the rebase
subcommands
This is simple: list the suspended patches
Moves selected patches into the suspended state. Once the patch is suspended it is no longer active in the repository.
Note: once you suspend a patch, it changes its identity. That means that even if you suspend a patch and unsuspend it immediately, you will get a different repository that you have started with. Let this be a good reason (one of a couple!) for doing rebase on a separate branch.
> cat file
test
123
> darcs rebase suspend
patch 64523bc4622fad02a4bdb9261887628b7997ebdd
Author: Daniil Frumin
Date: Thu Jul 23 18:49:30 MSK 2015
* 123
Shall I suspend this patch? (1/5) [ynW…], or ? for more options: y
patch cc54d7cf4b9e3d13a24ce0b1b77b76581d98d75d
Author: Daniil Frumin
Date: Thu Jul 23 18:43:53 MSK 2015
* Test
Shall I suspend this patch? (2/5) [ynW…], or ? for more options: d
Rebase in progress: 1 suspended patches
> darcs rebase log
patch 64523bc4622fad02a4bdb9261887628b7997ebdd
Author: Daniil Frumin
Date: Thu Jul 23 18:49:30 MSK 2015
* 123
Shall I view this patch? (1/?) [yN…], or ? for more options: y
[123
Daniil Frumin **20150723154930
Ignore-this: 43e09e6503ac74688e74441dc29bce25
] hunk ./file 2
+123
Rebase in progress: 1 suspended patches
> cat file
test
Does the opposite of suspend
: applies a suspended patch to the repository and changes its state to normal.
> darcs rebase unsuspend
patch 64523bc4622fad02a4bdb9261887628b7997ebdd
Author: Daniil Frumin
Date: Thu Jul 23 18:49:30 MSK 2015
* 123
Shall I unsuspend this patch? (1/1) [ynW…], or ? for more options: y
Do you want to unsuspend these patches? [Yglqk…], or ? for more options: y
Rebase finished!
Rebase apply takes a patch bundle and tries to apply all the patches in the bundle to the current repository. If a patch from the bundle conflicts with a local patch, then the local patch gets suspended. You will thus have a chance to resolve the conflict by amending your conflicting patches, at a price of.. well, changing the identity of your local patches.
Sort of like rebase apply
, but instead of a patch bundle it obtains the patches from a remote repository.
Specifically, rebase pull
applies all the remote patches, one-by-one, suspending any local patches that conflict. We will see more of rebase pull
in the second example.
Imagine the following situation: at point A you add a configuration file to your repository, then you record a patch B that updates the settings in the configuration file. After that you make some more records before you realize that you’ve included by accident your private password in patch A! You want to get rid of it in your entire history, but you can’t just unrecord A, because B depends on A, and possibly some other patches depend on B.
The contents of the configuration file after patch A:
port = 6667
host = irc.freenode.net
password = awesomevcs
Patch B, diff:
@@ -1,3 +1,4 @@
-port = 6667
+port = 6697
+usessl = True
host = irc.freenode.net
password = awesomevcs
You cannot just amend patch A, because the patch B depends on A:
> darcs amend
patch 1925d640f1f3180cb5b9e64260c1b5f374fce4ca
Author: Daniil Frumin
Date: Tue Jul 21 13:23:07 MSK 2015
* B
Shall I amend this patch? [yNjk…], or ? for more options: n
Skipping depended-upon patch:
patch 22d7c8da83141f8b1f80bdd3eff02064d4f45c6b
Author: Daniil Frumin
Date: Tue Jul 21 13:22:24 MSK 2015
* A
Cancelling amend since no patch was selected.
What we will have to do is temporarily suspend patch B, amend patch A, and then unsuspend B.
> darcs rebase suspend
patch 1925d640f1f3180cb5b9e64260c1b5f374fce4ca
Author: Daniil Frumin
Date: Tue Jul 21 13:23:07 MSK 2015
* B
Shall I suspend this patch? (1/2) [ynW…], or ? for more options: y
patch 22d7c8da83141f8b1f80bdd3eff02064d4f45c6b
Author: Daniil Frumin
Date: Tue Jul 21 13:22:24 MSK 2015
* A
Shall I suspend this patch? (2/2) [ynW…], or ? for more options: d
Rebase in progress: 1 suspended patches
At this point, the state of our repository is the following: there is one (active) patch A, and one suspended patch B.
> darcs rebase changes -a
patch 4c5d45230dc146932b21964aea938e2a978523eb
Author: Daniil Frumin
Date: Tue Jul 21 13:28:58 MSK 2015
* B
Rebase in progress: 1 suspended patches
> darcs changes -a
patch 21f56dfb425e4c49787bae5db4f8869e96787fb2
Author: Daniil Frumin
Date: Tue Jul 21 13:28:49 MSK 2015
* A
Rebase in progress: 1 suspended patches
> cat config
port = 6667
host = irc.freenode.net
password = awesomevcs
> $EDITOR config # remove the password bit
> darcs amend
patch 22d7c8da83141f8b1f80bdd3eff02064d4f45c6b
Author: Daniil Frumin
Date: Tue Jul 21 13:22:24 MSK 2015
* A
Shall I amend this patch? [yNjk…], or ? for more options: y
hunk ./config 3
-password = awesomevcs
Shall I record this change? (1/1) [ynW…], or ? for more options: y
Do you want to record these changes? [Yglqk…], or ? for more options: y
Finished amending patch:
patch 21f56dfb425e4c49787bae5db4f8869e96787fb2
Author: Daniil Frumin
Date: Tue Jul 21 13:28:49 MSK 2015
* A
Rebase in progress: 1 suspended patches
Now that we’ve removed the password from the history, we can safely unsuspend patch B (in this particular situation we actually know that applying B to the current state of the repository won’t be a problem, because B does not conflict with our modified A)
> darcs rebase unsuspend
patch 1925d640f1f3180cb5b9e64260c1b5f374fce4ca
Author: Daniil Frumin
Date: Tue Jul 21 13:23:07 MSK 2015
* B
Shall I unsuspend this patch? (1/1) [ynW…], or ? for more options: y
Do you want to unsuspend these patches? [Yglqk…], or ? for more options: y
Rebase finished!
And that’s done!
> cat config
port = 6697
usessl = True
host = irc.freenode.net
You may use this rebase strategy for removing sensitive information from the repository, for removing that 1GB binary .iso that you added to your repository by accident, or for combining two patches into one deep down in the patchset.
Imagine you have a fork R’ of a repository R that you are working on. You are implementing a feature that involves a couple of commits. During your work you record a commit L1 that refractors some common datum from modules A.hs and B.hs. You proceed with your work recording a patch L2. At this point you realise that after you forked R, the upstream recorded two more patches U1 and U2, messing with the common datum in A.hs. If you just pull U1 into your fork R’, you will have a conflict, that you will have to resolve by recording another patch on top.
S
/ \
/ \
L1 U1
Note: if you run darcs rebase pull
in R’, then the only patches that will be suspended are the ones which are already in R’. Because suspended patches gain new identity, make sure that you do not have other people’s conflicting patches present in R’.
The way to solve this would be to first do darcs rebase pull
, which would suspend the conflicting patches, and then start unsuspending the patches one by one, making sure that you fix any conflicts that may arise after each unsuspend.
Consider a concrete example with two repositories rep1
and rep1_0
.
rep1_0 > darcs changes
patch ebaccd5c36667b7e3ee6a49d25ef262f0c7edf2b
Author: Daniil Frumin
Date: Mon Jul 27 20:56:25 MSK 2015
* commit2
patch a7e0d92a53b0523d0224ef8ffae4362adf854485
Author: Daniil Frumin
Date: Mon Jul 27 20:56:25 MSK 2015
* commit1
rep1_0 > darcs diff —from-patch=commit2
patch ebaccd5c36667b7e3ee6a49d25ef262f0c7edf2b
Author: Daniil Frumin
Date: Mon Jul 27 20:56:25 MSK 2015
* commit2
diff -rN -u old-rep1_0/dir1/file2 new-rep1_0/dir1/file2
— old-rep1_0/dir1/file2 1970-01-01 03:00:00.000000000 +0300
+++ new-rep1_0/dir1/file2 2015-07-28 12:25:54.000000000 +0300
@@ -0,0 +1 @@
+double whatsup
rep1_0 > cd ../rep1
rep1 > darcs changes
patch e3df0e23a3915910a81eb8181d7b3669e8f270a9
Author: Daniil Frumin
Date: Tue Jul 28 12:27:55 MSK 2015
* commit2’
patch a7e0d92a53b0523d0224ef8ffae4362adf854485
Author: Daniil Frumin
Date: Mon Jul 27 20:56:25 MSK 2015
* commit1
rep1 > darcs diff —from-patch=“commit2’”
patch e3df0e23a3915910a81eb8181d7b3669e8f270a9
Author: Daniil Frumin
Date: Tue Jul 28 12:27:55 MSK 2015
* commit2’
diff -rN -u old-rep1/dir1/file2 new-rep1/dir1/file2
— old-rep1/dir1/file2 1970-01-01 03:00:00.000000000 +0300
+++ new-rep1/dir1/file2 2015-07-28 12:28:39.000000000 +0300
@@ -0,0 +1 @@
+touch file2
\ No newline at end of file
diff -rN -u old-rep1/file1 new-rep1/file1 — old-rep1/file1 2015-07-28 12:28:39.000000000 +0300 +++ new-rep1/file1 2015-07-28 12:28:39.000000000 +0300
@@ -1 +1 @@
-whatsup
\ No newline at end of file
+double whatsup
\ No newline at end of file
The patch commit2
from rep1_0
conflicts with commit2’
from rep1
.
rep1 > darcs rebase pull ../rep1_0
patch ebaccd5c36667b7e3ee6a49d25ef262f0c7edf2b
Author: Daniil Frumin
Date: Mon Jul 27 20:56:25 MSK 2015
* commit2
Shall I pull this patch? (1/1) [ynW…], or ? for more options: y
Do you want to pull these patches? [Yglqk…], or ? for more options: y
The following local patches are in conflict:
patch e3df0e23a3915910a81eb8181d7b3669e8f270a9
Author: Daniil Frumin
Date: Tue Jul 28 12:27:55 MSK 2015
* commit2’
Shall I suspend this patch? (1/1) [ynW…], or ? for more options: y
Do you want to suspend these patches? [Yglqk…], or ? for more options: y
Finished pulling.
Rebase in progress: 1 suspended patches
Now we have one patch — commit2’
— in the suspended state. We want to resolve the conflict by amending commit2’
. We will do that by unsuspending it and manually editing out the conflicting lines. This will also make it depend on commit2
.
rep1 > darcs rebase unsuspend
patch e3df0e23a3915910a81eb8181d7b3669e8f270a9
Author: Daniil Frumin
Date: Tue Jul 28 12:27:55 MSK 2015
* commit2’
Shall I unsuspend this patch? (1/1) [ynW…], or ? for more options: y
Do you want to unsuspend these patches? [Yglqk…], or ? for more options: d
We have conflicts in the following files:
./dir1/file2
Rebase finished!
rep1 > cat dir1/file2
v v v v v v v
=============
double whatsup
*************
touch file2
^ ^ ^ ^ ^ ^ ^
rep1 > $EDITOR dir1/file2
rep1 > darcs amend -a
patch 40b3b4123c78dba6a6797feb619572072654a9cd
Author: Daniil Frumin
Date: Tue Jul 28 12:32:56 MSK 2015
* commit2’
Shall I amend this patch? [yNjk…], or ? for more options: y
Finished amending patch:
patch c35867259f187c1bc30310f1cacb34c1bb2cce41
Author: Daniil Frumin
Date: Tue Jul 28 12:34:30 MSK 2015
* commit2’
rep1 > darcs mark-conflicts
No conflicts to mark.
Another repository saved from conflicting patches, yay!
See this discussion for details
Darcs 2.10.1 has been released!
Citing the official release notes
> The darcs team is pleased to announce the release of darcs 2.10.1 !
> ..
>
> # What's new in 2.10.1 (since 2.10.0) #
>
> - generalized doFastZip for darcsden support
> - support terminfo 0.4, network 2.6, zlib 0.6, quickcheck 2.8 and
> attoparsec 0.13
> - errorDoc now prints a stack trace (if profiling was enabled) (Ben Franksen)
> - beautified error messages for command line and default files (Ben Franksen)
> - fixed the following bugs:
> - issue2449: test harness/shelly: need to handle
> mis-encoded/binary data (Ganesh Sittampalam)
> - issue2423: diff only respecting --diff-command when a diff.exe
> is present (Alain91)
> - issue2447: get contents of deleted file (Ben Franksen)
> - issue2307: add information about 'darcs help manpage' and
> 'darcs help markdown' (Dan Frumin)
> - issue2461: darcs log --repo=remoterepo creates and populates
> _darcs (Ben Franksen)
> - issue2459: cloning remote repo fails to use packs if cache is
> on a different partition (Ben Franksen)
>
> # Feedback #
>
> If you have an issue with darcs 2.10.0, you can report it on
> http://bugs.darcs.net/ . You can also report bugs by email to
> bugs at darcs.net, or come to #darcs on irc.freenode.net.
I’ve updated Mac OS to version 2.10.1. You can install it with
brew install http://darcs.covariant.me/darcs.rb
Recently, I’ve implemented HTTP Basic auth for darcsden and wrote a simple wreq
test for it. In this post I would like to outline the main technical details.
A lot of darcsden code is (especially the parts that are closer to the users’ web browser — handlers, pages, so on) is written around sessions. Sessions are stored in a special storage — implemented by the DarcsDen.Backend.Transient
, but if we abstract away from the details we have a Session
datatype. Authorization and authentication information is handled by sessions using functions setUser :: (BTIO bt) => Maybe User -> Session -> Snap Session
, notice :: (BTIO bt) => String -> Session -> Snap ()
(display a message to the user) and others. The BTIO bt
part is just a synonym for
type BTIO bt = (BackendTransient bt, ?backendTransient :: bt, MonadIO (BackendTransientM bt))
Which basically says that we are operating with a transient backend that supports all of necessary operations, and we can also do IO in it. Right now there are only two transient backends (read: two ways of storing sessions): Redis and in-process memory.
If we have a piece of Snap code that we want to “sessionify” we use the following interface:
withSession :: (BTIO bt) => (Session -> Snap ()) -> Snap ()
What this does is it basically checks for a cookie — in case it is present it grabs the session information from the storage (in accordance with the cookie); if the cookie is not present it creates a new session and stores it in a cookie.
If we have a page of a type Session -> Snap ()
, we might want to give user an option to do HTTP authentication on that page. We introduce another function
withBasicAuth :: (BP bp, BTIO bt)
=> (Session -> Snap ())
-> (Session -> Snap ())
withBasicAuth act s = do
rq do
rawHeader <- maybe throwChallenge return $ getHeader “Authorization” rq
let (Just (usr,pw)) = getCredentials rawHeader
c errorPage “Unknown user”
Just u -> if checkPassword (fromBS pw) u
then doLogin (fromBS usr)
else errorPage “Bad password”
_ -> act s
So, what is going on in here? First of all, we check if the “login” parameter is set to “true”. If it does, we try to get the “Authorization” header, de-encode it, and check whether the credentials are good.
throwChallenge :: Snap a
throwChallenge = do
modifyResponse $ (setResponseStatus 401 “Unauthorized”) .
(setHeader “WWW-Authenticate” “Basic realm=darcsdenrealm”)
getResponse >>= finishWith
If the response header is present, it is of a form Basic x
, where x
is a base64 encoded string user:password
. We can extract the credentials from the header like this:
import qualified Data.ByteString as B
import qualified Data.ByteString.Base64 as B
…
getCredentials :: B.ByteString — ^ Header
-> Maybe (B.ByteString, B.ByteString) — ^ Possibly (username, password)
getCredentials header =
if (isInfixOf “Basic “ header)
then fmap extract (hush (B.decode (B.drop 6 header)))
else Nothing
where
extract cred = case (B.breakByte (c2w ‘:’) cred) of
(usr, pw) -> (usr, safeTail pw)
The tests that I am currently writing for darcsden are all of the same form: I use wreq to do requests to the darcsden server, then, if necessary, I run taggy to extract information from the webpage, and compare it to the “canonical” information.
As it turns out, doing HTTP Basic Auth is very easy with wreq! First of all, we define a function for doing a GET request that will do some exception handling for us:
getSafeOpts :: Options -> String -> IO (Either Status (Response ByteString))
getSafeOpts opts url = fmap Right (getWith opts url) `catch` hndlr
where
hndlr (StatusCodeException s _ _) = return (Left s)
hndlr e = throwIO e
This way, we won’t get a runtime exception when accessing a non-existing page or getting a server error. Doing a GET request with HTTP Basic Auth is now very easy:
getWithAuth :: (String, String) -> String -> IO (Either Status (Response ByteString))
getWithAuth (username,pw) url = getSafeOpts opts url
where
opts = defaults & auth ?~ basicAuth (toBS username) (toBS pw)
& param “login” .~ [“true”]
In that snippet we use lens
es to set up an auth header and an HTTP parameter (?login=true
).
Finally, after obtaining a Response ByteString
, we can parse it with taggy-lens:
parsed :: Fold (Response L.ByteString) Text.Taggy.Node
parsed = responseBody
. to (decodeUtf8With lenientDecode)
. html
We can then play with it in GHCi
*Main> Right r r ^.. parsed
[NodeElement (Element {eltName = “DOCTYPE”, eltAttrs = fromList [(“html”,””)], eltChildren = [NodeElement (Element {eltName = “html”, eltAttrs = fromList [], eltChildren = [NodeElement (Element {eltName = “head”, eltAttrs = fromList [], eltChildren = [NodeElement (Element {eltName = “title”, eltAttrs = fromList [], eltChildren = [NodeContent “localhost”]}),NodeElement (Element {eltName = “link”, eltAttrs = fromList [(“href”,”http://localhost:8900/public/images/favicon.ico”),…
If we want to check that we are indeed logged in correctly, we should look for the “log out” button. Taggy does all the heavy lifting for us, we just have to write down a lens (more precisely, a fold) to “extract” a logout button from the page
logoutButton :: HasElement e => Fold e Text
logoutButton = allAttributed (ix “class” . only “logout”)
. allNamed (only “a”)
. contents
logoutButton
searches for <div class=“logout”>
and returns the text in the link inside the div. There might be many such links inside the node, hence we use a fold.
*Main> r ^.. parsed . logoutButton
[“log out”]
In this case, since we only care if such link is present, we can use a preview
*Main> r ^? parsed . logoutButton
Just “log out”
Well, that’s about it for now. I regret taking way too much time writing this update, and I hope to deliver another one soon. Meanwhile, some information regarding the darcsden SoC project can be found on the wiki.
Recently I’ve updated my Darcs homebrew build to Darcs 2.10. You can install it with
brew install http://darcs.covariant.me/darcs.rb
The formula contains a context (--exact-version
) and it is a static binary.
This is my first post from the (hopefuly fruitful!) series of blog posts as part of my Haskell SoC project. I will spend a great chunk of my summer hacking away on DarcsDen; in addition, I will document my hardships and successes here. You can follow my progress on my DarcsHub.
This particular post will be about my working environment.
Hoogle is an amazing tool that usually needs no introduction. Understandably, the online version at haskell.org indexes only so many packages. This means that if I want to use hoogle to search for functions and values in packages like darcs and darcsden, I will have to set up a local copy.
Cabal sandboxing is a relatively recent feature of the Cabal package manager, but I don’t think it is reasonable in this day to install from the source (let alone develop) a Haskell package without using sandboxing.
The problem seems to be that the mentioned tools do not play well together out of the box, and some amount of magic is required. In this note I sketch the solution, on which I’ve eventually arrived after a couple of tries.
The presumed setup: a user is working on a package X using the cabal sandboxes. The source code is located in the directory X
and the path to the cabal sandbox is X/.cabal-sandbox
.
Step 1: Install hoogle inside the sandbox. This is simply a matter of running cabal install hoogle
inside X
. If you want to have a standard database alongside the database for your packages in development, now is the time to do .cabal-sandbox/bin/hoogle data
.
Step 2: Generate haddocks for the packages Y,Z you want to use with hoogle. In my case, I wanted to generate haddocks for darcs and darcsden. This is just a matter of running cabal haddock --hoogle
in the correct directory.
Step 3: Convert haddocks to .hoo files. Run the following commands in X/
:
.cabal-sandbox/bin/hoogle convert /path/to/packageY/dist/doc/html/*/*.txt
You should see something like
Converting /path/to/packageY/dist/doc/html/Y/Y.txt
Converting Y... done
after which the file Y.hoo appears in /path/to/packageY/dist/doc/html/Y/
Step 4: Moving and combining databases. The hoogle database should be stored in .cabal-sandbox/share/*/hoogle-*/databases
. Create such directory, if it’s not present already. Then copy the ‘default’ database to that folder:
cp .cabal-sandbox/hoogle/databases/default.hoo .cabal-sandbox/share/*/hoogle-*/databases
Finally, you can combine your Y.hoo
with the default database.
.cabal-sandbox/bin/hoogle combine /path/to/packageY/dist/doc/html/*/*.hoo .cabal-sandbox/share/*/hoogle-*/databases/default.hoo
mv default.hoo .cabal-sandbox/share/*/hoogle-*/databases/default.hoo
And you are done! You can test your installation
$ .cabal-sandbox/bin/hoogle rOwner
DarcsDen.State.Repo rOwner :: Simple Lens (Repository bp) String
For additional usability, consider adding .cabal-sandbox/bin
to your $PATH.
Happy holidays, everyone!
I would like to announce a new version of the Hastache library, version 0.6.1. Some interesting and useful changes, as well as improvements and bugfixes are included in the release. See below for an extended changelog.
Hastache is a Haskell implementation of the mustache templating system.
cabal update
cabal install hastache
A simple example:
import Text.Hastache
import Text.Hastache.Context
import qualified Data.Text.Lazy.IO as TL
main = hastacheStr defaultConfig (encodeStr template) (mkStrContext context)
>>= TL.putStrLn
template = "Hello, {{name}}!\n\nYou have {{unread}} unread messages."
context "name" = MuVariable "Haskell"
context "unread" = MuVariable (100 :: Int)
Read Mustache documentation for template syntax; consult README for more details.
Most of the new features in this release deal with generic contexts.
composeCtx
is a left-leaning composition of contexts. Given contexts c1
and c2
, the behaviour of (c1 <> c2) x
is following: if c1 x
produces ‘MuNothing’, then the result is c2 x
. Otherwise the result is c1 x
. Even if c1 x
is ‘MuNothing’, the monadic effects of c1
are still to take place.
The mkGenericContext
function now supports additional datatypes like Maybe
(with Nothing
being an empty/null value) and Either
.
The new mkGenericContext'
is a generalized version of mkGenericContext
and it takes two addition arguments. The first one, of type (String -> String)
is simply a renaming function, similar to fieldLabelModifier
of aeson
. To see this feature in action, consider the following example:
{-# LANGUAGE DeriveDataTypeable #-}
import Text.Hastache
import Text.Hastache.Context
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.IO as TL
import Data.Data (Data, Typeable)
import Data.Decimal
import Data.Generics.Aliases (extQ)
data Test = Test {f :: Int}
deriving (Data, Typeable)
val1 :: Test
val1 = Test 1
val2 :: Test
val2 = Test 2
r "f" = "foo"
r x = x
example :: Test -> IO TL.Text
example v = hastacheStr defaultConfig
(encodeStr template)
(mkGenericContext' r defaultExt v)
template = "An integer: {{foo}}"
main = do
example val1 >>= TL.putStrLn
example val2 >>= TL.putStrLn
In the example we use the renaming function r
to rename a field “f” to “foo”.
The second additional argument is a query extension, of type Ext
:
type Ext = forall b. (Data b, Typeable b) => b -> String
A query extension is a way of turning arbitrary datatypes into strings. This might come in very handy, if you want to generate mustache contexts from records/datatypes that contain non-primitive datatypes (from non-base modules) that you want to display. Before 0.6.1, if you had a record that contained, for example, a Decimal
field, and you wanted to convert it to a context and access that field, you were simply out of luck. With this release you can basically extend the mkGenericContext'
function to support any datatypes you want! Once again, I believe an example is worth a thousand words, so let us consider a slightly modified version of the example above:
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE StandaloneDeriving #-}
-- Custom extension function for types that are not supported out of
-- the box in generic contexts
import Text.Hastache
import Text.Hastache.Context
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.IO as TL
import Data.Data (Data, Typeable)
import Data.Decimal
import Data.Generics.Aliases (extQ)
data DecimalOrInf = Inf | Dec Decimal deriving (Data, Typeable)
deriving instance Data Decimal
data Test = Test {n::Int, m::DecimalOrInf} deriving (Data, Typeable)
val1 :: Test
val1 = Test 1 (Dec $ Decimal 3 1500)
val2 :: Test
val2 = Test 2 Inf
query :: Ext
query = defaultExt `extQ` f
where f Inf = "+inf"
f (Dec i) = show i
r "m" = "moo"
r x = x
example :: Test -> IO TL.Text
example v = hastacheStr defaultConfig
(encodeStr template)
(mkGenericContext' r query v)
template = concat [
"An int: {{n}}\n",
"{{#moo.Dec}}A decimal number: {{moo.Dec}}{{/moo.Dec}}",
"{{#moo.Inf}}An infinity: {{moo.Inf}}{{/moo.Inf}}"
]
main = do
example val1 >>= TL.putStrLn
example val2 >>= TL.putStrLn
As you can see, the query extensions are combined using the extQ
function from Data.Generics
, and the “unit” of this whole thing is defaultExt
function.
This release would not have been possible without Tobias Florek, Edsko de Vries, Janne Hellsten, @clinty on Github, Stefan Kersten, Herbert Valerio Riedel, and other people who were submitting issues, patches, and requests.
Prototype for interesting things to come. Controlled by lisp.