Tuesday, June 19, 2018

The PERL Conference

TPC (the PERL conference)

Yikes, this group is skewing old.  Even with the young folks that my work forces to learn PERL, the crowd was looking pretty gray.  Had some distopian daydreams about how we could revitalize the community.
Even considering men and women, this was pretty dark

Had to jettison that one pretty quick. The next one was a little bit better(?)


Who doesn't have fond memories of The Dark Crystal?


Bonus fact, after draining the essence of interns, is that their willpower is gone and they would probably be easy to convince to work on POD documentation

Anyhoo, this is where I will place the TPC slide deck when I'm good and ready, dammit.



OpenWest 2018

Had a presentation at OpenWest again this year. I really dislike the South Towne Exposition Center as a technical conference hall. Don't know if it's the location or public interest that is waning, but I hope they can inject new life back into it because it felt worn out. Anyways, here is a link to the Prezi that I made for my discussion on Event Driven Architecture I enjoy making presentations in Prezi. You can build a dynamic deck, but it's really not suited for coding presentations. You need to subscribe to a premium tier to embed video and even then it's only YouTube and not something that can simulate entering code and running it. Speaking of tired venues, I subscribed for a trial version of Prezi so I could embed an old video of Meredith Burgess Burke's Law: Who killed 711? and his 'do nothing' machine, but when I got to my 'room' for the presentation, I found out that there was no microphone or even sound. Perhaps that was purposeful since these were just curtained enclosures in the cavernous main hall, but seemed disrespectful of the time that I put in to make a presentation for their conference. I should learn not to include the word 'PERL' in my RFP response.

Friday, March 23, 2012

Facebook and KRL

This is a repost from an earlier post.  My earlier blog exploded messily so I am reposting some of my technical posts from the past


Facebook has opened up access to most of their data through their Graph API. I bitch elsewhere about their decision to implement OAuth 2.0, but that should not detract from the fact that this new REST based interface is simple, straightforward, and a breeze to use.  The number of requests to parse a user’s feed is not insignificant compared to what is possible with FQL.
For our Kynetx Code Run, we have already done some pretty exciting things with the FB API.I really thought about drawing a big cowboy mustache on Mike Grace's picture Previously, Kynetx has treated data sources as read-only operations.  With this release, we have introduced writes as a user action.  The format is similar to the usual get syntax, but it is an action so it needs to be called from the Action part of your rule (use it like you would notify or other actions like: after, before, float…)
Facebook calls their data the Social Graph.  I may use that term interchangeably with Facebook or the Graph API.
Skip to the examples

 

Create a Facebook applicationfb_post4

The easy way that I did it was to just go to the Facebook Developer page. You will need to accept the FB terms and conditions and name your app.  It doesn’t matter what you name your app, but the name will be used by Facebook during the authorization process and for any content that you create through the API.
For our purposes, we are only interested in a couple bits of information; however, this does create a real app so you should spend some time filling in profiles, adding logos and generally tarting-up your app.
If you are familiar with OAuth, you know that you need an id and secret for the authorization process.  Conveniently for us, Facebook takes us straight to the required information

fb_post5
The Graph API uses the Application ID and Secret as the consumer_key and consumer_secret respectively.
It is important that you do the next step correctly!  Set your Facebook application’s Connect URL to http://cs.kobj.net:80/ruleset/fb_callback/ Facebook uses the Connect URL as an additional security measure to make sure developers are not up to something naughty.  As part of the OAuth process, KRL tells FB to send a token to a URL on our server (That’s how your user can log in and authorize through Facebook and never give out their username and password).  If your Connect URL and the URL that Kynetx provides don’t match, the authorization process will FAIL.
Facebook's Connect URL

FACebook’s social graph

The Graph API exposes several objects from the social graph. From what I have read on the forums, there are a few objects that were available in the old API or FQL that are not available from the Graph API. I would recommend that you become familiar with what information is available and where to find it.  From the Facebook documentation, these are the objects that are available

