dannyman.toldme.com


News and Reaction, Technical, Technology

Our Future: Autonomous Cars and Transit

Link: https://dannyman.toldme.com/2013/01/04/our-future-autonomous-cars-and-transit/

My opinion, one of many, as left in a comment:

The current Google Car can operate on city streets autonomously, but it needs someone doing the backend work of getting all the streets mapped out perfectly, figuring out exactly where the lanes are. Then in order to do a truly autonomous taxi service, you’ll want a two-way video linkup for the dispatcher to pilot the car if it gets stuck in some situation like the fire department blocking the street, or to monitor security.

For that reason, the current livery model works really well: a small, local company will service its fleet and its IT needs. The biggest expense, the driver, will be eliminated. This will serve an evolutionary role of a taxi service within a limited service area. This will be mostly shopping trips for car-less people, and “last mile” services to transit connection points, like Taxis serve now. The evolution comes with lower cost: short-haul, off-peak commuter needs, more “last mile” transit service where an autotaxi will be faster and more convenient than the local bus service, but also cheap.

What happens next? “Roaming” agreements among carriers sharing a common technology platform. The service areas of the autotaxi companies grow larger: your local autotaxi can drop you off on a shopping trip to a regional big-box store two towns over and the local autotaxi there can bring you back cheap. Expanded mobility, less reliance on transit.

This doesn’t mean the end of transit. Individual automobiles still require more energy and infrastructure to operate. The autotaxi will dominate short trips, but especially at peak demand, we will need to rely on higher-capacity transit backbones.

The biggest driver of the need for peak-period transit handoff is the capacity limitations of the autotaxi carriers. You simply can not carry everyone, but you want to be a part of the picture. So, yeah, the service gets you from your house to the transit hub, maybe work out relationships with local transit agencies so thaty “last mile” can be served by auto-taxi as a part of the transit fare itself.

The other limitation is for longer-range travel, even a fully autonomous rubber-on-pavement highway system will not be able to match the speed of rail-based or air travel. The autotaxi might drive you fifty miles to the high-speed train station, but then you’ll board the bullet train for LA which will be faster and charge a lower fare.

Anyway, the roaming evolution will mean that we go from local taxi service to regional airport shuttle service, and this will be great for those who live some distance from a long-haul transportation hub who want to make it to/from the airport, &c.

I think autonomous cars are a very reasonable evolution on human-piloted cars, which were a very reasonable evolution on horse-drawn carriages. In the twentieth century we evolved from horses to humans, and in the twenty-first we will evolve even more seamlessly from human to computer.

Our streets didn’t change much from the carriage to the automobile era. They’re wider and too dangerous for people to walk in. I doubt the streets will change much in the autonomous era, except they’ll narrow again and it will be safe to walk, bike, and play in them again.

My other prediction is that the autotaxi will make getting around so convenient, that car ownership will continue to decline. You will see a winners-and-losers scenario in the auto industry: the losers will realize too late just how badly they are in trouble. They will try to spread Fear, Uncertainty, and Doubt as to the safety and wisdom of reliance on autonomous vehicles, just as they try to sell some. The winners will have identified the coming trend and geared their business to serving the needs of autonomous fleet operators, and to those niche consumers for whom autonomous vehicles are not appropriate, or who just love driving their own car. Other winners will include pedestrians, cyclists, the young, the elderly, people with disabilities, suburbanites, night life, and very likely the environment.

Feedback Welcome


JIRA

JIRA Cascading Select in Jython

Link: https://dannyman.toldme.com/2012/12/06/jira-cascading-select-in-jython/

The Cascading Select Custom Field type in JIRA is a bear. The first trick is learning to set the “null” value and then the “1” child value. The next trick is building out a ModifiedValue object to hold your change. Then you get to jump down the rabbit hole of finding the correct Option values for the custom field, and setting them with the tricks just mentioned.

So, in the interests of saving me sanity next time I need to set a Cascading Select, here’s a Jython function that works in Jira 4.2:

import logging
 
from com.atlassian.jira import ComponentManager
from com.atlassian.jira.issue.customfields.manager import OptionsManager
from com.atlassian.jira.issue.customfields.view import CustomFieldParamsImpl
from com.atlassian.jira.issue import ModifiedValue
from com.atlassian.jira.issue.util import DefaultIssueChangeHolder
from java.util import HashSet
 
