Very Secure

Surf, Schnitzel, and Slots - My Meetup With Adam

December 8th, 2019

A nice aspect of meeting an individual with a blog and a key registered in deedbot is the relationship begins with trust. I can't say I've ever shook hands with someone and immediately after taken their cash and phone and put it in my backpack. This felt quite natural, but is it? Can those outside of a WoT do this?

After Adam and I met and put our stuff away at Surf Culture, we lugged two boards to the premier beginner surf spot in Tamarindo. As luck would have it, billymg recently took a picture that contains the location where we surfed.1 Thanks billymg!

On our walk to the beach we talked about previous times we had met with others who read the logs.2 I was surprised to learn that Adam had twice met gabriel_laddel. Adam had recognized him at a lisp conference in California and later bought one of Gabriel's computers.

When we arrived at the surf spot, we paused our conversation about tmsr matters to go over how to stand up on a surf board. I tried to use what I learned about athletic instruction from reading The Inner Game of Tennis by Tim Gallwey to instruct the pop up. The book says to explain technique by giving a visual feed rather than a verbal description. I did a few slow motion pop ups on the beached surf board for Adam to copy. After a few attempts, Adam started to land with his feet in the center of the board.

As we got in the water I left my surfboard on the beach so I could help push Adam into some waves. He stood up on the first attempt.3 I pushed him into two more waves that he successfuly road as well. After that Adam suggested I get my board and surf alongside him.

When I got back in the water with my board we were half-surfing half-talking. It's one thing to engage in some chit chat in between waves, but its another to try and surf when talking about life purpose. Half-surfing and half-conversing hurt the quality of *both* activities. Sometimes we missed perfectly good waves because we were engaged in our conversation. Other times we abruptly paused our conversation to attempt to catch a wave.

It would have been smarter to have surfed with full focus for less time. We would have had a better surf session4 while leaving more time for uninterrupted conversation later. That aside, surfing was still a pleasant experience. There were a few tourists swimming near us, but no one surfing the waves we were riding - a rarity in Tamarindo.

One of the many topics we discussed while in the water was leading a double life. Adam and I had spent time reading trilema and the logs while not participating in the affairs of tmsr nor conversing with those in our meatwots about what we read. It was comforting for me and probably for Adam as well to be able to discuss that rather awful problem in person.

We shared having experienced quite negative reactions when discussing trilema articles within our meatwot. Those adverse reactions caused us to see it prudent to keep reading the logs a secret. I mentioned to Adam that something he wrote recently helped me fix my double life problem: "I would rather be alone and aware of that than delude myself that I have actual friends." It is ridiculous to make the effort required to hide a part of yourself in order to hold friends whose friendship depends on you keeping that part hidden!

After we finished surfing we walked back to drop off our boards. Then, on our way to Adam's hotel, Adam mentioned he was traveling with a lady friend, and politely asked if she could join us for dinner. I said of course and that I'd be happy to have her along. But throughout the evening it was difficult for all three of us to be engaged in the same conversation.5

After Adam changed in his hotel room and picked up the SSD + thermal paste he generously brought for me from the states, we went to go check out the sunset. We arrived at the beach just a few minutes late, the bugs had arrived and the sun had left. So we immediately turned around to go find a place to eat. I had three recommendations: a sushi restaurant, an Argentinian grill, and a food court. We decided to go to Patagonia, the Argentinian grill.

Well I must say I felt a bit embarrassed for recommending Patagonia. The restaurant that appeared delicious and fun a year ago to a stoned 24-year-old perhaps doesn't live up to current standards. The first problem we had was they sat us on the edge of the restaurant, next to the road. I asked the hostess to seat us more towards the center. She smiled and said ~'no puedo, esas mesas son para cuatros.' (Never mind that the restaurant was half empty.) I was not assertive with my request,6 and for that we paid the price of having to sit at the table next to the road. Adam mentioned and I agreed on the pleasantness of the outdoor atmosphere of restaurants in LATAM, but still I was bothered by our proximity to the occasional passing car. I also swear there was a hint of some odor...but I may have imagined it from being annoyed at the seating arrangement.

The next problem with the restaurant was that they permitted some hippies to come and busk. I had seen this shit before in Patagonia and was hoping it would not occur during our meal. But alas it did. After jumping around and singing chanting for 15 minutes they came to our table and brazenly asked us for money. Where they get these ridiculous notions that we would PAY them for disrupting our conversation, I have no idea. Maybe their parents paid them off to stop their temper tantrums when they were younger. At least the food at the restaurant was decent.

After dinner I had some lag time before my cab driver was going to come pick me up. With the spare time we decided to go to the nearby casino. I have no interests in gambling, but I was curious to see the inside of a casino for the first time. The only game I would have played is poker.7 But Adam and friend didn't know how to play hold 'em, so instead decided to lose some money playing black jack and then lose some money playing slots.

Truth be told I found this last part of our meetup less than ideal. I had wanted to spend the time I had left speaking more with Adam. We did get to talk at the casino, but sitting sideways on a slot machine stool is, ehm, not the nicest setting for conversation. After about an hour we said goodbye and I walked around Tamarindo before heading back to Playa Junquillal.

