Tuesday, June 6, 2017

user agent via simple spring cli groovy script

Looking for a simple way to test out spring boot cli and determine user agent information for a browser in 3 steps?

Steps


  • Step 1: write groovy script to provide restful interface
  • Step 2: run groovy script via spring boot cli
  • Step 3: hit the server from your web browser



Step 1: Groovy Script  'useragent.groovy':


import javax.servlet.http.HttpServletRequest;

@RestController
class MyWebApplication {
  @RequestMapping("/useragent")
  String useragent(HttpServletRequest request) {
    String x = "user agent: " + request.getHeader("User-Agent")  println x
    x
  }
}

Step 2: Run the script


$ spring run useragent.groovy -- --server.port=9900



Step 3 Hit the server:


  • Now hit the script from a browser.
  • URL:  http://localhost:9900/useragent





Computer
Browser
User Agent
Chromebook 11
Chrome
Mozilla/5.0 (X11; CrOS x86_64 9202.64.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.146 Safari/537.36
Mac Sierra
Chrome Version 58.0.3029.110 (64-bit)
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
Mac Sierra
Firefox 53.0.2 (64-bit)
Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:53.0) Gecko/20100101 Firefox/53.0
Mac Sierra
Safari Version 10.1.1 (12603.2.4)
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/603.2.4 (KHTML, like Gecko) Version/10.1.1 Safari/603.2.4
Windows 10 (VM)
IE 11
Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko
Windows 10 (VM)
Edge
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586

re-learning spring boot cli

So our project is ready to upgrade spring once again.  We do this every 4-5 years.  I know, far too slowly...don't ask.

Anyways here I'll be writing about my experience.

I usually take the "I don't know what _____ is approach" meaning I am interested in learning fresh the usage patterns of a new technology, or even a technology that I have been away from for a while.  The spring environment is an example.

So there is something called the Software Developer Kit Manager (sdk).  I'll be using it to manage some of the installation details. [note: I had its predecessor .gvm installed, but I uninstalled it first] Once it is installed you can run the following to install spring boot:

sdk install springboot

Verify it's been successfully installed:

$ spring --version
Spring Boot v1.5.3.RELEASE

Great, so now we have spring boot command-line interface (CLI) installed.  We can get a web server up and running in no time.

Create a file called helloWorld.groovy and load with the following contents:

@RestController
class MyWebApplication {
  @RequestMapping("/")
  String home() {
    "PRETTY SLICK Hello World of Spring CLI"
  }

}

This is a groovy script file and you may notice that the class described 'MyWebApplication' bares no relationship to the file name 'helloWorld.groovy'.  Don't sweat it just continue.

We can run this with the spring CLI:

$ spring run helloWorld.groovy

When you do run the file you will see a lot of information scroll down the page.  Behind the scenes a server is started and it is listening on port 8080.  You can go to the page in browser http://localhost:8080 or from the command line type:

$ curl http://localhost:8080

The output will be something like:
PRETTY SLICK Hello World of Spring CLI

This is pretty cool.  With very little effort we have a web server running and producing some info.

Let's take it a bit further.  Let's convert our script into an executable jar file (myApp.jar).  No worries, just type:

$ spring jar myApp.jar helloWorld.groovy

Once built, we can run the jar without any knowledge of spring CLI.  Just run:

$ java -jar myApp.jar

Again, we have a running web server listening on port 8080.  And, like before, we can access it by hitting http://localhost:8080 and we get the same output:
PRETTY SLICK Hello World of Spring CLI

Hmm...what if we want to listen on a port different than the standard port 8080?  No problem.  We take advantage of one of Spring's system properties 'server.port'.  Let's listen on port 8765 (instead of 8080).  Here's how:

$ java -Dserver.port=8765 -jar myApp.jar

To get the output we would hit url:  http://localhost:8765 and we get the same output as before.  Pretty cool.

By the way, we could have done the change of port number without even creating an executable jar from within the spring cli:

$ spring run helloWorld.groovy -- --server.port=8765

The one thing that becomes obvious is that there are many ways to accomplish a similar task.  When prototyping or wanting to get something going super fast I prefer to use the Spring CLI.  You can get some idea of what you are up against before formalizing activities in java.

What about testing the code?  We can actually test this web controller using the familiar junit semantics.