# cf = custom field
# issue = issue to modify
# parent = top value to set (string value)
# child = child value to set (string value)
def set_cascading_select(cf, issue, parent, child):
    # Get the managers
    cfm = ComponentManager.getInstance().getCustomFieldManager()
    om = ComponentManager.getComponentInstanceOfType(OptionsManager)
    fli = ComponentManager.getInstance().getFieldLayoutManager().getFieldLayout(issue).getFieldLayoutItem(cf)
 
    parent_options = om.getOptions(cf.getRelevantConfig(issue))
    parent_option = None
    child_option = None
    try:
        parent_option = parent_options.getOptionForValue(parent, None)
    except:
        pass
    try:
        child_option = parent_options.getOptionForValue(child, parent_option.getOptionId())
    except:
        pass
 
    if parent_option and child_option:
        old_application = issue.getCustomFieldValue(cf)
        new_application = CustomFieldParamsImpl(cf)
        a_none = HashSet()
        a_none.add(parent_option)
        a_1 = HashSet()
        a_1.add(child_option)
        new_application.put(None, a_none)
        new_application.put("1", a_1)
        mf = ModifiedValue(old_application, new_application)
        cf.updateValue(fli, issue, mf, DefaultIssueChangeHolder())
        logging.debug("set issue " + issue.getKey() + " cf " + cf.getName() + " setting " + parent + "/" + child)
        return True
    else:
        logging.error("invalid parent/child option: " + parent + "/" + child)
        return None

Example function calls from within a validation hook:

cfm = ComponentManager.getInstance().getCustomFieldManager()
 
application_cf = cfm.getCustomFieldObjectByName("Beverages")
 
# good
set_cascading_select(application_cf, issue, "Hard Drinks", "Whiskey")
# bad child
set_cascading_select(application_cf, issue, "Hard Drinks", "Coke")
# bad parent
set_cascading_select(application_cf, issue, "Soft Drinks", "Whiskey")
# total crap
set_cascading_select(application_cf, issue, "Illicit Drugs", "Bath Salts")

The logging stuff is useful for debugging, if you have that set up, else just remove those bits.

Feedback Welcome


Excerpts, Letters to The Man, Technical

Collocation vs Colocation

Link: https://dannyman.toldme.com/2012/12/03/collocation-vs-colocation/

This drives me insane. Part of the challenge is that most software dictionaries are unaware of the word “colocation” and are happy to offer “collocation” as an alternative, but that is wrong wrong wrong wrong and it makes me a little nuts every time.

So, here is some explanation I just sent to the NOC and copied to the Sales team of a “Colocation Provider” who keeps sending me messages from something called “Collocation Status Report”:

Dear NOC:

A collocation is a statistic used by linguists to determine the
frequency with which words and phrases are found together.

On your contact information page, there is an option to contact Sales
about “Colocation”

Assuming that you are indeed in the business of Colocation, and not
actually updating us on the status of word frequencies, please fix the
name in your outgoing envelope from “Collocation Status Reports” to
“Colocation Status Reports”

Thanks,
-danny

Yup. That’s all I have to say about that.

1 Comment


Technical, Technology

Amazon Hack: Reverse Showrooming

Link: https://dannyman.toldme.com/2012/11/12/amazon-hack-reverse-showrooming/

Modern retailers have a challenge we have come to call “showrooming” where a consumer visits the local store to try out a product, then they go and order the product off Amazon.com or another retailer for less money. Some retailers will do online price matching, which is reasonable because even though that lowers their margin, they still get the sale, and can upsell you a few accessories. I saved a few dollars this way while buying a TV from Fry’s.

However, I was just browsing Amazon.com for a resin adirondack chair, where I saw:

Twenty six bucks!? Sounds good . . . not eligible for Prime, so let’s check the shipping . . .

Whiskey . . . Tango . . . Foxtrot . . . $192 shipping you say?!! Something is fishy here . . .

So, I surf on over to True Value’s web site, where the chairs are $20, and they’ll ship to the local store.

Which makes me wonder if this is a case of “reverse showrooming” . . . I go to Amazon.com because I can probably find what I am looking for, then I am led to a local retailer to save money. Very clever . . .

Feedback Welcome


JIRA, Technical

JIRA Workflow Transition Condition: check_parent_resolved.py

Link: https://dannyman.toldme.com/2012/11/07/jython-workflow-transition-check-parent/

It took a few hours to figure this hook out, so I’m including my hard-won lines of code here.

# -*- coding: UTF-8 -*-
# Check if PARENT is resolved.
# Monitoring creates Events in the Event queue, these Events
# automatically create Incident children.
# We don't want to resolve any Incident children until the parent Event
# resolves.
# 
# (Normally you want to block on your children instead of your parent.)
 
from com.atlassian.jira import ComponentManager
from com.atlassian.jira.issue.link import IssueLinkManager
 