Create your Kynetx Application

For KRL, the process of integrating Facebook into your application is the same as the process we use for Twitter and Google.  The Twitter documentation is fairly extensive, so I will just hit the highlights.
Set up your facebook application information in the META section
key facebook { "consumer_key" : "892934849920029", "consumer_secret" : "1a3836d9d025f9e2738bb50976" }

Create first rule to AUTHORIZE your user with Facebook
rule auth_app is active { select using ".*" setting () if (not facebook:authorized()) then facebook:authorize(["publish_stream","email","user_photos","read_stream", "user_notes","offline_access","user_about_me","user_notes", "user_photos","user_likes","user_online_presence" ]) with opacity = 1 and sticky = true; fired { last; } }
As a bonus, if the user clicks on the name of the application, they will be taken to the app's Facebook homepage Before any FB request, KRL checks to see if the application has been authorized to access the current user’s information.  The auth_app rule explicitly runs that check for you.  If the user does not have a valid OAuth token, the OAuth authorization process is started.
Let’s examine the authorize command in more detail:
facebook:authorize(["publish_stream","email","user_photos",
  "read_stream","user_notes","offline_access","user_about_me",
  "user_notes","user_photos","user_likes","user_online_presence"
])
authorize takes as an argument an array of extended permissions.  They are separated into two major categories: Publishing and Data.  Data is further divided into User and Friends permissions.
Permissions
Table 1 Facebook's extended permissions
Publishing Data
User Friend
publish_stream email
create_event read_insights
rsvp_event read_stream
offline_access user_about_me friends_about_me
user_activities friends_activities
user_birthday friends_birthday
user_education_history friends_education_history
user_events friends_events
user_groups friends_groups
user_hometown friends_hometown
user_interests friends_interests
user_likes friends_likes
user_location friends_location
user_notes friends_notes
user_online_presence friends_online_presence
user_photo_video_tags friends_photo_video_tags
user_photos friends_photos
user_relationships friends_relationships
user_religion_politics friends_religion_politics
user_status friends_status
user_videos friends_videos
user_website friends_website
user_work_history friends_work_history
read_friendlists
read_requests
The full breakdown on permissions is found on Facebook.  Two permissions which are particularly relevant to KRL are publish_stream and offline_access. Without publish_stream permission, you won’t be able to post to your user or their friends accounts. Without offline_access, users would have to be logged into facebook for your queries to work. Here are the allowed values—any other values will just be ignored.
I suspect that some might be tempted to pile all the permissions into an authorize request. Aside from missing the point of writing context sensitive rules to fulfill specific needs, there is an Internet Explorer limitation which restricts the size of an HTTP query.  Just to keep you from piling on permissions, I’m not going to tell you what that limit is.
Despite the permissions the user has authorized, there is often public data which is available regardless of authorization. Do not be misled by a user’s public information into thinking that your app is authorized to request the information; ie: to allow other people to find you in a friend search, your first and last name has public permissions. So anyone who types the URL: https://graph.facebook.com/100001078761602/ will see the information that Kay Netticks has made public.
Connections
Connections are the way that facebook links objects together.  Most every object has connections to other objects.  This allows a group to have members, photos and a news feed.  A status message only has comments.  The user object has many, many connections—basically all the various stuff that you can see on your FB home page.
Not specifying a connection will return the profile information for the current object.
For convenience, there is a special function facebook:connections() which will tell you what are valid connections for a particular object.
IDs
Almost every object in the Social Graph has an id.  Getting information for a particular object is as easy as providing the correct id.  If you don’t specify an id, the currently authorized user is used as the default object.  Facebook has a special alias for the currently authorized user “me”.  KRL doesn’t require you to specify an id, but you may see request urls in your debug statements that use “me” so you should be aware of the meaning.
Paging
Several of the Social Graph queries can return multiple items.  Facebook provides some paging functions so you have some control over which and how many results are returned.
  • limit
  • offset
  • since
  • until
