Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon.

Pages: 1-4041-8081-120121-

Practical /Prog/ Challenge

Name: Anonymous 2007-09-08 17:17 ID:P8+/2q3A

The challenge is to make a PROGWATCH program

What it does is, scans this file:
http://dis.4chan.org/prog/subject.txt
every 1 min, 10 mins or 30 seconds or so..

When a change occurs (e.g. someone makes a new post or whatever) then it should exec some program set by the user, with the given args

so for example, you could set it up to open your webbrowser for  the page, or get growl to display "New thread on /prog/, title: Ive read SICP!" etc etc

I will post mine afterwards.. anyway good luck and GO FOR IT!

Name: Anonymous 2007-09-08 17:23 ID:Heaven

while true; do wget -O /dev/null http://dis.4chan.org/prog/subject.txt; done

Name: Anonymous 2007-09-08 17:35 ID:P8+/2q3A

>>2
that doesn't do it....

Name: Anonymous 2007-09-08 17:43 ID:P8+/2q3A

more like
while true; do cp prog.txt prog2.txt && curl -o prog.txt http://dis.4chan.org/prog/subject.txt && diff prog* | grep "^<" ; done

Name: Anonymous 2007-09-08 17:43 ID:P8+/2q3A

>>4
but obviously needs to parse output etc

Name: sage 2007-09-08 17:46 ID:Heaven

>>3
while true; do curl -A sage -F bbs=prog -F id=1189285965 -F  lol what 2 -F meiru=sage -F kotehan=sage -F com=sage -F email= http://dis.4chan.org/post; sleep 5; done

Name: sage 2007-09-08 17:48 ID:Heaven

>>6
Oh yeah, forgot about that wordfilter...
while true; do curl -A sage -F bbs=prog -F id=1189285965 -F shiichan=proper2 -F meiru=sage -F kotehan=sage -F com=sage -F email= http://dis.4chan.org/post; sleep 5; done

Name: sage 2007-09-08 17:49 ID:Heaven

sage

Name: sage 2007-09-08 17:49 ID:Heaven

sage

Name: sage 2007-09-08 17:49 ID:Heaven

sage

Name: sage 2007-09-08 17:49 ID:Heaven

sage

Name: sage 2007-09-08 17:50 ID:Heaven

sage

Name: sage 2007-09-08 17:50 ID:Heaven

sage

Name: sage 2007-09-08 17:50 ID:Heaven

sage

Name: sage 2007-09-08 17:50 ID:Heaven

sage

Name: sage 2007-09-08 17:50 ID:Heaven

sage

Name: sage 2007-09-08 17:50 ID:Heaven

sage

Name: sage 2007-09-08 17:50 ID:Heaven

sage

Name: sage 2007-09-08 17:50 ID:Heaven

sage

Name: sage 2007-09-08 17:51 ID:Heaven

sage

Name: Anonymous 2007-09-08 18:17 ID:P8+/2q3A

>>20
why are you saging lol

Name: Anonymous 2007-09-08 18:21 ID:v8LJ153d

sage

Name: Anonymous 2007-09-08 18:31 ID:vH2kB9X5

Funny you should mention this, I've already starting writing a search engine for /prog/, using subject.txt to look for changed threads to download. It'll be ready this coming week sometime.

Name: Anonymous 2007-09-08 18:57 ID:P8+/2q3A

>>23
in java?

Name: Anonymous 2007-09-08 22:03 ID:P8+/2q3A

>>24
it must be java if hes taking this long lol

Name: Anonymous 2007-09-08 23:55 ID:P8+/2q3A

>>24
>>25
same person

Name: Anonymous 2007-09-08 23:56 ID:P8+/2q3A

oh for fucks sake, Im far too tired today... never realised all 3 posts were me lol

gah.. this is what staying up trying to finish fucking c homework does to you

Name: Anonymous 2007-09-09 0:08 ID:v6kfGJnq

>>27
this made my fucking day
too bad it's 12 am here and i'm awake for two days ... fuck i wish you posted that earlier!
fuck1!

Name: Anonymous 2007-09-09 0:08 ID:v6kfGJnq

>>27
wait, C homework? post it here and i'll help

Name: Anonymous 2007-09-09 0:12 ID:ESwnjzn2

>>29
lol
I am doing ok, it's just time consuming thanks for the offer though very kind :)

Name: sage 2007-09-09 4:39 ID:Heaven

sage

Name: sage 2007-09-09 4:39 ID:Heaven

sage

Name: Anonymous 2007-09-09 5:36 ID:i39FV6TP

I'll do your C homework in Python

Name: Anonymous 2007-09-09 5:58 ID:LiOsF/B5