ilm = ComponentManager.getInstance().getIssueLinkManager()
 
# Assume we are okay ...
result = True
 
for link in ilm.getInwardLinks(issue.getId()):
    if link.getIssueLinkType().getName() == "Parent" and link.getSourceObject().getResolution() == None:
        result = False

Feedback Welcome


Technical

HOWTO: Style a Multi-Column List in HTML

Link: https://dannyman.toldme.com/2012/10/22/html-css-ul-li-columns/

For a project at work I was asked if I could lay out a long table-of-contents in our CMS as multiple columns. Logically enough, the table-of-contents renders as a flat, unordered list (UL) of list items (LI) … arranging that as multiple columns is a preposterous idea! Of course, preposterous questions can be very interesting.

So, we start with something like this:

		<h1>Yadda Yadda</h1>
 
		<ul class="columns">
			<li>BLAH blah blah one</li>
			<li>BLAH blah blah two</li>
			<li>BLAH blah blah three</li>
			<li>BLAH blah blah four</li>
			<li>BLAH blah blah five</li>
			<li>BLAH blah blah six</li>
			<li>BLAH blah blah seven</li>
			<li>BLAH blah blah eight really long example</li>
			<li>BLAH blah blah nine</li>
			<li>BLAH blah blah ten</li>
			<li>BLAH blah blah eleven</li>
			<li>BLAH blah blah twelve</li>
		</ul>
 
		<h1>Yappa Yappa</h1>

Which renders as:

Yadda Yadda

Yappa Yappa

Okay. So, multiple columns? That is what TABLE is for, but we are dealing with UL. But I have my old friend the float attribute, so I define a style sheet:

			ul.columns li {
				list-style: none;
				float: left;
				width: 30%;
			}
			h1 { clear: left; }

Now we render as three columns:

Yadda Yadda

Yappa Yappa

Two columns? Four? Just tune the width attribute:

			ul.columns li {
				list-style: none;
				float: left;
				width: 45%;
			}
			h1 { clear: left; }

And you get:


It is not perfect. The content renders left-to-right, so strictly speaking, these aren’t columns.

If you narrow enough to cause wrapping you get some odd gaps.

Due to margins and the like, you can’t just say three columns is 33%, two columns is 50% . . . if you narrow this page enough you’ll see a graceful degradation from more columns to fewer.

Here’s a more dynamic example, where wider pages will get more columns:

			ul.columns li {
				list-style: none;
				float: left;
				width: 15em;
			}
			h1 { clear: left; }

Renders as:


The block following your UL will need to clear the floated content, hence the clear: left on the H1, above.

See also:

Feedback Welcome


JIRA, Python, Technical

Jython Validator Cookbook

Link: https://dannyman.toldme.com/2012/09/25/jython-validator-cookbook/

Building on a previous post to validate user time tracking, a few “cookbook” scripts that may be handy to you or me in the future.

JIRA 4.2, YMMV.

Validate User Time Tracking

Somewhat elaborate: enforce that time worked has been logged, except under certain circumstances. See original post.

import com.atlassian.jira.issue.worklog.Worklog
from com.atlassian.jira import ComponentManager
 
# Time Already Logged
timespent = issue.getTimeSpent()
# Time Logged via current screen
try:
    timelogged = dict(issue.getModifiedFields())['worklog']
except:
    timelogged = False
 
# Duplicate Issue?  It is as good as logged!
resolution = issue.getResolution()
if resolution['name'] == "Duplicate":
    timelogged = True
if resolution['name'] == "Self Corrected":
    timelogged = True
 
# Nagios likes to close tickets, but doesn't get paid
user = ComponentManager.getInstance().getJiraAuthenticationContext().getUser()
if user.getName() == "nagios":
    timelogged = True
 
if timespent < = 0 and timelogged == False:
    result = False
    description = "Please log the time you spent on this ticket."

Assign Unassigned Issue to User

This helps make sure tickets get assigned.

# -*- coding: UTF-8 -*-
from com.atlassian.jira import ComponentManager
 
assignee = issue.getAssignee()
user = ComponentManager.getInstance().getJiraAuthenticationContext().getUser()
 
if not issue.getAssignee():
    issue.setAssignee(ComponentManager.getInstance().getJiraAuthenticationContext().getUser())

Validate Custom Field Value

We have a particular custom field which can be set UNKNOWN by the Reporter, but which should be cleaned up by the Assignee.

from com.atlassian.jira import ComponentManager
 
cfm = ComponentManager.getInstance().getCustomFieldManager()
product = issue.getCustomFieldValue(cfm.getCustomFieldObject('customfield_12345'))
 
