Technical Musings

Sunday, March 29, 2026

The Dangerous Valley of self driving cars

Five Nines

    When I was a teenager in the late 80s I worked as a gopher (As in: Hey kid, go for something I want; a less fancy name for Intern) for the company my Dad worked at.  It was a financial news agency with an office in Manhattan.  They were investigating the latest in Optical Character Recognition (OCR).  They wanted to bypass the expensive data services to get government market information by scanning newspapers.  Unfortunately, if you ever looked at a newspaper with a magnifying glass you would see a large amount of the text was nearly unrecognizable when looked at closely.  Humans have an amazing ability to see word patterns in badly written text that was only matched by early Convoluted Neural Networks decades later (2009).

    So the latest Macs, stacked on desks made from unfinished doors supported by short file cabinets, had horrible accuracy: around 85%.  Which to my young mind, seemed pretty good.  But having to edit 15 words out of a hundred would take much longer than having a human type them up, so the whole idea failed.

    Later, in my career, I first had to deal with Service Level Agreements (SLAs) as a customer, and then as someone who had to makes these agreements come true.  I learned quickly that 99% of the time is not a very impressive stat for any thing that happens more that 100 times.  1 in a 100 is good odds when betting a single race, but a 99% uptime guarantee allows two weeks of downtime over a year.  SLAs are normally specified in how many 9s are in the uptime guarantee: 99.9, 99.99, 99.999, etc.  Five 9s is considered the gold standard for any service; I don't know any service that advertise six 9s.  And five 9s is only reachable when the problems are well understood and the solutions are mature.  It can take decades before a technology can meet that standard.

Uncanny Valleys

    Computer special effects in films started in the 80s and continued to get better and better, and every improvement was met with Wow!  Well, until the early 2000 with films like The Polar Express (2004) when audiences found the dead eyes of the otherwise improved characters to be disturbing.  It was explained at the time that the faces of the characters had gotten so good that audience's minds started to really recognize them as human faces, but the closeness to reality created a dissonance that the earlier, cruder faces did not.

    This "Uncanny Valley" was dealt with by pulling back from realism (better) and using the improved technology to make simpler (worse) cartoon-like images.  The Incredibles (also 2004) was a good example of this.  Worse is better.

Self Driving Cars

    There are other things that follow this same pattern: Not using a technology to it's fullest extent until it is mature can be for the best.  I think self driving cars fit this pattern.  If I let a self driving car that has a 99.99% effectiveness, there would be only a minute and a half each 24 hours when the system would fail.  Going 60mph, you can definitely die in an badly driven car in less than a minute and a half.  It probably wouldn't be a single failure - it would be many small error spread over the whole 24 hour period.  But it wouldn't take more than a few seconds to lead to a crash.  For most people, it would take over a week to drive 24 hours total.  It would be incredibly easy to get complacent and/or bored over a week's time, and in doing so let the almost good.  Instead, if the system was to fail every 5 minutes, you'd be watching like a hawk.  Paradoxically, by failing more often, it would keep a human more alert to it's fallibility, and better prepared to take corrective action.  Worse is better.

Dangerous Valley 

    The stakes are much higher for a millions of vehicles caring millions of people than for people being disturbed by a character's dead eyes.  It's literally life and death.  It's not an Uncanny Valley, it's a Dangerous Valley.

A Modest Proposal

    We should restrict self driving cars to Level 2 (Current driver assist systems) until they can prove they can reach Level 5 (Full driving automation).  The onus should be on the creators of these systems to prove they are safe.  Allow them make cars that have all the cameras and sensors that will be used for self driving, but they can only use them to gather data, not drive the car.  The car companies will have to do something to entice owners to allow this - maybe free satellite radio?  Since they will only be gathering data, the systems can be much cheaper than a real self-driving setup.  Use that data to simulate what the AI would do.  Don't let the computer drive until those simulations show it can handle %99.999 of all real world situations.  Avoid the Dangerous Valley between a human driver forced to pay attention and a car that can safely do the job completely on it's own.

