Pokazywanie postów oznaczonych etykietą dziwne narzędzia. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą dziwne narzędzia. Pokaż wszystkie posty

sobota, października 07, 2023

Kopia zapasowa ważna ;-)

Zawsze i wszędzie piszą by zrobić kopię zapasową przed czymś ryzykownym....

Mam Ci ja sobie Todoista i Obsidiana i je kiedyś pożeniłem przy pomocy Pythona, do tego mam w Alfredzie wtyczkę która dodaje cosie do Todoista...

Mam więc takie coś:


W Alfredzie robię todo, które trafia do Todoist, a później mój skrypt robi mi taska w ToDo w Obsidianie...

Wpadłem na pomysł, że jeszcze fajnie by było dodać zapytanie do OpenAPI i ChatGPT z promptem:

Between triple backtics is item from my todo list it may be in English or Polish, if possible add some details like possible steps, sources and so on. Format text for "description" as markdown, and place it in JSON field "description".
Results should be JSON with original ToDo item as "title" and additional info as "description", if you are not able to do it return empty JSON. ```{item}```

I by zamienić mój flow w:



Nie było to jakieś przesadnie trudne...

Poza jednym małym problemem ;-)

W kodzie mojego skryptu chciałem się zabezpieczyć tak by skrypt nie pytał ChatGPT o rzeczy, które już mają jakieś dokumenty w Obsidian'ie...

Ale mi się źle warunek napisał, więc on pytał o te właśnie które już miały coś ;-)

Więc straciłem wszystkie własne notatki związane z moim ToDo...

Time Machine z macOS nie do końca chciało pomóc bo się ciągle wieszało, ale w końcu wejście na dysk z Time Machine i skopiowanie ręcznie plików pomogło ;-)



Podobne postybeta
Search it later ;-)
Żenienie Todoist z Obsidian przy pomocy Pythona ;-)
Rube Goldberg machine do reminderów ;-)
GPT + Python = sprawdzanie czy 5 książka z Bobiverse już jest dostępna ;-)
Mistral czeka na książkę

środa, września 27, 2023

Promptem w ToDo ;-)

W ramach inżynierii promptowej próbuję dziś użyć Barda i ChatGPT do przeprowadzenia krytyki mojego ToDo ;-)

Na razie prompt wygląda mniej więcej tak:

Poniżej jest lista rzeczy na moim ToDo, Twoim zadaniem jest skrytykować każdy z elementów, Twoja krytyka powinna opierać się na zadawaniu pytań, czy dana rzecz jest rzeczywiście potrzebna, na ocenianiu jasności elementu ToDo, oraz stwierdzać czy może istnieje znane rozwiązanie dla danej rzeczy.

Jeśli istnieją jakieś gotowe rozwiązania takie jak produkt, aplikacja, strona które oferuje daną funkcję podaj do nich linki, lub nazwy modeli.

Oto moje Todo:
<Todo>

Na razie działa to tak sobie, ale po dodanie po odpowiedzi kolejnego zdania: "w przypadkach gdy istnieją aplikacje lub urządzenia które wypełniają cele punktu w ToDo podaj ich nazwy i jeśli możliwe linki do nich."

ChatGPT zaczął nawet podawać jakieś linki, Bard nazwy aplikacji, ale tak bardziej generycznie.

Jeden z ToDo które mam brzmi:

  • jakaś apka na iPhone'a do ćwiczenia Tai-Chi
I odpowiedź z pierwszego prompta z ChatGPT to:
  • Czy sprawdziłeś już dostępne aplikacje, takie jak „Tai Chi for Beginners” czy „Tai Chi Step by Step”?
Z Barda:
  • Czy istnieje już taka aplikacja? Jeśli nie, to może warto ją stworzyć.
  • Aplikacja ta może być przydatna do nauki i ćwiczenia Tai-Chi. Może zawierać instrukcje, filmy i inne materiały pomocnicze.
Dla drugiego.

ChatGPT:
  • Tai Chi for Beginners (iOS)
  • Tai Chi Step by Step (iOS)
Bard:
  • Tai Chi for Beginners - aplikacja na iPhone'a, która zawiera instrukcje i filmy do nauki Tai-Chi.
  • Tai Chi Master - aplikacja na iPhone'a, która zawiera instrukcje, filmy i inne materiały do ćwiczenia Tai-Chi.
Nie jest jeszcze dobrze, ale wygląda to to obiecująco ;-)

Hmmm.... dodałem jeszcze jeden prompt ;-)
Dla każdego elementu z ToDo podaj 2 oceny (w skali od 1 do 7 gdzie 1 to najgorsza, a 7 najlepsza), pierwsza ocena dla sensowności/potrzeby, druga dla jasności celu

I tutaj nie ma zgody między Bardem i ChatGPT ;-)
ChatGPT uznał, że szukanie apki do Tai-Chi to 5/5, a Bard że 7/7.

Bard pokazał też wyniki w ślicznej tabelce :-)

Oba podały też słowne uzasadnienie dla swoich ocen.

Ale ogólnie się zgadzają, że np. taki cel na moim ToDo: "Coś do przeliczania Coli na kawy ;-)" to coś co nie jest zbyt sensowne (2 wg ChatGPT i 3 wg Barda bo uznał, że to może być zabawne), ale mają inne zdanie co do jasności celu (2 wg ChatGPT "Niejasne jest, do czego dokładnie ma służyć taki kalkulator." i 7 dla Barda.

Mam dostęp do API ChatGPT i właśnie mi świta pomysł na wtyczkę do Obsidiana... ale nie mam zbyt jasnych wymagań.


Podobne postybeta
Be human for engineers: Instrukcja obsługi człowieka - marzy mi się coś takiego ;-)
Szybszy = lepszy?
Bard vs ChatGPT ;-)
Zaskakujący killer feature....
Przygotowywanie jajecznicy jako analogia procesu produkcji oprogramowania ;-)

czwartek, listopada 24, 2022

Rube Goldberg machine do panowania nad spotkaniami... częściowego chociaż ;-)

Mam naturę tinkera ;-) lubię coś budować, mam straszną słabość w filmach do wszystkich rzeczy, które bohaterowie budują z innych rzeczy (w całym Interstellar moją ulubioną sceną jest ta gdy ścigają drona, kocham Marsjanina i to jako film i książkę, to samo z Project Hail Mary (OK, tu na razie jako książkę ;-)).
W życiu jakoś tego zwykle nie stosuję bo jakoś nie mam daru do fizycznych projektów, ale mnie to pociąga ;-)

W komputerach to jest prostsze i trudniejsze zarazem, ale czasem uda mi się zbudować potwora ;p

W pracy nienawidzę spotkań przed 11:00, zwykle staram się zaczynać koło 10:00 albo 9:30 i głupio tak zaczynając się zorientować, że "O, spotkanie było o 9:00", a oczywiście ludzie mają często dziwne pomysły i np. o 20:00 tworzą spotkanie na następny dzień na 9 ;-)

