Woanders
  • Deviantart
  • Flattr
  • GitHub
  • Google+
  • Twitter
Blogroll
  • bitowl
  • Der Datux
  • linux4ever
  • LinuxDoku
  • Lukzifer
  • Speedyland
Eigenes
  • 1337walls
  • bakerolls.de
  • D2DB
  • Pastebin
  • Subdomains
  • Tweetcast
Kategorien
  • Aktuelles 10
  • Allgemein 36
  • Changelog 32
  • etc. 10
  • Filme 3
  • Linux 14
  • Technik 25
  • Zitate 82
  • Fotos 3
wachtl
  • Posts
  • BakeRolls
  • Categories
  • Tweets via JavaScript nach API 1.1

    Nachdem Twitters erste Version der API gestern abgeschaltet wurde, hier ein schneller Workaround OAuth-Frei via JavaScript an ein paar Daten zu kommen. Demo.

    Man erstellt schnell ein Widget das Tweets des Zielnutzers anzeigt und merkt sich die ID (data-widget-id im Code). Nach kurzem Überfliegen finden wir einige angefragte URLs wie Beispielsweise https://cdn.syndication.twimg.com/widgets/timelines/widget-id, unter der die letzten 20 Tweets angezeigt werden (mehr sind möglich, der Aufwand übersteigt aber den Sinn). Was man nun lesen darf ist JSON in seiner hässlichsten Form: Als HTML Wrapper.

    HTML

    Na gut, dann kommt eben ein Schritt dazwischen (Resultierende JS Version).

    widget_id = '1234567890' # should be a string
    tweets    = []
    
    $(document).ready ->
        $.getJSON 'https://cdn.syndication.twimg.com/widgets/timelines/' + widget_id + '?callback=?', (data) ->
            # einen div .tweets erzeugen und temporär füllen
            $('body').append $ '<div/>',
                class: 'tweets'
                html: data.body
    
            # jedes li entspricht einem tweet
            $('.tweets ol.h-feed > li').each (data) ->
                me = $(this)[0]
    
                # screen_-/name ...
                user = /([a-zA-Z0-9_]+) \(screen name: ([a-zA-Z0-9_]+)\)/.exec $(this).find('a.profile').attr 'aria-label'
    
                # tweet-objekt
                tweets.push
                    id_str: $(me).attr 'data-tweet-id'
                    id: parseInt $(me).attr 'data-tweet-id'
                    created: $(me).find('time').attr 'datetime'
                    text: $(this).find('p.e-entry-title').text()
                    user:
                        name: user[1]
                        screen_name: user[2]
    
            # fertig? dann weg damit!
            $('.tweets').html ''
    
            # ... und personalisiert ausgeben
            for tweet in tweets
                console.log tweet
                $('.tweets').append $ '<p/>',
                    html: '@' + tweet.user.name + ': ' + tweet.text + ' (<a href="https://twitter.com/' + tweet.user.screen_name + '/status/' + tweet.id_str + '">' + tweet.created + '</a>)'
    

    Auch schön zu sehen ist users/show.json: /1/users/show.json?screen_name=BakeRolls.

    Mal schauen wie lange das aktiv bleibt ...

    Posted 7 days ago by Fabian. Short: http://w8l.org/290
  • Titanium und SQlite Full Text Search

    In den vergangenen Woche durfte ich eine kleine App basteln die nichts anderes zutun hat, als in einem großen Haufen Daten einen etwas kleineres Haufen Datensätze zu finden. Und zwar auf Android. Nativ sollte es aussehen und schnell sein.

    Einsetzen würde ich Appcelerators Titanium, wobei hier im Grunde von einer JS API und nicht der IDE, die an sich nicht mehr als ein Fork der in Java geschrieben und dementsprechend nicht funktionierenden und unbedienbar scheinenden IDE Aptana wurde, die Rede ist - Eben ganz so, wie man es von Java erwartet. Zum Glück aber lässt sich die Source auch außerhalb - in meinem Fall in Sublime - schreiben und nur der Bau in Titanium triggern.

    Ebenso wenig wie die Entwicklungsumgebung wollte der CLI builder mit mir zusammenarbeiten und die Source kompilieren oder wenigstens einen vernünftigen Fehler anzeigen, wieso er sich dagegen weigert. Letzteres ist mir auch vollkommen unverständlich; Die IDE/Das CLI Tool startet ein Python Script, welches alles weitere regelt. Bei einem Fehler erscheint aber nicht der entsprechende eigene Code (oder einer in der Tiapp.xml ... wie ich dieses Ding hasse), stattdessen wird man von einem netten "Ey, dein Python is' kaputt!" begrüßt. Sollte das bauen aber nach ein wenig blindem debuggen funktioniert haben, erschließt sich einem nun auch die Möglichkeit, mit richtigen Fehlern, Zeilen und Zeichenangaben zu arbeiten - Diese wirft die Debugging Version der APK nämlich recht schön zurück.

    Zurück zum Thema: Nach ein paar Stunden Java-Auffrischung, war ich selbst über Titanium froh, denn es ließ mich in JavaScript schreiben, was die ganze Sache erheblich vereinfacht - Vor allem dann, wenn es sich bei der Source (der Source) um CoffeeScript handelt. So lässt sich relativ einfach eine Objektorientierte, kleine App schreiben, die auf Native UI Elemente bzw. die entsprechende API zurückgreift - Was doch schon sehr cool ist!

    Im Endeffekt sollte es eine kleine, aus drei Views (Suche nach Text in gesonderter Tabelle, Suche nach Text + Eigenschaften, Text + Eigenschaften + gesonderten Text anzeigen) werden. Für jeden View erstellte ich also eine kleine Klasse (Namen wurden verfremdet um beteiligten zu schützen):

    app.js

    var root = {};
    Ti.include('js/Database.js');
    Ti.include('js/TabView.js');
    Ti.include('js/LeftWindow.js');
    Ti.include('js/RightWindow.js');
    Ti.include('js/Details.js');
    Ti.include('js/main.js');
    

    main.coffee

    root.database    = new root.database()
    root.leftWindow  = new root.leftWindow()
    root.rightWindow = new root.rightWindow ()
    root.tabView     = new root.tabView()
    
    root.tabView.tabGroup.open()
    

    TabView.coffee

    class TabView
        constructor: ->
            @tabGroup = Titanium.UI.createTabGroup()
    
            @tabGroup.addTab Titanium.UI.createTab
                title: 'Links'
                window: root.leftWindow.window
    
            @tabGroup.addTab Titanium.UI.createTab
                title: 'Rechts'
                window: root.rightWindow.window
    
    root.tabView = TabView
    

    LeftWindow.coffee

    class LeftWindow extends root.Database
        constructor: ->
            @window = new Ti.UI.Window()
    
            # crazy stuff with sql
            result = @db.execute '...'
    
            result.close()
    
            textField = new Ti.UI.TextField()
    
            @window.add textField
    
    root.SearchView = SearchView
    

    ... und erfreute mich meines Lebens als JS Fan. Nein, ehrlich: Es funktioniert. Die UI steht, fehlt noch die Datenbank dahinter.

    Nach - ich glaube insgesamt waren es drei Tage und zwei Versionen - hatte ich ein funktionierendes Script, das mit eine große XML in eine kleine SQLite verwandelte. Nicht 1:1, denn vieles flog heraus, wurde an einem anderen, logischeren Ort abgelegt oder musste noch geparst werden.

    Verwendung zum lesen der XML fand PHPs simplexml_load_file(), das zumindest versucht, seinem Namen alle Ehre zu machen. Ob meine kleinen Probleme damit an der Funktion an sich lagen, oder ob sie das beste aus diesem Haufen ... sagen wir einfach "XML" herausholte, weiß ich nicht. So weit, so gut: Die XML ist eingelesen, ich weiß wie viele Elemente vorhanden sind, kann erahnen wie viele Queries generiert werden.

    Wieso PHP? Weil aktuelle Versionen schon ein paar coole Neuerungen mitbringen. Eckige Klammern für Arrays zum Beispiel. Oder einer Funktion mehrere Rückgabewerte zu geben.

    Die INSERTs dauerten durchschnittlich 4s, was bei 100k einige Stunden beanspruchte. Doch SQLite schafft Abhilfe: INSERTe einfach Asynchron.

    $db = new PDO('sqlite:fuckingbigdata.db');
    $db->exec('PRAGMA synchronous = OFF');
    

    So konnten meine 6k Einträge innerhalb von acht Sekunden (!) eingefügt werden.

    Wichtig war natürlich vor allem die Performance der Suche. Zum Test nahm ich ca. 10k Datensätze mit je ca. 20 Zeilen, die einzeln suchbar sein mussten. Und was liegt bei Android als Zielplattform näher als eine SQLite DB mit Full Text Search?

    Als ich anfangs in der Doku las, es ginge um relativ extreme Unterschiede, war ich noch recht skeptisch. Es war von 0,03s (MATCH, FTS3) zu 22,5s (LIKE) die Rede. Also los, App halbwegs lauffähig bekommen, testen. Nach schon der ersten Runde mit FTS4 wollte kein fallback auf LIKE mehr geschrieben werden, die Geschwindigkeit schwankte nicht, selbst bei einer scheinbar unendlich großen Datenbank (im Test: 10MB (1k Zeilen rendern), 10MB (100 Zeilen), 100MB, 500MB) blieb alles nahezu gleich:

    Legende und Kommentare hierzu: Links Zeit in ms, unten Anzahl der Chars des gesuchten Strings. Die Ausschläge bei einem bzw. neun Zeichen stammen von (viel) mehr Ergebnissen bzw. einem Leerzeichen, das FTS wohl nicht gefiel.

    Leider bereitete mir Titanium, mit seinen nicht nachvollziehbaren Fehlern auf bestimmten (Android) Versionen, mehr Ärger als Spaß. Der allseits bekannte Fehler (KrollRuntimeThread) [n,n] APP PROXY: ti.modules.titanium.app.AppModule@randomstr beispielsweise hilft überhaupt nicht, taucht aber jedes mal auf, wenn eine mit Tabs arbeitende App unter - im Test - Android 4.0.4 startet und beendet sie sofort. Nachdem sie fertig gerendert wurde.

    Posted 1 week ago by Fabian. Short: http://w8l.org/289
  • /unpacker/

    @mkzer0s Hintergrund ist animiert - und zwar in einem Canvas. Das JS wurde mit Dean Edwards /packer/ verkleinert, der auch decompression zulässt.

    Da der Browser die Source aber noch interpretieren muss, reicht es sie in die JS Konsole zu kopieren und das einleitende eval duch console.log zu ersetzen. Dabei heraus kommt wunderschönes JavaScript, das größtenteils auf Leerzeichen, Zeilenumbrüche etc. verzichtet. Leserlicher wird es durch Scripte wie einem der vielen JS beautifier.

    Ja, die Überschrift ist falsch.

    Posted 1 week ago by Fabian. Short: http://w8l.org/288
← Previous
wachtl
  • RSS
  • Twitter
  • BakeRolls