Thursday, November 15, 2012

@Delegate vs. Extends

// "favor composition over inheritance" ~Effective Java

class Parent {
    def getAll() {
        String resp = ""
        2.times {
            resp += get(it)
        }
        return resp
    }
    
    def get(def i) {
        "get PARENT $i\n"
    }
}

class Child1 extends Parent {
    def get(def i) {
        "get CHILD $i\n" // is used by parent's getAll
    }
}

class Child2 {
    @Delegate Parent p = new Parent() // decorated Parent instance
    
    def get(def i) {
        "get CHILD $i\n" // not used by parent's getAll
    }
}

Parent c1 = new Child1()
assert c1.getAll() == "get CHILD 0\nget CHILD 1\n" // calls child's get()
assert c1.get(0) == "get CHILD 0\n"

//Parent c2 = new Child2() // Child2 is not a Parent!
Child2 c2 = new Child2()
assert c2.getAll() == "get PARENT 0\nget PARENT 1\n" // calls parent's get()
assert c2.get(0) == "get CHILD 0\n"

Monday, November 5, 2012

DNS lookup - timed

int maxTimeout = 30000
int minTimeout = 15000

List domainList = [
    'gmail.com', 'google.co.uk', 'google.com', 'bbc.co.uk', 'cnn.com', 'java.oracle.com',
    'facebook.com', 'twitter.com', 'oracle.com', 'zen.co.uk', 'java.net', 'www.scala-lang.org',
    'plus.google.com', 'guardian.co.uk', 'linkedin.com', 'www.typesafe.com', 'www.yahoo.com',
    'www.ibm.com', 'www.apache.org', 'www.adobe.com', 'www.microsoft.com', 'www.stackoverflow.com',
    'www.apple.com', 'groovy.codehaus.org', 'java.oracle.com', 'www.telegraph.co.uk', 'www.jroller.com',
    'www.dell.com', 'www.samsung.com', 'www.amazon.co.uk', 'docs.oracle.com', 'www.infoq.com',
    'www.devoxx.com', 'www.qconlondon.com', 'www.smashingmagazine.com', 'en.wikipedia.com' ]

int count = 1
while (true) {
    int idx = (int)( Math.random() * domainList.size )    
    println "[$count]  nslookup ${domainList[idx]}"
    def process = "nslookup ${domainList[idx]}".execute()
    println "Found text ${process.text}"
    
    int sleepTime = (int)( minTimeout + Math.random() * ( maxTimeout  - minTimeout))
    Thread.sleep( sleepTime );
    
    ++count
}

Monday, October 29, 2012

Resolve an HTTP Redirect

// source: https://gist.github.com/3899754

def findRealUrl(url) {
    HttpURLConnection conn = url.openConnection()
    conn.followRedirects = false
    conn.requestMethod = 'HEAD'
    if(conn.responseCode in [301,302]) {
        if (conn.headerFields.'Location') {
          return findRealUrl(conn.headerFields.Location.first().toURL())
        } else {
            throw new RuntimeException('Failed to follow redirect')
        }
    }
    return url
}

Wednesday, August 1, 2012

match/when implemented with Groovy's GEP-3

//WOW! https://gist.github.com/3002724

// No commas
def a = 'tim'
def nocom = match( a ) {
  when 'dave' 'Hi Dave'
  when 'tim'  'Hi Tim'
  otherwise 'none of the above'
}
assert nocom == 'Hi Tim'

// Commas
a = 'William'
def com = match( a ) {
  when 'dave', 'Hi Dave'
  when 'tim',  'Hi Tim'
  otherwise 'none of the above'
}
assert com == 'none of the above'

// Lists (can't use commas)
a = [1,3]
def list = match( a ) {
  when [1,2] 'One and two'
  when [1,3] 'One and three'
  when [2,1] 'Two and one'
}
assert list == 'One and three'

// Wildcard Lists (can't use commas)
a = [1,2,3]
def wild = match( a ) {
  when [1,3,2] 'One, three and two'
  when [1,_]   'One and something'
  when [1,_,3] 'One, something and three'
  when [1,_,_] 'One, something and something'
  otherwise    'Something else'
}
assert wild == 'One, something and three'

// Closures as the when/results
String toRoman( int num ) {
  match( num ) {
    when { it >= 100 } { "C"  + toRoman( num - 100 ) }
    when { it >= 90  } { "XC" + toRoman( num - 90  ) }
    when { it >= 50  } { "L"  + toRoman( num - 50  ) }
    when { it >= 40  } { "XL" + toRoman( num - 40  ) }
    when { it >= 10  } { "X"  + toRoman( num - 10  ) }
    when { it >= 9   } { "IX" + toRoman( num - 9   ) }
    when { it >= 5   } { "V"  + toRoman( num - 5   ) }
    when { it >= 4   } { "IV" + toRoman( num - 4   ) }
    when { it >= 1   } { "I"  + toRoman( num - 1   ) }
    otherwise ""
  }
}

assert "I"       == toRoman( 1 )
assert "II"      == toRoman( 2 )
assert "IV"      == toRoman( 4 )
assert "V"       == toRoman( 5 )
assert "VI"      == toRoman( 6 )
assert "IX"      == toRoman( 9 )
assert "X"       == toRoman( 10 )
assert "XVII"    == toRoman( 17 )
assert "XXXVIII" == toRoman( 38 )
assert "CCCXCIX" == toRoman( 399 )
    