Stąd od jakiegoś czasu już próbowałem ten problem pokonać jakimś automatem, ale nie działał tak jak chciałem ;-)
Stąd dziś "stworzyłem" tego potwora:

Mamy tu Shortcut który jest o 21:00 każdego dnia odpalany przez cron'a ;-)
Sam shortcut pobiera pierwszy event z mojego pracowego kalendarza (który sobie z Outlooka firmowego eksportuję ;-)).
Następnie liczy ile jest minut od teraz do początku spotkania.
Przekazuje to do skryptu w Pythonie, który liczy czy będzie to przed 11:00 (OK, jak to będzie piątek 21:00 i w poniedziałek o 9:00 będzie spotkanie to też zadziała, ale spoko z tym ;-)).
Jeśli spotkanie jest przed 11:00 to skrypt wypisze na wyjście info o tym kiedy będzie spotkanie...
Jeśli output nie jest pusty to pojawi się notyfikacja i doda reminder z alarmem na 21:10...
To spowoduje wyświetlenie alertu na komputerze ;-)

Teraz próbuję sprawić by się też ten alert pojawił na Apple Watchu ;p



Podobne postybeta
Potok świadomości - Machine Learning może tagować posty ;-), iPhone ssie, fajne książki, spać.....
Rube Goldberg machine do reminderów ;-)
Jak ogarnąć ładowanie kilku iPadów i Macbooków, tak by nie były non-stop na ładowarce, ale by zawsze w nich było na tyle prądu by się ich choć trochę dało poużywać? ;-)
Lipcowe książki :-)
Alert RCB - minimalizacja false negative prowadzi do zwiększenia false positive ;-)

wtorek, sierpnia 02, 2022

Żenienie Todoist z Obsidian przy pomocy Pythona ;-)

Zawsze brakowało mi połączenia ToDo z miejscem gdzie mógłbym mieć notatki i żeby to było jeszcze przeszukiwalne ;-)

No JIRA tak prawie działa, ale przecież nie będę trzymał JIRAy na swoim komputerze, a do tego ile by mnie to w ogóle kosztowało.

Stąd spróbowałem pożenić prostym skryptem w Pythonie Todoista z Obsidianem :-)

Działa to tak, że jak uruchamia się skrypt to pobiera moje aktualne taski z Todoista, i jeśli są w odpowiednim projekcie to tworzy w odpowiednim katalogu Obsidiana pliki z danym taskiem, do tego dodaje do Obsidiana dokument ToDo z listą rzeczy do zrobienia.

Na razie używałem tego dziś i wydaje się pomagać :-)

Skrypt wygląda tak:

import urllib
import urllib.request
import json
import os.path

projectFilter = <ID PROJECT WORK>

token = "<TOKEN FOR TODOIST API>"

headers = {"Authorization":"Bearer "+token}

url = "https://api.todoist.com/rest/v1/tasks"

req = urllib.request.Request(url, headers=headers)
response = urllib.request.urlopen(req)
jsonResponse = response.read()

tasks = json.loads(jsonResponse)

# print(json.dumps(tasks, indent=4, sort_keys=True))

pathToObsidian="<Obsidian Vault Location>"
path=pathToObsidian+"<Subfolder to keep tasks>"

content="# ToDo #\n-----\n"
for task in tasks:
projectId=task["project_id"]
if projectId!=projectFilter:
continue
title=task["content"]
# OK, for me it works in this way that when I'm adding stuff to Todoist using Python and Alfred my work tasks have [Work] in front, so I want to remove it
fName=title.replace("[Work]","").replace("/"," or ").strip()
desc=task["description"]
url=task["url"]
print(title)
print(json.dumps(task, indent=4, sort_keys=True))
try:
fName=path+"/"+fName+".md"
titleStr=title.replace("[Work]","").strip()
content=content+"* [["+titleStr+"]]\n"
if os.path.exists(fName):
continue
outF=open(fName,"w+")
outF.write("# "+titleStr+" #\n"+desc+"\n[In Todoist]("+url+")")
outF.close()
print("Success with "+title)
except:
print("Problem.....")
print("Problem with "+title)
outF=open(pathToObsidian+"/ToDo.md","w+")
outF.write(content)
outF.close()

Teraz wystarczy to dodać np. do crontaba i uruchamiać co np. 15 minut i mamy magię ;p
Brakuje tutaj dużo, np. zamiast używać nazwy pliku lepiej by było używać ID taska i tak dalej, ale to popełniłem wczoraj koło 2 w nocy ;p
A używałem dziś "w pracy" i działa ;-)


Podobne postybeta
Mistral czeka na książkę
Rube Goldberg machine do reminderów ;-)
Kiedy skończyć pracę...
Jak nie zapomnieć kupić biletu miesięcznego - revised ;-)
Jak nie zapomnieć kupić biletu miesięcznego ;-)

sobota, lutego 20, 2021

Hacky tool ;-) - workflow do Alfreda, który pozwala wykonywać różne konwersje na zawartości schowka ;-)

Ostatnio robiłem coś w pracy i było tak, w jednym miejscu miałem pewną listę (jako tekst ;-)), chciałem się upewnić, że nie ma w niej powtórzeń, a później zmienić ją w linię...

I miałem problem ;-)

Niby wiem, że kawałek z wyrzuceniem elementów z listy to:

  • wrzuć listę do schowka
  • w terminalu wykonaj:
    pbpaste | sort | uniq | pbcopy
  • wklej do edytora
Zapewne da się też jednolinijkowcem zrobić zamianę listy w linię (oddzieloną spacjami)...

Ja postanowiłem pójść inną drogą ;-)

Zrobiłem sobie dziś workflow do Alfreda ;-) który po wpisaniu tx daje mi do wyboru kilka poleceń które jestem w stanie na tym tekście zrobić ;-)


Wszystkie operacje odbywają się na zawartości schowka i do tego jeśli jestem w jakimś edytorze to worklfow będzie próbował wkleić wynik do tego edytora ;-)

Ciągle się zastanawiam czy może macro do Keyboard Maestro by nie było lepsze, ale jeszcze nie wiem, choć pewnie zaraz zrobię ;-)

Sam skrypt, którego używam do konwersji jest napisany strasznie ;-)

Np. do pobrania zawartości schowka używam takiej linii ;-)

text="\n".join(os.popen("pbpaste").readlines()).strip()

czyli Python wykonuje pbpaste i czyta jego wynik ;-)