>>30
Let me do your homework. I'll do it, faggot.

Name: Anonymous 2007-09-09 6:12 ID:v6kfGJnq

>>34
not me!

Name: Anonymous 2007-09-09 8:43 ID:Alm8D+R2

My prog is finished, changed an old directory watch program I had, took half an hour. Produces output like:

Thread bumped: abelson and sussman, by Anonymous
Thread created: XXXXXXXXXXXXXX, by Anonymous

Will let it run for a bit and post my code if it works without errors.

Name: Anonymous 2007-09-09 8:43 ID:Alm8D+R2

It just said: Thread bumped: Practical /Prog/ Challenge, by Anonymous

Name: not anon 2007-09-09 8:44 ID:Alm8D+R2

It just said: Thread bumped: Practical /Prog/ Challenge, by Anonymous

Name: Anonymous 2007-09-09 8:45 ID:Alm8D+R2

Oh shit, the name tag in the subject file is not the last poster, it's the original

Name: Anonymous 2007-09-09 8:45 ID:Alm8D+R2

Thread bumped: Practical /Prog/ Challenge, by Anonymous

Name: Anonymous 2007-09-09 8:46 ID:Alm8D+R2

Thread bumped: Practical /Prog/ Challenge, by Anonymous

Name: sage 2007-09-09 8:49 ID:Alm8D+R2

trying something

Name: Anonymous 2007-09-09 8:49 ID:Heaven

fuck

Name: Anonymous 2007-09-09 8:50 ID:Heaven

post

Name: Anonymous 2007-09-09 8:52 ID:Heaven

post

Name: Anonymous 2007-09-09 9:04 ID:Alm8D+R2

It opens firefox now to view the thread, cool.

Name: Anonymous 2007-09-09 9:05 ID:Heaven

test

Name: Anonymous 2007-09-09 9:08 ID:Heaven

Now only the post

Name: sage 2007-09-09 9:10 ID:Heaven

sage

Name: Anonymous 2007-09-09 9:15 ID:Alm8D+R2


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Vector;

class Observer extends Thread
{
    private URL                url;
    private String[]         subOld;
    private String[]         subNew;
    private BufferedReader     br;

    Observer( String path )
    {       
        try {
            url = new URL( path );
        } catch (MalformedURLException e) {
            System.out.println("Error, malformed URL: " + e.getLocalizedMessage());
        }
        subNew     = getList();
    }

    public void run()
    {
        while( true )
        {
            sleep( 100 );
           
            subOld         = subNew;
            subNew         = getList();
            int change     = getChange();
           
            if( change != -1 )
            {
                String[] threadLine = subNew[change].split("<>");
                int nr = Integer.valueOf(threadLine[4]);
                if( nr == 1 )
                    System.out.println("Thread created: " + threadLine[0] + ", by " + threadLine[1]);
                else
                    System.out.println("Thread bumped: " + threadLine[0] + ", post number " + nr);
               
                try {
                    Runtime.getRuntime().exec("firefox http://dis.4chan.org/read/prog/"; + threadLine[3] + "/" + nr + "-" + nr);
                } catch (IOException e) {}
            }
        }
    }
    private String[] getList(){
        Vector<String>     list        = new Vector<String>();
        int             line        = 0;
        String[]         stringList = null;
       
        try {
            br = new BufferedReader(new InputStreamReader(
                    url.openStream()));
            while( br.ready() )
            {
                list.add( br.readLine() );
                line ++;
            }
            stringList = new String[line+1];
           
            line = 0;
            for(String s:list)stringList[line++]=s;
            br.close();
           
        } catch (IOException e) {
            System.out.println("Error: " + e.getLocalizedMessage());
        }
        return stringList;
    }
    private void sleep( int t )
    {
        try {
            super.sleep( t );
        } catch (InterruptedException e) {}
    }
    private int getChange()
    {
        int len = subOld.length < subNew.length?
                subOld.length:subNew.length;
        for( int i = 0; i < len-1; i++)
        {
            if( !subOld[i].equals( subNew[i] )
                    && subOld[i] != null
                    && subNew[i] != null)
                return i;
        }
        return -1;
    }
}

public class DirObserver{
    public static void main( String[] args ){
        Thread Observer = new Thread( new Observer( "http://dis.4chan.org/prog/subject.txt"; ) );
        Observer.start();
    }
}


Produces output like:
Thread bumped: Practical /Prog/ Challenge, post number 49
Thread created: sage, by sage

And opens only the newest post in firefox.

Name: Anonymous 2007-09-09 9:23 ID:2naHzNYd

>>50
ENTERPRISE LEVEL CODE

Name: Anonymous 2007-09-09 9:30 ID:Heaven

Test.

