Monthly Archives: January 2016

JSON adatbányászat shellben

TL;DR: ha stock OS X alatt shell scriptben JSON-t akarsz parse-olni, jsc-vel csináld.

A probléma

Van egy Alfred workflow-m, amivel villámgyorsan át tudom állítani a Transmission torrent kliens speed limitjét - ez a script a bele.

Ehhez akartam olyat, hogy amint az Alfred querybe beírom a script filer kulcsszavát, azonnal jelenjen meg, hogy mennyi az aktuális speed limit a Transmission kliensben.

A megoldás: 1/3 (eFi)

Először abban reménykedtem, hogy egy Google search majd azonnal ontja magából a találatokat a "parse JSON in bash"-re, de amiket talált, abból egyik sem tetszett igazán, így aztán benga favágó módjára kikapáltam az engem érdeklő infót, duplán regexpelve (mint az állatok):

#!/bin/sh
## guess Transmission's speed limit
 
USER=yourUserName
PASS=yourPassword
server=http://yourTransmissionHostIP
SPEED=$1
 
curlout=$(curl -u $USER:$PASS ${server}:9091/transmission/rpc 2>/dev/null)
regex='(X-Transmission-Session-Id\: )([^<]*)'
 
if [[ $curlout =~ $regex ]]; then
    sessionid=${BASH_REMATCH[2]}
else
    exit 1
fi
 
data='{"method": "session-get"}'
R=$(curl -H $USER:$PASS ${server}:9091/transmission/rpc -d "$data" -H "X-Transmission-Session-Id: $sessionid")
 
ASD_ENABLED=`echo "$R" | grep -o -e '\"alt\-speed\-enabled\":[a-z]*'`
ASD_ENABLED=`echo "$ASD_ENABLED" | grep -o -e '[a-z]*$'`
 
ASD=`echo "$R" | grep -o -e '\"alt\-speed\-down\":[0-9]*'`
ASD=`echo "$ASD" | grep -o -e '[0-9]*$'`
 
SLD_ENABLED=`echo "$R" | grep -o -e '\"speed\-limit\-down\-enabled\":[a-z]*'`
SLD_ENABLED=`echo "$SLD_ENABLED" | grep -o -e '[a-z]*$'`
 
SLD=`echo "$R" | grep -o -e '\"speed\-limit\-down\":[0-9]*'`
SLD=`echo "$SLD" | grep -o -e '[0-9]*$'`
 
echo '<?xml version="1.0"?>'
echo '<items>'
echo " <item uid='tspd' arg='$SPEED' valid='yes'>"
echo " <title>Set Transmission speed limit</title>"
if [ "$ASD_ENABLED" = "true" ]
then
	echo " <subtitle>Current speed limit: $ASD kbps</subtitle>" 
else
	if [ "$SLD_ENABLED" = "true" ]
	then
		echo " <subtitle>Current speed limit: $SLD kbps</subtitle>" 
	else
		echo " <subtitle>Currently no speed limit is set</subtitle>" 
	fi
fi
echo ' <icon>speed-limit.png</icon>'
echo '</item>'
echo '</items>'

A megoldás: 2/3 (fds)

Mennyivel szebb lenne ez egy JSON parserrel!
Eltelt pár óra és Fazekas "fds" Dani barátom megjelent, majd kettő perc múlva kirázta a kisujjából ezt:

JSON='{"efi":24,"csokijat":42,"mar":242,"elvittek":666,"fene":[1,2,3,4]}'
/System/Library/Frameworks/JavaScriptCore.framework/Versions/Current/Resources/jsc -e "debug(JSON.parse(readline())['fene'][2])" <<< "$JSON"

Script az script, ez meg parsol, úgyhogy ezért INSTANT CSOKI jár.

A megoldás: 3/3 (fds)

fds a posztot látva azt mondta, hogy szerinte nem dolgozott meg a megacsokiért, de ha adnék egy Transmission kimenetet amit a curl leszippant, akkor faragna egy csinosabb verziót. A maximalizmusát már jól ismerve meg nem fosztottam volna a világot az új változattól, úgyhogy azonnal ment az output.
Nem is lenne fds, ha nem csinálta volna meg azonnal jsc, php, python és ruby használatával is az egészet (azért "csak" ennyi interpreterrel, mert ezek érhetők el a gyári OS X alól 2016 januárjában). A hozzám hasonló bolondok biztosan fülig érő szájjal olvassák a scriptet:

#!/bin/bash
 
## guess Transmission's speed limit
 
USER="yourUserName"
PASS="yourPassword"
server="http://yourTransmissionHostIP"
SPEED="$1"
JSONPARSER="jsc"
 
curlout=$(curl -u $USER:$PASS ${server}:9091/transmission/rpc 2>/dev/null)
regex='(X-Transmission-Session-Id\: )([^<]*)'
 