Gdyby kogoś interesowało to tutaj co robi która opcja ;-)
sort - sortuje zawartość schowka (line by line)
unique - usuwa powtórzone elementy (distinct? ;-)) ale bez sortowania
sort | unique - robi to co dwie poprzednie razem ;-)
list2line - zmienia listę w formie wielu linii w listę rzeczy oddzielonych spacją (pewnie dodam sobie jeszcze wersję z przecinkiem ;-))
line2list - odwrotne do list2line ;-) bierze listę oddzielonych spacją cosiów i zmienia w listę w liniach
add * in front - dodaje * na początku każdej z linii ;-)
remove after first space - usuwa wszystko co jest za pierwszą spacją (nie licząc spacji wiodących, które są i tak usuwane)
wrap with " - owija każdą linie w "" :-)
pretty json - zmienia "compacted" JSONa w takiego lepiej sformatowanego ;-)

Jakby ktoś chciał przygarnąć to tutaj można ;-)




Podobne postybeta
Nie wierze w polyglot developer, ale... ;-)
AI kradnie może (na razie?) nie pracę, ale „wieczorną zabawę w kodowanie” już tak ;-)
Jak walczyć z gigantycznym kodem w Java'ie, część 1 ;-)
OOo2GD (OpenOffice.org2GoogleDocs) 1.2.2
OOo2GD 2.1.2 i malutka poprawka :-)

niedziela, czerwca 07, 2020

Workflow dla Alfreda do dodawania tasków z projektami i labelkami do Todoista :-)

Pogoda nie chce współpracować ;-) więc postanowiłem wrzucić na GitHub'a mój workflow dla Alfreda, który pozwala na dodawanie tasków do Todoist wraz ze skierowaniem takiego taska do odpowiedniego projektu i dodaniem doń wskazanych labelek ;-)


Kod skryptów w Pythonie jest dostępny w katalogu src, nie jest to jakiś piękny Python, ale mnie wystarcza :-)

Jak ktoś zainteresowany to zapraszam na Githuba ;-)


Podobne postybeta
Alfred + Todoist i wysyłanie tasków do projektu, a nie tylko do Inbox&#39;a ;-)
Rejestracja na szczepionkę
OOo2GD - zabawa w dodawanie folderów
Żenienie Todoist z Obsidian przy pomocy Pythona ;-)
Duże obrazki w Bloggeroidzie

piątek, maja 29, 2020

Alfred + Todoist i wysyłanie tasków do projektu, a nie tylko do Inbox&#39;a ;-)

Od jakiegoś czasu używam Alfreda.

Dostałem sobie już nawet własny "workflow", który dodaje mi taski do Todoista.

No i było nieźle, ale trochę mi z czasem zaczęło brakować możliwości dodawania nie tylko do Inbox'a, ale też do projektów.

Wczoraj więc posiedziałem i mam, działa :-)

Wystarczy w trakcie tworzenia taska wpisać # i pojawia się lista projektów :-) co widać poniżej :-)



Mój workflow to aż 3 akcje ;-)


Pierwsza reaguje na słowo kluczowe todo i składa się z 2 skryptów w Pythoni'e ;-) pierwszy to Script Filter, którego zadaniem jest reagowanie na to co użytkownik pisze, i jak w tekście pojawi się # to skrypt ma zaproponować znane projekty :-) [oczywiście z filtrowaniem]
Gdy user już wszystko napisze i naciśnie Enter to (poza selekcją w autocomplete ;-))wynik jest wysyłany do drugiego skryptu w Pythonie, który wysyła item do Todoista i w razie w treści jest #<nazwaProjektu> to dodaje wpis do tego projektu, jeśli nie znajdzie takiego projektu to dodaje do Inboxa.

Druga reaguje na słowo todosync, i po prostu odpala skrypt który pobiera listę projektów z Todoista (ten Script Filter to też zrobi jeśli zauważy, że nie ma na dysku pliku z projektami ;-)).

Trzecia reaguje na słowo todotoken po którym powinien wystąpić ciąg znaków będący tokenem pozwalającym na korzystanie z API Todoista.
Jeśli poprzednie skrypty nie znają tokena to zamiast pomagać i robić to co jest ich zadaniem, poproszą o użycie todotoken ;-)

Sam Alfred nie wspiera jakoś szczególnie (a przynajmniej ja jeszcze nie umiem) reużywania kodu, więc w moich skryptach jest dość dużo powtórzeń ;-)

Jakby ktoś był zainteresowany to tutaj można sobie pobrać mój workflow :-) [ikonkę ukradłem stąd https://github.com/rbnh/todoist-alfred-workflow, zresztą jest tu mój pull request sprzed jakichś 2 tygodni, ale nikt tego projektu nie utrzymuje od paru lat więc raczej nie zostanie zmergowany ;-)]




Podobne postybeta
Workflow dla Alfreda do dodawania tasków z projektami i labelkami do Todoista :-)
Żenienie Todoist z Obsidian przy pomocy Pythona ;-)
Hacky tool ;-) - workflow do Alfreda, który pozwala wykonywać różne konwersje na zawartości schowka ;-)
Rube Goldberg machine do reminderów ;-)
Kopia zapasowa ważna ;-)

sobota, kwietnia 06, 2019

Electron + Airly = wskaźnik jakości powietrza w pasku ;-) - part 2, źródła ;-)

Jakiś czas temu pisałem o tym, że zrobiłem sobie narzędzie, które pokazuje mi aktualny indeks jakości powietrza (od Airly) w pasku :-)
Wygląda to tak:




Ale dziś udało mi się już zapewnić bym mógł je pakować do DMG i by działało tak jak chcę ;-)
Wrzuciłem też na GitHuba :-)

Testowałem jak na razie tylko na macOS, jeden kawałek może nie działać na innych systemach, ukrywanie w Doca, bo to jest podobno tylko w macOS.

Przy pierwszym uruchomieniu aplikacja stwierdza, że nie ma lokalizacji (długości i szerokości geograficznej), dlatego otworzy przeglądarkę pod adresem https://rmk-hrd.appspot.com/file/geoHelper.html, która to strona poprosi o zgodę na pobranie geolokalizacji, jeśli ją otrzyma to przekieruje do lokalnego serwera, który otwiera apka tak by sobie przekazać Twoją lokalizację.
Serwerek stoi na porcie 8000 i jest uruchamiany tylko gdy potrzeba pobrać dane o lokalizacji, czyli przy pierwszym uruchomieniu i jeśli user wybierze "Update location data".

Jeśli ktoś to chce uruchomić to będzie potrzebować też apikey od Airly, który można dostać tutaj https://developer.airly.eu/.
Niestety klucz starcza tylko na 1000 requestów dziennie :( więc nie dzielę się nawet apką w postaci zdolnej do instalacji bo nie chcę by ktoś używał mojego apikey ;-)

Po pobraniu repa, trzeba zainstalować sobie Electrona, co robimy wywołując komendę (w katalogu gdzie jest klon repo):

npm install --save-dev electron

póżniej:

npm start

i aplikacja powinna działać :-)