Name: Anonymous 2007-09-09 10:04 ID:Heaven

Test2.

Name: Anonymous 2007-09-09 10:14 ID:Heaven

Test2.

Name: Anonymous 2007-09-09 10:25 ID:Heaven

2Test.

Name: Anonymous 2007-09-09 10:28 ID:EBCj6yXA

#!/usr/bin/env python2.5

from os import system
from time import sleep
from urllib import urlopen

# The location of the subject file
subject_file = 'http://dis.4chan.org/prog/subject.txt';

# Thread and post fetch URLs
thread_url = 'http://dis.4chan.org/read/prog/%(thread_num)d';
post_url = thread_url + '/%(latest_post)d'

# Check interval in seconds
interval = 60

# Both callbacks get called with a single thread dictionary as an
# argument. See `dictify' for the list of keys.

def created(thread):
    "Called when a new thread is created."
    print "New thread: ``%(title)s''" % thread
    # system('open ' + thread_url % thread)

def posted(thread):
    "Called when a new post is posted in a thread."
    print "New post in ``%(title)s'' by %(poster)s: %(latest_post)d" % thread
    # system('open ' + post_url % thread)

def dictify(thread):
    "Convert a thread to a dict."
    return {
        'title':       x[0],
        'poster':      x[1],
        'thread_num':  int(x[3]),
        'latest_post': int(x[4])
        }

def parse_list(l):
    "Parse the specified subject file, returning a set of threads."
    return set([tuple(x.strip().split('<>')) for x in l])

def thread_num(thread):
    "Return the thread number."
    return thread[3]

def new_threads(changed, old_threads):
    "Return a list of newly created (as opposed to bumped) threads."
    old_nums = map(thread_num, old_threads)
    return set([x for x in changed if thread_num(x) not in old_nums])

if __name__ == '__main__':
    old_threads, threads = None, None

    while True:
        if threads: old_threads = threads
        threads = parse_list(urlopen(subject_file))
        if not old_threads: continue

        # Which threads have been updated since last check?
        changed = threads - old_threads
        if changed:
            new = new_threads(changed, old_threads)
            for x in new:
                created(dictify(x))
            for x in changed - new:
                posted(dictify(x))

        sleep(interval)

Name: Anonymous 2007-09-09 10:36 ID:Heaven

test

Name: Anonymous 2007-09-09 10:55 ID:Heaven

>>56
Blergh.

def dictify(thread):
    "Convert a thread to a dict."
    return {
        'title':       thread[0],
        'poster':      thread[1],
        'thread_num':  int(thread[3]),
        'latest_post': int(thread[4])
        }

Name: Anonymous 2007-09-09 11:42 ID:Alm8D+R2

Changed my code a bit, I store the threads in a hashmap now. Updates less often. Output is still the same. Firefox commented out.


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Vector;

class Observer extends Thread
{
    private URL                         url;
    private String[]                  subNew;
    private HashMap<Integer,Integer> hm;
    private BufferedReader              br;

    Observer( String path )
    {       
        try {
            url = new URL( path );
        } catch (MalformedURLException e) {
            System.out.println("Error, malformed URL: " + e.getLocalizedMessage());
        }
        subNew = getList();
        hm = new HashMap<Integer,Integer>();
        getHashMap( subNew );
    }

    public void run()
    {
        while( true )
        {
            sleep( 30000 );
           
            subNew     = getList();
            getHashMap( subNew );
        }
    }
   
    private String[] getList(){
        Vector<String>     list        = new Vector<String>();
        int             line        = 0;
        String[]         stringList = null;
       
        try {
            br = new BufferedReader(new InputStreamReader(
                    url.openStream()));
            while( br.ready() )
            {
                list.add( br.readLine() );
                line ++;
            }
            stringList = new String[line+1];
           
            line = 0;
            for(String s:list)stringList[line++]=s;
            br.close();
           
        } catch (IOException e) {
            System.out.println("Error: " + e.getLocalizedMessage());
        }
        return stringList;
    }
   
    /**
     * Generate int-int HashMap, mapping the thread number to current posts.
     * @param threadList Threads to map
     */
    private void getHashMap( String[] threadList )
    {
        // Practical /Prog/ Challenge<>Anonymous<><>1189285965<>57<><>1189348564
        // 0: Name
        // 1: OP
        // 2: Empty ( eMail? )
        // 3: OP Number
        // 4: Post Number
        // 5: Empty
        // 6: Last Post Number
        for(String s:threadList)
        {
            if(s==null)break;
            String[] thread = s.split("<>");
            int th = Integer.valueOf(thread[3]);
            int nr = Integer.valueOf(thread[4]);
           
            if( hm.containsKey( th ) )
            {
                if ( hm.get( th ) < nr )
                {
                    hm.put( th, nr );
                    System.out.println("Thread bumped: " + thread[0] + ", post number " + thread[4]);
                    //Runtime.getRuntime().exec("firefox http://dis.4chan.org/read/prog/"; + thread[3] + "/" + nr + "-" + nr);
                }
            } else {
                hm.put( th, nr );
                System.out.println("Thread created: " + thread[0] + ((thread[1].length()>0)?", by " + thread[1]:""));
            }
        }
    }
   