Notes

Airplanes 

Some might think that the autopilots that airplanes have used for years are comparable to self driving cars - but the tolerances are so much greater for airplanes.  They fly hundreds of feet away from each other in dedicated lanes, with professional pilots, and dedicated, professional traffic management.  The commercial air system is an incredibly safe way to travel.  This system that has taken decades to perfect, under heavy government regulation, and huge consequences ($$$) of even a single failure.

Informed Consent

    People are marketed "Full Self Driving" systems (Tesla) that are not.  Tesla does not publish meaningful statistics on their driving automation.  They provide some statistics, but not enough to compare them to human drivers or even previous versions of their software.  Consumers may conflate the systems that are completely computerized and the ones that have human elements (Waymo, Tesla).  A short test drive before buying a 'self driving' car would have a low probability of showing the errors of a greater than %99 (but less than %99.999) effective system.  Are consumers sufficiently informed for consent?

 

  

Thursday, August 1, 2024

Python Requests proxy all protocols through single URL

The Python Requests library requires you to specify multiple proxy URLs per protocol, 

like this:

import requests
proxies = {
    'http': 'http://10.10.1.10:3128',
    'https': 'http://10.10.1.10:1080', }
requests.get('http://example.org', proxies=proxies)
The annoying thing is if you leave off either protocol, 
it does not error - it just doesn't proxy that traffic.
While this flexibility is great, it would be nice to have
both http and https traffic go through the same proxy
without repeating oneself.
 
A somewhat silly way to make this more DRY is to use my favorite collection: 
defaultdict ( and lambda ).

import requests
from collections import defaultdict
proxies = defaultdict(lambda: 'http://10.10.1.10:3128') requests.get('http://example.org', proxies=proxies)
A defaultdict is usually given a default value of a type, like a list or an int.

Using lambda allows you to give it a specific value, in this case a string.

Monday, April 22, 2024

I found this template for Elixir scripts to be really useful:

https://arathunku.com/b/2024/shell-scripting-with-elixir/

To add to that, I wanted to require a particular version of Elixir:

elixir_version_required="~> 1.14" if not Version.match?(Version.parse!(System.version), Version.parse_requirement!(elixir_version_required)) do IO.write("Elixir version doesn't match requirement: #{elixir_version_required}") System.halt(0) end

Wednesday, December 20, 2017

Export Gnome Extension URLs

To export text list of the URLs of your installed Gnome Extensions:

sudo apt-get install jq