Create a file called helloWorldTests.groovy and populate with:

class MyApplicationTests {

  @Test
  void checkRestCall() {
    assertEquals("PRETTY SLICK Hello World of Spring CLI", new MyWebApplication().home())
  }

}

Run this by:

$ spring test helloworld.groovy helloworldtests.groovy

The output:
.
Time: 0.214

OK (1 test)

Think about what we just did.  As part of our testing we bootstrapped a web server, made a call to it and checked the expected results.




Sunday, May 14, 2017

CWIID python code to echo buttons on nintendo Wii Remote


Let's say you have a Nintendo Wii Remote connected to your Raspberry Pi via bluetooth.  You want to see which controls (buttons, arrow keys, etc.) are getting activated on the Wii Remote.  No problem.

The following Python code will as you to pair your Wii Remote with your Pi (by pushing the 1 and 2 buttons).

Then it will echo which buttons/controls on the device you are activating.



import cwiid
from time import sleep

def initWiimote():
    global wm
    print "push 1+2 buttons to pair"
    wm = cwiid.Wiimote()
    print "initWiimote, wm=",wm

def enableButtonReporting():
    wm.rpt_mode = cwiid.RPT_BTN

# Example:
# {'led': 15, 'rpt_mode': 2, 'ext_type': 0, 'buttons': 2, 'rumble': 0, 'error': 0, 'battery': 147}
def showState():
    print wm.state

def isButtonA():
    return isButton(cwiid.BTN_A)

def isButtonB():
    return isButton(cwiid.BTN_B)

def isButtonMinus():
    return isButton(cwiid.BTN_MINUS)

def isButtonPlus():
    return isButton(cwiid.BTN_PLUS)

def isButtonHome():
    return isButton(cwiid.BTN_HOME)

def isButton1():
    return isButton(cwiid.BTN_1)

def isButton2():
    return isButton(cwiid.BTN_2)

def isButtonUp():
    return isButton(cwiid.BTN_UP)
def isButtonDown():
    return isButton(cwiid.BTN_DOWN)
def isButtonLeft():
    return isButton(cwiid.BTN_LEFT)
def isButtonRight():
    return isButton(cwiid.BTN_RIGHT)

def isButton(btnConstant):
    #print "isButton, btnConstant=", btnConstant
    return bool(wm.state['buttons'] & btnConstant)

def listCwiidConstants():
    dir(cwiid)

def useLedCountTo15Binary():
    for i in range(16):
        wm.led = i
        time.sleep(.5)

def verboseArrows():
    if isButtonUp():
        print "button up"
    if isButtonDown():
        print "button down"
    if isButtonLeft():
        print "button left"
    if isButtonRight():
        print "button right"

def verboseButtons():
    if isButton1():
        print "button 1"
        print "wm.state:",wm.state
    if isButton2():
        print "button 2"
    if isButtonA():
        print "button A"
    if isButtonB():
        print "button B"
    if isButtonHome():
        print "button home"
    if isButtonPlus():
        print "button plus"
    if isButtonMinus():
        print "button minus"

def verbose():
    verboseArrows()
    verboseButtons()