    private void sleep( int t )
    {
        try {
            super.sleep( t );
        } catch (InterruptedException e) {}
    }
}

public class DirObserver{
    public static void main( String[] args ){
        Thread Observer = new Thread( new Observer( "http://dis.4chan.org/prog/subject.txt"; ) );
        Observer.start();
    }
}

Name: Anonymous 2007-09-09 11:49 ID:Heaven

>>59
Still the same ENTERPRISE QUALITY.

Name: Anonymous 2007-09-09 12:01 ID:Alm8D+R2

Revision 3: Made the code more bubbly, to look more enterprise style.




import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Vector;

class Observer extends Thread
{
    private URL                            url;
    private String[]                      subNew;
    private HashMap<Integer,Integer>     hm;
    private BufferedReader                  br;

    Observer( String path )
    {
        try {
            url = new URL( path );
        } catch ( MalformedURLException e ) {
            System.out.println( "Error, malformed URL: " + e.getLocalizedMessage() );
        }
        subNew = getList();
        hm = new HashMap<Integer,Integer>();
        getHashMap( subNew );
    }

    public void run()
    {
        while( true )
        {
            sleep( 30000 );
           
            subNew     = getList();
            getHashMap( subNew );
        }
    }
   
    private String[] getList()
    {
        Vector<String>     list        = new Vector<String>();
        int             line        = 0;
        String[]         stringList = null;
       
        try {
            br = new BufferedReader( new InputStreamReader(
                    url.openStream() ) );
            while( br.ready() )
            {
                list.add( br.readLine() );
                line ++;
            }
            stringList = new String[line];
           
            line = 0;
            for( String s: list )stringList[line++]=s;
            br.close();
           
        } catch ( IOException e ) {
            System.out.println( "Error: " + e.getLocalizedMessage() );
        }
        return stringList;
    }
   
    /**
     * Generate int-int HashMap, mapping the thread number to current posts.
     * @param threadList Threads to map
     */
    private void getHashMap( String[] threadList )
    {
        // Practical /Prog/ Challenge<>Anonymous<><>1189285965<>57<><>1189348564
        // 0: Name
        // 1: OP
        // 2: Empty ( eMail? )
        // 3: OP Number
        // 4: Post Number
        // 5: Empty
        // 6: Last Post Number
        for( String s: threadList )
        {
            if( s == null )break;
            String[] thread = s.split( "<>" );
            int th = Integer.valueOf( thread[3] );
            int nr = Integer.valueOf( thread[4] );
           
            if( hm.containsKey( th ) )
            {
                if ( hm.get( th ) < nr )
                {
                    hm.put( th, nr );
                    System.out.println( "Thread bumped: " + thread[0] + ", post number " + thread[4] );
                    //Runtime.getRuntime().exec("firefox http://dis.4chan.org/read/prog/";; + thread[3] + "/" + nr + "-" + nr);
                }
            } else {
                hm.put( th, nr );
                System.out.println( "Thread created: "
                        + thread[0] + ( ( thread[1].length() > 0 )
                                ? ", by " + thread[1]: null ) );
            }
        }
    }
   
    private void sleep( int t )
    {
        try {
            super.sleep( t );
        } catch ( InterruptedException e ) {}
    }
}

public class ProgWatch
{
    public static void main( String[] args )
    {
        Thread Observer = new Thread( new Observer( "http://dis.4chan.org/prog/subject.txt"; ) );
        Observer.start();
    }
}

Name: Anonymous 2007-09-09 12:02 ID:Heaven

>>59
import java.net.MalformedURLException;

Name: Anonymous 2007-09-09 12:19 ID:Heaven

>>62
OMG WHY YOU GO IMPORT EXCPETIONZZ?=???? WHEN ECXEPTION THEN YOU PROGRAM GOES BOOM LOL SO DONT IMPORT THEM

Name: Anonymous 2007-09-09 12:24 ID:14U848Hb

>>63
dude, to print e.getLocalizedMessage()
and I didn't wrote the program or in fact anything in java.

Name: Anonymous 2007-09-09 12:27 ID:Heaven