cat ~/.local/share/gnome-shell/extensions/*/metadata.json | jq '.url'

This works for most, but some do not include url in metadata.json.

Friday, March 3, 2017

How To Avoid Taking Down Your S3 With Ansible

The s3 outage summary (https://aws.amazon.com/message/41926/) describing the cause of the outage 2/28/2017, specifically says an 'established playbook' was used to take down s3, which sounds like they used an Ansible playbook.  And I'm pretty sure how such a terrible error happened, because I've worked around this problem with Ansible in my own projects.

The normal way you run a subset of a group of servers in Ansible is to add the '--limit' parameter, which filters the list of servers based on a group name.  So, of example, you say run on 'web' group with a filter of 'webserver01''; this would only run the Ansible playbook on 'webserver01', not on all the 'web' servers.

The problem is, if you badly specify '--limit' or leave it off, it runs against the whole group.  This is a horrible design flaw.

The work around is not to use '--limit' at all, but instead you specify `hosts: "{{ target }}"` in your playbook.  So you must specify '-e "target=webserver01' or you get an error saying no hosts specified.  The target can be a pattern, so "target=web:database" or "target=webserver0*" works, so this is flexible enough to not need '--limit' at all, and avoid this dangerous design flaw of Ansible.

Tuesday, January 6, 2015

'Compressing' CloudFormation template to get around size limit

Recently I hit the 51,200 byte body size limit of AWS's CloudFormation's templates.  I looked into creating Nested Stacks, but that seemed like a pain.  Looking at the created json template, I saw a lot of unneeded whitespace.

I used troposhere to generate the template, so it was easy to reduce the size by stripping out the beginning and ending whitespace of each line in the json file.

I just added the following line:
json_compressed="\n".join([line.strip() for line in t.to_json().split("\n")])
utils.validate_cloudformation_template(json_compressed)

This more than havled the size of the template from ~60K to ~25K bytes:

$ wc template.json
    1821    2860   60133 template.json

$ wc template_compressed.json
    1821    2860   24616 template_compressed.json


And CloudFormation accepted it, no problem.

Friday, January 2, 2015

Elixir Tgraph

In my attempt to learn Elixir, I've converted an Erlang version of a Python script I wrote years ago.  It takes a pipe of numeric values and plots lines in a character terminal.  Super simple, but handy sometimes.

Now, I know line count is a horrible way to compare code, but here it is:

150 tgraph.py https://gist.github.com/dgulino/4750099
136 tgraph.escript https://gist.github.com/dgulino/4750118
106 tgraph.ex https://gist.github.com/dgulino/298516f7977c57199a4a

The python code is many years old.  Maybe I've learned something since then, but I don't write very compactly, on purpose.  I only use standard libraries since I don't have the luxury of installing stuff on some of the systems I want to run this on, so can't use some of the cool libraries out there.

It's hard to compare the python code to the Erlang/Elixir.

The Erlang code has added cruft on top to run as Escript (so I don't have to compile changes).   I've yet to figure how to enable piping of stdin to Elixir without running a build ('mix escript.build').  So I get to compile my interpreted code!

Otherwise, the Elixir code is easier to read and more concise than Erlang, which is no suprise.  Elixir +1.


Friday, November 21, 2014

Number of New Connection Per Second

Under pressure, debuging a production system, given the following question:

"How many new connections per second are we creating to S3?".

My one-liner (Linux):

while true; do diff   <(netstat -an | grep ESTAB | grep ":443 "| grep -v "N.N.N.N:443 " | sort) <(sleep 1; netstat -an | grep ESTAB | grep ":443 "| grep -v "N.N.N.N:443 " | sort) | grep "<" | wc -l;sleep 1;done

Where N.N.N.N is the local IP.  Many better ways to do this, but I had this in a few minutes.

Done.

Thursday, August 22, 2013

linux mint privacy/security setup

Privacy/Security

Linux(Mint)
dns:
dnscrypt
init.d script
apt-get install sysv-rc-conf
sysv-rc-conf dnsycrypt-proxy on
apt-get install unbound
/etc/unbound/unbound.conf:
forward-zone:
  name: "."
  forward-addr: 127.0.1.1@53
airplane init.d # cat /etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 127.0.0.1

# OpenDNS Fallback (configured by Linux Mint in /etc/resolvconf/resolv.conf.d/tail).
nameserver 208.67.222.222
nameserver 208.67.220.220

disable dnsmasq (not caching):
airplane init.d # cat /etc/NetworkManager/NetworkManager.conf
[main]
plugins=ifupdown,keyfile
#dns=dnsmasq

disabled dnssec in unbound:
    # DNSSEC validation using the root trust anchor.
#    auto-trust-anchor-file: "/var/lib/unbound/root.key"





mail:
thunderbird/openpgp
http://www.mailvelope.com/

tor:
tor-browser
non-exit relay:
    bandwidth limit

secure-delete:
sudo apt-get install secure-delete
srm

password management:
passwordmaker

TODO:
filesystem encryption
#############
android:
apg

#############
firefox:
ghostery
adblock plus (disable reasonable ads)

linux mint 15 (cinnamon) on chromebook pixel

linux mint 15 (cinnamon) on chromebook pixel
(Sorry for the info dump, hopefully will fix soon)

setup mint 15 on chromebook

http://www.reddit.com/r/chromeos/comments/1eqsjp/tutorial_how_to_install_any_linux_distro_on_the/

http://www.webupd8.org/2011/12/how-to-enable-mac-os-x-like-natural.html

date/time in panel:
http://www.foragoodstrftime.com/

sudo apt-get install gnome-tweak-tool

sudo sh ./install_firmware_from_alsa_project.sh

sudo add-apt-repository ppa:zedtux/naturalscrolling
sudo apt-get update

sudo apt-get install naturalscrolling
    enable for trackpad, usb mouse
    enable start on login

firefox:
    default full zoom
    ghostery
    adblock plus

trackpad:
    disable left tap
    enable two finder scroll
    small amount of acceleration

windows tiling management:
gTile extension:
http://cinnamon-spices.linuxmint.com/extensions/view/21
https://github.com/shuairan/gTile/commit/3277b72e84407bc70df0dce95e96a7e283587481

screen:
    add brightness applet to panel

    keyboard shorcuts:
        sudo apt-get install xbacklight
        /usr/bin/xbacklight -dec 10
                        -inc 10

suspend fix:
http://blog.brocktice.com/2013/03/09/running-debian-wheezy-7-0-on-the-chromebook-pixel/

/etc/modules:
    tpm_tis force=1 interrupts=0


touchpad:
    disable right lower corner as right click:
    /usr/share/X11/xorg.conf.d/50-synaptics.conf
     31 ##Section "InputClass"
 32 ##        Identifier "Default clickpad buttons"
 33 ##        MatchDriver "synaptics"

 34 ##        Option "SoftButtonAreas" "50% 0 82% 0 0 0 0 0"
 35 ##EndSection

cursor:
 sudo apt-get install oxygen-cursor-theme
 settings...theme..other settings..mouse pointer: oxy-white

power:
    powertop
    arrow over to Tunables
    hit enter on each 'bad', turn it to 'good'
    esc to exit

    change whether plugged in/not
    http://askubuntu.com/questions/112705/how-do-i-make-powertop-changes-permanent
        add output of "sudo powertop --csv=powertop.csv" to battery /etc/pm/power.d/power

disable bluetooth by default:
    Run gksu gedit /etc/rc.local and add this before line with exit 0:
    rfkill block bluetooth

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

Cinnamon desktop optimizations:

windows management:
x-tile

keyboard launcher:
kupfer


themes:
window borders: HighContrast
check "show icons on buttons"

cursor:
fix comixcursors
apt-get install comixcursors
get .tar.bz2
extract to:
/etc/X11/cursors/
/usr/share/icons/
reload cinamon alt-f2 "r"


tar xjf ComixCursors-0.7.3.tar.bz2





Wednesday, June 5, 2013

monkeyrunner hanging on input/raw_input on Mac OS X: RESOLVED

I found recently that my monkeyrunner scripts started failing after updating the Android SDK Tools to version 22.0.1.  This is a known bug in the jython version shipped with it.  Luckily it's easily fixed by replacing one .jar file.

http://www.jython.org/latest.html:

Jython 2.5.4rc1 Release Notes
Bugs Fixed:

[ 1972 ] jython 2.5.3 sys.stdin.readline() hangs when jython launched as subprocess on Mac OS X

1)  Download latest jython 2.5.4rc1:

http://search.maven.org/remotecontent?filepath=org/python/jython-standalone/2.5.4-rc1/jython-standalone-2.5.4-rc1.jar

2) Copy into ${ANDROID_ROOT}/sdk/tools/lib/

3) move or delete the existing jython-standalone-2.5.3.jar

That's it!  monkeyrunner now process raw_input() and input() correctly.

Sunday, February 10, 2013

Move over Yahoo Notepad, welcome Github Gist

Github's gist are a pretty good match for a lot of stuff I do; simple one file scripts, not big projects.

I've been putting up a few scripts I've embedded in this blog, and I'm looking through old files for more.  I even have some stuff in an old Yahoo Notepad.  Yea, Yahoo Notepad.  It was/is a simple way to store text files in folders.  No support for sharing, and you had to cut and paste into a form to 'upload' them.  There doesn't seem to be any links in YMail to that system anymore, so you have to go directly to notepad.yahoo.com; but it still works.  I've had a Yahoo account since they first offered them back in 1997.  Unfortunately, during the early times they had pretty restrictive mailbox size limits (I think it started at 5MB), so I had to delete a bunch of stuff back then.  The earliest mail I still have is dated September 5, 2003.

It's terribly thing relegating some of this stuff to Notepad; I had embedded version numbers in the scripts themselves.  Not quite as reliable as Git, I must say.

My Gists:
https://gist.github.com/dgulino

Wednesday, February 6, 2013

OSX SSH Terminal Console Coloring, Redux 2.0

Something about my previous take on this breaks autocompletion in OSX in a weird way: After I finish my first SSH session, tab completion no longer autocompletes. It does provide suggestions as a list, but will not complete the line I'm typing.
I've tried all kinds of things to get this to work, and here's my latest take: simply create a bash script and create an ssh alias to it.
/Users/USERNAME/ash.sh:
#!/bin/bash
ARGS="$@"
A="${ARGS}"
IFS=" "
set -- "$ARGS"
ARGSARRAY=( $@ )
FQDN="${ARGSARRAY[0]}"
IFS="."
set -- "${FQDN}"
FQDNARRAY=( $@ )
HOST="${FQDNARRAY[0]}"
DOMAIN="${FQDNARRAY[1]}.${FQDNARRAY[2]}"
IFS="-"
set -- "${HOST}"
MYARRAY=( $@ )
SERVERTYPE="${MYARRAY[0]}"
ENVNAME="${MYARRAY[1]}"
if [ "${ENVNAME}" = "pro" ]; then
    if [ "${serverType}" = "p19" ]; then
        PROFILE="Basic Green"
    else
        PROFILE="Basic Black"
    fi
elif [ "${ENVNAME}" = "qa" ]; then
    PROFILE="Basic Grey"
elif [ "${ENVNAME}" = "stage" ]; then
    PROFILE="Man Page"
elif [ "${ENVNAME}" = "shadow" ]; then
    PROFILE="Basic Blue"
elif [ "${DOMAIN}" = "test.info" ];then
    PROFILE="Basic Grey"
elif [ "${DOMAIN}" = "test.net" ];then
    PROFILE="Basic Black"
else
    PROFILE="Basic"
fi 
echo "tell app \"Terminal\" to set current settings of \
 first window to settings set \"${PROFILE}\"" | osascript
/opt/local/bin/ssh "${A}"

echo "tell app \"Terminal\" to set current settings of \ 
 first window to settings set \"Basic\"" | osascript 
.profile:
alias ssh='/Users/USERNAME/ash.sh'
This isn't perfect; it doesn't color my csshX sessions, and seems to mess up scp file autocompletion (you use that?). But it's reliable, you don't have to remember anything but 'ssh', and you can use other ssh parameters, as long as the hostname is the first argument.

Wednesday, January 30, 2013

'yum update' that excludes Puppet managed files

I have many machines that I manage with Puppet. If you have more than one machine, you need to use a tool like it. It does a great job of managing the configuration of packages that we use directly or are direct dependencies. But we do not put every package that is installed on a box in Puppet; I don't think anyone does this. On our boxes we have around 500 packages installed. I imagine some environment would have the time to review each rpm to ensure it was compatible, and then change it's version in Puppet, ensuring that no dependencies for that package have changed. A much more realistic approach is to just update a test machine to the latest, and then test out your application, only reviewing the changes for the packages that are direct dependencies. Even better would be to have yum update all packages except the packages you have specified in Puppet. You want all the basic upgrades, like a kernel update, without changing that version of ruby you have been using.

How to do this?

First, run puppet a puppet no operation test, to update the local catalog:

/usr/bin/puppet agent --onetime --ignorecache --server ${puppet_master} \
 --no-daemonize --verbose --detailed-exitcodes \
 --logdest /var/log/puppet/puppet.log --noop --test

Then build up a list of packages that are controlled by Puppet, and exclude them from a 'yum update' command:

packages=$(grep "reference:\ \"Package" /var/lib/puppet/client_yaml/catalog/*.yaml \
| awk -F"[" '{print $2}' \
| awk -F"]" '{print $1}')

exclude=$(for package in ${packages};do echo -n " -x ${package}";done); 

yum update ${exclude}

You could use a similar approach with other package managers like apt.

Found the data when I checked out puppet-ls

Friday, January 25, 2013

OSX SSH Terminal Console Coloring, Redux

UPDATE: http://technicalmusings.blogspot.com/2013/02/something-about-my-previous-take-on.html
I've come up with a much better, simpler recipe to color my OSX Terminal session depending on the host I'm ssh-ing into. First, take a function with some cool BASH-only splitting and arrays and add that I found a way to address the current session in Applescript. Then add a one line way to enable bash ssh auto-complete when using the function. Ensure you pass all args to SSH so you can tunnel, etc. Finish with another line to switch the colors back to some default when you disconnect. Add this to your .profile, and voila!

This function assumes a certain host naming scheme, and that you have a Terminal profile for each environment.  I just copied 'Basic', and changed the background colors.  If you can't parse your server names, you need a better naming scheme ;)

ash() {
    ARGS="$@"
    IFS=" "
    set -- $ARGS 
    ARGSARRAY=( $@ )
    HOST=${ARGSARRAY[0]}
    IFS="-"
    set -- ${HOST}
    MYARRAY=( $@ )
    SERVERTYPE=${MYARRAY[0]}
    ENVNAME=${MYARRAY[1]}
    if [ "${ENVNAME}" = "pro" ]; then
        if [ "${serverType}" = "p19" ]; then
            PROFILE="Basic Green"
        else
            PROFILE="Basic Black"
        fi
    elif [ "${ENVNAME}" = "qa" ]; then
       PROFILE="Basic Grey"
    elif [ "${ENVNAME}" = "stage" ]; then
        PROFILE="Man Page"
    elif [ "${ENVNAME}" = "shadow" ]; then
        PROFILE="Basic Blue"
    else
        PROFILE="Basic"
    fi 
    echo "tell app \"Terminal\" to set current settings of first window to settings set \"${PROFILE}\"" | osascript
    ssh "${ARGS}" 

    echo "tell app \"Terminal\" to set current settings of first window to settings set \"Basic\"" | osascript 
}
complete -o default -o nospace -F _ssh ash
 
so:
$ ash test-pro-wxy01.test.com
 
will ssh to test-pro-wxy01.test.com and set the background to black, and when I logout, the background will be set to white.

gist: https://gist.github.com/4638756

One limitation currently, is that the hostname must be the first argument.

Another slight disadvantage is that you have to type something other than 'ssh'.  You could rename the ssh binary to something else, and then name the function 'ssh'.   Don't just name the function 'ssh' w/out renaming the binary (try it and find out why!)

Ideas taken from everywhere, including: https://raw.github.com/c3w/ash/master/ash

Monday, February 6, 2012

SSH LocalCommand / OSX Terminal Colors

UPDATE: http://technicalmusings.blogspot.com/2013/01/osx-ssh-session-coloring-redux.html If you're like me, you work in many different computing environments: home, test, QA, and production.  And it's REALLY important not to get them mixed up.  I've always used a color scheme in my ssh/console windows to help me differentiate each.   I've manually set the color of each console before I log in, and try not to reuse a console for different environments.  It's kind of a pain, and if I'm brain dead enough to not notice what host I'm logged into, chances are high that I'm not going to set the colors correctly either.  So I created an OSX (I'm on 10.7) AppleScript to automatically change the Terminal colors for each of my windows/tabs to match the environment that console is logged into.

To trigger the AppleScript, I added it to an until-now-unknown to me ssh client setting: LocalCommand.  It will run a command locally each time you make an ssh connection.

To setup the trigger, you must add the following lines into ~/.ssh/config:
(Note: it's important to add the & at the end of LocalCommand to put the command in background so it can wait for Terminal to connect)
 Host *
  
   PermitLocalCommand yes
  
   LocalCommand /Users/MYNAME/applescript/term_tab_style.scpt &
  

UPDATE: And this in /etc/ssh_config:
  PermitLocalCommand yes  

The AppleScript goes through all open Terminal windows/tabs and checks the title.  This is normally set to the user@hostname, and I have a naming convention 'purpose'-'env'-'location'-'number'.  Applescript has very limited parsing capabilites; I found the functions I used here to split the hostname up and get the environment name.  You can then set the Terminal window/tab to whatever Profile you desire.

The code for term_tab_style.scpt.  Copy this code into wherever you specified the LocalCommand in ~/.ssh/config and don't forget to run 'chmod u+x ~/term_tab_style.scpt'.

 #!/usr/bin/osascript
  
 on run argv

   delay 1
  
   tell application "Terminal"
     repeat with w from 1 to count windows
       repeat with t from 1 to count tabs of window w
         set title to custom title of tab t of window w  
         try
           set myArray to my theSplit(title, "@")
           set userName to my getArrayValue(myArray, 1)
           set restName to my getArrayValue(myArray, 2)
           set myArray to my theSplit(restName, "-")
           set envName to my getArrayValue(myArray, 2)
           if envName is "pro" then
             #display dialog ("" & envName)
                set current settings of tab t of window w to (first settings set whose name is "Basic Blue")
           else if envName is "qa" then
                set current settings of tab t of window w to (first settings set whose name is "Basic")
           end if
         end try
       end repeat
     end repeat
   end tell
  
 end run
  
 on theSplit(theString, theDelimiter) 
   -- save delimiters to restore old settings
   set oldDelimiters to AppleScript's text item delimiters
   -- set delimiters to delimiter to be used
   set AppleScript's text item delimiters to theDelimiter
   -- create the array
   set theArray to every text item of theString  
   -- restore the old setting  
   set AppleScript's text item delimiters to oldDelimiters  
   -- return the result  
   return theArray 
 end theSplit
  
 on getArrayValue(array, location)  
   -- very important -- The list index starts at 1 not 0  
   return item location in array  
 end getArrayValue
  

Thursday, January 12, 2012

Python JSON one-liner

I've seen the python one-liner to parse and pretty-print json:

cat test.json | python -mjson.tool

But I still have to grep/awk to get the value.  Here's a python one-liner to get a json value:

curl -s -u user:password "http://test.json.output" | python -c "import json,sys;input=json.load(sys.stdin);print (input.get('messages'))"

A reasonably short, pure python way to do this is with the requests library, but that's not built into python, and I find one-liners are only useful if they work across a lot of systems as-is:

import json,requests
r = requests.get("http://test.json.output/api/", auth=('user','pass'))
o = json.loads(r.content)
print (o.get('messages'))

Tuesday, December 6, 2011

Wireshark on OS X

I run Wireshark (formerly Ethereal) on OSX, but by default only root has rights to the ethernet devices.  So either you run it as root, which is a security risk, or you give your own user the rights.  The devices (/dev/bf*) that are used are recreated every boot, so just 'chown'ing them won't do.

First add your user to the wheel group:


dscl . append /Groups/wheel GroupMembership 'username'

The run this command:

sudo chmod g+rw /dev/bpf*; open /Applications/Wireshark.app

I added that command to my .profile file as an alias for convenience:

alias wireshark='sudo chmod g+rw /dev/bpf*; open /Applications/Wireshark.app'

MSudo: Mac OSX Graphical SUDO

UPDATE: I've created a git repository for this: https://github.com/dgulino/msudo

I develop a lot on OSX and there are times I need to run a GUI app as root, like a gui editor of a systems file, or running Wireshark. I could just run it from a terminal using "sudo", but that's not very cool. There is the Pseudo app, which is quite cool, and only $15, but I figured it wouldn't be too hard to script something together. Well, Many Hours Later, I've got something! An AppleScript droplet that can be added to your dock and when you drag another App on it, a GUI popup will ask for your password, and voila!  You have a GUI app running as root.

Open Applications..Utilities..AppleScriptEditor, paste this below, and then save it as MSudo.app, as an Application.  Then drag it onto your Dock

Open
on open {filename}
     set p to POSIX path of filename
     set myArray to my theSplit(p, "/")
     set numItems to (count myArray) - 1
     set AppNameFull to getArrayValue(myArray, numItems)
     set myArray to my theSplit(AppNameFull, ".")
     set numItems to (count myArray) - 1
     set AppName to getArrayValue(myArray, 1)
     do shell script p & "/Contents/MacOS/" & AppName with administrator privileges
end open
on theSplit(theString, theDelimiter)
     -- save delimiters to restore old settings
     set oldDelimiters to AppleScript's text item delimiters
     -- set delimiters to delimiter to be used
set AppleScript's text item delimiters to theDelimiter
     -- create the array
     set theArray to every text item of theString
     -- restore the old setting
     set AppleScript's text item delimiters to oldDelimiters
     -- return the result
     return theArray
end theSplit
on getArrayValue(array, location)
     -- very important -- The list index starts at 1 not 0
     return item location in array
end getArrayValue

Update 2012/03/12: You can add a nice icon for this: http://stackoverflow.com/questions/8371790/how-to-set-icon-on-file-or-directory-using-cli-on-os-x http://icons.iconarchive.com/icons/iconshock/super-heros/128/superman-icon.png

Thursday, April 28, 2011

Compiling Erlang escript to .beam

As part of my experiments in command line Erlang escripts, I've been looking into compiling escripts into .beam files. There is a bit of a wait on starting my .escript files, and command line tools should have as little delay on startup as possible since they are generally started and stopped often.

First, I compiled my .escript files to .beam, I did this with this bash script:

erlsee.sh (get it?):
#!/usr/bin/bash
test=$1
echo $test

args=("$@")
file="$1"
echo ${file}
temp_file=$1.tmp
echo $temp_file
cp $file $temp_file
file=`echo "$1" | sed s/.escript/.erl/g` 
sed -n '1!p' $temp_file > $file
/usr/bin/env erlc $file
cp $temp_file $file
rm $temp_file

This allows you to compile an escript directly without having to remove the #! directives at the top or rename the file to have an .erl ending.

Secondly, I added the same #! headers to the .beam files, and set execution permissions (`chmod u+x *.beam`). Just open the .beam file with a text editor and paste the following lines at the top:

#!/usr/bin/env escript
%%! -smp disable


Third, I tested the running times with a very small input file with the 'time' utility. I figure this time should be dominated by the basic start up time, not the execution speeds.

$ time cat test.txt | ./runavg.escript -s 5 -i 5 | ./tgraph.escript
************************************************************************24
*********************************************15

real 0m2.077s
user 0m0.121s
sys 0m0.045s

$ time cat test.txt | ./runavg.beam -s 5 -i 5 | ./tgraph.beam
************************************************************************24
*********************************************15

real 0m2.182s
user 0m0.090s
sys 0m0.138s

I ran this multiple times, and the averages were almost equal; certainly not a big improvment. So it's not worth the extra effort to compile your escript files to .beam to improve startup times.

Execution time is another matter; it is probably improved, but that doesn't really matter for programs that just output text. They are fast enough as is.