limit and offset both require integers for their values.  With limit, you can specify how many items you want to receive for one request. Offset allows you to skip any number of elements before you start returning results.
Since and until operate like a min and max date respectively.  They take a date as an argument, but that date can be formatted according to what the PHP strtotime function allows.  That means that ‘2010-04-01’ and ‘yesterday’ are both valid values.  The online PHP manual gives these as valid examples:
Valid formats for FBs since and until query parameters
"now”
"10 September 2000"
"+1 day”
"+1 week”
"+1 week 2 days 4 hours 2 seconds"
"next Thursday"
"last Monday”
fields
If you are only interested in select fields of a Social Graph object, you may use the fields argument to limit the response to only your desired fields. The argument takes the form:
  • fields : <string> | <CSV string> | [<string1>,…,<stringN>]
A field name string, comma separated list of field names, or an array of field names are all valid values for fields.  For convenience, there is a special function facebook:fields() which will tell you what are valid fields for a particular object.
Queries
Query syntax should be familiar to KRL users.  There are 5 basic facebook queries which are available in KRL. Each can accept a hash as an argument, though facebook:search is the only function that requires an argument.  Not specifying an id, will perform the query in the context of the currently authorized user.


facebook:metadata()
  • optional
  • id :<string>
I debated whether I should provide access to the metadata query.  The metadata is designed to allow for introspection.  That’s kind of like telling you what know about what you know about an object.  It returns profile information, but it also returns preformatted url references to all of the connections that are valid for your object.  It’s a good idea, but when you have a token with your metadata request and are defaulting to the currently authorized user (“me”), the urls come pre-configured with the access token attached.  That may not make much difference for people who are writing pure javascript implementations of the Social Graph, but KRL is a MUCH more secure environment and I don’t like the idea of leaving that token lying around.
facebook:picture()
  • optional
  • id :<string>
  • type : square | small | large
Most all objects have a picture or an icon associated with them. When you make a request for the picture, Facebook returns a redirect to the actual URL.  I follow that re-direct and return the actual URL for the picture.  This makes a picture call a little bit more complicated so bear that in mind if you are going to do large amounts of picture requests.  If it would be more useful, I could include something like a ‘nofollow’  tag so that I just return the location of the redirect, but that is currently not provided
facebook:search()
  • required
  • type : post | user | page | event | group | home
  • q : <string>
  • optional
  • id :<string>
I haven’t found FB’s search functionality to be terribly robust. As I say to my kids, “You get what you get and you don’t throw a fuss”. If you find that you aren’t getting the results that you think you should, grab the url from the debug and enter it with your browser to see if it’s just bad indexing on FB’s part.
home is a special case where the search will be performed only on the currently authorized users news feed or whomever is specified by the optional id parameter
facebook:get()
  • optional
  • id :<string>
  • connection: <string>
  • type : <facebook object> 
If you would like to follow a connection; ie: get all the comments associated with a post, just provide a “connection” : <value>.  If you would like KRL to do some sanity checking, you can use the optional “type” : <object> syntax in conjunction with connection.  KRL will check to see if your connection is valid for that type of object.  If not, a warning will be printed to your console.
facebook:ids()
  • required 
  • ids :<string> | <CSV string> | [<string1..stringN>] | url
This method allows you to get profile information for multiple ids. <string> can be a username or the numeric id (it is not guaranteed that the user will have a username defined).
An optional usage is to provide a URL instead of an id.  You can use this to look up or check to see if there is an object already associated to a URL in Social Graph

POSTS


Table 2 Posting to Facebook
Connection Requires* Arguments
feed (wall) <profile id>
  • message
  • picture
  • link
  • name
  • caption
  • description
comments <post id>
  • message
likes <post id>
notes <profile id>
  • message
  • subject