Jeśli chcemy spakować ją do postaci wykonywalnej to:

electron-packager . --overwrite --platform=darwin --arch=x64 --prune=true --out=release-builds --icon=air.icns

I jeśli chcemy zrobić z tego DMG dla macOS to:

electron-installer-dmg --overwrite ./release-builds/AirQualityInfo-darwin-x64/AirQualityInfo.app/ AirQualityInfo

Oczywiście trzeba w razie potrzeby zainstalować electron-packager i electron-installer-dmg, to pierwsze robimy przez:

npm install electron-packager -g

To drugie przez:

npm i electron-installer-dmg -g


Podobne postybeta
Electron + Airly = wskaźnik jakości powietrza w pasku ;-)
Airly + Python + Oczyszczacz Powietrza = lepsze oddychanie ;-)
Kiedy następny on-call?
Symlink zamiast zmiany nazwy usera ;-)
Moja własna akcja w Google Home ;-)

wtorek, lutego 27, 2018

Dodawanie i usuwanie metod i pól z klas Java w locie ;-)

Praca z Javą jest zwykle dość fajna i ciekawa, ale czasem bywa dziwnie.

Jak masz fajne środowisko gdzie można mieć uruchomioną aplikację i zmieniać ją w locie to wszystko jest wygodne, ale raz na jakiś czas jest amba bo dodaje się lub kasuje metodę czy pole w klasie i przeładowanie klasy nie działa....

No i trzeba restartować aplikację...

Chociaż okazuje się, że nie zawsze ;-)
Tak koło 2010 roku ktoś wpadł na pomysł by może spróbować zmienić JVM tak by można było jednak przeładowywać klasy w locie ;-) wpadł na pomysł i stworzył DCEVM, czyli Dynamic Code Evolution VM.

DCEVM to nic innego jak zestaw patchy na JVM z OpenJDK.

Patche te po pierwsze ustawiają JVM w taki sposób by zawsze używała tego samego GC, a następnie zmieniają kod tego GC tak by w trakcie uruchamiania sprawdzał czy aby nie ma nowszej definicji klas, a jeśli są to by probował przepisać instancje tak by korzystały z nowego kodu...
Do tego w momencie gdy IDE przesyła do JVM nową wersję klasy to DCEVM zaznacza sobie, że ma tą nową wersję i wywołuje GC ;-)...

No i teraz jest tak, że developując "przeciwko" DCEVMowej JVM można swobodnie dodawać i odejmować metody i pola w klasach :-)

W najgorszym przypadku, gdy to GC połączone ze zmianą definicji klasy wykona się w trakcie wykonywania metody, która woła metodę którą skasowaliśmy właśnie w updacie tej klasy to poleci nam MethodNotFoundException ;-)

Do tego DCEVMa można zainstalować jako alternatywną JVM i mówić tylko IDE by uruchamiało debugowaną apkę w DCEVM... co robimy używając opcji dla JVM +XXaltjvm=dcevm :-)

Czemu o tym piszę? Bo lekko grzebię w DCEVMie ostatnio ;-) [firmowo :-)]
Fakt, moje grzebanie to na razie zaaplikowanie poprawek kolegi, kompilacja i wrzucenie wersji pre-release ;-)
Na moim GitHubie zrobiłem też wersję dla najnowszej Java'y 8 (Jdk8u161/162) :-)
Ale projekt mi się wydaje bardzo ciekawy, stąd się dzielę :-)


Podobne postybeta
Jak wykryć, że ktoś nam zmienia klasy w JVM?
Jak masz doła to nawet rozwiązanie problemu niezbyt cieszy ;-)
Defragmentacja SSD - o tym dlaczego nie należy jej robić
Windows 8 po kilku dniach
Moto 360 i Lollipop na Nexusach

czwartek, października 19, 2017

Jak zrobić plik OVPN (dla OpenVPN) w wersji unified format?

Dziś próbowałem przerzucić pliki konfiguracyjne mojego VPNa na iPada Pro...

Przez iTunes się nie udało i naprawdę cieszę się, że nie używam tego softu.
To postanowiłem przez HTTP.

Ale co pobrało plik ovpn to płakało, że nie może pobrać ani certyfikatu dla centrum autentykacji, ani klucza klienta, ani samego certyfikatu.

Myślałem, że to przez to, że serwuję to po HTTP.
Więc zacząłem walczyć z konfigurowaniem HTTPS.

Zrobiłem na Tomcacie, ale nadal nie działało.
Przy okazji przewalczyłem tworzenie nowego certyfikatu i parę innych rzeczy.

Firewall mi blokował połączenia. Przewalczyłem. Dodałem wyjątek i nic, nadal.....

Wtedy do mnie dotarło, że drań by chciał wszystko w jednym pliku, a nie w kilku ;-)

Ja miałem certyfikat dla centrum autnentykacji w pliku ca.crt, certyfikat klienta w client1.crt i klucz klienta w client1.key.... no i sam plik ovpn...

Stąd jakby ktoś chciał to tutaj skrypt, który wyprodukuje plik ovpn na podstawie takiego rozbitego:

import sys

def load(fName):
return "".join(open(fName).readlines())

lines = open(sys.argv[1]).readlines()

f=open("unified_"+sys.argv[1],"w+")

keys = ["ca","cert","key"]

for line in lines:
found=False
    line=line.strip()
    for key in keys:
if line.find(key)==0:
s = line.split(" ")
if len(s)==2 and s[0]==key:
found=True
                f.write("<"+key+">\n")
                f.write(load(s[1]))
f.write("</"+key+">\n")
if not found:
f.write(line+"\n")
f.close()

U mnie działa :-)

Żeby użyć zapisujemy sobie skrypcik jako np. build.py i robimy z linii poleceń:

python build.py naszPlik.ovpn

Jako wynik w tym samym folderze pojawi się plik unified_naszPlik.opvn.

Podobne postybeta
Jak walczyć z gigantycznym kodem w Java'ie, część 1 ;-)
Zabawy z Chrome, chrome.storage.sync jest wielkie :-)
GZIP mi oddał 119 GB dysku ;-)
Od Buffy do egzaminu językowego ;-)
SSD a programowanie

sobota, czerwca 03, 2017

Czy się stoi czy się siedzi... Rasbperry Pi z czujnikami ultradźwiękowymi to stwierdzi ;-)

Chwaliłem się ostatnio, że zrobiłem coś co ma posłużyć jako czujnik SIT/STAND przy moim biurku.

Zamontowałem wszystko i działa ;-)

Schemat połączeń wygląda tak:

Czujnik, który ma sprawdzać czy ktoś jest przy biurku został zamontowany na podstawie monitora, tak by "patrzał" w kierunku w którym powinien być "operator":


Czujnik, który ma ustalać na jakiej wysokości jest biurko został zamontowany na podstawce pod monitor i ślepi w górę:


Na razie wszystko kontroluje prosty programik, który jest przeróbką programu stąd.
Program wygląda tak:

import RPi.GPIO as GPIO                    #Import GPIO library
import time                                #Import time library
GPIO.setmode(GPIO.BCM)                     #Set GPIO pin numbering

# Define outputs & inputs
_TRIG1 = 23 # TRIG for checking if somebody is near desk
_ECHO1 = 24 # ECHO for checking if somebody is near desk

_TRIG2 = 25 # TRIG for sit/stand
_ECHO2 = 18 # ECHO for sit/stand


GPIO.setup([_TRIG1,_TRIG2],GPIO.OUT)                  #Set pins as GPIO out
GPIO.setup([_ECHO1,_ECHO2],GPIO.IN)                   #Set pins as GPIO in

def measure(TRIG1,ECHO1,txt):
      GPIO.output(TRIG1, False)                 #Set TRIG as LOW
      time.sleep(2)                            #Delay of 2 seconds
      GPIO.output(TRIG1, True)                  #Set TRIG as HIGH
      time.sleep(0.00001)                      #Delay of 0.00001 seconds
      GPIO.output(TRIG1, False)                 #Set TRIG as LOW
      while GPIO.input(ECHO1)==0:               #Check whether the ECHO is LOW
        pulse_start = time.time()              #Saves the last known time of LOW pulse
      while GPIO.input(ECHO1)==1:               #Check whether the ECHO is HIGH
        pulse_end = time.time()                #Saves the last known time of HIGH pulse

      pulse_duration = pulse_end - pulse_start #Get pulse duration to a variable
      distance = pulse_duration * 17150        #Multiply pulse duration by 17150 to get distance
      distance = round(distance, 2)            #Round to two decimal points

      GPIO.output(TRIG1,False)
      return distance


while True:
    dist1=measure(_TRIG1,_ECHO1,"Sensor1")
    dist2=measure(_TRIG2,_ECHO2,"Sensor2")
    print dist1,dist2
    if dist2<150:
       print "desk in STAND mode"
    else:
       print "desk in SIT mode"
    if dist1<80:
       print "somebody at the desk"

Jego działanie jest proste jak konstrukcja cepa ;-)
Po prostu instruuje Raspberry Pi by ustawiło na wyjściu (TRIG) 1 przez 10 µs, co powinno spowodować wyemitowanie ultradźwięku przez HC-SR04, po czym ustawiło 0 i czekało aż na wejściu (ECHO) pojawi się sygnał.
Gdy to się zdarzy liczy różnicę czasu między ustawieniem 1 na TRIG, a pojawieniem się 1 na ECHO.

W tym czasie dźwięk wystartuje z czujnika, doleci do celu, odbije się i wróci do czujnika. Pokona więc drogę 2 razy.
Przyjmujemy tutaj, że prędkość dźwięku w powietrzu to 343 m/s.
Stąd:
odległość = 343 m/s * czas / 2

A, że wynik chcemy w centymetrach to zamiast 343 m/s używamy 34300 cm / s, które to 34300 po podzieleniu przez dwa daje 17150.

Dokonujemy za każdym razem pomiaru na 2 czujnikach (w pętli) i jeśli z czujnika 1 dostaniemy odległość mniejszą niż 80 to zakładamy, że ktoś jest przy biurku. Gdy z czujnika 1 dostajemy informację, że do sufitu jest mniej niż 150 cm to stwierdzamy, że biurko jest w trybie stand :-)





Podobne postybeta
Roboty są trudne ;-)
Debugowanie sprzętu jest trudne....
~ - czyli "tak sobie"
Czy się stoi czy się siedzi.... kamerka w laptopie jako detektor tego czy biurko jest w trybie stand czy sit ;-)
Matematyczne podstawy zakupu skarpetek ;-)

sobota, maja 06, 2017

Moja własna akcja w Google Home ;-)

Nad Airly się już tu rozpływałem, wczoraj w nocy zaś połączyłem je z Google Assistant w Google Home ;-)

Działa tak:


Całość opiera się na połączeniu API.AI z servletem w Google App Engine, który to servlet gada z API Airly.

Mówię "OK, Google. Air Index" i słyszę jakie jest CAQI (czyli Common Air Quality Index) wg. Airly.

Wszystko jest proste jak konstrukcja cepa bo podaje wynik dokładnie dla mojej okolicy ;-), do tego działa tylko na moim Google Home, albo w web symulatorze. Na Pixelu w Google Assistant nie działa ;-)

Ale fajne jest :-)
Nie muszę sięgać po telefon by spytać o jakość powietrza ;-)

Jakby ktoś się zabierał za zrobienie jakiejś akcji dla Google Assitant w ważne tylko by pamiętać, że w razie chcemy użyć Webhooka to format odpowiedzi webhooka jest prosty jak konstrukcja cepa :-)
W moim przypadku odpowiedź to:
{
    "speech": "air index is 54",
    "displayText": "air index is 54"
}

Trzeba też pamiętać by Content-Type był ustawiony na application/json.
Webhook MUSI być hostowany przez HTTPS, stąd GAE dobrze się nadaje.

Podobne postybeta
Google Actions działają już w Google Assitant nie tylko na Google Home, ale i w innych jego inkarnacjach :-)
No i mam skilla dla Alexy ;-) [wcześniej już miałem akcję dla Google Home :-)]
Electron + Airly = wskaźnik jakości powietrza w pasku ;-)
GeoJSON jest fajny ;-)
GAE zmienia ceny i darmową quota'ę... a ja zmieniam kod ;-)

niedziela, kwietnia 23, 2017

Airly + Python + Oczyszczacz Powietrza = lepsze oddychanie ;-)

W Krakowie powstaje genialny produkt zwany Airly, który pokazuje w real time poziom zanieczyszczenia powietrza.
Ostatnio szerzej otworzyli swoje API. Co mnie ucieszyło, bo chociaż mają genialną apkę na Androida to chciałem mieć możliwość napisania sobie skryptu, który w momencie osiągnięcia odpowiednio wysokiego poziomu zanieczyszczenia wysyłał by mi maila z sugestią włączenia oczyszczacza powietrza (najlepiej jakby go sam włączał, ale to jednak takie proste nie jest ;-)).

Chciałem, to mam ;-)

import urllib2
import json
import os
import string
import sendmail

ALERT_LEVEL = 40
MAIL_TO = "<MAIL>"
apikey = "<APIKEY from https://apiportal.airly.eu/>"
url = "https://airapi.airly.eu/v1/mapPoint/measurements?latitude=<yourLatitude>&longitude=<yourLongitude>"
prevCaqi = 0
if os.path.exists("prevCaqi.txt"):
prevCaqi = float("".join(open("prevCaqi.txt").readlines()))

req = urllib2.Request(url)
req.add_header('apikey', apikey)
resp = urllib2.urlopen(req)
content = resp.read()