>>64
LOL YOU SOUCK, ALL MY ETNERPRISE SOLUTIONS ARE PORGRAMMED WITH

EXPORT EPXCITON , NO IMPORT NIGGERS

Name: sage 2007-09-09 12:38 ID:Heaven

sage

Name: Anonymous 2007-09-09 12:40 ID:Heaven

changed the program to sage this thread everytime something is bumped

Name: sage 2007-09-09 12:50 ID:Heaven

sage

Name: sage 2007-09-09 12:51 ID:Heaven

sage

Name: sage 2007-09-09 12:52 ID:Heaven

sage

Name: sage 2007-09-09 12:53 ID:Heaven

sage

Name: sage 2007-09-09 12:53 ID:Heaven

sage

Name: sage 2007-09-09 12:54 ID:Heaven

sage

Name: sage 2007-09-09 12:55 ID:Heaven

test

Name: sage 2007-09-09 13:00 ID:Heaven

LISP

Name: sage 2007-09-09 13:01 ID:Heaven

'LISP

Name: sage 2007-09-09 13:02 ID:Heaven

'Practical

Name: sage 2007-09-09 13:02 ID:Heaven

test test

Name: sage 2007-09-09 13:03 ID:Heaven

'Practical

Name: sage 2007-09-09 13:04 ID:Heaven

"Why

Name: sage 2007-09-09 13:05 ID:Heaven

"Practical

Name: sage 2007-09-09 13:06 ID:Heaven

"Practical

Name: sage 2007-09-09 13:09 ID:Heaven

"Static

Name: sage 2007-09-09 13:10 ID:Heaven

"Practical

Name: Anonymous 2007-09-09 13:10 ID:8qs12Acw

Here is my solution in OCaml: (I suck at OCaml, but it was fun)

open Http_client.Convenience
open Unix
open Str
open List
open Hashtbl
open Printf

type post = {
  post_subject: string;
  poster: string;
  thread_id: string;
  post_id: string;
  post_num: int
}

type thread = {
  id: string;
  subject: string;
  known_posts: (string, post) t;
  mutable num_posts: int
}


(* logic goes here, feel free to use Unix.system to call some interesting program *)
let on_new_thread thread =
  printf "New thread %s about %s\n" thread.id thread.subject;;

let on_bump_thread thread post =
  printf "Thread %s (%s) bumped by %s with post %s, #%d in thread\n" thread.id thread.subject post.poster post.post_id post.post_num;;

let re_split_lines = (regexp "[\r\n]+");;
let re_split_token = (regexp "<>");;

let parse_posts raw_posts =
  let parse_post raw_post =
    let bits = (Str.split re_split_token raw_post) in
    { post_subject=(nth bits 0); poster=(nth bits 1); thread_id=(nth bits 3); post_id=(nth bits 6); post_num=(int_of_string (nth bits 4)) }
  in
  map parse_post (Str.split re_split_lines raw_posts);;

let update_threads threads posts =
  let update_thread post =
    let thread =
      try
        find threads post.thread_id
      with Not_found ->
        let new_thread = { id=post.thread_id; subject=post.post_subject; known_posts=(Hashtbl.create 50); num_posts=post.post_num } in
        add threads new_thread.id new_thread;
        on_new_thread new_thread;
        new_thread
    in

    (* Yeah, we lose some known threads at the start here, who cares. *)
    if (not (mem thread.known_posts post.post_id)) && (thread.num_posts < post.post_num)
    then begin
      thread.num_posts <- post.post_num;
      add thread.known_posts post.post_id post;
      on_bump_thread thread post;
    end;
  in
  List.iter update_thread posts;;

let thread_watch url =
  let threads = (Hashtbl.create 50) in
  let rec loop () =
    let fresh_posts = (parse_posts (http_get url)) in
    update_threads threads fresh_posts;
    flush_all ();
    sleep 20;
    loop ()
  in
  loop ();;

(* lets start our thread watcher... *)
thread_watch "http://dis.4chan.org/prog/subject.txt";;;


----

Requires netclient, compiles with ocamlfind ocamlopt -package netclient -linkpkg -o subject str.cmxa subject.ml

Name: Anonymous 2007-09-09 13:36 ID:TWv7+hVQ

So, fetch subject.txt (\approx 165 000 bytes) every minute for one day, 165 000B * 60 * 24 \approx 226 MB traffic per day, per retard who leaves this script open. That's quite the load compared to regular textboard usage.

Name: Anonymous 2007-09-09 13:37 ID:8qs12Acw

Except I'm doing it every 20 seconds because I'm cool like that.

Name: Anonymous 2007-09-09 13:39 ID:Heaven

>>86
Yeah, and considering world4ch has RSS feeds, these things are not very ``practical''. But this is still a better challenge than those copied Project Euler problems.