///////////////////////////
// Implementation below...

def match( v, c ) {
  new Matcher( var:v, closure:c ).match()
}

class Matcher {
  def var
  Closure closure
  List cases = []
  Otherwise otherwise

  def propertyMissing( name ) {
    if( name == '_' ) {
      new Any()
    }
    else {
      def w = new When()
      cases << w
      w
    }
  }
  def when( condition )         { cases << new When( condition:condition ) }
  def when( condition, result ) { cases << new When( condition:condition, result:result ) }
  def otherwise( result )       { this.otherwise = new Otherwise( result:result ) }
  public match() {
    closure.delegate = this
    closure.resolveStrategy = Closure.DELEGATE_ONLY
    closure()
    def ret = cases.find {
      it.condition instanceof Closure ?
        it.condition( var ) :
        it.condition == var
    }?.result ?: otherwise?.result
    ret instanceof Closure ? ret() : ret
  }
}

class When {
  def condition
  def result
  def getAt( List a )                  { condition = a ; this }
  def call( result )                   { this.result = result }
  def propertyMissing( String result ) { this.result = result }
}

class Otherwise {
  def result
}

class Any {
  boolean equals( other ) { true }
}

println 'DONE'

Sunday, July 15, 2012

GPars DataflowQueues

//source: http://jaxenter.com/tutorial-gpars-making-parallel-systems-groovy-and-java-friendly-43529-2.html
//a sample code build process //

//source: http://jaxenter.com/tutorial-gpars-making-parallel-systems-groovy-and-java-friendly-43529-2.html
//a sample code build process //

import static groovyx.gpars.dataflow.Dataflow.operator
import groovyx.gpars.dataflow.*


def _checkout = { String a ->
    Thread.sleep( (Long)Math.random() * 5 ); // a bit of random delay for fun
    println ">checking out...$a"
    return "checkout-$a"
}
def _compileSources = { a ->
    println ">compiling...$a"
    return "compileSources-$a"
}
def _generateAPIDoc = { a ->
    println ">api Docs...$a"
    return "generateAPIDoc-$a"
}
def _generateUserDocumentation = { a ->
    println ">user Docs...$a"
    return "generateUserDocumentation-$a"
}
def _packageProject = { project, api, doc ->
    println ">packaging...$project $api $doc"
    return "packageProject-$project $api $doc"
}
def _deploy = { a ->
    println ">deploying...$a"
    return (!!Math.round(Math.random()))
}


/* We need a Broadcaster and Queues to wire elements together */
def checkedOutProjects_B = new DataflowBroadcast()
def urls_Q = new DataflowQueue()
def compiledProjects_Q = new DataflowQueue()
def apiDocs_Q = new DataflowQueue()
def userDocs_Q = new DataflowQueue()
def packages_Q = new DataflowQueue()
def done_Q = new DataflowQueue()



/* Here's the composition of individual build steps into a process */
operator(inputs: [urls_Q], outputs: [checkedOutProjects_B], maxForks: 3) { url ->
    bindAllOutputs _checkout(url)
}
operator([checkedOutProjects_B.createReadChannel()], [compiledProjects_Q]) { projectRoot ->
    bindOutput _compileSources(projectRoot)
}
operator(checkedOutProjects_B.createReadChannel(), apiDocs_Q) { projectRoot ->
    bindOutput _generateAPIDoc(projectRoot)
}
operator(checkedOutProjects_B.createReadChannel(), userDocs_Q) { projectRoot ->
    bindOutput _generateUserDocumentation(projectRoot)
}
operator([compiledProjects_Q, apiDocs_Q, userDocs_Q], [packages_Q]) { project, api, doc ->
    bindOutput _packageProject(project, api, doc)
}

def deployer = operator(packages_Q, done_Q) { packagedProject ->
    boolean ok = _deploy(packagedProject)
    println "! Deployed? $ok"
    bindOutput (ok)
}


/* add data, start the machine a rollin! */
5.times { urls_Q << "url #$it" }
5.times { urls_Q << "url #${++it*5}" }


/* Now we're set up, and can just wait for the build to finish */
println "==Starting the build process. This line MIGHT NOT be printed out first ...=="

//deployer.join()  //Wait for the last operator in the network to finish??

Thursday, July 12, 2012

GBench - easy code benchmarking

//source: http://nagaimasato.blogspot.jp/2012/07/gbench-031-released.html
//requires Groovy 2.0.0+

@Grab('com.googlecode.gbench:gbench:0.3.1-groovy-2.0') 
import gbench.BenchmarkBuilder
import groovy.transform.CompileStatic
 
int fib(int n) {
    if (n < 2) return n 
    return fib(n - 1) + fib(n - 2)  
} 
 
@CompileStatic 
int fib2(int n) { 
    if (n < 2) return n 
    return fib2(n - 1) + fib2(n - 2)  
} 
 
new BenchmarkBuilder().run { 
    int n = 20  
    "Normal Version" { fib n } 
    "@CompileStatic Version" { fib2 n } 
}.prettyPrint() 

Wednesday, July 11, 2012

Conceptual Map/Reduce Example

//inspiration: http://hamletdarcy.blogspot.ca/2008/01/mapreduce-for-mere-mortals.html

// general purpose function
def mapReduceFunc = { data, mapFunction, reduceFunction ->
  def mappedData = data.collect(mapFunction)
  reduceFunction(mappedData)
}

