Compare commits

...

10 Commits

Author SHA1 Message Date
Jonathan Bernard
49b7524eb7 Migrated common build to 1.10 (from 1.3). 2013-08-27 19:03:27 -05:00
Jonathan Bernard
c3dfb014a2 Reworking and expanding documentation to use JLP. 2012-01-23 13:09:59 -06:00
Jonathan Bernard
6041c284ec Added online documentation. 2011-06-15 09:50:23 -05:00
Jonathan Bernard
f7d35ec39c Added confirmation interactions and messages to actions that create permanent change. 2011-06-14 18:04:06 -05:00
Jonathan Bernard
5ae49f2d3e Fixed typo in logging call. 2011-06-14 17:46:01 -05:00
Jonathan Bernard
0749145ce0 Added error message for unimplemented commands. 2011-06-14 17:34:29 -05:00
Jonathan Bernard
9819315fa9 Started adding real documentation.
The documentation style is meant for a doc system I have not written yet.
Existing systems--javadoc and groovydoc--are not sufficient, primarily due
to their reliance on HTML. I envision something that crosses javadoc-style
annotations with python-like use of reStructuredText and Docco-like inline
presentation of the code with its comments.
2010-12-10 15:15:55 -06:00
Jonathan Bernard
68cc604d6b Fixed a small bug in how list references were being parsed. 2010-12-10 11:32:52 -06:00
Jonathan Bernard
3b1d919c5a Implemented 'delete' command.
Basic implementation for displaying a list of users.
2010-12-06 07:28:01 -06:00
Jonathan Bernard
0c3a11d567 Renamed README to take advantage of github's nice formatting. 2010-11-15 17:37:42 -06:00
8 changed files with 1225 additions and 660 deletions

View File

View File

@ -1,7 +1,7 @@
<project name="gritter" basedir=".">
<project name="gritter" basedir="." default="ng-deploy">
<property file="project.properties"/>
<import file="jdb-build-1.3.xml"/>
<import file="jdb-build-1.10.xml"/>
<target name="init">
<mkdir dir="${build.dir}/main/classes"/>

View File