links <profile id>
  • link
  • message
events <profile id>
  • name
  • start_time
  • end_time
attending (events) <event id>
maybe (events) <event id>
declined (events) <event id>
albums <profile id>
  • name
  • message
photos <album id>
  • message
Facebook allows you to create new instances of a few of their Social Graph objects; ie: write a message on someone’s wall.  This requires the publish_stream permission from the user.  What information you supply is determined by the type of object that you are trying to create.
Here are the objects that you can publish via the Graph API:
Syntax for publishing is very simple, but remember that publishing is an action.  In this case, the action is not producing JavaScript, but posting data to the Graph API.
facebook:post()
  • required 
  • connection : <string>
  • id: <string>
  • optional
  • <arg> : <string>
See table 2 for a list of what arguments are available for each connection.
*id is optional when the connection requires a profile id.  As in previous cases, if the id is not supplied, it will default to the id of the currently authorized user.  The following connections require a profile id: feed, notes, links, events, albums.  I would suggest always supplying the id for consistency.
The post method cross checks the connection type with the permitted arguments.  If an argument is not associated with the connection, it will just be ignored.
For convenience, there is a special function facebook:writes() which will tell you what are valid argument keywords for a particular connection.

Examples


facebook:metadata()
Request for metadata by id
facebook:metadata({“id” : “100001078761602”});
returns: JSON
Request for metadata for currently authorized user
facebook:metadata();
returns: JSON
facebook:writes()
Writable fields/allowed parameters for a Facebook object
facebook:writes(“feed”);
returns: Array
facebook:post()
Post a message to a user’s feed
facebook:post({"id" : "100001078761602", "connection" : "feed", "message" : "Contactless not, swipe again", "picture" : "https://kynetx-images.s3.amazonaws.com/KynetxLogo273.png", "link" : "http://www.kynetx.com", "name" : "Things I like", "description" : "I am integrated into Facebook!" });
“like” a post
facebook:post({"id" : "641349049_124260134272950", "connection" : "likes"});
facebook:ids()
Search for these ids and return their profile data
facebook:ids(“ids” : [“100001078761602”,”116360591732083”]);
returns: JSON
Search the Facebook Social Graph to see if a URL has an ID
facebook:ids(“ids” : “http://www.kynetx.com);
returns: JSON
facebook:get()
Request specific user’s feed
facebook:get({“id” : “100001078761602”, ”connection” : “feed”});
returns: JSON
Request default user’s albums
facebook:get({”connection” : “albums”});
returns: JSON
Request default user’s home with optional “type” syntax
facebook:get({”connection” : “home”, ”type” : “user”});
returns: JSON
Request an object by id
facebook:get({”id” : “511048495_446064733495});
returns: JSON
Request all the messages posted to a specific object (link)
facebook:get({“id” : “511048495_446064733495”, ”connection” : “comments”});
returns: JSON
facebook:search()
Search the Social Graph for a page
facebook:search({”type” : “page”, ”q” : “Lehi, Utah”});
returns: JSON
Search the Social Graph for a user
facebook:search({”type” : “user”, ”q” : “Steve Fulling”});
returns: JSON
facebook:picture()
Get the large picture associated with the currently authorized user
facebook:picture({“type” : “large”});
returns: url (string)
Get the picture for an object
facebook:picture({“id” : “116360591732083”});
returns: url (string)
Request for object picture by id and type
facebook:picture({“id” : “100001078761602”, ”type” : “small”});
returns: url (string)
facebook:connections()
Allowed connections for a Facebook object
facebook:connections(“page”);
returns: Array
facebook:fields()
Allowed fields for a Facebook object
facebook:fields(“user”);
returns: Array
facebook:authorize()
Authorization Action with desired Facebook permissions
facebook:authorize(["publish_stream","email","user_photos","read_stream"]);
facebook:authorized()
Authorization predicate
facebook:authorized();
returns: true or false
limit
Search the Social Graph for a group and limit results to 3
facebook:search({"type" : "post", "q" : "bacon", "limit" : 3});
returns: JSON
offset
Search the Social Graph for a user and start with the 20th object
facebook:search({"type" : "user", "q" : "John Smith", "offset" : 20});
returns: JSON
until
Search the Social Graph for users named who signed up before 2010-05-18
facebook:search({"connection" : "feed", "q" : "John Smith", "until" : "2010-05-08"});
returns: JSON
since
Search default user’s news for posts made within last day
facebook:get({"connection" : "feed", "since" : "yesterday”});
returns: JSON
fields
Get specific fields for the default user
facebook:get({“fields” : [“last_name”,”email”]});
returns: JSON

Friday, October 1, 2010

New Time functions

One of the quirky things that I noticed while I was building the Google Calendar integration is that KRL has numerous functions to make decisions based upon time, but no simple way to get the current time.

Furthermore, Google calendar uses a specific time format (RFC 3339) and is very strict about enforcing it.

In response, I wrote several new functions for the time module.

  time:now()

  time:new()

  time:add()

  time:strftime()

  time:atom()

Default Time Format

The default format for a time string is RFC 3339 which looks something like this:

1985-04-12T23:20:50.52Z


Functions


time:now()



  • Current datetime based upon user’s location data
Usage

time:now()

time:now({“tz” : <timezone>)

 


time:new()



  • Create a new RFC 3339 datetime string from a string (allows some flexibility in how the source string is formatted)
Usage

time:new() # Equivalent to time:now()

time:new(<string>)

 


  Valid formats for the datetime source string can be found in ISO8601 (v2000).


time:add()



  • Add (or subtract) a specific number of time units to a source string 
Usage

time:add(<string>,{<unit> : n}) 

 


time:strftime()



  • Convert a datetime string to a different format
Usage

time:strftime(<string>,<format>) 


  Valid format arguments to strftime follow the POSIX strftime conventions.



time:atom()



  • Convert a datetime string to an ATOM compatible format
Usage

time:atom(<string>)

time:atom(<string>,{“tz” : <timezone>}) 


Examples


time:now()

Samples

xTime = time:now() # 2010-10-06T18:11:47Z

xTime = time:now({ # 2010-10-06T18:11:47Z

“tz” : “America/Los_Angeles”

})



time:new()

Samples

time:new(“2010-08-08") # 2010-08-08T00:00:00Z (Date only—defaults to 00:00)

time:new(“67342”) # 1967-12-08T00:00:00Z (Year DayOfYear)

time:new(“2011W206T1345-0600”) # 2011-05-21T19:45:00Z (Year WeekOfYear DayOfWeek)

time:new(“083023Z") # 2010-10-05T08:30:23Z (Time only—defaults to today)


time:add()

Samples

time:add(“2010-08-08",{“weeks” : 5}) # 2010-09-12T00:00:00Z

time:add(“67342”,{“hours”:3}) # 1967-12-08T04:00:00Z

time:add(“2011W206T1345-0600”,{“days”:-65}) # 2011-03-17T13:45:00Z

time:add(“083023Z",{“seconds” : 632}) # 2010-10-06T08:40:55Z


time:strftime()

Samples

time:strftime(xTime,”%F %T”) # 2010-10-06 18:15:24

time:strftime(xTime,”%F”) # 2010-10-06

time:strftime(xTime,”%T”) # 18:19:29

time:strftime(xTime,”%A %d %b %Y”) # Wednesday 06 Oct 2010

time:strftime(xTime,”%c”) # Oct 6, 2010 6:25:55 PM



time:atom()

Samples

time:atom(“2010-10-31") # 2010-10-31T00:00:00Z

time:atom(“2010-10-31",{ # 2010-10-31T06:00:00Z

“tz” : “America/Denver”

})