data=json.loads(content)

caqi = float(data["currentMeasurements"]["airQualityIndex"])

open("prevCaqi.txt","w+").write(str(caqi))

if prevCaqi<ALERT_LEVEL and caqi>=ALERT_LEVEL:
content = string.Template("""Current CAQI: $airQualityIndex
pm25: $pm25
pm10: $pm10
pollution level: $pollutionLevel
pressure: $pressure
humidity: $humidity
temperature: $temperature""").safe_substitute(data["currentMeasurements"])
sendmail.sendEMail(MAIL_TO,"Turn on AirCleaner",content)


Żeby działał ten skrypt trzeba mieć swój klucz do API, który idzie pod apikey. Trzeba ustawić też maila w MAIL_TO i długość i szerokość geograficzną (które można sobie odczytać np. używając mojego toola do wyliczania czasu wschodu i zachodu słońca ;-)).
Jeszcze trzeba mieć moduł sendmail, który można znaleźć w moim wpisie o tym jak nie zapomnieć o kupnie biletu miesięcznego ;-)


Podobne postybeta
Raspberry Pi + no-ip.org ;-)
Jak nie zapomnieć kupić biletu miesięcznego - revised ;-)
Electron + Airly = wskaźnik jakości powietrza w pasku ;-) - part 2, źródła ;-)
Jak nie zapomnieć kupić biletu miesięcznego ;-)
Electron + Airly = wskaźnik jakości powietrza w pasku ;-)

środa, lipca 20, 2016

Jak nie zapomnieć kupić biletu miesięcznego - revised ;-)

Jakiś czas temu opisałem tu skrypt, który "lata" na jednej z moich Malinek i sprawdza czy aby nie zbliża się termin końca ważności mojego biletu miesięcznego.

Niestety kilka dni temu dostałem maila od skryptu, w którym skarżył mi się, że nie może znaleźć informacji o dacie i że podejrzewa, że spowodowane to jest zmianą struktury strony....

Miał rację.

MPK zmieniło stronę i zmieniły się adresy...

Od teraz by sprawdzić datę ważności biletu trzeba pójść pod adres:
http://www.mpk.krakow.pl/pl/sprawdz-waznosc-biletu/index,1.html?cityCardType=0&identityNumber=<id>&cityCardNumber=<cityCardNumber>

Dodatkowo normalny request z Pythona skończy się 403 Forbidden...
Chwila zabawy wyjaśniła, że pluje się z powodu nagłówków (podejrzewam, że chodzi o User-Agent).
Wystarczy jednak dodać kilka nagłówków i wszystko działa tak jak należy :-)

Skrypt teraz wygląda tak:

#!/usr/bin/python
import urllib2
import sendmail
import datetime
import os

id = "<numer legitymacji KMK>"
cityCardNumber = "<nr seryjny karty>"
cityCardType = "0"
SEND_TO="<mail na ktory ma przyjsc informacja>"
limits = [31,21,14,7,1]

def getUrl(id, cityCardType, cityCardNumber):
url = "http://www.mpk.krakow.pl/pl/sprawdz-waznosc-biletu/index,1.html?cityCardType=0&identityNumber="+id+"&cityCardNumber="+cityCardNumber
return url

def getDateFor(id, cityCardType, cityCardNumber):
MARKER = "Data ko"
url = getUrl(id, cityCardType, cityCardNumber)
hdr = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
'Accept-Encoding': 'none',
'Accept-Language': 'en-US,en;q=0.8',
'Connection': 'keep-alive'}
req=urllib2.Request(url,headers=hdr)
lines=urllib2.urlopen(req).readlines()
    str="".join(lines)
date=None
if str.count(MARKER):
idx=str.index(MARKER)+27
substr = str[idx:idx+20]
date = substr[:substr.index("<")]
return date

date = getDateFor(id, cityCardType, cityCardNumber)

if not date:
url = getUrl(id, cityCardType, cityCardNumber)
sendmail.sendEMail(SEND_TO,u"[KMK watchdog] lack of date",u"""Cannot find end of period date on """+url+"""
Page was changed?
Or you don't have KKM?""")
else:
d = datetime.datetime.strptime(date,"%Y-%m-%d")
daysTillDate = (d-datetime.datetime.now()).days
for limit in limits:
if daysTillDate<limit:
fName=date+"_"+str(limit)
if not os.path.exists("kmk_watchodg"):
os.mkdir("kmk_watchodg")
if not os.path.exists("kmk_watchodg/"+fName):
sendmail.sendEMail(SEND_TO,"[KMK watchdog] only "+str(limit)+" days till end of KMK","""Hi,
It seems that you have only """+str(limit)+""" days to end of your KMK card.
Go to http://www.kkm.krakow.pl to buy new ticket, or disable this alarm on Raspberry Pi.""")
f=open("kmk_watchodg/"+fName,"w+")
f.write(str(datetime.datetime.now()))
f.close()

I znów działa :-)
Dzięki czemu codziennie o 8:00 skrypt sprawdza czy aby nie zbliża się data końca ważności mojego biletu miesięcznego ;-)



Podobne postybeta
Jak nie zapomnieć kupić biletu miesięcznego ;-)
Airly + Python + Oczyszczacz Powietrza = lepsze oddychanie ;-)
Jak się dowiedziałem o tym, że w Polsce rusza Google Play Movies ;-)
Polowanie na Nexus 4 - wersja automagiczna ;-)
Żenienie Todoist z Obsidian przy pomocy Pythona ;-)

poniedziałek, czerwca 06, 2016

Jak nie zapomnieć kupić biletu miesięcznego ;-)

Jako jednostka z natury leniwa staram się ograniczać swoje działania do absolutnego minimum.
Stąd bilet miesięczny na tramwaj kupuję 2 razy w roku, od razu na 6 miesięcy*.
Dodatkowo dostaję bonus w postaci jakieś tam zniżki.

Ma to jednak ten minus, że muszę zawsze pamiętać by ustawić sobie w kalendarzu przypominajkę...
A przynajmniej tak musiałem robić do wczoraj ;-)

Bo wczoraj postanowiłem zautomatyzować proces pilnowania kupna biletu.

Na 31, 21, 14, 7 i 1 dzień przed końcem ważności biletu dostanę maila z przypomnieniem (oczywiście jeśli np. po 1 mailu z okazji 31 dni kupię nowy bilet to nie dostanę już kolejnych maili).

Magia, która to robi jest w Pythonie i wygląda tak jak poniżej ;-)

#!/usr/bin/python
import urllib2
import sendmail
import datetime
import os

id = "<numer legitymacji KMK>"
cityCardNumber = "<nr seryjny karty>"
cityCardType = "0"
SEND_TO="<mail na ktory ma przyjsc informacja>"
limits = [31,21,14,7,1]