if [[ $curlout =~ $regex ]]; then
    sessionid=${BASH_REMATCH[2]}
else
    exit 1
fi
 
data='{"method": "session-get"}'
R=$(curl -H $USER:$PASS ${server}:9091/transmission/rpc -d "$data" -H "X-Transmission-Session-Id: $sessionid")
 
getargument() {
	local ret
 
	case "$JSONPARSER" in
		jsc)
			ret=$(2>&1 /System/Library/Frameworks/JavaScriptCore.framework/Versions/Current/Resources/jsc -e "debug(JSON.parse(readline())['arguments']['$2'])" <<< "$1")
			ret="${ret#-->* }"
			;;
		php)
			ret=$(php -nr "echo json_encode(json_decode(file_get_contents('php://stdin'), true)['arguments']['$2']);" <<< "$1")
			;;
		python)
			ret=$(python -c "import json,sys
print(json.dumps(json.load(sys.stdin)['arguments']['$2']))" <<< "$1")
			;;
		ruby)
			ret=$(ruby -e "require 'json'
puts JSON.parse(STDIN.read)['arguments']['$2']" <<< "$1")
			;;
	esac
 
	echo "$ret"
}
 
ASD_ENABLED=$(getargument "$R" "alt-speed-enabled")
ASD=$(getargument "$R" "alt-speed-down")
SLD_ENABLED=$(getargument "$R" "speed-limit-down-enabled")
SLD=$(getargument "$R" "speed-limit-down")
 
echo '<?xml version="1.0"?>'
echo '<items>'
echo $'\t''<item uid="tspd" arg="'"$SPEED"'" valid="yes">'
echo $'\t'$'\t'"<title>Set Transmission speed limit</title>"
if [ "$ASD_ENABLED" = "true" ]; then
	echo $'\t'$'\t'"<subtitle>Current speed limit: $ASD kbps</subtitle>" 
else
	if [ "$SLD_ENABLED" = "true" ]; then
		echo $'\t'$'\t'"<subtitle>Current speed limit: $SLD kbps</subtitle>" 
	else
		echo $'\t'$'\t'"<subtitle>Currently no speed limit is set</subtitle>" 
	fi
fi
echo $'\t'$'\t''<icon>speed-limit.png</icon>'
echo $'\t''</item>'
echo '</items>'

Persze ennyivel nem érte be, megmérte, hogy melyik verzió mennyi időt zabál el az életemből:

for p in jsc php python ruby; do
	echo -n "$p: "
	JSONPARSER="$p"
	OUT=$(( time -p (
		ASD_ENABLED=$(getargument "$R" "alt-speed-enabled")
		ASD=$(getargument "$R" "alt-speed-down")
		SLD_ENABLED=$(getargument "$R" "speed-limit-down-enabled")
		SLD=$(getargument "$R" "speed-limit-down")
		echo "${ASD_ENABLED}|${ASD}|${SLD_ENABLED}|${SLD}"
	) ) 2>&1)
	echo -n $(tail -n 3 <<< "$OUT" | head -n 1 | cut -d ' ' -f 2)s
	echo ' '$(head -n 1 <<< "$OUT")
done
exit

Az eredmény az, hogy a jsc mindent lever:

jsc: 0.04s false|10|true|500
php: 0.25s false|10|true|500
python: 0.11s false|10|true|500
ruby: 0.23s false|10|true|500

Maximalista grafikusnak megismert Rack barátom szokta azt mondani az árajánlatot sokalló ügyfélnek, hogy "de minden pixel a helyén van". Nos, nekem Dani ugyanez a szerethető fanatikus coderben. Le vagyok nyűgözve, mint mindig :)

Excel VBA: Application.Evaluate – Error (2015|2029)

Ha legközelebb egy formulát akarsz kiértékeltetni a VBA engine Application.Evaluate() metódusával és a rohadék a nem túl beszédes "Error 2015" vagy "Error 2029" stringeket adná vissza cserébe, akkor ne a formulákban keresd a hibát, hanem azt nézd meg, hogy a kiértékelés forrásaként használt képlet és az aktív workbook referenciastílusa megegyezik-e. Ha nem, akkor állítsd át az

Application.ReferenceStyle = (xlA1|xlR1C1)

értékadással és problem solved, a redmondi felelősök meg süllyedjenek el szégyenükben a gusztustalan workaroundjukkal együtt.

3D nyomtatás: amikor veszettül keresel két egyforma click pen rugót

A dolog úgy indult, hogy a hugom gyerekeinek szerettem volna karácsonyra valami olyat gyártani, ami miatt esetleg elkapja őket a gépszíj és fotózni kezdenek a telefonjukkal. Az első ötlet egy telefonos mount volt, de végül egy fénysátor mellett döntöttem:

DIY-light-tent