if product == 'UNKNOWN':
    result = False
    description = "Please set CUSTOM_FIELD value appropriately."

Feedback Welcome


Linux, Sundry, Technical, Technology, Testimonials

Smoothing Out Fonts on kubuntu-desktop

Link: https://dannyman.toldme.com/2012/09/13/make-kubuntu-kde-fonts-pretty/

So, I really like Ubuntu. Its Linux and it just mostly works. Except when they try to force everyone into some experimental new desktop environment. That is pretty awful, but I’m happy again now that I switched to kubuntu-desktop. (apt-get install kubuntu-desktop)

Kubuntu is Ubuntu with a nicely set-up KDE environment. They try to get you to use their own home-grown web browser, and the file manager takes some getting used to, but you can pretty quickly get under the hood, set up all your little window manager preferences, and get back to jamming. (Focus Follows Mouse in my house!)

The only thing that was missing is the fonts were rendering . . . not as pretty as regular Ubuntu. Kubuntu is set up to use the Ubuntu font, but in KDE things render kind of pixelly looking, like I was still in the 90s. A bit of searching and they seem to look nicer:

System Settings > Application Appearance > Fonts
Use anti-aliasing: Enabled
Configure…
Use sub-pixel rendering: RGB
Hinting style: Slight

Now things feel a little more 21st century.

Feedback Welcome


Linux

Merge Multiple PDF Documents

Link: https://dannyman.toldme.com/2012/06/09/e-pdfs-unum/

By the way, let’s say you have to print, sign, scan, and email back a document using the flatbed scanner attached to your Linux workstation. No trouble scanning in each page as an individual PDF document using XSane, but assembling the multipage project into one document proved a modest challenge last time I tried.

Solution? Install pdftk, and then the command goes something like:

pdftk AVID000*.pdf cat output AVID.pdf

That’s will merge all the documents named AVID0001.pdf, AVID0002.pdf, etc into AVID.pdf. Or to put it another way:

pdftk <a bunch of PDF files> cat output <target PDF file>

Cheers!

1 Comment


Linux, Technical, Technology, Testimonials

Dear Ubuntu: Stop Asking me for my Password!

Link: https://dannyman.toldme.com/2012/05/24/ubuntu-password-prompt/

I like Ubuntu. Or at least I liked it a few years back when you got a very nice functional desktop out of the box … but that is a different gripe.

I really like an OS that updates the software for me. Really, downloading and installing updates is for chumps! Way to go, Ubuntu!

But here’s a feature that has been bugging me for years: the system pops up a window saying “hey, I’m going to update the system software for you.”

And I’m like “sure, go ahead, be my guest!”

Then it’s like “okay, please give me the administrator password.”

And I’m like “well, okay . . . but . . .”

Each time the computer pops up a window unbidden offering to do me a favor in exchange for my password, I am wondering when some bastard will get around to writing a bit of malware that offers to do something nice for me in exchange for my password. Maybe a web site can launch a convincing-looking software-update window and prompt me for a password. It is going to be epic just how many users can be convinced to type their system passwords into a malware site.

If you are a part of the system that has access to do heavy lifting, please do not approach the user asking for a password. It teaches the user that “hey, its normal for your computer to pop up some window and ask for a password and when that happens you should totally humor the computer and give it your password.” You want to update my software? Great! You want to check with the person using the computer to make sure its a good time? Great, ask away, tell them your plans. But when they say yes, just fricking do it, and don’t ask them for their password.

1 Comment


FreeBSD, JIRA, Linux, Mac OS X, Technical

Strip Non-Ascii From a File

Link: https://dannyman.toldme.com/2012/05/10/mysql-not-configured-for-utf8/

I have had bad luck trying to coax this out of Google, so here’s a Perl one-liner:

perl -pi -e 's/[\x80-\xEF]//g' file.txt

Where file.txt is a file you want to clean up.

Why this comes up is because we have a web application that was set up to hit a MySQL database, which is incorrectly configured to store text as ASCII instead of UTF-8. The application assumes that all text is Unicode and that the database is correctly configured, and every week or two someone asks me why they are getting this weird gnarly error. Typically they are pasting in some weird UTF-8 whitespace character sent to us from Ukraine.

Eventually the database will be reloaded as UTF-8 and the problem will be solved. Until then, I can tell folks to use the Perl command above. It just looks for anything with the high bit set and strips it out.

Feedback Welcome


JIRA, Technical

Work Note: Quarterly Reports from MySQL

Link: https://dannyman.toldme.com/2012/05/08/jira-sla-sql-query/