def getUrl(id, cityCardType, cityCardNumber):
url = "http://www.kkm.krakow.pl/pl/sprawdz-waznosc-biletow-zapisanych-na-karcie/index,1.html?cityCardType="+cityCardType+"&identityNumber="+id+"&cityCardNumber="+cityCardNumber+"&sprawdz_kkm=Sprawd%C5%B$
return url

def getDateFor(id, cityCardType, cityCardNumber):
MARKER = "Data ko"
url = getUrl(id, cityCardType, cityCardNumber)
lines=urllib2.urlopen(url).readlines()
str="".join(lines)
date=None
if str.count(MARKER):
idx=str.index(MARKER)+27
substr = str[idx:idx+20]
date = substr[:substr.index("<")]
return date

date = getDateFor(id, cityCardType, cityCardNumber)

if not date:
url = getUrl(id, cityCardType, cityCardNumber)
sendmail.sendEMail(SEND_TO,u"[KMK watchdog] lack of date",u"""Cannot find end of period date on """+url+"""
Page was changed?
Or you don't have KKM?""")
else:
d = datetime.datetime.strptime(date,"%Y-%m-%d")
daysTillDate = (d-datetime.datetime.now()).days
for limit in limits:
if daysTillDate<limit:
fName=date+"_"+str(limit)
if not os.path.exists("kmk_watchodg"):
os.mkdir("kmk_watchodg")
if not os.path.exists("kmk_watchodg/"+fName):
sendmail.sendEMail(SEND_TO,"[KMK watchdog] only "+str(limit)+" days till end of KMK","""Hi,
It seems that you have only """+str(limit)+""" days to end of your KMK card.
Go to http://www.kkm.krakow.pl to buy new ticket, or disable this alarm on Raspberry Pi.""")
f=open("kmk_watchodg/"+fName,"w+")
f.write(str(datetime.datetime.now()))
f.close()


Skrypt dodany jest do crontaba na jednym z moich Raspberry Pi i uruchamia się raz dziennie.

Można spytać czemu skrypt pisze do mnie po angielsku...
Odpowiadam - bo polskie literki w Pythonie mnie przerastają ;-)

Skrypt może się też posypać jeśli zmieni się struktura strony... wtedy trudno, ale dostanę maila z informacją o tym ;-)

Cały "mechanizm" nie otrzymywania maili ponownie opiera się na plikach ;-) po prostu po wysłaniu maila dla danej daty i limitu skrypt tworzy plik który mu w razie czego powie, że mail już został wysłany (niby skrypt jest odpalany raz dziennie, ale mógłby być odpalany częściej, a i tak by działał).

Wysyłanie maili wykonuje ten kawałek (sendmail.py):

import urllib2
import smtplib
import sys
from datetime import datetime

FROM = "<adres z ktorego wysyłamy>"
PWD = "<haslo do konta>"
# jesli hasło i user są z GMAILa to trzeba osłabić jego bezpieczeństwo, dlatego ja mam oddzielne konto do wysyłania takich maili.

def _sendEMail(usr, psw, fromaddr, toaddr, subject, content):
runtime=datetime.now()
server=smtplib.SMTP('smtp.gmail.com:587')
server.starttls()
server.login(usr,psw)
senddate=datetime.strftime(datetime.now(), '%Y-%m-%d')
m="Date: %s\r\nFrom: %s\r\nTo: %s\r\nSubject: %s\r\nX-Mailer: My-Mail\r\n\r\n" % (senddate, fromaddr, toaddr, subject)
msg=content
server.sendmail(fromaddr, toaddr, m+msg)
server.quit()

def sendEMail(toaddr, subject, content):
_sendEMail(FROM,PWD,FROM,toaddr,subject,content)


Tu warto dodać, że konto, którego używam do wysyłania maili jest całkiem niezależne od moich kont, specjalnie w Google Apps for Domain stworzyłem 1 konto do takich działań.

Tak oto lenistwo prowadzi do pracy i tworzenia skryptów by można było nadal być leniwym ;-)



* - można by spytać czemu na 6 miesięcy, a nie na 12, odpowiedzią jest to, że nie do końca wiem co będzie za rok, pewnie będzie tak samo jak teraz, ale jednak nie mam tej pewności i może np. przeprowadzę się do innego miasta? Wtedy mogłoby się okazać, że przez pół roku albo i dłużej bym nie korzystał, a i tak bym zapłacił. Przy 6 miesiącach ryzyko jest mniejsze.


Podobne postybeta
Jak nie zapomnieć kupić biletu miesięcznego - revised ;-)
Jak się dowiedziałem o tym, że w Polsce rusza Google Play Movies ;-)
Polowanie na Nexus 4 - wersja automagiczna ;-)
Airly + Python + Oczyszczacz Powietrza = lepsze oddychanie ;-)
Kiedy skończyć pracę...

wtorek, grudnia 22, 2015

Jak walczyć z gigantycznym kodem w Java'ie, część 1 ;-)

Bawiąc się kilkoma milionami linii kodu, które mamy w repo stwierdzam, że nic nie pobije grep'a w poszukiwaniu kodu po różnych projektach ;-)
Najpierw miałem skrypt, który leciał po liście projektów w repo, robił dla każdego z nich checkout,
później go buildował używając Mavena, a w końcu analizował przy pomocy javap.
Skrypt, który to robi wygląda tak:

import os

f = file("java_poms.txt")
lines = f.readlines()

out = open("decompiled.txt","w+")

def removeDir():
os.popen("rm -rf asources")

def choeckout(repo):
os.popen("hg clone "+repo+" asources")
print("Checkouted "+repo)

def make(repo):
os.chdir("asources")
os.popen("mvn clean compile -DskipTests=true")
res = os.path.isdir("target")
os.chdir("..")
print("Made "+repo)
return res

def analyze(repo):
f = os.popen("""javap -c $(find asources/target/classes/. | grep ".class$")""")
lines = f.readlines()
out.write("REPO:"+repo+"\n")
for line in lines:
out.write(line)
out.flush()
print("Analyzed "+repo)


for line in lines:
line = line.strip()
print(line)
choeckout(line)
buildSomething = make(line)
print buildSomething
if buildSomething:
analyze(line)
removeDir()

out.close()


Po paru godzinach biegania na jednym z serwerów zrobił mi gigantyczny plik, w którym mam zdekomplikowany do "assemblera" JVM kod naszych wszystkich aplikacji ;-)

Do tego mam jeszcze inne skrypty w Pythonie, które lecą po zdekompilowanym kodzie i np. budują mapę wszystkich miejsc gdzie są tworzone i wszystkich miejsc gdzie są używane message JMS, które dziedziczą po odpowiedniej klasie ;-)
W końcu jak szukam repo w którym jest dana klasa, to na razie po prostu szukam w tym wielkim pliku tekstowym nazwy klasy i sprawdzam jakie to repo ;-) [po to jest linia REPO: ;-)]

