Skip to main content
 

Afrofuturism Exhibit

Anyone want to go to Oakland Museum a week from Sunday? With me and some other interesting folks? Pop into this twitter thread..

https://twitter.com/lindner/status/1426379023802724354

 

CORS vs Gmail = no doggo pics

Any of the Chrome folks want to figure out why SameSIte cookies are making
it impossible to add inline images in gmail compose?

Bug appears to be here: https://b.corp.google.com/issues/144398439

Looks like it's more than just Googlers:

https://support.google.com/mail/thread/19811479?hl=en

 

My wife Julie passed away from last month. Today I published her obit in @StarTribune @SFChronicle @PB_News and at https://t.co/pH6ii9cwry

We knew right away that we completed each other and fell deeper in love for 27 years. She meant everything to me.

https://t.co/cseUfQ1ZB9

 

Android Phone Transfer thread

Not sure where to file feedback about things, but my Pixel 2XL screen started to fail so got a Pixel 3 XL (want to keep fingerprint sensor, plus way discounted and pink!)

 

 

Feedback...

_People long to be treated as co-creators. Not cattle._

[pulled from the massive Google+ feedback thread...]

 

I wish I could find the thread/post discussing admin-disabling Chrome Extensions on Mac. There has to be a way.

Not sure if this is just the skeezy myway.com developers or if it's some kind of XSS they enable. In any case the extension rewrites your google search results. Badly. You know you're in trouble when the support page has uninstall directions...

http://support.mindspark.com/










 

Decentralized Web Summit

Attending the Decentralized Web Summit day 2. Hope to see some familiar and new faces.

http://www.decentralizedweb.net/

 

 

Diversity and Haircuts

There's a good discussion on industryinfo about diversity and how haircuts factor into that. Don't want to derail that thread so posting here..

At 22 I went to work for the UN in Geneva. My wife and I drove 3h to Zurich to get our cuts at Time Tunnel. Geneva Salons were too snobby for a metalhead and a punk used to the Hair Police in Minneapolis.

Eventually we found found our counter cultural tribe at http://usine.ch/ and http://www.lecheveusurlasoupe.net/

What I will say is that working and living abroad taught me valuable lessons on diversity, inclusion and empathy.

http://timetunnelhair.ch/category/salon/

 

Reddit

Digging into some Sharing patterns wrt to Reddit.

This reddit thread:

https://www.reddit.com/r/Android/comments/3mh63x/artem_russakovskii_3450mah_battery_confirmed_on/

Posted by some random user:

https://www.reddit.com/user/sajdx1

Contains a link to a post by an Android Police author and prolific G+ user:

https://plus.google.com/+ArtemRussakovskii

That link in Reddit was clicked on 28k times (probably much more since these logs are only web requests..)

select top(request,15) as h, count(*) as c from
gfstmp_oz.tmp_oz_fe_weblog.20150927 where AppsFrameworkExtension.action_class = 'PermalinkedUpdate' and referer like '%reddit.com%';
+-----------------------------------------------------------------------------------+-------+
| h | c |
+-----------------------------------------------------------------------------------+-------+
| GET /+ArtemRussakovskii/posts/T9fdFDBp1fd HTTP/1.1 | 28917 |
| GET /+ArtemRussakovskii/posts/hpc36iQuRSR HTTP/1.1 | 3665 |
| GET /u/0/108441771977176576567/posts/QQNFtAeEjTY HTTP/1.1 | 2088 |
| GET /100098741112799154035/posts/Lavu4mVTvpX HTTP/1.1 | 1899 |
| GET /+ArtemRussakovskii/posts/bA4ryjrT9MJ HTTP/1.1 | 1827 |

*Someone send Artem a cookie, or some G+ swag...*

https://www.reddit.com/r/Android/comments/3mh63x/artem_russakovskii_3450mah_battery_confirmed_on/

 

Anyone interested in a structured data/markup/schema group to coordinate external facing efforts?