// the data
Map dictionary = [
  abacus: "a device for making arithmetic calculations", 
  arc: "any unbroken part of the circumference of a circle", 
  beaver: "a large, amphibious rodent of the genus Castor"
]

// the mapping function impl
def startingCharacter = { pair ->
  pair.value = pair.key[0].toLowerCase()
  return pair
}

// the reducing function impl
def countCharacters = { dataMap ->
  Map result = [:]
  ('a'..'z').each{ result[it] = 0 }
  dataMap.each { pair -> result[pair.value]++ }
  return result
}

// put it all together!
def result1 = mapReduceFunc(dictionary, startingCharacter, countCharacters)
println result1

//// TWEAK THE I/O FUNCS!  ////

// the mapping function impl
startingCharacter = { pair ->
  return pair.key[0].toLowerCase()
}

// the reducing function impl
countCharacters = { dataList ->
  Map result = [:]
  ('a'..'z').each{ result[it] = 0 }
  dataList.each { it -> result[it]++ }
  return result
}

// put it all together!
def result2 = mapReduceFunc(dictionary, startingCharacter, countCharacters)
println result2

assert result1 == result2

Saturday, June 23, 2012

MockFor

//http://groovy.codehaus.org/Using+MockFor+and+StubFor

import groovy.mock.interceptor.*

/*sample data class*/
class Movie {
    // Lots of expensive method calls, etc.
}

/*helper class*/
class MovieAnalyzer {
    def isGood( movie ) {
        if( movie.hasGalifinakis() )
            return true;
        else if( movie.hasSparklyVampires() )
            return false;

        return ( new Date().getTime() / 2 ) == 0 
    }
}

/*unit test the helper class by mocking the data class*/
def testTwitlightMovie(){
    def mock = new MockFor(Movie)
    //StubFor is similar to MockFor except that 
    //the expectaion of methods called is order independent ...
    mock.demand.hasGalifinakis { true }
    mock.demand.hasSparklyVampires( 0..1 ) { true } // demand the method 0 or 1 times
    mock.use {
       assert true == new MovieAnalyzer().isGood( new Movie() )
    }
}

testTwitlightMovie()

Tuesday, May 22, 2012

Quartz Job Scheduler

//a better Groovy DSL example: https://gist.github.com/1505600
//Note: a simple timer implementation with runAfter(): http://mrhaki.blogspot.ca/2009/11/groovy-goodness-run-code-at-specified.html

@Grapes(
    @Grab(group='org.quartz-scheduler', module='quartz', version='2.1.5')
)
import org.quartz.*
import org.quartz.impl.*
import static org.quartz.JobBuilder.*
import static org.quartz.TriggerBuilder.*
import static org.quartz.SimpleScheduleBuilder.*

class HelloJob implements Job {
    public void execute(JobExecutionContext context) {
        println "Hello "+(new Date().getTime())
    }
}

try {
    // Grab the Scheduler instance from the Factory 
    Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler()

    // Start it!
    scheduler.start()

     JobDetail job = newJob(HelloJob)
         .withIdentity("myJob"+(new Date().getTime()), "group1")
         .build()
         
     Trigger trigger = newTrigger()
         .withIdentity(new TriggerKey("myTrigger"+(new Date().getTime()), "group1"))
         .withSchedule(simpleSchedule()
             .withIntervalInSeconds(5)
             .repeatForever())
         .startNow()
         .build()

    // Tell quartz to schedule the job using our trigger
    scheduler.scheduleJob(job, trigger)
    
    // Pause thread for 60 seconds
    Thread.sleep(60000)
    
    // End it!
    scheduler.shutdown()
}
catch (SchedulerException se) {
    se.printStackTrace()
}

Beep Sound

java.awt.Toolkit.getDefaultToolkit().beep() // doesn't always work

println ("\007"*3) //3 beeps

Tuesday, April 24, 2012

self-referenced tree, in one line!

//source: https://gist.github.com/2478499

def tree = { [:].withDefault{ owner.call() } } // ta-da!

users = tree()

users.harold.username = 'hrldcpr'
users.yates.username = 'tim'

users.with {
    al.username = 'al1'
    derek.username = 'skinnyk1d'
    
    frier.with {
        username = 'great1'
        password = 'changeme1'
        updatedOn = '4/26/2012'
    }
    
    bob.with {
        age = 4
        isOld = false
    }
}

println new groovy.json.JsonBuilder( users ).toPrettyString()

CodeNarc bundle

Simple starter zip file for running CodeNarc (groovy static analysis) 0.17 inside a local groovy source code folder. (Windows .bat file) Generates html report page.

Wednesday, March 28, 2012

JRegex

@Grapes(
    @Grab(group='net.sourceforge.jregex', module='jregex', version='1.2_01')
)
import jregex.*
//http://jregex.sourceforge.net/gstarted-advanced.html#imatching

String userNameChars="[\\w.\\-]+" //letters, dots, hyphens
String alphaNums="\\w+"
String dot="\\."
Pattern email=new Pattern(userNameChars + "@" + "(?:"+ alphaNums + dot + ")*" + alphaNums)

List ls = ['s@1.com','2@3.com','howdy@d.']

ls.each {
    println email.matcher(it).matches()
}

Pattern re=new Pattern("\\d\\d:\\d\\d") //two digits + colon + two digits
println("Pattern: "+re)