Sam plik java_poms.txt powstał przez puszczenie na serwerze gdzie jest zainstalowany Mercurial komendy:

find repos/ | grep ".hg" | grep "pom.xml"

i późniejszym wyrzuceniu nadmiarowych informacji.

W kolejnym odcinku, krótka opowieść o tym jak śledzić zależności między kilkuset repozytoriami ;-)


Podobne postybeta
Odzyskać trochę miejsca na dysku... w macOS ;-)
Jak zrobić plik OVPN (dla OpenVPN) w wersji unified format?
SSD a programowanie
Jak walczyć z gigantycznym kodem w Java'ie, część 1.6 - podłe metody prywatne ;-)
Hacky tool ;-) - workflow do Alfreda, który pozwala wykonywać różne konwersje na zawartości schowka ;-)

niedziela, września 27, 2015

PocketTags 0.0.5 - to działa :-)

Przeniosłem dziś wszelkie działania sieciowe do WebWorkera, dzięki czemu GUI rozszerzenia nie cierpi na czkawkę spowodowaną "kradzieżą" wątku przez operacje sieciowe ;-)


Na zrzucie widać listę reguł, które są stosowane by dodawać automagicznie tagi do postów które mam w Pocket.

To pomaga :-)

Choć nadal mam wyższą prędkość dodawania artykułów niż czytania.

Rozszerzenie jest w końcu używalne, stąd można je już swobodnie pobierać i znajdować w Chrome Web Store.

PocketTags w Chrome Web Store.

Cały kod jest dostępny w GitHub'ie - kod PocketTags w GitHub'ie.


Podobne postybeta
Dodawaj automagicznie tagi do swoich postów w Pocket :-)
EEE Pad Transformer nadal ma czkawkę...
TimeToRead w działaniu
TimeToRead 0.0.2 - nowy tag i poprawki ;-)
OAuth pokonany, wersja 0.0.1 TimeToRead gotowa ;-)

poniedziałek, września 21, 2015

Dodawaj automagicznie tagi do swoich postów w Pocket :-)

Będąc na emigracji nadganiałem trochę z Pocket'em i zapragnąłem posiąść narzędzie, które automagicznie będzie mi na podstawie pewnych reguł dodawać tagi do postów w Pocket.

I oto jest wersja przedpremierowa ;-)


Mamy tutaj zestaw reguł, które opisują warunki w których zostanie dodany dany tag.
Są 2 rodzaje reguł - linkowe i tytułowe.

Linkowe to takie, które dodadzą taga gdy w adresie do oryginalnego artykułu występują zadane słowa.
Tytułowe to takie, które dodadzą tag gdy w tytule postu występują zadane słowa (i nie występują inne zadane).

Wbrew pozorom jest to dość dobre narzędzie, które pozwala na szybkie rozbicie artykułów na wiele podgrup.

Ciekawe jest np. to, że filtrowanie artykułów z "can" i "you" w tytule prawie zawsze opisuje artykuły, które można by opatrzyć tagiem "self improve" ;-)

Zestaw reguł jest trzymany w chmurze Chrome'a, stąd wszystkie miejsca gdzie używać będziemy rozszerzenia przy tym samym koncie będą miały ten sam zestaw reguł.

Wtyczka jest w pierwszej wersji, stąd cierpi na pewne choroby wieku dziecięcego ;-) np. wszystko odbywa się w 1 wątku (to JavaScript w końcu) i gdy wtyczka odwala roboty sieciowe to GUI nie działa ;-) [docelowo chcę to poprawić przepisując roboty sieciowe na webworkera]

Zapraszam do pobieranie PocketTags z Chrome Web Store. (w ciągu jakiejś godziny powinna być dostępna wersja 0.0.4.
Wersja dla ciekawskich: PocketTags w GitHub'ie ;-)


Podobne postybeta
PocketTags 0.0.5 - to działa :-)
Automagiczne dodawanie tagów do Pocket :-)
Python z urllib = najlepszy menadżer pobierania ;-)
TimeToRead 0.0.2 - nowy tag i poprawki ;-)
OAuth pokonany, wersja 0.0.1 TimeToRead gotowa ;-)

poniedziałek, sierpnia 24, 2015

Automagiczne dodawanie tagów do Pocket :-)

Pracuję nad nową wtyczką do Chrome, która doda do Pocket możliwość tworzenia reguł dla tagów.


Zrobienie pierwszej wersji zajęło mi jakieś 20-30 minut.
Wziąłem TimeToRead i zmieniłem kod generujący tagi.

Później zmieniłem serię if'ów w zestaw zahardcodowanych reguł.
Pierwsze 2 reguły to taka, która na podstawie słowa lifehack w urlu dodawała tag "lifehack" i druga, która w razie zobaczenia słów "you" i "how" albo "you","can" dodawała tag "self improve".
Od wtedy doszło jeszcze parę, ale jak na razie wszystkie są 1 lub 2 słowne.

Działa to zadziwiająco sprawnie.

Problemem jest tylko stworzenie UI, które pozwoli dodawać/zmieniać/kasować reguły.
Problemem będzie też znalezienie miejsca na ich trzymanie.
Współdzielony między instancjami przeglądarki obiekt wydaje się być zbyt mały, stąd możliwe, że trzeba będzie plik z regułami trzymać w Google Drive.

UI tworzę od wczoraj w AngularJS. Niby AngularJS pomaga (trzeba przyznać jednak, że nie pisząc w AngularJS od paru jakichś 6 miesięcy nie do końca pamiętam jak to się robi ;-)).

Ktoś zainteresowany testowaniem jak będzie gotowe? ;-)

Podobne postybeta
Dodawaj automagicznie tagi do swoich postów w Pocket :-)
Polymeryzacja AngularJS ;-)
Bayesian Inference Tool jako Chrome App ;-)
Tak Maven'ie, zbłądziłem ;-)
A może by tak Projekt Yes!? ;-)

niedziela, stycznia 25, 2015

Bayesian Inference Tool jako Chrome App ;-)

Przerobiłem moje narzędzie w AngularJS, które pozwala na przeprowadzanie wnioskowania z użyciem twierdzenia Bayesa na aplikację dla Chrome.
Jeśli ktoś chce pobrać to tutaj jest Bayesian Inference Tool.

Do czego można go użyć?

Do stwierdzenia czy ewolucja jest prawdziwa ;-)
Do stwierdzenia czy to jest ta jedna jedyna ;-)
Albo do stwierdzenia czy dziś jest sobota ;-)

Można też testować tak różne inne hipotezy ;-)



Podobne postybeta
Ciekawy artykuł
Polymeryzacja AngularJS ;-)
Czy jest dziś sobota? ;-)
Potrzebny mi radar....
Automagiczne dodawanie tagów do Pocket :-)