Name: Anonymous 2007-09-09 13:39 ID:8qs12Acw

Although, it should be trivial to make it fetch say, only the first 1KB or something like that.

Name: Anonymous 2007-09-09 13:51 ID:DWe23HTk

>>89
Well, you don't want to miss saged replies to posts on the last page, now do you?

Name: Anonymous 2007-09-09 13:51 ID:uyxePQ7x

Name: Anonymous 2007-09-09 13:54 ID:Heaven

>>91
That is not a full solution, though. Even when the list actually gets updated, we are only interested in the updated lines, all of which seem to be at the beginning of the file.

Name: Anonymous 2007-09-09 14:08 ID:Heaven

>>90
Oh crap. You're right. Disregard >>92.

Name: Anonymous 2007-09-09 14:39 ID:8qs12Acw

Here is a better version of my OCaml one.

This time it doesn't keep track of all the posts that it's seen (because it seems pointless). Another thing to do would be to drop threads that it can't see in the file anymore out of the hashtable.

No, I didn't have to be that anal about the types with the poster, but why not.

open Http_client.Convenience
open Unix
open Str
open List
open Hashtbl
open Printf

type poster = Poster of string | Unknown_poster;;

type post = {
  subject: string;
  poster: poster;
  thread_id: string;
  post_id: string;
  post_num: int
};;

let poster_of_string str =
  if (String.length str) = 0 then Unknown_poster else Poster str;;

let string_of_poster poster =
  match poster with
      Poster p -> p
    | Unknown_poster -> "Unknown";;


(* logic goes here, feel free to use Unix.system to call some interesting program *)
let on_new_thread post =
  let poster_str = (string_of_poster post.poster) in
  if post.post_num = 1 then
    printf "New thread %s about %s started by %s\n" post.thread_id post.subject poster_str
  else
    printf "New thread %s about %s last posted in by %s has %d posts already\n" post.thread_id post.subject poster_str post.post_num;;

let on_bump_thread post =
  printf "Thread %s (%s) bumped by %s with post %s, #%d in thread\n" post.thread_id post.subject (string_of_poster post.poster) post.post_id post.post_num;;


let re_split_lines = (regexp "[\r\n]+");;
let re_split_token = (regexp "<>");;

let parse_posts raw_posts =
  let parse_post raw_post =
    let bits = (Str.split re_split_token raw_post) in
    { subject=(nth bits 0); poster=(poster_of_string (nth bits 1)); thread_id=(nth bits 3); post_id=(nth bits 6); post_num=(int_of_string (nth bits 4)) }
  in
  map parse_post (Str.split re_split_lines raw_posts);;

let update_threads threads fresh_posts =
  let update_thread post =
      try
        let thread = (find threads post.thread_id) in
        if thread.post_num < post.post_num
        then begin
          Hashtbl.replace threads post.thread_id post;
          on_bump_thread post
        end;
      with Not_found ->
        add threads post.thread_id post;
        on_new_thread post
  in
  List.iter update_thread fresh_posts;;

let thread_watch url =
  let threads = (Hashtbl.create 50) in
  let rec loop () =
    let fresh_posts = (parse_posts (http_get url)) in
    update_threads threads fresh_posts;
    flush_all ();
    sleep 20;
    loop ()
  in
  loop ();;

(* lets start our thread watcher... *)
thread_watch "http://dis.4chan.org/prog/subject.txt";;;

Name: Anonymous 2007-09-09 16:16 ID:699WrGup

>>88
Since when does world4ch have RSS feeds??

Name: Anonymous 2007-09-09 16:17 ID:Heaven

>>92
No, lines are updated far down the subject.txt if it is due to sage

Name: Anonymous 2007-09-09 16:28 ID:Heaven

>>96
I already corrected myself in >>93.

>>95
Okay, it doesn't. They are atom feeds. I can't remember when they appeared, though.

Name: Anonymous 2007-09-09 16:32 ID:699WrGup

>>97
Where are they? Is what I meant.

Name: Anonymous 2007-09-09 16:33 ID:699WrGup

Anyway, I don't see the point of atom/rss feeds on a messageboard like this.

Name: Anonymous 2007-09-09 16:33 ID:Heaven

Name: Anonymous 2007-09-09 16:34 ID:Heaven

>>99
Me neither.

Name: Anonymous 2007-09-09 20:49 ID:2naHzNYd

>>100
WE HAVE AN EXPERT WINNER

Name: Anonymous 2007-09-09 20:53 ID:ESwnjzn2

>>100
AWESOME!

Name: Anonymous 2007-09-09 20:57 ID:ESwnjzn2

asdf