Matcher m=re.matcher()
test(m,"") // true
test(m,"1") // true
test(m,"12") // true
test(m,"1:2") // true
test(m,"12:") // true
test(m,"12:1") // true
test(m,"12:12") // true
test(m,"12:123") // true
test(m,"1:") // false
test(m,"123:1") // false

void test(Matcher m1, String s) {
   m1.setTarget(s)
   println("\""+s+"\" : "+m1.matchesPrefix()) //note: .matchesPrefix()
}

////*Pure Java/Groovy*////
//credit: http://glaforge.appspot.com/article/incomplete-string-regex-matching
List inp = [
    /12:/,/12:1/,/1/,/12:12/ //trues
    ,/1:/,/123:1/ //falses
]

inp.each {
    def matcher = it =~ /\d{2}:\d{2}/
    println matcher.matches() || matcher.hitEnd()
}

println 'done'

Sunday, March 4, 2012

Thread Pools

import java.util.concurrent.Callable
import java.util.concurrent.Executors

long ts // timer
def pool = Executors.newFixedThreadPool(THREADS)
def defer = { c -> pool.submit(c as Callable) }

//PLAIN//////////////////////////////////////////

ts = (new Date().time)
doit = { n ->
  def left = { def slp = Math.random()*n*1000+500l as Long; Thread.sleep(slp);  println Thread.currentThread().name + '!!left!!'+slp }()
  def right = { def slp = Math.random()*n*1000+500l as Long; Thread.sleep(slp);  println Thread.currentThread().name + '!!right!!'+slp }()
}
(1..3).each{ n -> println "n=$n => ${doit(n)}" }
println ((new Date().time)-ts)

//POOLED//////////////////////////////////////////////

ts = (new Date().time)
THREADS = 3
fib = { n ->
  def left = defer{ def slp = Math.random()*n*1000+500l as Long; Thread.sleep(slp);  println Thread.currentThread().name + '!!left!!'+slp }
  def right = defer{ def slp = Math.random()*n*1000+500l as Long; Thread.sleep(slp);  println Thread.currentThread().name + '!!right!!'+slp }
}
(1..3).each{ n -> println "n=$n => ${fib(n)}" }
pool.shutdown()
while(!pool.isTerminated()) { Thread.sleep(100) }
println ((new Date().time)-ts)

//FIB//////////////////////////////////////////////////

println "Calculating Fibonacci sequence in parallel..."
CUTOFF = 12    // not worth parallelizing for small n
THREADS = 10
serialFib = { n -> (n < 2) ? n : serialFib(n-1) + serialFib(n-2) }
fib = { n ->
  if (n < CUTOFF) return serialFib(n)
  def left = defer{ println Thread.currentThread().name; fib(n-1) }
  def right = defer{ println Thread.currentThread().name; fib(n-2) }
  left.get() + right.get()
}

(11..16).each{ n -> println "n=$n => ${fib(n)}" }
pool.shutdown()

Thursday, March 1, 2012

Jetty server

//src: http://www.redtoad.ca/ataylor/2012/02/simple-servlets-in-groovy/

@Grab(group='org.mortbay.jetty', module='jetty-embedded', version='6.1.26')
import org.mortbay.jetty.Server
import org.mortbay.jetty.servlet.*
import groovy.servlet.*;
import javax.servlet.http.*;
import javax.servlet.ServletConfig;
 
class SimpleGroovyServlet extends HttpServlet {
    def requestHandler
    def context
    void init(ServletConfig config) {
        super.init(config)
        context = config.servletContext
    }
    void service(HttpServletRequest request, HttpServletResponse response) {
        requestHandler.binding = new ServletBinding(request, response, context)
        use (ServletCategory) {
            requestHandler.call()
        }
    }
    static void run(int port, Closure requestHandler) {
        def servlet = new SimpleGroovyServlet(requestHandler: requestHandler)
        def jetty = new Server(port)
        def context = new Context(jetty, '/', Context.SESSIONS)
        context.addServlet(new ServletHolder(servlet), '/*')
        jetty.start()
    }
}

SimpleGroovyServlet.run(8080) { ->
    response.contentType = 'text/plain'
    println "hello world!"
    println "my path is ${request.pathInfo}"
    println "my params are $params"
}

//also try: groovy -l 8080 -e "println 'hello world'"
//alternate: https://github.com/groovypp/gretty/wiki/Getting-Started

Wednesday, February 29, 2012

collate

//src: http://blog.bloidonia.com/post/18073244930/whats-new-in-groovy-1-8-6-the-collate-method

//v1.8.6+//
def list = 1..10
def listInFours  = list.collate( 4 )
assert listInFours == [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ], [ 9, 10 ] ]

def listInFours2 = list.collate( 4, false )

// Notice the [ 9, 10 ] remainder has been dropped
assert listInFours2 == [ [ 1, 2, 3, 4 ], [ 5, 6, 7, 8 ] ]

def gridList = list.collate( 3 ).collate( 2 )

assert gridList == [ [ [1, 2, 3], [4, 5, 6] ],
                     [ [7, 8, 9], [10]      ] ]

def mph        = [ 10, 26, 30, 32, 27, 14, 19, 22, 40, 14 ]
def window     = mph.collate( 3, 1, false )

assert window == [ [10, 26, 30],
                   [26, 30, 32],
                   [30, 32, 27],
                   [32, 27, 14],
                   [27, 14, 19],
                   [14, 19, 22],
                   [19, 22, 40],
                   [22, 40, 14] ]
                   