@ -39,14 +39,14 @@
*listuser*/*list id*
[X] *listName*, *isPublic*, *description*
[ ] delete/destroy/remove
[ ] status
[ ] *status_id*
[ ] list
[ ] member
[ ] *list id* || *list name*, *user id*
[ ] subscription
[ ] *list id*
[X] delete/destroy/remove
[X] status
[X] *status_id*
[X] list
[X] member
[X] *list id* || *list name*, *user id*
[X] subscription
[X] *list id*
[ ] follow
[ ] *user*

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<project name="Jonathan Bernard Build Common">
<project name="Jonathan Bernard Build Common"
xmlns:ivy="antlib:org.apache.ivy.ant">
<property environment="env"/>
@ -16,6 +17,7 @@
<property name="build.dir" value="${basedir}/build"/>
<property name="lib.dir" value="${basedir}/lib"/>
<property name="resources.dir" value="${basedir}/resources"/>
<property name="splash.image" value="splash.png"/>
<!--======== PATHS ========-->
<path id="groovy.classpath">
@ -47,19 +49,42 @@
<target name="-init-groovy">
<taskdef name="groovyc" classpathref="groovy.classpath"
classname="org.codehaus.groovy.ant.Groovyc"/>
<taskdef name="groovy" classpathref="groovy.classpath"
classname="org.codehaus.groovy.ant.Groovy"/>
</target>
<target name="init"/>
<target name="clean" depends="-init">
<delete dir="${build.dir}"/>
</target>
<!--======== LIBRARY TARGETS ========-->
<target name="lib" depends="-lib-local,-lib-ivy"/>
<target name="-lib" depends="-lib-local,-lib-ivy,lib"/>
<target name="lib"/>
<target name="-lib-ivy" unless="${lib.local}"/>
<target name="-init-ivy">
<ivy:settings id="ivy.settings" file="ivysettings.xml"/>
</target>
<target name="-lib-ivy" depends="-init-ivy" unless="${lib.local}">
<ivy:retrieve settingsRef="ivy.settings"
pattern="${lib.dir}/[conf]/[type]/[artifact]-[revision].[ext]"
conf="compile,runtime"/>
</target>
<target name="-lib-groovy" if="${lib.local}">
<copy todir="${build.dir}/lib/runtime/jar">
<fileset dir="${env.GROOVY_HOME}/embeddable"/>
</copy>
</target>
<target name="-lib-local" if="${lib.local}">
<echo message="Resolving libraries locally."/>
<mkdir dir="${build.dir}/lib/compile/jar"/>
<mkdir dir="${build.dir}/lib/runtime/jar"/>
<copy todir="${build.dir}/lib/compile/jar" failonerror="false">
<fileset dir="${lib.dir}/compile/jar"/>
</copy>
@ -84,13 +109,15 @@
<propertyfile file="${versioning.file}">
<entry key="version" value="${new-version}" operation="="
type="string"/>
<entry key="build.number" value="0" type="int" operation="="/>
</propertyfile>
</target>
<!--======== COMPILATION TARGETS ========-->
<target name="-compile-groovy" depends="-init,-init-groovy,lib">
<groovyc srcdir="${src.dir}" destdir="${build.dir}/main/classes"
includeAntRuntime="false">
<target name="-compile-groovy" depends="-init,-init-groovy,-lib,-lib-groovy">
<mkdir dir="${build.dir}/main/classes"/>
<groovyc srcdir="${src.dir}/main" destdir="${build.dir}/main/classes"
includeAntRuntime="false" fork="true">
<classpath>
<path refid="groovy.classpath"/>
@ -100,8 +127,9 @@
</groovyc>
</target>
<target name="-compile-java" depends="-init,lib">
<javac srcdir="${src.dir}" destdir="${build.dir}/main/classes"
<target name="-compile-java" depends="-init,-lib">
<mkdir dir="${build.dir}/main/classes"/>
<javac srcdir="${src.dir}/main" destdir="${build.dir}/main/classes"
includeAntRuntime="false" classpathref="compile-libs"/>
</target>
@ -109,8 +137,9 @@
<!--======== JUNIT TARGETS ========-->
<target name="-compile-tests-groovy" depends="-init,compile">
<groovyc srcdir="${test.dir}" destdir="${build.dir}/test/classes"
includeAntRuntime="false">
<mkdir dir="${build.dir}/test/classes"/>
<groovyc srcdir="${src.dir}/test" destdir="${build.dir}/test/classes"
includeAntRuntime="false" fork="true">
<classpath>
<path refid="groovy.classpath"/>
@ -121,7 +150,8 @@
</target>
<target name="-compile-tests-java" depends="-init,compile">
<javac srcdir="${test.dir}" destdir="${build.dir}/test/classes"
<mkdir dir="${build.dir}/test/classes"/>
<javac srcdir="${src.dir}/test" destdir="${build.dir}/test/classes"
includeAntRuntime="false">
<classpath>
<path refid="compile-libs"/>
@ -152,25 +182,56 @@
<!--======== RESOURCES TARGETS ========-->
<target name="resources" depends="-init">
<mkdir dir="${build.dir}/main/classes"/>
<copy todir="${build.dir}/main/classes" failonerror="false">
<fileset dir="${resources.dir}/main/"/>
</copy>
</target>
<target name="resources-test" depends="-init">
<mkdir dir="${build.dir}/test/classes"/>
<copy todir="${build.dir}/test/classes" failonerror="false">
<fileset dir="${resources.dir}/test/"/>
</copy>
</target>
<!--======== BUILD TARGETS ========-->
<target name="-build-modular"
<target name="-build-modular-lib" unless="executable.jar"
depends="compile,increment-build-number,resources">
<jar destfile="${build.dir}/${name}-${version}.${build.number}.jar"
basedir="${build.dir}/main/classes"/>
</target>
<target name="-build-modular-executable" if="executable.jar"
depends="compile,increment-build-number,resources">
<pathconvert property="jar.classpath" pathsep=" " refid="runtime-libs">
<mapper>
<chainedmapper>
<!-- remove absolute path -->
<flattenmapper />
<!-- add lib/ prefix -->
<globmapper from="*" to="lib/*" />
</chainedmapper>
</mapper>
</pathconvert>
<jar destfile="${build.dir}/${name}-${version}.${build.number}.jar"
basedir="${build.dir}/main/classes">
<manifest>
<attribute name="Main-Class" value="${main.class}"/>
<attribute name="Class-Path" value="${jar.classpath}"/>
<attribute name="SplashScreen-Image" value="${splash.image}"/>
</manifest>
</jar>
</target>
<target name="-build-modular"
depends="-build-modular-lib,-build-modular-executable"/>
<target name="-build-packed-libs"
depends="compile,increment-build-number,resources">

View File

@ -1,7 +1,7 @@
#Thu, 11 Nov 2010 13:10:43 -0600
#Tue, 27 Aug 2013 19:02:29 -0500
lib.local=true
name=gritter
version=0.1
build.number=140
version=1.0
build.number=2
linux.nailgun.classpath.dir=/home/jdbernard/programs/nailgun/classpath
nailgun.classpath.dir=C\:/Documents and Settings/jbernard/My Documents/ng-classpath

View File

@ -1,635 +0,0 @@
package com.jdbernard.twitter
import com.martiansoftware.nailgun.NGContext
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import twitter4j.Paging
import twitter4j.Status
import twitter4j.Twitter
import twitter4j.TwitterFactory
import twitter4j.conf.Configuration
import twitter4j.conf.PropertyConfiguration
public class TwitterCLI {
private static String EOL = System.getProperty("line.separator")
private static TwitterCLI nailgunInst
private Twitter twitter
private Scanner stdin
private Map colors = [:]
private int terminalWidth
private boolean colored
private boolean printStatusTimestamps
private boolean strict
private boolean warnings
private Logger log = LoggerFactory.getLogger(getClass())
public static void main(String[] args) {
TwitterCLI inst = new TwitterCLI(new File(System.getProperty("user.home"),
".gritterrc"))
// trim the last argumnet, not all cli's are well-behaved
args[-1] = args[-1].trim()
inst.run((args as List) as LinkedList)
}
public static void nailMain(NGContext context) {
if (nailgunInst == null)
nailgunInst = new TwitterCLI(new File(
System.getProperty("user.home"), ".gritterrc"))
else
nailgunInst.stdin = new Scanner(context.in)
// trim the last argumnet, not all cli's are well-behaved
context.args[-1] = context.args[-1].trim()
nailgunInst.run((context.args as List) as LinkedList)
}
public static void reconfigure(LinkedList args) {
if (nailgunInst == null) main(args as String[])
else {
nailgunInst = null
nailgunInst = new TwitterCLI(new File(
System.getProperty("user.home"), ".gritterrc"))
nailgunInst.run(args)
}
}
static String wrapToWidth(String text, int width, String prefix, String suffix) {
int lastSpaceIdx = 0;
int curLineLength = 0;
int lineStartIdx = 0;
int i = 0;
int actualWidth = width - prefix.length() - suffix.length()
String wrapped = ""
text = text.replaceAll("[\n\r]", " ")
for (i = 0; i < text.length(); i++) {
curLineLength++
if (curLineLength > actualWidth) {
if (lastSpaceIdx == -1) // we haven't seen a space on this line
lastSpaceIdx = lineStartIdx + actualWidth - 1
wrapped += prefix + text[lineStartIdx..<lastSpaceIdx] + suffix + EOL
curLineLength = 0
lineStartIdx = lastSpaceIdx + 1
i = lastSpaceIdx + 1
lastSpaceIdx = -1
}
if (text.charAt(i).isWhitespace())
lastSpaceIdx = i
}
if (i - lineStartIdx > 1)
wrapped += prefix + text[lineStartIdx..<text.length()]
return wrapped
}
public TwitterCLI(File propFile) {
// load the configuration
Properties cfg = new Properties()
propFile.withInputStream { is -> cfg.load(is) }
// create a twitter instance
twitter = (new TwitterFactory(new PropertyConfiguration(cfg))).getInstance()
// configure the colors
colors.author = new ConsoleColor(cfg.getProperty("colors.author", "CYAN:false"))
colors.mentioned = new ConsoleColor(cfg.getProperty("colors.mentioned", "GREEN:false"))
colors.error = new ConsoleColor(cfg.getProperty("colors.error", "RED:true"))
colors.option = new ConsoleColor(cfg.getProperty("colors.option", "YELLOW:true"))
colors.even = new ConsoleColor(cfg.getProperty("colors.even", "WHITE"))
colors.odd = new ConsoleColor(cfg.getProperty("colors.odd", "YELLOW"))
// configure the terminal width
terminalWidth = (System.getenv().COLUMNS ?: cfg.terminalWidth ?: 79) as int
colored = (cfg.colored ?: 'true') as boolean
strict = (cfg.strict ?: 'false') as boolean
warnings = (cfg.warnings ?: 'true') as boolean
printStatusTimestamps = (cfg."timeline.printTimestamps" ?: 'true') as boolean
stdin = new Scanner(System.in)
}
/* ======== PARSING FUNCTIONS ========*/
public void run(LinkedList args) {
if (args.size() < 1) printUsage()
log.debug("argument list: {}", args)
while (args.peek()) {
def command = args.poll()
switch (command.toLowerCase()) {
case ~/delete|destroy|remove/: delete(args); break
case ~/get|show/: get(args); break // get|show
case ~/help/: help(args); break // help
case ~/post|add|create/: post(args); break // post|add|create
case ~/reconfigure/: reconfigure(args); break // reconfigure
case ~/set/: set(args); break // set
default: // fallthrough
if (strict) {
log.error(color("Unrecognized command: '$command'", colors.error))
} else {
if (warnings) {
println "Command '$command' unrecognized: " +
"assuming this is a parameter to 'show'"
}
args.addFirst(command)
get(args)
}
}
}
}
public void delete(LinkedList args) {
}
public void get(LinkedList args) {
def option = args.poll()
log.debug("Processing a 'get' command, option = {}.", option)
switch(option) {
case "list": showList(args); break
case "lists": showLists(args); break
case ~/subs.*/: showSubscriptions(args); break
case "timeline": showTimeline(args); break
case "user": showUser(args); break
default: args.addFirst(option)
showTimeline(args)
}
}
public void help(LinkedList args) {
log.debug("Processing a 'help' command.")
}
public void post(LinkedList args) {
def option = args.poll()
log.debug("Processing a 'post' command: option = '{}'", option)
if (!option) {
println color("post", colors.option) +
color(" command requires at least two parameters: ",
colors.error) + "gritter post <status|retweet|list> " +
"<options>..."
return
}
switch (option) {
case "status": postStatus(args.poll()); break
case "retweet": retweetStatus(args.poll()); break
case "list": createList(args); break
default: postStatus(option)
}
}
public void set(LinkedList args) {
def option = args.poll()
def value = args.poll()
log.debug("Processing a 'set' command: option = '{}', value = '{}'",
option, value)
if (!value) { // note: if option is null, value is null
println color("set", colors.option) +
color(" command requires two options: ", colors.error) +
"gritter set <param> <value>"
return
}
switch (option) {
case "terminalWidth": terminalWidth = value as int; break
case "colored": colored = value.toLowerCase() ==~ /true|t|on|yes|y/
break
default:
println color("No property named ", colors.error) +
color(option, colors.option) +
color(" exists.", colors.error)
}
}
public void showList(LinkedList args) {
def option = args.poll()
log.debug("Processing a 'show list' command, option = '{}'", option)
switch(option) {
case "members": showListMembers(args); break
case "subscribers": showListSubscribers(args); break
case "subscriptions": showListSubscriptions(args); break
default: args.addFirst(option)
showListTimeline(args)
}
}
public void showLists(LinkedList args) {
def user = args.poll()
log.debug("Processing a 'show lists' command, user = '{}'", user)
if (!user) user = twitter.screenName
printLists(twitter.getUserLists(user, -1)) // TODO paging
}
public void showListMembers(LinkedList args) {
def listRef = parseListReference(args)
log.debug("Processing a 'show list members' command, list = '{}'",
listRef)
if (!listRef) {
println color("show list members", colors.option) +
color(" command requires a list reference in the form of " +
"user/list: ", colors.error) +
"gritter show list members <user/list>"
return
}
printUserList(twitter.getUserListMembers(
listRef.username, listRef.listId, -1)) // TODO paging
}
public void showListSubscribers(LinkedList args) {
def listRef = parseListReference(args)
log.debug("Processing a 'show list subscribers' command, list = '{}'",
listRef)
if (!listRef) {
println color("show list subscribers", colors.option) +
color(" command requires a list reference in the form of " +
"user/list: ", colors.error) +
"gritter show list subscribers <user/list>"
return
}
printUserList(twitter.getUserListSubscribers(
listRef.username, listRef.listId, -1)) // TODO: paging
}
public void showListSubscriptions(LinkedList args) {
def user = args.poll()
log.debug("Processing a 'show list subscriptions' command, list = '{}'",
listRef)
if (!user) user = twitter.screenName
printLists(twitter.getUserListSubscriptions(user, -1)) // TODO: paging
}
public void showListTimeline(LinkedList args) {
if (args.size() < 1) {
println color("show list", colors.option) +
color(" command requires a list reference in the form of " +
"user/list: ", colors.error) +
"gritter show list <user/list>"
return
}
def listRef = parseListReference(args)
log.debug("Showing a list timeline, list = '{}'", listRef)
if (listRef.listId == -1) {
println color("show list", colors.option) +
color(" command requires a list reference in the form of " +
"user/list: ", colors.error) +
"gritter show list <user/list>"
return
}
printTimeline(twitter.getUserListStatuses(
listRef.username, listRef.listId, new Paging())) // TODO: paging
}
public void showTimeline(LinkedList args) {
String timeline = args.poll() ?: "home"
log.debug("Processing a 'show timeline' command, timeline = '{}'",
timeline)
switch (timeline) {
// friends
case "friends": printTimeline(twitter.friendsTimeline); break
// home
case "home": printTimeline(twitter.homeTimeline); break
// mine
case "mine": printTimeline(twitter.userTimeline); break
// public
case "public": printTimeline(twitter.publicTimeline); break
// user
case "user":
String user = args.poll()
if (user) {
if (user.isNumber())
printTimeline(twitter.getUserTimeline(user as int))
else printTimeline(twitter.getUserTimeline(user))
} else println color("No user specified.", colors.error)
break;
default:
println color("Unknown timeline: ", colors.error) +
color(timeline, colors.option)
break;
}
}
public void showUser(LinkedList args) {
def user = args.poll()
log.debug("Processing a 'show user' command, user = '{}'", user)
}
public void createList(LinkedList args) {
def option = args.poll()
switch(option) {
case "member": addListMember(args); break
case "subscription": addListSubscription(args); break
default: args.addFirst(option)
createNewList(args); break
}
}
/* ======== WORKER FUNCTIONS ========*/
public void printLists(def lists) {
int colSize = 0
// fins largest indentation needed
lists.each { list ->
def curColSize = list.user.screenName.length() +
list.slug.length() + list.id.toString().length() + 3
colSize = Math.max(colSize, curColSize)
println colSize
}
lists.each { list ->
println colSize
def col1 = color("@${list.user.screenName}", colors.author) + "/" +
color("${list.slug} (${list.id})", colors.option)
println col1.padLeft(colSize) + ": ${list.memberCount} members " +
"and ${list.subscriberCount} subscribers"
println wrapToWidth(list.description, terminalWidth,
"".padLeft(8), "")
println col1.length()
}
}
public void printTimeline(def timeline) {
log.debug("Printing a timeline: {}", timeline)
Map formatOptions = [:]
formatOptions.authorLength = 0
timeline.each { status ->
if (status.user.screenName.length() > formatOptions.authorLength)
formatOptions.authorLength = status.user.screenName.length()
}
formatOptions.indent = "".padLeft(formatOptions.authorLength + 2)
timeline.eachWithIndex { status, rowNum ->
formatOptions.rowNum = rowNum
println formatStatus(status, formatOptions)
}
}
public void postStatus(String status) {
log.debug("Posting a status: '{}'", status)
if (!status) {
println color("post status ", colors.option) +
color("command requires one option: ", colors.error) +
"gritter post status <status>"
return
}
if (status.length() > 140) {
println color("Status exceeds Twitter's 140 character limit.", colors.error)
return
}
println "Update status: '$status'? "
if (stdin.nextLine() ==~ /yes|y|true|t/) {
try {
twitter.updateStatus(status)
println "Status posted."
} catch (Exception e) {
println "An error occurred trying to post the status: '" +
e.localizedMessage
log.error("Error posting status:", e)
}
} else println "Status post canceled."
}
public void retweetStatus(def statusId) {
log.debug("Retweeting a status: '{}'", statusId)
if (!statusId.isLong() || !statusId) {
println color("retweet ", colors.option) +
color("command requires a status id: ", colors.error) +
"gritter post retweet <statusId>"
}
statusId = statusId as long
def status = twitter.showStatus(statusId)
println "Retweet '" + color(status.text, colors.odd) + "'? "
if (stdin.nextLine() ==~ /yes|y|true|t/)
twitter.retweetStatus(statusId)
}
public void addListMember(LinkedList args) {
def listRef = args.poll()
def user = args.poll()
def list
log.debug("Adding a member to a list: list='{}', user='{}'",
list, user)
if (!user) {
println color("add list member", colors.option) +
color(" requires two parameters: ", colors.error) +
"gritter add list member <list-ref> <user>"
return
}
// look up the list id if neccessary
if (listRef.isInteger()) listRef = listRef as int
else list = findListByName(twitter.screenName, listRef)
if (!list) {
println color("No list found that matches the given description: ",
colors.error) + color(listRef, colors.option)
return
}
// look up the user id if neccessary
if (user.isLong()) user = user as long
else user = twitter.showUser(user).id
twitter.addUserListMember(list, user)
}
public void addListSubscription(LinkedList args) {
def listRef = parseListReference(args)
log.debug("Subscribing to a list: list='{}'", listRef)
if (!listRef) {
println color("add list subscription ", colors.option) +
color("expects a list name, user/list: ", colors.error) +
"gritter add list subscription <user/list>"
return
}
twitter.subscribeUserList(listRef.username, listRef.listId)
}
public void createNewList(LinkedList args) {
def name = args.poll()
def isPublic = args.poll()
def desc = args.poll()
log.debug("Creating a new list: name='{}', isPublic='{}', desc='{}'",
name, isPublic, desc)
if (desc == null) {
println color("create list ", colors.option) +
color("command requires three arguments: ", colors.error) +
"gritter create list <listName> <isPublic> <listDescription>"
return
}
println "Create list '${color(list, colors.option)}'?"
if (stdin.nextLine() ==~ /yes|y|true|t/)
twitter.createUserList(name, isPublic ==~ /yes|y|true|t/, desc)
}
public def parseListReference(LinkedList args) {
def username = args.poll()
def listId
log.debug("Looking up a list: ref = '{}'", username)
log.debug("remaining args='{}'", args)
if (!username) return false
username = username.split("/")
if (username.length != 2) {
listId = username[0]
username = twitter.screenName
} else {
listId = username[1]
username = username[0]
}
if (listId.isInteger()) listId = listId as int
else listId = findListByName(username, listId)
// TODO: err if list does not exist
return [username: username, listId: listId]
}
public int findListByName(String userName, String listName) {
def userLists
long cursor = -1
int listId = -1
while(listId == -1) {
userLists = twitter.getUserLists(userName, cursor)
userLists.each { list ->
if (listName == list.name || listName == list.slug)
listId = list.id
}
if (!userLists.hasNext()) break
cursor = userLists.nextCursor
}
return listId
}
public String formatStatus(Status status, Map formatOptions) {
def indent = formatOptions.indent ?: ""
def authorLength = formatOptions.authorLength ?: 0
def rowNum = formatOptions.rowNum ?: 0
String result
def textColor = (rowNum % 2 == 0 ? colors.even : colors.odd)
// add author's username
result = color(status.user.screenName.padLeft(
authorLength) + ": ", colors.author, textColor)
// format the status text
String text = status.text
// if this status takes up more room than we have left on the line
if (text.length() > terminalWidth - indent.length()) {
// wrap text to terminal width
text = wrapToWidth(text, terminalWidth, indent, "").
substring(indent.length())
// if we are
}
// color @mentions in the tweet
text = text.replaceAll(/(@\w+)/, color("\$1", colors.mentioned, textColor))
result += text
return result
}
public static void printUsage() {
// TODO
}
public String resetColor() { colored ? "\u001b[m" : "" }
public String color(def message, ConsoleColor color,
ConsoleColor existing = null) {
if (!colored) return message
return color.toString() + message + (existing ?: resetColor())
}
}

View File

@ -1,7 +1,19 @@
/**
* # ConsoleColor
* @author Jonathan Bernard (jdbernard@gmail.com)
* @org jdbernard.com/twitter/ConsoleColor
* @copyright 2010-2012 Jonathan Bernard
*/
package com.jdbernard.twitter;
/**
* The ConsoleColor class is a wrapper around [ANSI escape codes].
*
* [ANSI escape codes]: http://en.wikipedia.org/wiki/ANSI_escape_code
*/
public class ConsoleColor {
// Storage for color information.
public final Colors fg;
public final Colors bg;
public final boolean bright;

File diff suppressed because it is too large Load Diff