Name: Anonymous 2007-09-09 20:57 ID:ESwnjzn2

105

Name: Anonymous 2007-09-09 21:15 ID:Mlb21P8h

how far does this go anyways

Name: Anonymous 2007-09-09 22:25 ID:Heaven

>>106
pretty damn far

Name: Anonymous 2007-09-09 22:36 ID:ynCRakIl

Come on fuckers, where are your solutions? I still haven't seen any lisp ones.

Name: Anonymous 2007-09-09 22:41 ID:Mlb21P8h

>>108
lisp is a nerd joke; it's not for actually developing programs

Name: Anonymous 2007-09-09 22:58 ID:ynCRakIl

>>109
I was going to write one in lisp, but then I decided to write the OCaml one - thinking that someone would shortly write one in lisp.

Name: Anonymous 2007-09-09 23:24 ID:Heaven

>>110
ocaml is for fags

Name: Anonymous 2007-09-10 0:21 ID:PClu1KVF

>>108
It hardly seems worthwhile when there are so many versions already.

Name: Anonymous 2007-09-10 0:30 ID:cHAiMhj/

>>112
ooo, Mr PClu1KVF is TOO CHICKEN!!!!!!! BUK BUK BUKKAKE!!!!

Name: Anonymous 2007-09-10 0:32 ID:PClu1KVF

>>113
NOW YOU DID IT

Name: Anonymous 2007-09-10 0:42 ID:2FXDvzsf

bukkake

Name: Anonymous 2007-09-10 1:29 ID:Heaven

>>112
Just three, really, if we don't count the shellscript hacks.

Name: Anonymous 2007-09-10 6:44 ID:2vgkCCNf

>>108
Below. It took a bit of time, because I'm hired as a Rails programmer right now, so I had to fight the confusion. Also, I misinterpreted the format, and then couldn't be bothered to change the code to match the actual format, and only did it today (it actually took surprisingly little time and code, something like 5 lines).

It's designed to be run as a single file, like that:
sbcl --noinform --noprint --disable-debugger --load progwatch.lisp

Tested and known to run in SBCL, should in others but I can't say for sure. Also, SBCL is a whiny bitch and I can't get it to STFU with all compilation warnings.

(in-package :cl-user)