def windowAvg  = window*.sum()*.intdiv( 3 )
assert windowAvg == [22, 29, 29, 24, 20, 18, 27, 25]

def items   = [ 'ham', 30, 'cheese', 20, 'steak', 95 ]
def itemMap = items.collate( 2 ).collectEntries()

assert itemMap == [ ham:30, cheese:20, steak:95 ]

def range   = 1..20
def (odds,evens) = range.collate( 2 ).transpose()

assert odds  == (1..19).step( 2 ) // odd numbers 1 - 19
assert evens == (2..20).step( 2 ) // even numbers 2 - 20

Monday, February 27, 2012

Regex look-ahead/behind syntax

//http://groovy.codehaus.org/Regular+Expressions
def r = /e+/
def str = 'me cheese please'
def m = str =~ r

assert m.size() == 5
println m*.toString() //[e, ee, e, e, e]

/////////////////////////////

def r = /(This boy) is/
def str = 'This boy is 10. This boy wants chocolate. This boy is tall.'
def m = str =~ r

assert m.size() == 2
assert m.collect { it[1] } == ['This boy','This boy']

/////////////////////////////

assert "abc".replaceAll(/(a)(b)(c)/, "\$1\$3") == 'ac' //back references

/////////////////////////////

//http://www.regular-expressions.info/captureall.html
r = /((?:abc|123)+).*?/
str = '123abc 123abc123'
m = str =~ r

assert m.size() == 2
println m*.toString()
print m[0][1..-1]
println m[1][1..-1]

/////////////////////////////

//password of 8 characters long and two non-letters
def r1 = /.*[^a-zA-Z].*[^a-zA-Z].*(?<=.{7})/  //look-behind ?<=

assert 'abc' !=~ r1
assert 'abcde12' !=~ r1
assert 'abcdef12' ==~ r1
assert 'abc1defgggg2' ==~ r1
assert 'abc1defgggg' !=~ r1

//word is foo$wrd*, store $wrd*
def wrd = 'bar'
def r2 = /foo((?=$wrd)[\w]+)/  //look-ahead ?=

def foo = "foo${wrd}hellow"
assert foo ==~ r2
def m = foo =~ r2
assert m[0][1] == "${wrd}hellow" // note: $wrd not consumed by check, is stored in result

foo = 'foohellow' // no $wrd
assert foo !=~ r2

//ADVANCED/////////////////////////////
def churnText(String text) {
    def points = [[k: ~/(N|n)orth(E|e)ast(ern)?/                                                                , v:'NE'],
              [k: ~/(?>(N|n)orth(W|w)est(ern|:)?)(?! Territories)/                                              , v:'NW'],
              [k: ~/(S|s)outheast(ern)?/                                                                        , v:'SE'],
              [k: ~/(?>(S|s)outh(\s)?(W|w)est(ern)?)(?! Hill| Bend)/                                            , v:'SW'],
              [k: ~/(?>(N|n)orth(ern)?|Upstate)(?! Carolina| Dakota| Platte| Neck| Mariana Islands| Bay|ridge)/ , v:'N' ],
              [k: ~/(E|e)ast(ern)?/                                                                             , v:'E' ],
              [k: ~/(?>(S|s)outh(ern|side)?)(?! Carolina| Dakota)/                                              , v:'S' ],
              [k: ~/(?!(?<=George ))(?>(W|w)est(ern| of the)?)(?! Virginia| Palm Beach)/                        , v:'W' ],
              [k: ~/(?>(C|c)entral|Center|Middle|the middle section of the)(?!town| Peninsula| Tennessee|ia)/   , v:'C' ]]
    
    points.each {p ->
      def matcher = (text =~ p.k)
      text = matcher.replaceAll(p.v)
      println "p.v: ${p.v} text: $text"
    }
}

churnText('Northwest Virginia')
println '='*40
churnText('NorthWestern Territories')
println '='*40
churnText('East George West')
return

Thursday, February 23, 2012

Swing Notification Popup

//see: http://groovy.codehaus.org/GUI+Programming+with+Groovy

import groovy.swing.*
import java.awt.*
import javax.swing.*
import javax.swing.border.*
import groovy.util.slurpersupport.NodeChild as Node
 
public class Notify { 
 def sb = new SwingBuilder()

 public static void main(String[] args) {
  // creates and displays itself
  new Notify(args)
 }