A tárgyfotózáshoz kellemes szórt fényt csináló fénysátor nem egy nagy etvasz: 3 ágú sarkok kellenek, amibe belemegy a 15 mm-es alu cső, összedugod, letakarod egy lepedővel, belecsíptetsz egy 50x70-es kartonpapírt háttérnek (vagy ráakasztasz a felső hátsó rúdra egy IKEA TUPPLUR-t, aztán oldalról meg esetleg felülről fényt adsz neki és kész is. Az STL file-okat szedheted a youmagine-ről.

Fénysátor pipa, viszont még mindig izgatott a zsebben hordható telefonos állvány mount ötlete. Két szimpatikus megoldással már találkoztam a neten, sőt, az egyikből van is egy rakat a családban. Mindkét megoldás letisztult minimalista, gondoltam teszek egy próbát, hogy le tudom-e őket saját magam gyártani.

Az első delikvens a Studio Neat GLIF nevű terméke:

The New Glif (It's Adjustable) from Studio Neat on Vimeo.

A srácok imbuszcsavarral fix méretre állítható megoldást találtak ideálisnak.

A másik jelölt a Joby GripTight névre keresztelt mountja:

A GripTight két apró rugót használ ahhoz, hogy a foglalatban tarsta a telefont.

A GLIF klónozása

Előbb a GLIF-nek estem neki: ~10 iteráció után el is készült az a verzió, ami fixre állítható közök helyett rugósan tartott mindkét oldalon, valahogy így:

GLIF-clone-schematics

A középső, piros elem közepén levő 4 mm átmérőjű, 25 mm hosszú furatban M4-es menet van. A két szélső elembe előbb egy apró nyomórugó, majd azokba egy-egy M4-es csavar kerül, ami a középső elem menetébe van betekerve. A nyomórugók hosszával és az M4-es csavarok méretével lehet játszani, hogy mekkorára nyíljon a két oldal.
Miután a két szélső elem a helyén van, a végükre kerül egy-egy 1/4-20-as UNC anya és innentől már fel is lehet tekerni egy szabvány állványcsavarra (vagy akár egy kulcstartóra, amin egy 1/4-20-as apamenet lóg):

GLIF-clone

Csináltam egy párat, mire minden mérettel elégedett lettem:

GLIF-iterations

Mivel az 1/4-20 UNC a kisebbik szabvány fotós állványmenet, így simán passzol a gyári GripTight állványba is:

GLIF_w_GripTight_stand

Korrektül tartja a böszme nagy telefont is:

GLIF-clone-w-GripTight-stand-and-phone

Állvány nélkül is jól funkcionál:

GLIF-clone-w-phone

A GLIF klón még zsugorodhatna, ha az UNC anyacsavar helyett ugyanilyen belső menetű rivet nut-ot, vagy threaded insertet használnék, de ezekből nem volt itthon, így egyelőre marad ekkora.

A GripTight klón

A JOBY még minimalistább cuccot készített. Ahogy említettem, az ő megoldásuknál két nyomórugó fogja össze a két, telefont rögzítő pofát. Mivel itt a talpban van az UNC menet, lehet picit zsugorítani a GLIF-es verzióhoz képest, ezért 40 mm-es M3-as imbuszcsavarokat használtam a szárban levő tengelyeknek, amelyekre nagyjából perfekt módon passzolnak a golyóstollak rugói. A GripTight klón így néz ki belül:

GripTight-clone-schematics

Az eredeti termék összecsukva roppant szexi:

GripTight_original-closed

Kinyitva se buta:

GripTight_original-opened-on-side

GripTight_original

Állványon pedig:

GripTight_original_w_stand

Az állvány szintén összecsukható, a végében egy mini gömbfejjel, amiből az 1/4-20-as UNC menet áll ki:

GripTight_stand

Amire passzol az itthon alig kapható filléres anyacsavar:

GripTight_stand-w-UNC1-4_20

Telefonnal ilyen az egész:

GripTight_w-phone

Ez pedig a rondább klón, mindkét lábában UNC menettel:

GripTight-clone-side-closed

GripTight-clone-side

GripTight-clone

GripTight-clone-opened-on-side

Mindez ennyi iterációból jött össze:

GripTight_iterations

Ez is szépen tartja a böszme telefont, akár állvánnyal, akár anélkül:

GripTight-clone-w-phone

GripTight-clone-w-stand-and-phone

A szokásostól eltérően ezúttal nincs youmagine link a két klónra. Ennek az az egyszerű oka, hogy a két, relatíve megfizethető terméken (=30 USD mindkettő jelenleg) egy csomó ember dolgozott, akiknek az eredetik értékesítése adja többek között a megélhetést.
#3dprint geek lévén lemodelleztem őket saját magamnak, de mások szellemi termékéből nem csinálok szabad prédát, hisz amint feljebb elmagyaráztam, a modellek nem pusztán saját kútfőből születtek.