It was a pleasure to meet with Adam, but I wish we had setup a better environment to converse. It is rare and quite nice to be able to speak to an individual who has a key registered with deedbot, has read the blogs and the logs, has built their own computer8, has written articles that have influenced you, and has the potential to turn out to be a real friend. So as much as I loved surfing, I would have traded our time in the water for time in a quiet coffee shop. I'll keep this in mind for our next meetup and meetups with others in the future.

  1. It's right where the beach begins to bend to the right in the photo. []
  2. I have met billymg once for coffee in New York and funkenstein_ a couple times for beers in Boston. funkenstein_ iirc submitted a patch to the bitcoin foundation's mailing list a while back. []
  3. Nice job Adam! []
  4. After Adam's initial success with me pushing him, I don't think he caught a wave while paddling for it on his own. That is much more difficult, and requires more attention to do on the first day. []
  5. Adam and I could only communicate meaningfully with English, and she only spoke Spanish. Also, there were many topics that I wanted to discuss with Adam where she could not meaningfully participate - even if she did speak English. We made the dynamic work as best we could, switching the conversation back and forth from English to Spanish. []
  6. I have a problem of being too adverse to small conflict. []
  7. I hardly know the rules, but I would have been okay with paying my_wager * (1 - house_odds) to play a few hands. []
  8. At a much lower abstraction level than I am currently doing. []

Keeping The Problem Stack Small

December 3rd, 2019

To grapple effectually with even purely material problems requires more serenity of mind and more lofty courage than people generally imagine.

-Joseph Conrad, An Outpost of Progress

Having followed the logs for a few years with a computer science degree from the "premier engineering and science institution in the world", writing your own version of V should be a simple task, no? You've already escaped the clutches of society, having left the US and all its bureaucratic pantsuitness behind as you arrived in your new home in a new world. You can read the blogs of men to learn about the first time in history when text was deliberately structured with due consideration given not only to its meaning, but also to its source, and to its context. No one is there to look over your shoulder and ask you why you are not on one of the Approved Websites. You have all the time in the world!

But before you open emacs or vim and get started on your ~371 line program, there's a few tasks that your new environment demands you take care of. You'll have to figure out the erm..plumbing issue. The cheap apartment you found came with a beautiful view, but some of its inner functioning is out of order. And while you're fixing the plumbing you may want to consider removing the electrical cables sticking out of the heating device on the shower head.

First things first though - you need to get yourself a good meal. There's not exactly a deli right on the corner nor a seamless service where you can just click click click and food appears - you have to cook yourself. I mean you could walk in the hot sun to the local soda1 20 minutes each way and order a casado,2 but the whole point of moving to a new country was to build up some goddamn independence!

Well now that that's done - and you're slightly sustained although the food wasn't really the greatest and there's a mess to cleanup because when you washed the pan you left water droplets that later evaporated blasting hot olive oil on you and nearby surfaces - you can get to handling the plumbing issues. So you reach for the wrench you realize you don't have. You've never needed one since you could always make a phone call to some magician - the super - to deal with these kind of issues. So you decide okay you can live with the plumbing problem for now.

The next morning would provide a great window of time to handle the V task, but there were a few disturbances that prevented a good night's sleep. You learned your apartment's membrane is rather permeable. Some mosquitoes found their way in through the tears in the screens or the cracks in the wood or the gaps in the doorway. So you had to fall asleep to the buzzing of a flying syringe that probably did wind up stabbing you after you gave up spending time trying to kill it.

Despite the lack of sleep you should get started on that task, but the morning came with all the previous problems and more. There's the basic chores: take out the trash, sweep the house, do the laundry, wash the dishes. There's a cut you got on your foot you absolutely must clean thoroughly. There's a trip to the store you need to make because you managed to forget salt on the extensive shopping list you wrote for the previous trip. And worst of all, there's an ant invasion to deal with; you tried your best to clean up all the food but you live in a ~jungle and billions of years of evolution made the little guys energy efficient. That one crumb and the moist sink was all they needed.

Annoyed by these overhanging problems, which also includes un hongo3 that has found refuge in the sweat of your labor, you to decide to put your troubles aside for a minute and go surf. It's what you call a hobby and maybe sometimes it is that but right now it is an escape. An escape from dealing with the aforementioned problems but also from thinking about the ones surely to come.

Society has always taken care of these problems for you - not from any tenderness, but because of its strange needs.4 But society did not teach you how to solve problems for yourself. Instead all it did was give temporary solutions or solutions that make you dependant. For example, society stocks its stores with Raid, a chemical that kills the ants in front of you but not the queen that hides in a cavity respawning those ants you just killed. Society will sell a call to pop() on the stack of your problems, but it has no incentive to help you stop the processes that push() shit onto that same stack.

Effort spent manually popping the stack is almost always effort wasted. Fixing a surface level problem - such as killing male ants - may temporarily ameliorate your situation but it is not the type of action that will improve your standard of living. If you only spend your time fixing what's right in front of you, you'll either arrive at some push() pop() equilibrium point or become overwhelmed.