 public Notify(String[] args){
  // arg is path to xml message file, 
  // will be deleted after popup displayed
  if (args.size() != 1) return 
  
  String appTitle = ".:. Notification .:."
  String filePath = args[0]
  Color backgroundColor = Color.yellow
  Border emptyBorder = BorderFactory.createMatteBorder(5, 5, 5, 5, backgroundColor)
    
  Toolkit tk = Toolkit.getDefaultToolkit()
  Dimension screenSize = tk.getScreenSize()
  final int WIDTH = screenSize.width
  final int HEIGHT = screenSize.height
  
  int w = WIDTH / 2
  int h = HEIGHT / 2
  
  int x = (WIDTH / 2) - (w / 2)
  int y = (HEIGHT / 2) - (h / 2) - 50
  
  Font fontSubject = new Font("Serif", Font.PLAIN, 24)
  Font fontMessage = new Font("Serif", Font.PLAIN, 16)
  
  //generate frame//
  sb.dialog(id:"popupBox", title:appTitle, visible:true, alwaysOnTop:true, defaultCloseOperation:JFrame.DISPOSE_ON_CLOSE, resizable:false, location:[x, y], size:[w, h]) 
  {
   borderLayout()
   label(id:"subject", constraints:BorderLayout.NORTH, horizontalAlignment:JTextField.CENTER, font:fontSubject, "SUBJ")
   
   panel(constraints:BorderLayout.CENTER){
    gridLayout(cols:1, rows:1, hgap:1, vgap:1)
    scrollPane(border:emptyBorder) {
     textArea(id:"message", editable:false, lineWrap:true, wrapStyleWord:true, font:fontMessage, "MESG")
    }
   }
  }
  def frame = sb.popupBox
  
  //decorate frame color//
  def cp = frame.contentPane
  cp.background = backgroundColor
  sb.message.background = cp.background
  
  //populate frame data//
  File xmlFile
  Node root
  try {
   xmlFile = new File(filePath)
   root = new XmlSlurper().parse(xmlFile)
   //println root.getClass().name
  } 
  catch (Exception) {
   xmlFile = new File("")
   root = new XmlSlurper().parseText('''
    Error
    Sorry, file path or XML syntax error.
    ''')
  }
  
  sb.subject.text = root.subject.text() // if not found, subject UI label is hidden
  sb.message.text = root.message.text() ? 
   root.message.text().replaceAll('\\\\n', System.getProperty( "line.separator" )) :
   'Sorry, empty notification.'
  
  //display form//
  frame.show()
  
  try {
   xmlFile.delete()
  } catch (Exception ignore) {}
 }
}

Thursday, February 16, 2012

Shell/Command line execution

//def cmd = "cmd /C dir"
def cmd = ["cmd","/C","dir g*.bat"] // more flexible format

//Groovyish Java//
Runtime r = Runtime.runtime
Process p = r.exec(cmd.toArray(new String()))
BufferedReader inp = new BufferedReader(new InputStreamReader(p.getInputStream()))
while (line = inp.readLine()) { println line }

//Groovy!//
println cmd.execute().text

Friday, February 10, 2012

Colt - Random Number Generators

/*
 * see: http://acs.lbl.gov/software/colt/
 */
@Grapes(
    @Grab(group='colt', module='colt', version='1.2.0')
)
import cern.jet.random.*

println Binomial.staticNextInt(500,0.5d)
println ChiSquare.staticNextDouble(10.0d)
println Exponential.staticNextDouble(1.0d)
println ExponentialPower.staticNextDouble(1.0d)
println Normal.staticNextDouble(10.0d,1.0d)
println Poisson.staticNextInt(100.0d)
println Uniform.staticNextDoubleFromTo(1.0d,100.0d)
println VonMises.staticNextDouble(10.0d)

Apache Commons Collections

@Grapes(
    @Grab(group='commons-collections', module='commons-collections', version='3.2.1')
)
import org.apache.commons.collections.*
import org.apache.commons.collections.map.*
import org.apache.commons.collections.bidimap.*

IterableMap map1 = [a:1, b:2] as HashedMap
map1.each {
    print it.key
    println it.value
}

OrderedMap map = new LinkedMap()
map.with {
    put("FIVE", "5")
    put("SIX", "6")
    put("SEVEN", "7")
    assert firstKey() == "FIVE"
    assert nextKey("FIVE") == "SIX" 
    assert nextKey("SIX")  == "SEVEN"
}

BidiMap bidi = new TreeBidiMap()
bidi.with {
    put("SIX", "6")
    assert get("SIX") == "6"
    assert get("SIX") == "6"
    assert getKey("6") == "SIX"
    removeValue("6")
    assert getKey("SIX") == null
    put("ONE", "1")
}
BidiMap inverse = bidi.inverseBidiMap()  // returns a map with keys and values swapped
assert inverse.getKey("ONE") == "1"

Buffer buffer = new UnboundedFifoBuffer()
buffer.with {
    add("ONE")
    add("TWO")
    add("THREE")
    assert remove() == "ONE"
    assert remove() == "TWO"
}

Bag bag = new HashBag()
bag.with {
    add("ONE", 6)  // add 6 copies of "ONE"
    remove("ONE", 2)  // removes 2 copies of "ONE"
    assert getCount("ONE") == 4
}

Trove - high speed regular and primitive collections

/*
 * see: http://trove.starlight-systems.com/
 */
@Grapes(
    @Grab(group='net.sf.trove4j', module='trove4j', version='3.0.2')
)
import gnu.trove.set.*
import gnu.trove.set.hash.*
import gnu.trove.list.*
import gnu.trove.list.array.*
import gnu.trove.list.linked.*
import gnu.trove.map.*
import gnu.trove.map.hash.*

//Most Trove classes start with the letter "T" to indicate that they're part of the Trove library.
THashSet s = new THashSet()
100.times { i ->
  s.add ((i / 2).toInteger())
}
assert s.size() == 50
assert s.contains(0)

TIntArrayList a = new TIntArrayList()
100.times { i ->
  a.add ((i / 3).toInteger())
}
assert a.size() == 100
assert a.get(0) == 0

TIntLinkedList l = new TLinkedList()
100.times { i ->
  l.add ((i / 4).toInteger())
}
assert l.size() == 100
assert l.get(0) == 0

THashMap m = new THashMap()
m['a'] = 1
m.b = 2
assert m.a == 1

Thursday, February 9, 2012

Google Guava

/*
 * see: http://code.google.com/p/guava-libraries/
 * grails caching idea: http://refactr.com/blog/2012/05/grails-in-memory-cache-using-googles-guava-library/
 */