It seems that we're moving in the same directions:

- Publisher Markup (authorship/schema)
- Interactive Posts for Google+
- Moments API
- Inbox Actions (JSON-LD)
- Tools (SDTT, markup helper)

If interested you can plus people into this thread and I'll create a G+ community with these people as seed members...









 

_This is just like when they cancelled Firefly!_

said someone in a Reader-related comment thread.

So have hope.  Veronica Mars is returning and Cougar Town was picked up by TBS -- Dollhouse?  sorry, can't help you there.









 

Another java project "goes guava"

Another java project "goes guava"

Originally shared by James Snell

More Abdera2 Updates... this is a copy of an email I just sent to the Abdera-dev mailing list...

----------

Ok, for those of you who may not have seen it, I posted another major update to the Abdera2 code yesterday. Where as the first round of updates focused primarily on updating dependencies and the introduction of the Activity Streams capability, this update focused more on API Refactoring and the introduction of two new major dependencies: the Joda-Time Library (http://joda-time.sourceforge.net/) and the Google Guava Libraries (http://code.google.com/p/guava-libraries/).

First up, Joda-Time... for those who aren't familiar with it, joda-time is a comprehensive code library for working with dates, times, durations, intervals, etc. When I wrote the first version of the Abdera Feed Object Model API, there wasn't a good open-source implementation of the ISO8601 DateTime format required by the Atom specification available so I wrote a fairly limited, down and dirty implementation in the form of the AtomDate class. It had decent performance, fairly good coverage and got the job done. Joda-Time, however, has emerged since as a top quality rich implementation of the 8601 standard... so even though it is a breaking change to the existing Feed Object Model API, I have gone through an have replaced Abdera's own implementation with Joda-Time's DateTime class, which, when used in combination with the mechanisms provided by the Google Guava libraries, provides for some very interesting and compelling new capabilities.

Which, of course, brings me to Guava. This library is a collection of extremely useful utility classes from google. This update brings significant deep integration with Guava in a number of ways, the most important of which is the new Selector API that I introduced as part of the first Abdera2 checkin.

Among many other things, Guava defines a number of interfaces and utility classes aimed at making it easier for developers to write quality, functional, readable code that has a more natural flow to it. It is easiest to show by example.

In Abdera 1.x, if I wanted, for instance, to extract a list of entries from an Atom feed that had been edited after a specific date and time, it would look something like this...

AtomDate ad = new AtomDate("2011-09-10T12:12:12Z");

List list = feed.getEntries();

List selected = new ArrayList();

for (Entry entry : list) {

if (entry.getEdited() != null) {

if (entry.getEdited().after(ad.getDate()))

selected.add(entry);

}

}

Note that feed.getEntries() will return every entry from the feed whether we want it or not. We then have to iterate back over that list, check to make sure there's an edited date, compare those and build up a new list. The code is ugly and cumbersome and inefficient. With the code I just checked in, the same process looks like this...

import static org.abdera.abdera2.model.selector.Selectors.*;

import static org.abdera.abdera2.common.date.DateTimes.*;

List list =

feed.getEntries(

edited(after(dt("2011-09-10T12:12:12Z")))

);

The portion, edited(after(dt("..."))) constructs a Selector that filters the list of items returned by getEntries(), keeping us from having to iterate back over the list.

Suppose we wanted to add another condition to the mix.. say some custom selector that checks for the presence of a particular extension... We can implement our CustomSelector by extending the AbstractSelector class, and merely append that in to the code above like so...

import static org.abdera.abdera2.model.selector.Selectors.*;

import static org.abdera.abdera2.common.date.DateTimes.*;

Selector customSel = new AbstractSelector { ... }

List list =

feed.getEntries(

edited(after(dt("2011-09-10T12:12:12Z")))

.and(customSel)

);

Underlying the Selector API a large chunk of the Guava API... specifically the Predicate, Function, and Constraint interfaces. The Selector interface actually extends from Predicate and Constraint and provides a mechanism for being cast as a Function.

A broad range of utility methods have been provided that create constructors for many of the most common cases, in particular DateTime related operations. Look at the following classes for those utility methods...

org.apache.abdera2.common.date.DateTimes

org.apache.abdera2.common.selector.Selector.Utils

org.apache.abdera2.model.selector.Selectors (for Atom specific utilities)

org.apache.abdera2.activities.extra.Extra (for Activity Streams specific utilities)

The Selector mechanism has been baked into both the Atom and Activity Streams APIs now. For instance, suppose we have an Activity stream but we only want a max of 10 activities for which a given user is the intended target (using the Activity Streams Audience Targeting Extension.. which I can explain later .. lol).. We could get that list of entries using...

PersonObject person = new PersonObject();

person.setId("acct:john.doe@example.org");

Iterable list = stream.getItems(isTo(person).limit(10));

Additional changes in this update include....

1. Refactoring classes into immutable thread-safe objects. This will be an ongoing change. As much as possible, a Factory/Builder model for most basic object types will be used as opposed to the more traditional getter/setter model. The motivation behind this change is simple in that it helps make more a much more scalable architecture and significantly more readable code.

For instance, if you wish to construct a Cache-Control header, you can use a simple fluent builder api...

CacheControl cc =

CacheControl

.make()

.isPublic(true)

.noTransform(true)

.maxAge(1000)

.get();

Likewise if you wish to construct a new WebLink HTTP Header,

WebLink link =

WebLink

.make()

.iri("http://example.org")

.rel("alternate")

.title("Home")

.get();

The pattern is simple and consistent throughout.

2. Added support for Guava objects in the URI Template implementation... specifically, a URI Template Context can now include the Guava Multimap, Supplier and Optional values. In addition, support for java.util.concurrent.Future, java.lang.ref.Reference and java.util.concurrent.Callable were also added. The one caveat when using Future, however, is that the context will not wait for a value to become available. The Context calls Future.get() and takes whatever it gets back as the value so before you use a Future in a URI Template, make sure it's been completed.

3. org.apache.abdera2.common.text.CharUtils has been refactored. This class was always a bit of a hacky mess. It's been cleaned up significantly around a new CodepointMatcher that is modeled after Guava's CharMatcher interface. Codepoint matcher, however, is designed to work specifically with Unicode Codepoints rather than Java Chars. For the most part, CharUtils and CodepointMatcher are internal classes that the majority of users won't ever have to mess with.

4. Filter/FilterChain has been refactored. This is the part of the Server framework that allows you to plug in a chain of filters before invoking a Publishing Protocol Provider. Previously, the Filter and FilterChain interfaces were very specific to the Server API.. they have been refactored into generic Chain and Task interfaces and moved to org.apache.abdera2.common.misc.*. This allows the use of Chain anywhere you may need a simple interceptor framework...

A trivial example,

Task lower =

new Task() {

public Void apply(

String input,

Chain flow) {

if (input == null) return null;

return flow.next(input.toLowerCase());

}

};

Function print =

new Function() {

public Void apply(String input) {

System.out.println(input);

return null;

}

};

Function chain = new Chain(print,lower);

chain.apply("HELLO!");

The Google Guava api does provide the means of composing multiple Function objects together such that the output of one flows into the input of another, but it only works in one direction.. the Chain here allows you to intercept inputs and outputs.

There are a number of other additions here and there throughout the code, and there will be more to come. One MAJOR change that I'm currently exploring is the use of Guice as a complete replacement for the Classpath-based configuration model we currently have. Let's face it, the current stuff provides a significant amount of flexibility and power, but initialization is slow. Guice is significantly faster and much more powerful than what we currently have.

Anyway, that's it for now.------

 

private to you.

private to you.

I am not engaging in RN discussions in public and probably won't be doing much of it inside Google due to the mischaracterization of my views on this subject which are not as black and white as some people might think.

Thread hijackiing is pretty rude too you know.

 

LOL - comment from a thread on consumer + :

*Darren Bounds* - I hope the day never comes where I'm able to import RSS, Atom, Twitter or Facebook content directly into +. Give a Hoot. Don't Pollute.









 

Cross posted from a buzz thread about implicit graph matching.



creepy/yuck factor? At one time organ transplants were considered frankenstein creepy. Street view was (and some say is) considered creepy. The facebook news feed was once considered creepy. People's views change over time, especially if there's an underlying value that one can understand. For all of the above I'd say that the value is there and folks have adjusted.


Having a benevolent trusted partner that can search all of your content and knows you better than you know yourself using heuristics and AI? That stuff is science fiction magic. We can make it happen, and it forms the basis for serendipitous search.


I'd say we're going to have a lot more moments like this where we surface stuff to the user that they didn't expect nor ask for. Making everything opt-in is not the answer -- there has to be a middle ground here where value is given before it is asked for.









 

The Mysteries of Java Character Set Performance

"Two Characters Sets?  Seems like plenty!"

 

So I've been pushing Java to it's limits lately and finding some real nasty concurrency issues inside the JRE code itself.  Here's one particulary ugly one -- we had 700 threads stuck here:

 
       java.lang.Thread.State: BLOCKED (on object monitor)                                                                    
         at sun.nio.cs.FastCharsetProvider.charsetForName(FastCharsetProvider.java:118)
         - waiting to lock <0x00002aab4cdf91b8> (a sun.nio.cs.StandardCharsets)
         at java.nio.charset.Charset.lookup2(Charset.java:450) 
         at java.nio.charset.Charset.lookup(Charset.java:438)
         at java.nio.charset.Charset.isSupported(Charset.java:480) 
         at java.lang.StringCoding.lookupCharset(StringCoding.java:85) 
         at java.lang.StringCoding.decode(StringCoding.java:165)                                                                      
         at java.lang.String.(String.java:516) 
 
Digging deeper we find the lookupCharset is called all over the place.  The app in question is functions as a web proxy, so it's constantly reading and writing data from web pages in a variety of character sets.  The method charsetForName() uses a synchronized data structure to lookup defined character sets.  (Yay serialized access....)
 
But wait, lookup and lookup2 provide us with a cache so we can avoid the big bad synchronized method..  Sigh, here's the implementation:
 
     private static Charset lookup(String charsetName) {
         if (charsetName == null)
             throw new IllegalArgumentException("Null charset name");
 
         Object[] a;
         if ((a = cache1) != null && charsetName.equals(a[0]))
             return (Charset)a[1];
         // We expect most programs to use one Charset repeatedly.
         // We convey a hint to this effect to the VM by putting the
         // level 1 cache miss code in a separate method.
         return lookup2(charsetName);
     }
 
     private static Charset lookup2(String charsetName) {
         Object[] a;
         if ((a = cache2) != null && charsetName.equals(a[0])) {
             cache2 = cache1;
             cache1 = a;
             return (Charset)a[1];
         }
 
         Charset cs;
         if ((cs = standardProvider.charsetForName(charsetName)) != null ||
             (cs = lookupExtendedCharset(charsetName))           != null ||
             (cs = lookupViaProviders(charsetName))              != null)
         {
             cache(charsetName, cs);
             return cs;
         }
 
         /* Only need to check the name if we didn't find a charset for it */
         checkName(charsetName);
         return null;
     }
 
Yes, a whopping 2-entry cache!!
 
Also, the keys used are not canonical, so if my app asks for "UTF-8", "utf-8", and "ISO-8859-1" with regularity this 2 entry cache is worthless, every call ends up blocking in the evil thread-synchronized data structure.
 
Someone send them a copy of the ConcurrentHashMap doc.  please.
 
....
 
 

shoving all app server background tasks into a single thread pool... fun