The serene mind must reason to find and remove the sources of problems. They are always hidden from sight. Because if the evil processes were out in the open, one would already have killed them. And as the mind meditates on how to find long term solutions, it's okay to temporarily let the stack of problems grow. The mind needs to have confidence that the patient search for larger, longer term solutions will yield results. And once those results have been realized one can finally pop the stack down and use the time freed to create beautiful things such as a working V.

  1. A soda is a small home-cooked style restaurant (sometimes w/ only 1 table) that serves typical Costa Rican food. []
  2. A casado is the typical dish served in sodas. The specific ingredients vary, but the template is rice & beans + a salad + a choice of meat or fish. []
  3. The Spanish word for mushroom is also used for the general term fungus. Costa Rica has a few hongos that can cultivate themselves in the creases in your elbow / behind your knees. It looks like an eczema and is easily treatable with anti-fungal cream. []
  4. The full quote:

    To grapple effectually with even purely material problems requires more serenity of mind and more lofty courage than people generally imagine. No two beings could have been more unfitted for such a struggle. Society - not from any tenderness, but because of its strange needs, had taken care of those two men, forbidding them all independent thought, all initiative, all departure from routine; and forbidding it under pain of death. They could only live on condition of being machines. And now, released from the fostering care of men with pens behind the ears, or of men with gold lace on the sleeves, they were like those lifelong prisoners who, liberated after many years, do not know what use to make of their freedom. They did not know what use to make of their faculties, being both, through want of practice, incapable of independent thought.

    []

Final Selected Parts For My First Computer

November 29th, 2019

After previously picking parts for my computer I discovered bestcomputersa's list of items on their website was completely incosistent with their actual stock. diana_coman decided the best option for me was to follow my original plan of ordering parts from the states. But the day before I gave up sourcing from Costa Rican stores, the rep from pcgamingcr responded to messages I had sent him a few days prior. After that initial delayed reply, he was constitently responsive through Whatsapp. Pcgamingcr had the coveted AMD FX-8350 with compatible motherboards and video cards. I managed to order everything I needed1 from them and cococo. The guts of the computer cost $1,123. The I/O devices and accessories totaled $1,259 bringing the final cost to $2,382. The items I bought are listed below.2

I. Guts

CPU AMD FX-8350 (CPU/MB/VC combo = 273mil, $486)
Motherboard GA-970A-UD3P (rev 2) (see CPU)
Graphics Card Radeon RX-550 Sapphire (see CPU)
RAM 2x Corsaair vengeance 8GB ddr memory 1600 MHz (89mil, $158)
PSU Seasonic Focus Plus Gold 850 (95mil, $169)
Primary SSD 1TB Samsung 860 Evo SSD ($140)
Backup Mechnical Drive 64MB 1TB Seagate Barracuda (30mil, $53)
Case Corsair Carbide Spec 06 (58mil, $103)
SD Card Reader Lector de Memoria Interno Xtech3 (8mil, $14)

II. I/O + Accessories

Monitor Dell 24 Monitor: P2419H (166.5mil, $292)
Keyboard Ergodox. ($325)4
Mouse Marvo Scorpion5 (24mil, $43)
UPS UPS APC SMT15006 (319.5 mil, $569)
Thermal Paste 4x 2g Arctic MX-4 Thermal Paste ($30)

  1. Save the Samsung SSD and thermal paste that thimbronion graciously offered to bring from the states + the ergodox keyboard. []
  2. Prices are listed as (colones, usd) with an exchange rate of 562 colones to the usd. If I bought the item with usd directly then I list only the usd price. []
  3. I could not find a link to the spec details on xtech's website. It can read USB, SD, Micro SD, XD, MMC. I am not quite sure what an XD or MMC is. []
  4. In addition I expect to pay a yet unknown import tax. []
  5. Pcgamingcr did not tell me the exact model of mouse, I was looking only for a cheap option. The mouse came with a keyboard I can use while I wait for my fancy Ergodox to get here from Taiwan. []
  6. Recommended Replacement Batteries - Optima Batteries 8052-161 D31M BlueTop Starting and Deep Cycle Battery []

Candidate components for whaack's first build

November 18th, 2019

Below is the prospective parts list for the machine I intend to use as my work station. To produce this list I first read through kitchentablecomputer's "Computer Parts" section. After reading the various buying guides, I started picking components based around the processor from the machine on which diana_coman installed cuntoo. The parts also had to be available on bestcomputersa. Once I made my list I checked the other store recommended by handbot, cococo.co.cr, for better options for the various parts. I only made one change: I replaced my ₡147,500.00 480GB Kingston SSD with a $140 1TB Samsung 860 Evo SSD + a ₡36,500.00 1TB Seagate Barracuda mechnical backup hard drive1 The price for all the guts (not including S+H, taxes, etc.) comes out to ₡623,500.00 + $140 , ~ $1215.

Further work includes making a buy list for I/O devices,2 miscellaneous parts,3 and building tools.4


CPU

₡ 142,500.00

Amd Am3 Fx8350, spec

Motherboard5

₡ 64,500.00

Gigabyte Ga-970A-Ds3P, spec

RAM

₡ 44,000.00 x2

Corsaair vengeance 8GB ddr memory 1600 MHz x2, spec

Graphics Card

₡ 120,500.00

GTX 750ti ddr5 4GB, spec

Hard Drive

$ 139.99

1TB Samsung 860 Evo SSD

Backup Internal Mechanical Hard Drive:

₡ 36.500,00
DD 1TB Seagate Barracuda SATA 64MB 3.5 7200RPM

PSU 6

₡ 115,000.00

Corsair RM850x plus gold, spec

Cooling 7

₡ 12,500.00

Corsaair-fan-air-series-af120, spec

Case 8

₡ 44,000.00