@Grapes([
     @Grab("com.google.guava:guava:14.0.1")
])
import java.util.concurrent.TimeUnit
import com.google.common.primitives.Ints
import com.google.common.collect.Iterables
import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableMap
import com.google.common.hash.Hashing
import com.google.common.cache.Cache
import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader

List list = [1,2,3,3]
assert Iterables.frequency(list, 2) == 1
assert Iterables.frequency(list, 3) == 2

String temp = "test"
md5 = Hashing.md5()
String hash = md5.newHasher().putBytes(temp as byte[]).hash()
assert hash != temp
assert hash == "098f6bcd4621d373cade4e832627b4f6"

ImmutableList of = ImmutableList.of("a", "b", "c", "d");
// Same one for map
ImmutableMap map = ImmutableMap.of("key1", "value1", "key2", "value2");
//list of ints
List theList = Ints.asList(1, 2, 3, 4, 522, 5, 6);

//see: https://code.google.com/p/guava-libraries/wiki/CachesExplained
Cache cache = 
CacheBuilder.newBuilder()
  .weakKeys()
  .maximumSize(10000)
  .expireAfterWrite(10, TimeUnit.MINUTES)
  .build( new CacheLoader() {
    @Override
    public String load(Integer key) throws Exception {
      return retreveStringForKey(key);
    }
    @Override
    public Object load(Object o) { return o; } //???
  });

cache.metaClass.propertyMissing { k -> delegate.get(k) }
cache.metaClass.propertyMissing { k, v -> delegate.put(k, v) }
cache["a"] = 9
assert cache.size() == 1
assert cache["a"] == 9

Wednesday, February 8, 2012

Java2Html

@Grapes(
    @Grab(group='de.java2html', module='java2html', version='5.0')
)
import de.java2html.*;
import de.java2html.options.*;

String javaText = '''
/**
 * This is about ClassName.
 * {@link com.yourCompany.aPackage.SuperClass}
 * @author author
 */
public class ClassName extends SuperClass {
  /* This comment may span multiple lines. */
  private int integer = 0;
  public final static char character = 'A';
  // This comment may span only this line
  private String string = "zero";
}
'''

JavaSourceConversionSettings conversionOptions = new JavaSourceConversionSettings(new JavaSourceConversionOptions());
String htmlText = Java2Html.convertToHtmlPage(javaText, conversionOptions);
println (htmlText)

Tuesday, February 7, 2012

Geb Web Test

//updated Jan 12 2013
//check out Geb/Phantomjs integration via RemoteWebDriver support!

@Grapes([
     @Grab("junit:junit-dep:4.8.2"),
     @Grab("org.codehaus.geb:geb-junit4:0.7.2"),  //soon to go 0.9.0
     @Grab("org.seleniumhq.selenium:selenium-firefox-driver:2.28.0"),
     @Grab("org.seleniumhq.selenium:selenium-remote-driver:2.28.0"),
     @Grab("org.seleniumhq.selenium:selenium-support:2.28.0")
])
import geb.*
import geb.driver.CachingDriverFactory
import org.openqa.selenium.*
import org.openqa.selenium.remote.*
//import org.openqa.selenium.firefox.FirefoxProfile
//import org.openqa.selenium.firefox.FirefoxDriver
//import java.awt.Robot // see http://docs.oracle.com/javase/7/docs/api/java/awt/Robot.html#createScreenCapture(java.awt.Rectangle)


def cachedDriver = CachingDriverFactory.clearCacheAndQuitDriver() // clean-up old window & driver if any :)

File path = new File("C:\\geb-test\\")
path.mkdirs()

String searchFor = "dogs" // or null = off

String downloadImgURL = 'http://freemailtemplates.com/wp-content/themes/psdfiles-freemailtemplates/images/download-button.png' // or null = off
String downloadImgPathFile = path.absolutePath+'\\pic.png'

String screenshotURL = 'http://www.yahoo.com' // or null = off
String screenshotPathFile = path.absolutePath+'\\screenshot.png'
// NOTE: these two webdrivers ONLY init'ed for the URL page screenshots (which need a headless/remote browser like phantomjs) //
// you could probably just go to the URL and generate a report, too...? //
final RemoteWebDriver rdriver
final WebDriver augmentedDriver
if (screenshotURL) {
    try {
        rdriver = new RemoteWebDriver( "http://localhost:9134".toURL(), DesiredCapabilities.firefox() )
        augmentedDriver = new Augmenter().augment(rdriver)
    } 
    catch (Exception e) { screenshotURL = null }
}

// NOTE: config ONLY init'ed for reporting purposes //
def config = new Browser().getConfig() // steal a default config(??)
config.reportsDir = path