(eval-when (:compile-toplevel :load-toplevel :execute)
  (setf *compile-verbose* nil)
  (setf *compile-print* nil)

#+sbcl (setf *invoke-debugger-hook*
             (lambda (condition hook)
               (declare (ignore hook))
               ;; Uncomment to get backtraces on errors
               ;; (sb-debug:backtrace 20)
               (format *error-output* "Error: ~A~%" condition)
               (quit)))

  (require :asdf)
  (asdf:oos 'asdf:load-op :asdf-install :verbose nil)
  (asdf:oos 'asdf:load-op :cl-ppcre :verbose nil)
  (asdf:oos 'asdf:load-op :trivial-http :verbose nil)
  (asdf:oos 'asdf:load-op :iterate :verbose nil))

(defpackage :progwatch
  (:use :cl :cl-user :ppcre :iterate :trivial-http))

(in-package :progwatch)

(defvar *last-post* 0)
(defvar *known-posts* (make-hash-table :size 3000))
(defparameter *url* "http://dis.4chan.org/prog/subject.txt";)
(defparameter *update-interval* 60)

(defun group-threads (posts)
  (let (threads)
    (iter (for (post-id thread-id subject) in posts)
          (let ((thread (getf threads thread-id)))
            (setf (getf threads thread-id)
                  (cons (list post-id subject)
                        thread))))
    threads))

(defun extract-new-posts (status known last)
  (let ((last-seen last))
    (values
     (iter (for post in status)
           (unless (or (<= (car post) last)
                       (<= (car post) (gethash (nth 1 post) known 0)))
             (setf last-seen (max last-seen (car post)))
             (setf (gethash (nth 1 post) known) (car post))
             (collect post)))
     last-seen)))

(defun new-posts (status known last out)
  (multiple-value-bind (new last-seen) (extract-new-posts status known last)
    (setf new (group-threads new))
    (values
     (when new
       (format out "~%New posts:  ~{~&  Thread ~a: ~{~&    ~{Post ~a: ~a~}~}~}" new))
     last-seen)))

(defun success (response)
  (= response 200))

(defun unescape (post)
  (destructuring-bind (topic x y thread-id z d post-id) post
      (declare (ignore x y z d))
      (flet ((convert (target-string start end match-start match-end reg-starts reg-ends)
               (declare (ignore start end reg-starts reg-ends))
               (format nil "~a"
                       (code-char (parse-integer
                                   (subseq target-string
                                           (+ 2 match-start)
                                           (1- match-end)))))))
        (list
         (parse-integer post-id)
         (parse-integer thread-id)
         (cl-ppcre:regex-replace-all "&#[0-9]+;" topic #'convert)))))

(defun get-status (url)
  (destructuring-bind (response headers text) (http-get url)
    (declare (ignore headers))
    (when (success response)
      (iter (for line in-stream text using #'read-line)
            (collect (unescape (split "<>" line)))))))

(defun run ()
  (loop
     (multiple-value-bind (new last-post)
         (new-posts (get-status *url*) *known-posts* *last-post* t)
       (declare (ignore new))
       (setf *last-post* last-post))
     (finish-output)
     (sleep *update-interval*)))

(handler-case (run)
  (t () nil))

Name: Anonymous 2007-09-10 7:26 ID:zTctovPs

That's more like it.

Name: Anonymous 2007-09-10 7:36 ID:Fj/3x8oh

>>117
You forgot -O3 -funroll-loops -malign-double rite?

Name: Anonymous 2007-09-10 7:40 ID:Heaven

>>118
What?

Name: Anonymous 2007-09-10 7:51 ID:zTctovPs

>>120
Cheese.

Name: Anonymous 2007-09-10 7:53 ID:1IO9cPDn

>>117
That's fucking horrible.

Name: Anonymous 2007-09-10 7:54 ID:Heaven

>>122
What isn't?

Name: Anonymous 2007-09-10 8:44 ID:zTctovPs

>>122
show me your better version

Name: Anonymous 2007-09-10 8:56 ID:2vgkCCNf

>>122
I eagerly await your version to put my humble creation to shame, sir.

Name: Anonymous 2007-09-10 9:01 ID:cHAiMhj/

>>125
Don't worry too much, any time anyone ever posts code almost everyone says "[b][u]FUCKS SAKE THATS SHIT[/u][/b]" no matter what it is

Name: Anonymous 2007-09-10 9:27 ID:zTctovPs

>>126
I don't think that was worry, I think that was more of a challenge

Name: Anonymous 2007-09-10 9:29 ID:Heaven

>>126
E.g.: Your BBCode is shit.

Name: Anonymous 2007-09-12 14:10 ID:LdS0Qs1r

MOAR!

Name: Anonymous 2007-09-12 14:11 ID:Heaven

>>129
NO U.

Name: Anonymous 2007-09-12 14:11 ID:Heaven

Actually, we need a new challenge.

Name: Anonymous 2007-09-12 14:53 ID:LdS0Qs1r

>>131
YOU DECIDE!

Name: Anonymous 2007-09-12 15:24 ID:Heaven

>>132
I don't have any really good ideas. Maybe a BBCode interpreter?

Name: Anonymous 2007-09-12 15:28 ID:LdS0Qs1r

>>133

(  ____ \|\     /|(  ____ \| \    /\  |\     /|(  ___  )|\     /|
| (    \/| )   ( || (    \/|  \  / /  ( \   / )| (   ) || )   ( |
| (__    | |   | || |      |  (_/ /    \ (_) / | |   | || |   | |
|  __)   | |   | || |      |   _ (      \   /  | |   | || |   | |
| (      | |   | || |      |  ( \ \      ) (   | |   | || |   | |
| )      | (___) || (____/\|  /  \ \     | |   | (___) || (___) |
|/       (_______)(_______/|_/    \/     \_/   (_______)(_______)

Name: Anonymous 2007-09-12 15:30 ID:Heaven

>>134
There are already enough banner programs. We need something exclusive to /prog/.

Name: Anonymous 2007-09-12 15:58 ID:o+PD0v9T

>>135
Suave space toad lisp banner?

Name: Anonymous 2007-09-12 16:05 ID:Heaven

>>136
Maybe a variation of the SICP functional graphics language with suave space toad lisp as the image?

Name: Anonymous 2007-09-12 16:32 ID:fhPRcjaU

>>137
Yes..

Name: Anonymous 2011-02-03 1:16

Name: Anonymous 2012-10-28 21:35

>>23
Still waiting. Fucking vaporware.

Name: Anonymous 2012-10-28 21:40

Name: Anonymous 2012-10-28 21:47

>>36
use vim

Name: Anonymous 2012-10-28 22:24

What it does is, scans this file:
USE SCANF! *BITES YOUR TESTICLES*

Name: Anonymous 2012-10-28 22:30

or get growl to display
GRRRRRRRRRR!

Name: Anonymous 2012-10-28 23:17

>>143
*holds up spork*

Name: Anonymous 2012-10-29 0:24

>>145
There is no spoon()

Don't change these.
Name: Email:
Entire Thread Thread List