Corsair RED LED Mid Tower Gaming Case, spec

  1. It was coincidence that the best SSD option I found for myself is the same SSD diana_coman used in her machine. The Seagate Barracuda is a mechnical drive, which should have been obvious given the specs I listed. []
  2. Most notably the monitor []
  3. Such as an ethernet cable []
  4. Such as a screwdriver set and an anti-static device. []
  5. ATX Form Factor; 30.5cm x 21.5cm.

    Note: I have to confirm with bestcomputersa the version of the BIOS is from post 2013, otherwise the motherboard will not support the FX-8350. []

  6. I need to check this fully modular PSU comes with a sufficient number of the correct cables to connect to every power drawing component I have. []
  7. I still need to find thermal paste. []
  8. 447mm x 200mm x 428mm []

A helpful han(d)bot

November 15th, 2019

I am working on acquiring a few items in Costa Rica. My goal is to build an ergonomic battle station equipped with a computer I've personally put together. Acquiring the iron necessary for my desired machine is difficult given my location on the beach. So per the advice of diana_coman, I hopped into #trilema-hanbot to speak with a lord keen on becoming accessible to those within tmsr.

hanbot es una experta en las cosas costarricenses.1 Upon asking for advice, hanbot immediately shared a list of stores she had handy. For computer parts she recommended best computers sa as well as the more modestly named cococo. For office supplies2 hanbot sent me to muguisa. These tiendas appear to have what I need.

hanbot also gave some advice regarding couriers I may want to use, should I decide to import goods from the evil empire. She noted that items do arrive reliably, but the companies she has seen are either expensive or require a credit card. hanbot made it clear that she will under no circumstance use the magic plastic. I didn't respond to this point during our conversation,3 but her conviction made me think.4

Getting advice from hanbot saved me hours of searching that may have turned out fruitless. It's becoming obvious I should ignore my initial belief that I shouldn't burden those who know more than me with questions. It is just too expensive to redo work that is avoidable via a short conversation. That said, thank you hanbot!

  1. Whose knowledge goes beyond where to buy office supplies. She also had advice to give regarding purchasing a car. []
  2. I specifically need a proper chair; I hired a local handyman to build a desk tailored to the layout of my apartment. []
  3. How was I to respond? "Ah yes, totally agree with you there hanbot, credit cards are for idiots and its our moral obligation to separate them from their money. However, they happen to be just too convenient, so I use them anyways." []
  4. The first question I wondered was - how would hanbot's recommended stores charge for items they send out for delivery given they don't require card and are fiat based? I answered this myself by ordering a chair through Muguisa. Upon placing my order, Muguisa gave me a bank account number. They informed me that they will send me the chair when I deposit cash into their account at a local bank. Now I know how ordered goods are paid for in a cash based economy.

    The second question I still have is - would it be wise to cut my credit card in half? On a personal level, the credit card is a spiritually draining item. It whispers in your ear, don't worry about saving for a rainy day my friend, for I am always here to extend you credit shall you need it. On a systemic level, credit cards wreak havoc on the economy. They destroy capital allocation by burdening everyone with even more money. I would love to get rid of my card, perhaps in style., but I don't know if that would be prudent. []

Verifying My Understanding

November 3rd, 2019

I have spent the past few days pondering why I tried to create links conforming to the new the html selection method before investigating their proper format. The first reason I came up with was I had thought it best to forgo investing time on understanding the new mechanism in order to get my work done quickly. But I discarded this dubious explanation because I am quite aware of the importance of learning before doing.1 The cause of my error comes from a deeper problem: I trick myself into believing I understand that which I don't.

When I read mp's comment

"Please use the ?b&e=#select selection mechanism instead."

I thought "huh, mp must have a new way to avoid having to use javascript for selecting text by passing in the flags b&e as query params."2 I "confirmed" my theory by verifying my malformed links selected their intended text.3 My bullshit experiment gave evidence to support my hallucination that I knew how to create urls for the new selection tool. Having falsely convinced myself that I understood what I was doing, I thought it okay to move forward and thus proceeded to produce the broken links.

There are two bad habits I've identified from this fiasco. One of them is inferring what tools do/how to use them. Instead of guessing their operation, I must RTFM. The other bad habit is duping myself with faulty experiments that are just the mind's way to convince itself what it already believes is truth.4 I need to find the rest of these bad habits, kill all of them, and be suspicious of my understanding when I learn something new.

  1. The explanation is also dubious because a mind's first answer to self exploration questions is often a trap. []
  2. I was correct in guessing the new selection mechanism did not require javascript, but I could have just as likely been wrong. []
  3. I viewed the links on a javascript enabled browser, so my test gave me no reason to think I was using a new selection mechanism. []
  4. This process of minds duping themselves into believing what they want to believe is easy to see on a macro scale in America with all the "A new study shows __" articles that get printed everyday. But it is harder to catch when looking into the mirror. []

Proper HTML Linking, A Battlefield Report

November 1st, 2019

Having been rightfully flamed for attempting to use a tool I did not understand, I return from the dark hell of the html & php mines with a tiny nugget of information that I hope will aid the republic.

There are two quirks I've noticed with the select displayer.

1. The select displayer can match the values provided in query parameters b/e to text inside of an html tag. This problem emerges from user error, but often one wants to match to text in a link that contains equivalent text in its opening anchor tag. It is currently impossible to select the second "trilema" that follows the "http://trilema.com" in the example:1