try{

    Browser.drive(config) {
        if (searchFor) {
            go "http://www.google.ca/"
            assert title.contains("Google")
            
            // basic searching/reading/etc ////////////////////////////////////////////
            def inputs = $("input, button")
            assert inputs.size() > 2
            inputs.each {
                println ":"+it.value()
            }
            
            // try a real Google search! ////////////////////////////////////////////
            def textSearch = $("form[action='/search'] input[type='text']")
            assert textSearch.size() == 1

            textSearch.value( searchFor )
            
            def buttonSearch = waitFor { $("input[type='button'], button") }.findAll{ it.text().toLowerCase().contains("search") }
            if (buttonSearch.size() == 0)
                // try another DOM node search //
                buttonSearch = waitFor { $("input[type='button']#gbqfb, button#gbqfb", 0) }
            
            assert buttonSearch.size() == 1
            
            buttonSearch.click()
            
            def items = waitFor { $("li.g") }
            // show the first item's text
            println items[0].text()
                
            def imgs = $("img")
            def srcs = imgs*.@src
            srcs.each { src ->
                // show the img sources
                println "img: " + (src ?: 'n/a')
            }
        }

        // try another page! ////////////////////////////////////////////
        go "http://cnn.com"
        assert title.contains("CNN.com")
        println ">>>" + title

        // try to dump the page's HTML and screenshot! ////////////////////////////////////////////
        reportGroup "cnn"
        report "homepage"

        // try to inject jQuery into the page! ////////////////////////////////////////////
        injectLibrary(js, 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js') ////////////////////////////////////////////
        js."jQuery.noConflict"()

        // try to grab the body's raw HTML! ////////////////////////////////////////////
        String body = ''+js."document.body.innerHTML"+''

        // try a URL file download! ////////////////////////////////////////////
        if (downloadImgURL) {
            try {
                downloadFile(browser, downloadImgURL, downloadImgPathFile)
            }
            catch (Exception e) { println "[ERROR] downloading: ${e.message}\n${e.printStackTrace()}" }
        }

        // try a URL page screenshot! ////////////////////////////////////////////
        if (screenshotURL) {
            try {
                screenshot(augmentedDriver, screenshotURL, screenshotPathFile)
            } 
            catch(Exception e) { println "[ERROR] screenshot: ${e.message}\n${e.printStackTrace()}" }
        }
        
        println '==Done=='

        //close() // close window, not neccesary with CachingDriverFactory.clearCacheAndQuitDriver()
        //quit()  // quit window, not neccesary with CachingDriverFactory.clearCacheAndQuitDriver()
    }

    cachedDriver = CachingDriverFactory.clearCacheAndQuitDriver() // clean-up window & driver if successful :)
    
} 
catch(Exception e) { println "[ERROR] Please try again: ${e.message}" }
//==END MAIN==//


//these util methods all get their context object passed in as a final//
def downloadFile(final Browser browser, String downloadImgURL, String downloadImgPathFile) {
    input = browser.downloadStream(downloadImgURL) // geb function
    output = new BufferedOutputStream(new FileOutputStream(downloadImgPathFile))
    output << input
}

def screenshot(final WebDriver driver, String url, String filename) {
    /*********************************************************
     * Note: you need a headless/remote web server running (like phantomjs)
     *  - beware, this doesn't seem to like HTTP redirects
     *********************************************************/
    driver.get(url)

    final File scrFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE)
    scrFile.renameTo(filename ?: 'screenshot.png')
}

def injectLibrary(final js, String library){
    if (!js."document.body.innerHTML".contains(library))
        js.exec("document.body.appendChild(document.createElement('script')).src='$library'");
    //assert js."document.body.innerHTML".contains(library)
}

Thursday, January 26, 2012

Simple SHA Digest/Hash

import java.security.*

makeDigest = {String msg, int loops = 1, long t1 = (new Date()).getTime(), double q1 = Math.random() ->
    MessageDigest md = MessageDigest.getInstance("SHA")
    (Math.abs(loops) ?: 1).times {
        byte[] randm = {
            ByteArrayOutputStream byteOut = new ByteArrayOutputStream()
            DataOutputStream dataOut = new DataOutputStream(byteOut)
            dataOut.writeLong(t1)
            dataOut.writeDouble(q1)
            return byteOut.toByteArray()
        }()
        md.update(randm)
        md.update(msg.getBytes())
    }
    return md.digest()
}

String user = "admin"
String password = "s3cr3t"

int loops = 1
byte[] hash1 = makeDigest(user+password, loops, 0, 0) // not randomized
byte[] hash2 = makeDigest(user+password) // randomized
assert hash1 != hash2
println "$hash1\n$hash2"

Wednesday, January 25, 2012

File/Directory Traverse

//helpful file properties: http://groovy.codehaus.org/JN2015-Files
 
import groovy.io.FileType

def walkFiles = {filepath, filterOnly, onFind, onEnd = {} ->
    try {
        File f = new File(filepath)
        f.traverse([type:FileType.FILES, nameFilter:filterOnly], onFind)
        onEnd()
    }
    catch (FileNotFoundException e) { println "ERROR: invalid file/directory"}
}

def pf = { file ->
    if (file.name.contains("a"))
        println file.name
}

walkFiles("C:\\123", ~/.*\.ico/, pf)

Tuesday, January 24, 2012

FastMap and IdentityHashMap

@Grapes(
    @Grab(group='javolution', module='javolution', version='5.5.1')
)
import javolution.util.FastMap // also FastSet, FastList

Map labels1 = new FastMap().shared()
Map labels2 = [:] as IdentityHashMap // unsorted

100.times { i ->
    labels1[String.valueOf(i)] = i*i
    labels2[String.valueOf(i)] = i*i
}

assert labels1 == labels2.sort()

see http://javolution.org/target/site/apidocs/javolution/util/FastMap.html

Fibonacci

/**
 * Fibonacci series:
 * the sum of two elements defines the next
 */

int LIMIT = 1000

(a,b) = [0,1]
while (b < LIMIT) {
    print "$b "
    (a,b) = [b, a+b]
}

(source)