I am not a DBA. I am but a humble SysAdmin who gets asked to figure out things like “how have we been at meeting our SLAs over time?” After I try to excuse myself I’ll inevitably end up say at the JIRA database running a query like this:

echo
echo "Incidents (P3)"
mysql -u jira jiradb< <__id3q
select year(created) as "Year", quarter(created) as "Quarter",
    count(pkey) as "Total",
    sum(resolutiondate < date_add(created, interval x day)) as "Met SLA",
    sum(resolutiondate < date_add(created, interval x day)) / count(pkey) as "SLA %%"
    from jiraissue where pkey like 'OPS-%' and priority = 3
    and assignee != 'nagios' and issuetype = 26
    group by year(created), quarter(created) order by created;
__id3q

That above is a fragment from a shell script. Shell scripts are great for complex SQL queries, I find. Set a value x at interval x day and the output looks something like:

Incidents (P3)
Year    Quarter Total   Met SLA SLA %%
2011    2       xxx     xxx     x.xxxx
2011    3       xxx     xxx     x.xxxx
2011    4       xxx     xxx     x.xxxx
2012    1       xxx     xxx     x.xxxx
2012    2       xxx     xxx     x.xxxx

The query does some things that are newer to my limited understanding of SQL. For me the magic bits are sum()ed columns and the availability of quarter() … you can do monthly reports just as easily with month(). I’d love to concatenate Year-Month into a string like “2012-05” but for the purposes of making my boss a little happier queries like this are good to have in the locker.

Some day I’ll be hip enough to convert things like this into JIRA widgets.

Oh yeah, and if your SLAs are measured in “business hours” or “business days” this will give you only a crude understanding of how well you have met your SLAs … an accurate measure would probably get embedded in a handler that gets called on issue close which can evaluate SLA fulfillment per issue priority and the local work schedule.

1 Comment


About Me, Technical, Technology

Usability Example: Unsubscribe FAIL

Link: https://dannyman.toldme.com/2012/03/07/linkedin-unsubscribe-not/

Last week I dug through several menus to try and unsubscribe from all the spam LinkedIn sends me. Today I got another email and at the bottom was an “unsubscribe” link that I clicked on. Here’s what I got:

Unsubscribe screen doesn't actually unsubscribe . . .

Not only is this not an unsubscribe feature, LinkedIn gets bonus points for trying to sign you up for MORE e-mail.

Instead of screwing around with the half-dozen sub-menus again, I dropped them a feedback saying that this burns up good will, damages the brand, discourages me from engaging, and may in time lead me to delete my profile. There’s more than one way to search for resumes online.

2 Comments


Python, Sundry, Technology

PYCON Starts March 7th!

Link: https://dannyman.toldme.com/2012/02/08/derr/

From an email to colleagues:

Yesterday I got Dr Sick Wife to drop me off at the Santa Clara Convention Center so Mr Sicker Light-Headed Husband wouldn’t miss any PYCON. After an awkward twenty minutes of asking people there for the lighting and LED conference where the Python was, I checked my smart phone and noted that … PYCON is *MARCH* 7th.

So I took the light rail home and told $BOSS I was on PTO (well, I call it MLK day due to Puppet Training) I then slept a lot, and did other things sick people do that don’t bear repeating in a professional context, and watched Dr Who save the Earth on TV, slept some more, and I am feeling way better today, which means I feel regular sick, not super sick.

So, I’ll be WFH today. Trust me, whatever this is, you’re lucky to miss out! I don’t normally get sick so this is a novel experience … I’ll likely be seen in the office next week, though if I’m coughy or sneezy I’ll keep that train wreck at home, because, as you might gather, you don’t want a piece of this!

If you’re attending PyCon, I look forward to seeing you there … next month! Hopefully I won’t be light-headed!

Feedback Welcome


Linux, Technical

Notes: Make Ubuntu GUI Less Annoying

Link: https://dannyman.toldme.com/2011/12/07/ccsm-ubuntu-gui-tweaks/

First, install ccsm.

Terminal windows resize themselves stupidly when changing font size. I don’t know how to fix that, but in the CompizConfig Settings Manager, I can enable Resize Info to overlay the dimensions of any window as I resize it.

Often, when dragging a window around, it tries to go full-screen on me. This is obnoxious! Just disable Grid in CCSM.

If anyone knows how to reconcile Focus Follows Mouse with “menu bar at the top of the screen” I would love to hear it! Or if you know how to configure the pager to something besides 2×2 …

1 Comment

« Newer Stuff . . . Older Stuff »
Site Archive