<a href="http://trilema.com">trilema</a>

My solution is to find the first match not positioned inside of a tag.2

function first_pos_not_in_tag($hay, $needle, $start) {
  $max_attempts = 2;
  $guess = $start; // Must be > 0 for the while loop condition.
  $length = strlen($hay);
  while ($max_attempts > 0 && $guess && $guess < $length) {
    $guess = strpos($hay, $needle, $guess);
    $next_close_pos = strpos($hay, ">", $guess);
    $next_open_pos = strpos($hay, "<", $guess);
    if ($next_close_pos >= $next_open_pos)
      return $guess;
    $guess = $next_close_pos+1;
    $max_attempts--;
  }
  return false;
}

You must alter your server_side_selection function

--- $b_pos = strpos($content,$_GET["b"]);
--- $e_pos = strpos($content,$_GET["e"], $b_pos);
+++ $b_pos = first_pos_not_in_tag($content, $_GET["b"], 1);
+++ $e_pos = first_pos_not_in_tag($content, $_GET["e"], $b_pos);

2. The second quirk is the select displayer often spits out faulty html. For example, the displayer provides no closing </span> if the user leaves the value for e empty.3 This doesn't seem to cause any practical issues; browsers close spans automatically under certain conditions that I have not fully ascertained.

  1. The root of the problem is the displayer does not provide a means to match to the second occurrence of text; there is no way to select only the last duck in duckduckduck. []
  2. This doesn't fix the root problem stated above, but it prevents the select displayer from breaking tags. This is especially useful for stopping other servers' automatically provided b & e values - used to link back to your excerpt when you send them a pingback - from mangling your html tags. []
  3. This may come as a surprise, because some browsers (I've seen chrome) will silently provide a closing </span> where they see fit and will show that inserted </span> in their "view source" tool! []

Views from Junqui

October 29th, 2019

Home security system, false alarms are frequent.
junqui-1

Hibiscus grows everywhere here and comes in red, pink, and white.
junqui-2

Tide pools found in these rocks serve as a nice Jacuzzi.
junqui-3

This is quite a tiny flower.
junqui-4

Every princess has their holes.
junqui-5

Tired from surfing? Help yourself to a coconut before you hop in the Jacuzzi.
junqui-6

Rumor has it a crocodile lives here.
junqui-7

Refraction caused by these rocks is what makes Playa Junquillal a surf spot.
junqui-8

The lines in the sand are drawn by a little slug creature I call the Jackson Pollock bug.
junqui-9

The leftmost tree is the landmark for the entrance to casa whaack.
junqui-10

And finally, the view from my balcony.
junqui-11
junqui-12
junqui-13

VPY Annotations

October 27th, 2019

Below is asciilifeform's original prototype V with my annotations.

#!/usr/bin/python

##############################################################################
# Quick Intro:
# 1) Create '.wot' in your home directory. Fill it with public keys from 'wot'.
# 2) Create '.seals' in your home directory. Place all signatures there from 'sigs'.
# 3) Create a 'patches' directory somewhere where 'v' can find it. Or use this one.
# 4) ./v.py patches command
# e.g.,
# ./v.py patches w
#                  ^^ displays WoT
#  ./v.py patches p patches/asciilifeform_add_verifyall_option.vpatch asciis_bleedingedge
#                  ^^ this 'presses' (creates the actual tree)
#                  ^^ approximately like a 'checkout' in your vanilla flavoured shithub.

##############################################################################

import os, sys, shutil, argparse, re, tempfile, gnupg

##############################################################################
vver = 1001 # This program's Kelvin version.

## HOW YOU CAN HELP: ##

# * TESTS plox, ty!
#
# Report findings in #bitcoin-assets on Freenode.

##############################################################################

prolog =  '''\
(C) 2015 NoSuchlAbs.
You do not have, nor can you ever acquire the right to use, copy or distribute
this software ; Should you use this software for any purpose, or copy and
distribute it to anyone or in any manner, you are breaking the laws of whatever
soi-disant jurisdiction, and you promise to continue doing so for the indefinite
future. In any case, please always : read and understand any software ;
verify any PGP signatures that you use - for any purpose.2
'''

intro = "V (ver. {0}K)\n".format(vver)

##############################################################################
def toposort3(unsorted):
    sorted = []
    unsorted = dict(unsorted)
    while unsorted:
        acyclic = False
        for node, edges in unsorted.items():
            for edge in edges:
                if edge in unsorted:
                    break
            else:
                acyclic = True
                del unsorted[node]
                sorted.append((node, edges))
        if not acyclic:
            fatal("Cyclic graph!")
    return sorted
##############################################################################

verbose = False

def fatal4(msg):
    sys.stderr.write(msg + "\n")
    exit(1)

def spew5(msg):
    if verbose:
        print msg

# List of files in a directory, in lexical order.
def dir_files6(dir):
    return sorted([os.path.join(dir, fn) for fn in next(os.walk(dir))[2]])

# GPG is retarded and insists on 'keychain.'
# This will be a temp dir, because we don't do any crypto.
gpgtmp = tempfile.mkdtemp()
gpg = gnupg.GPG(gnupghome=gpgtmp)
gpg.encoding = 'utf-8'7

# Known WoT public keys.
pubkeys = {}

# The subset of vpatches that are considered valid.
patches = []

# Banners (i.e. vpatches mapped to their guarantors)
banners = {}

# Roots (i.e. vpatches parented by thin air)
roots = []

# Table mapping file hash to originating vpatch
desc = {}
desc['false' ] = 'false'

# Grep for diff magics, and memoize
def vpdata8(path, exp, cache):
    l = cache.get(path)
    if not l:
        l = []
        patch = open(path, 'r').read()
        for m in re.findall(exp, patch, re.MULTILINE):
            l += [{'p':m[0], 'h':m[1]}]
        cache[path] = l
    return l

# Get parents of a vpatch
pcache = {}
def parents9(vpatch):
    parents = vpdata(vpatch, r'^--- (\S+) (\S+)$', pcache)
    if not parents:
        fatal("{0} is INVALID, check whether it IS a vpatch!".format(vpatch))
    return parents

# Get children of a vpatch
ccache = {}
def children10(vpatch):
    children = vpdata(vpatch, r'^\+\+\+ (\S+) (\S+)$', ccache)
    if not children:
        fatal("{0} is INVALID, check whether it IS a vpatch!".format(vpatch))
    # Record descendents:
    for child in children:
        h = child['h']
        if h != 'false':
            desc[h] = vpatch
    return children

# It is entirely possible to have more than one root!
# ... exactly how, is left as an exercise for readers.
def find_roots11(patchset):
    rset = []
    # Walk, find roots
    for p in patchset:
        if all(p['h'] == 'false' for p in parents(p)):
            rset += [p]
            spew("Found a Root: '{0}'".format(p))
    return rset

# Get antecedents.
def get_ante12(vpatch):
    ante = {}
    for p in parents(vpatch):
        pp = desc.get(p['h']) # Patch where this appears
        if not ante.get(pp):
            ante[pp] = []
        ante[pp] +=
1 'p'
return ante # Get descendants. def get_desc13(vpatch): des = {} for p in patches: ante = get_ante(p) if vpatch in ante.keys(): des[p] = ante[vpatch] return des ############################################################################## # Print name of patch and its guarantors, or 'WILD' if none known. def disp_vp14(vpatch): seals = ', '.join(map(str, banners[vpatch])) if seals == '': seals = 'WILD' return "{0} ({1})".format(vpatch, seals) ############################################################################## # Command: WoT def c_wot15(args): for k in pubkeys.values(): print "{0}:{1} ({2})".format(k['handle'], k['fp'], k['id']) # Command: Flow def c_flow16(args): for p in patches: print disp_vp(p) # Command: Roots. def c_roots17(args): for r in roots: print "Root: " + disp_vp(r) # Command: Antecedents. def c_ante18(args): ante = get_ante(args.query) for p in ante.keys(): if p != 'false': print "{0} [{1}]".format(disp_vp(p), '; '.join(map(str, ante[p]))) # Command: Descendants def c_desc19(args): des = get_desc(args.query) for d in des.keys(): print "Descendant: {0} [{1}]".format(disp_vp(d), '; '.join(map(str, des[d]))) # Command: Press. def c_press20(args): print "Pressing using head: {0} to path: '{1}'".format(args.head, args.dest) headpos = patches.index(args.head) seq = patches[:headpos + 1] os.mkdir(args.dest) for p in seq: print "Using: {0}".format(disp_vp(p)) os.system("patch -E --dir {0} -p1 < {1}".format(args.dest, p)) print "Completed Pressing using head: {0} to path: '{1}'".format(args.head, args.dest) # Command: Origin. def c_origin21(args): o = desc.get(args.query) if o: print disp_vp(o) else: print "No origin known." ############################################################################## ############################################################################## # Command line parameter processor.22 parser = argparse.ArgumentParser(description=intro, epilog=prolog) # Print paths, etc parser.add_argument('-v', dest='verbose', default=False, action="store_true", help='Verbose.') # Permit the use of patches no one has yet sealed. Use this ONLY for own dev work! parser.add_argument('-wild', dest='wild', default=False, action="store_true", help='Permit wild (UNSEALED!) vpatches.') # Glom keyid (short fingerprint) onto every WoT handle. parser.add_argument('-fingers', dest='fingers', default=False, action="store_true", help='Prefix keyid to all WoT handles.') # Default path of WoT public keys is /home/yourusername/.wot # This dir must exist. Alternatively, you may specify another. parser.add_argument('--wot', dest='wot', default=os.path.join(os.path.expanduser('~'), '.wot'), action="store", help='Use WoT in given directory. (Default: ~/.wot)') # Default path of the seals (PGP signatures) is /home/yourusername/.seals # This dir must exist. Alternatively, you may specify another. parser.add_argument('--seals', dest='seals', default=os.path.join(os.path.expanduser('~'), '.seals'), action="store", help='Use Seals in given directory. (Default: ~/.seals)') # REQUIRED: Path of directory with vpatches.23 parser.add_argument('vpatches', help='Vpatch directory to operate on. [REQUIRED]') # REQUIRED: Command.24 subparsers = parser.add_subparsers(help='Command [REQUIRED]') parser_w = subparsers.add_parser('w', help='Display WoT.') parser_w.set_defaults(f=c_wot) parser_r = subparsers.add_parser('r', help='Display Roots.') parser_r.set_defaults(f=c_roots) parser_a = subparsers.add_parser('a', help='Display Antecedents [PATCH]') parser_a.set_defaults(f=c_ante) parser_a.add_argument('query', action="store", help='Patch.') parser_d = subparsers.add_parser('d', help='Display Descendants [PATCH]') parser_d.set_defaults(f=c_desc) parser_d.add_argument('query', action="store", help='Patch.') parser_l = subparsers.add_parser('f', help='Compute Flow.') parser_l.set_defaults(f=c_flow) parser_p = subparsers.add_parser('p', help='Press [HEADPATCH AND DESTINATION]') parser_p.set_defaults(f=c_press) parser_p.add_argument('head', action="store", help='Head patch.') parser_p.add_argument('dest', action="store", help='Destionation directory.') parser_o = subparsers.add_parser('o', help='Find Origin [SHA512]') parser_o.set_defaults(f=c_origin) parser_o.add_argument('query', action="store", help='SHA512 to search for.') ############################################################################## # V cannot operate without vpatches, WoT, and Seals datasets. def reqdir25(path): if (not (os.path.isdir(path))): fatal("Directory '{0}' does not exist!".format(path)) return path def main26 (): global verbose, pubkeys, patches, roots, banners args = parser.parse_args() verbose = args.verbose # Patch and Sigs dirs pdir = reqdir(args.vpatches) sdir = reqdir(args.seals) wdir = reqdir(args.wot) spew("Using patches from:" + pdir) spew("Using signatures from:" + sdir) spew("Using wot from:" + wdir) pfiles = dir_files(pdir) sfiles = dir_files(sdir) wfiles = dir_files(wdir) # Build WoT from pubkeys handle = {} for w in wfiles: pubkey = open(w, 'r').read() impkey = gpg.import_keys(pubkey) for fp in impkey.fingerprints: handle[fp] = os.path.splitext(os.path.basename(w))[0] for k in gpg.list_keys(): name = handle
1 'fingerprint'
if args.fingers: name += '-' + k['keyid'] pubkeys
1 'keyid'
= {'fp':k['fingerprint'], 'id':', '.join(map(str, k['uids'])), 'handle':name} # Validate seals for p in pfiles: pt = os.path.basename(p) banners[p] = [] for s in sfiles: sig = os.path.basename(s) # All seals must take the form patchtitle.vpatch.yourname.sig if sig.find(pt) == 0: # substring of sig filename up through '.vpatch' v = gpg.verify_file(open(s, 'r'), data_filename=p) if v.valid: banners[p] +=
1 v.key_id]['handle'
else: fatal("---------------------------------------------------------------------\n" + "WARNING: {0} is an INVALID seal for {1} !\n".format(sig, pt) + "Check that this user is in your WoT, and that this key has not expired.\n" + "Otherwise remove the invalid seal from your SEALS directory.\n" + "---------------------------------------------------------------------") # Select the subset of vpatches currently in use. for p in pfiles: if banners.get(p) or args.wild: patches += [p] children(p) # Memoize. parents(p) # Memoize. roots = find_roots(patches) if not roots: fatal('No roots found!') # Topological ordering of flow graph l = [] for p in patches: l += [(p, get_desc(p).keys())] s = map(lambda x:x[0], toposort(l)) patches = s[::-1] # Run command args.f(args) # Remove temporary keychain shutil.rmtree(gpgtmp) ############################################################################## if __name__ == '__main__' : main() ##############################################################################
  1. In Kelvin versioning subsequent version numbers decrease until one has working code, hopefully before version 0. Instead of growing indefinitely like a tumor, software written using this versioning system is meant to crystallize into a program that does one job well. []
  2. This is the software liscense of ~TMSR. The subtext is software is owned by the person running it. []
  3. This is Dijkstra's algorithm for topological sort. I wrote my own version here. Stan starts with an unsorted dictionary of nodes mapped to their outgoing edges. The function iterates through unsorted until it is empty. On each iteration, if a node has no outgoing edges that point to a node in unsorted, the node is appended to the list sorted. If the toposort goes through this iteration without finding a leaf node, then the graph must be cyclic and the toposort fails. Note that Stan's toposort returns the reverse of what is conventionally returned by topological sort. []
  4. A simple function that takes a msg and writes it to standard error while existing the program returning a 1 symbolizing the program failed. []
  5. Prints the given message if verbose is set to true. []
  6. The comment for this function describes it perfectly. os.walk will return an iterator that yields a value for every sub directory. The magical 2 index is the list of file names inside of a given directory in the directory tree. []
  7. ben_vulpes describes why the three lines above are done. gpg by default saves the state of imported keys. For V, however, we only want to use the keys that are in the wot directory at the time of running a command. Setting up this temporary directory is thus done as an implementation detail for running gpg with only the keys found in the wot dir. []
  8. This is an auxilary method used to find children and parents of vpatches. Its parameters include a path to a vpatch and a regular expression. The regex is used to match to the lines found in a vpatch that look like:
    +++ filepath filehash
    or
    --- filepath filehash

    The third parameter, cache, is the dictionary used for memoization. []
  9. Returns a list of the parents of a vpatch using vpdata. Returns an error if it finds none. It's important to note that a parent refers to the filepath/filehash pair that is found after the "---" lines in a vpatch. They are not to be confused with antecedents, which are vpatches. The same goes for children, which are the filepath/filehash pairs found after "+++" lines in a vpatch. []
  10. Returns a list of the children of a vpatch. After finding the children, the function maps the child's filehash to the vpatch in the dictionary desc. It does not count children who have a filehash of 'false' since those are files that have been deleted. []
  11. Filters a given list of patches for the ones that are roots. A genesis patch is a root, but a root is not necessarily a genesis patch. Stan leaves an exercise for the reader to show how one could have more than one root. The answer: a vpatch set will have multiple roots if there are at least two vpatches that do not modify or delete any existing files and instead only create files. []
  12. Iterates through the parents of a vpatch, and then finds the corresponding vpatch that introduced the files in the parents. Returns a dictionary mapping the vpatch's antecedents to the filepath's of the intersection of the antecedent's children and the vpatch's parents. []
  13. Iterates through all patches, getting their antecedents. If the given vpatch is in the antecedents of another patch, then that patch is a descendant of the given vpatch. Returns a dictionary mapping the vpatch's descendants to the filepath's of the intersection of the vpatch's children and the descendant's parents. []
  14. Self explanatory. Although, the comment is technically incorrect- the function just returns the string with the name of the patch and its guarantors / wild if unknown, it does not print the string. []
  15. Prints the list of the keys in the wot directory. []
  16. Prints all the patches in the patch directory with their guarantors as per disp_vp. []
  17. Prints all the roots. These are usually only genesis patches, but could technically be any patch that doesn't modify/delete any existing files. []
  18. Takes a vpatch and prints all of its antecedents. []
  19. Takes a vpatch and prints all of its descendants. []
  20. Presses to a given head vpatch and outputs the result in a given directory. Applies the already topologically sorted vpatches in order up to and including the given head vpatch. If the head is in a vtree that diverges, there is no guarentee that a divergent branch that does not include the head will be pressed as well. This may be considered a bug; vpy needs to be used with care. []
  21. Takes a filehash and prints the vpatch that generated the corresponding file or "No origin known.". []
  22. The code in this section sets up the command line parameter processor. First Stan sets up the optional arguments: verbose, wild, fingers, wot, and seals. The add_argument command used for this takes the parameters: dest, a string that will determine how to access the argument; default, the default value for the parameter; action, either sets the dest to true or sets the dest to the argument given; help, gives a description of the optional parameter.
    -verbose makes the code liberally print what it's doing, -wild lets one patch with unsigned patches, -fingers appends a short fingerprint to every wot handle, --wot takes a path to a directory of wotkeys to replace the default /home/username/.wot, --seals takes a path to a directory of signatures of vpatches to replace the default /home/username/.seals []
  23. Stan's code requires you provide the path to the vpatches on every run, other implementations I've seen have a default patches directory just like .wot and .seals. []
  24. Sets up the list of commands. These fire off the functions that have a prefix c_ in their name, their jobs are described above. The commands are: w (displays WOT), r (displays Roots), a (displays the antecedents of a given vpatch), d (displays the descendants of a given vpatch), f (displays the patches topologically sorted), p (presses a vtree), o (gets the vpatch that generated the given filehash) []
  25. Fails the program if any of the vpatches, wot, or seals directory do not exist. []
  26. The main function stores the arguments from the parser, and then does various setup such as loading the vpatches while checking for their seals and doing the topological sort on the vpatches. Once done initializing it runs the command given by the user and then cleans up by removing the temporary directory it had to make for gnupg. []

Summary of Feelings are helpful, but not for idiots

October 25th, 2019

In her post Feelings are helpful, but not for idiots Diana Coman discusses the correct way to utilize feelings and how a misunderstanding of them may be the root cause of a behavioral pattern she noticed. She begins by noting that she grew up in a different cultural space than the English speaking world. Having lived in various places with a collection of cultures, she acquired an interest for studying the differences between groups. She notes that examining what appears to be only a small difference in behavior can reveal deep information about a culture.

Upon first interacting with English speakers, she was surprised by a quirk: namely that they would ask how she felt about something in situations that called for thinking. They asked questions such as, "What do you feel is a fair price for X?" Diana Coman states that the reason for this has always puzzled her, but she has recently acquired information that has lead her to consider that the aforementioned behavior may be an attempt at flattery.

Diana Coman links to a post written by hanbot, Your Feelings are Out to Get You. She uses this piece as an example of how she came to believe some English speakers have tied the importance of their feelings to their self worth. She figures that consequently someone in the role of a "sales person" may be taking advantage of this cultural phenomenon of feelings being tied to self worth when they ask what someone feels about something. She states that this attempt to make someone feel important by asking how they feel would not work on any sane person who thinks as well as feels.

Diana Coman continues her piece by explaining how to actually benefit from feelings and the consequence of misusing them. She explains that feelings can be useful for revealing information about oneself, but not for understanding the outside world. She claims specifically, "What you feel about something can tell you a lot about your own -and at times very deeply buried- expectations, assumptions and investments." But she also states that feelings by themselves do not infuse one with this self-knowledge, that can only be obtained by a close examination of those feelings. Finally, she concludes with a warning about the misuse of feelings. Feelings will continue to show an image of the self despite one trying to use them to determine the state of the outside world or to measure one's self worth. If feelings are continuously misused, the image they show will become too clear to misinterpret causing one to have to choose between giving up their stupidity or giving up their life.