def listWhichButtonsAreAvailable():
    '''
    ['BATTERY_MAX', 'BTN_1', 'BTN_2', 'BTN_A', 'BTN_B', 'BTN_DOWN', 'BTN_HOME', 'BTN_LEFT', 'BTN_MINUS', 'BTN_PLUS', 'BTN_RIGHT', 'BTN_UP', 'CLASSIC_BTN_A', 'CLASSIC_BTN_B', 'CLASSIC_BTN_DOWN', 'CLASSIC_BTN_HOME', 'CLASSIC_BTN_L', 'CLASSIC_BTN_LEFT', 'CLASSIC_BTN_MINUS', 'CLASSIC_BTN_PLUS', 'CLASSIC_BTN_R', 'CLASSIC_BTN_RIGHT', 'CLASSIC_BTN_UP', 'CLASSIC_BTN_X', 'CLASSIC_BTN_Y', 'CLASSIC_BTN_ZL', 'CLASSIC_BTN_ZR', 'CLASSIC_LR_MAX', 'CLASSIC_L_STICK_MAX', 'CLASSIC_R_STICK_MAX', 'CMD_LED', 'CMD_RPT_MODE', 'CMD_RUMBLE', 'CMD_STATUS', 'ConvertMesgArray', 'ERROR_COMM', 'ERROR_DISCONNECT', 'EXT_BALANCE', 'EXT_CLASSIC', 'EXT_MOTIONPLUS', 'EXT_NONE', 'EXT_NUNCHUK', 'EXT_UNKNOWN', 'FLAG_CONTINUOUS', 'FLAG_MESG_IFC', 'FLAG_MOTIONPLUS', 'FLAG_NONBLOCK', 'FLAG_REPEAT_BTN', 'IR_SRC_COUNT', 'IR_X_MAX', 'IR_Y_MAX', 'LED1_ON', 'LED2_ON', 'LED3_ON', 'LED4_ON', 'MAX_READ_LEN', 'MESG_ACC', 'MESG_BALANCE', 'MESG_BTN', 'MESG_CLASSIC', 'MESG_ERROR', 'MESG_IR', 'MESG_MOTIONPLUS', 'MESG_NUNCHUK', 'MESG_STATUS', 'MESG_UNKNOWN', 'NUNCHUK_BTN_C', 'NUNCHUK_BTN_Z', 'PHI', 'PSI', 'RPT_ACC', 'RPT_BALANCE', 'RPT_BTN', 'RPT_CLASSIC', 'RPT_EXT', 'RPT_IR', 'RPT_MOTIONPLUS', 'RPT_NUNCHUK', 'RPT_STATUS', 'RW_DECODE', 'RW_EEPROM', 'RW_REG', 'SEND_RPT_NO_RUMBLE', 'THETA', 'Wiimote', 'X', 'Y', 'Z', '__doc__', '__file__', '__name__', '__package__']
    '''
    print "dir(cwiid)=",dir(cwiid)

initWiimote()
enableButtonReporting()
while (True):
    verbose()
    sleep(0.5)

Wednesday, April 12, 2017

Monday, April 10, 2017

Docker Menu and About Docker




Docker File System

Docker File System:

/Applications/Docker.app
├── Contents
│   ├── Frameworks
│   │   ├── Bugsnag.framework
│   │   │   ├── Resources -> Versions/Current/Resources
│   │   │   └── Versions
│   │   │       ├── A
│   │   │       │   ├── Resources
│   │   │       │   └── _CodeSignature
│   │   │       └── Current -> A
│   │   ├── KeychainAccess.framework
│   │   │   ├── Resources -> Versions/Current/Resources
│   │   │   └── Versions
│   │   │       ├── A
│   │   │       │   ├── Resources
│   │   │       │   └── _CodeSignature
│   │   │       └── Current -> A
│   │   ├── Result.framework
│   │   │   ├── Resources -> Versions/Current/Resources
│   │   │   └── Versions
│   │   │       ├── A
│   │   │       │   ├── Resources
│   │   │       │   └── _CodeSignature
│   │   │       └── Current -> A
│   │   └── Sparkle.framework
│   │       ├── Resources -> Versions/Current/Resources
│   │       └── Versions
│   │           ├── A
│   │           │   ├── Resources
│   │           │   │   ├── Autoupdate.app
│   │           │   │   │   └── Contents
│   │           │   │   │       ├── MacOS
│   │           │   │   │       └── Resources
│   │           │   │   │           ├── ar.lproj
│   │           │   │   │           ├── ca.lproj
│   │           │   │   │           ├── cs.lproj
│   │           │   │   │           ├── da.lproj
│   │           │   │   │           ├── de.lproj
│   │           │   │   │           ├── el.lproj
│   │           │   │   │           ├── en.lproj
│   │           │   │   │           ├── es.lproj
│   │           │   │   │           ├── fi.lproj
│   │           │   │   │           ├── fr.lproj
│   │           │   │   │           ├── he.lproj
│   │           │   │   │           ├── is.lproj
│   │           │   │   │           ├── it.lproj
│   │           │   │   │           ├── ja.lproj
│   │           │   │   │           ├── ko.lproj
│   │           │   │   │           ├── nb.lproj
│   │           │   │   │           ├── nl.lproj
│   │           │   │   │           ├── pl.lproj
│   │           │   │   │           ├── pt_BR.lproj
│   │           │   │   │           ├── pt_PT.lproj
│   │           │   │   │           ├── ro.lproj
│   │           │   │   │           ├── ru.lproj
│   │           │   │   │           ├── sk.lproj
│   │           │   │   │           ├── sl.lproj
│   │           │   │   │           ├── sv.lproj
│   │           │   │   │           ├── th.lproj
│   │           │   │   │           ├── tr.lproj
│   │           │   │   │           ├── uk.lproj
│   │           │   │   │           ├── zh_CN.lproj
│   │           │   │   │           └── zh_TW.lproj
│   │           │   │   ├── ar.lproj
│   │           │   │   ├── ca.lproj
│   │           │   │   ├── cs.lproj
│   │           │   │   ├── da.lproj
│   │           │   │   ├── de.lproj
│   │           │   │   ├── el.lproj
│   │           │   │   ├── en.lproj
│   │           │   │   ├── es.lproj
│   │           │   │   ├── fi.lproj
│   │           │   │   ├── fr.lproj
│   │           │   │   ├── fr_CA.lproj -> fr.lproj
│   │           │   │   ├── he.lproj
│   │           │   │   ├── is.lproj
│   │           │   │   ├── it.lproj
│   │           │   │   ├── ja.lproj
│   │           │   │   ├── ko.lproj
│   │           │   │   ├── nb.lproj
│   │           │   │   ├── nl.lproj
│   │           │   │   ├── pl.lproj
│   │           │   │   ├── pt.lproj -> pt_BR.lproj
│   │           │   │   ├── pt_BR.lproj
│   │           │   │   ├── pt_PT.lproj
│   │           │   │   ├── ro.lproj
│   │           │   │   ├── ru.lproj
│   │           │   │   ├── sk.lproj
│   │           │   │   ├── sl.lproj
│   │           │   │   ├── sv.lproj
│   │           │   │   ├── th.lproj
│   │           │   │   ├── tr.lproj
│   │           │   │   ├── uk.lproj
│   │           │   │   ├── zh_CN.lproj
│   │           │   │   └── zh_TW.lproj
│   │           │   └── _CodeSignature
│   │           └── Current -> A
│   ├── Library
│   │   ├── LaunchServices
│   │   └── LoginItems
│   │       └── DockerHelper.app
│   │           └── Contents
│   │               ├── Frameworks
│   │               ├── MacOS
│   │               ├── Resources
│   │               └── _CodeSignature
│   ├── MacOS
│   ├── Resources
│   │   ├── Base.lproj
│   │   ├── bin
│   │   ├── etc
│   │   ├── lib
│   │   ├── moby
│   │   ├── qemu
│   │   └── uefi
│   └── _CodeSignature
└── bower_components
    └── tree
        └── src

118 directories

Docker update

Finally got around to updating my docker installation on mac.  It went flawlessly. :-)

After


$ docker version
Client:
 Version:      17.03.1-ce
 API version:  1.27
 Go version:   go1.7.5
 Git commit:   c6d412e
 Built:        Tue Mar 28 00:40:02 2017
 OS/Arch:      darwin/amd64

Server:
 Version:      17.03.1-ce
 API version:  1.27 (minimum version 1.12)
 Go version:   go1.7.5
 Git commit:   c6d412e
 Built:        Fri Mar 24 00:00:50 2017
 OS/Arch:      linux/amd64
 Experimental: true
$ docker-compose version
docker-compose version 1.11.2, build dfed245
docker-py version: 2.1.0
CPython version: 2.7.12
OpenSSL version: OpenSSL 1.0.2j  26 Sep 2016
$ docker-machine version
docker-machine version 0.10.0, build 76ed2a6

Before


$ docker version
Client:
 Version:      1.12.0
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   8eab29e
 Built:        Thu Jul 28 21:15:28 2016
 OS/Arch:      darwin/amd64

Server:
 Version:      1.12.0
 API version:  1.24
 Go version:   go1.6.3
 Git commit:   8eab29e
 Built:        Thu Jul 28 21:15:28 2016
 OS/Arch:      linux/amd64
$ docker-compose version
docker-compose version 1.8.0, build f3628c7
docker-py version: 1.9.0
CPython version: 2.7.9
OpenSSL version: OpenSSL 1.0.2h  3 May 2016
$ docker-machine version
docker-machine version 0.8.0, build b85aac1