In some wordpress themes, youtube embeds just show up as a black screen. As discussed here, the solution is adding a transparency setting to the iframe’s src.
However, the solution in that thread only works if the src is right next to the frameborder. Updated code below if you are running into this problem
I love using Trello to organize my life and work. While I kind of like it’s iOS app, sometimes navigating to a board to add a card can be a little time consuming. I want this process to be faster.
I also use Launch Center Pro to get some quick actions that I miss from Android. Mostly around quick communication, adding events, and now, adding to Trello. LCP uses x-callback-urls for inter-app communication, but Trello doesn’t have any that I could see. Inspired by Federico Viticci‘s article on automating his iOS workflow, I decided to take a crack at it using pythonista. All code shown below can be found on GitHub.
Pythonista lets you edit and run python scripts on your phone. There are a few ways to get scripts onto your device:
Use pastebot. A great app that gives you multiple clipboards on your device that will also sync with your mac. This is my preferred method.
The endgame of all this: I want to be able to add a card to a specific board, with as few taps as possible. Check out this video for what we are going to build.
Digging into the Trello API, we can see that to add a card, we’ll need a name for the card and the ID of the list to add it to. We also see that we’ll need a token for any of the API calls. To get all of our lists, we’ll also need to know about all of our boards. This breaks our tasks out as follows:
Get an App API Key
Get an API Token
Get a list of every board we heve
Get the IDs of every list on each of these boards
Add a new card to our list of choice
To get an App API Key, you can generate one here https://trello.com/1/appKey/generate . In theory, the one I distribute with these scripts should be ok.
Get this first script into Pythonista and run it. It will generate a permanant API token for you that you can leave in Launch Center Pro when running these scripts.
#GetTrelloToken
import webbrowser
url = 'https://trello.com/1/authorize?key=3e2cd730f3dcccbe15eaf0d39d219a37&name=PythonistaTrello&expiration=never&response_type=token&scope=read,write'
#open web browser to get a permanant Trello API Token
webbrowser.open(url)
Now that we have our key and tokens, let’s get get all of our boards and the lists on each one. Run this script and pass in your token and your email address as arguments. (In pythonista hold down run to get the “Run with arguments dialog”). Add your arguments separated by spaces. For me, this could look something like: “EGYlyiOdggDOaPoTUxaTQobmS6gtiX timothy.broder@gmail.com”
#List all lists by user
import urllib2
import urllib
import json
import sys
if len(sys.argv) != 3:
raise Exception("Usage: list_trello_lists.py [token] [email]")
key = "3e2cd730f3dcccbe15eaf0d39d219a37"
args = { 'key': key,
'token': sys.argv[1],
'filter': 'open'}
#build out api url
username = sys.argv[2]
boards_url = "https://api.trello.com/1/members/%s/boards/?%s" % (username, urllib.urlencode(args))
#get board data from api
try:
data = urllib2.urlopen(boards_url)
except urllib2.HTTPError as inst:
raise Exception("Key or Token incorrect")
boards = json.loads(data.read())
#loop through each board
for board in boards:
board_id = board['id']
lists_url = "https://api.trello.com/1/boards/%s/lists?%s" % (board_id, urllib.urlencode(args))
data = urllib2.urlopen(lists_url)
lists = json.loads(data.read())
print "-- %s" % board['name']
#output each list in board
for lizt in lists:
print "\"%s\" %s" % (lizt['name'], lizt['id'])
print "\n"
Running this, we’ll get the IDs of the lists we need
Finally, we’ll need to take our key, the id of the list, what we want our card to say, and hit the API with them. I also add in a position so the cards I add this way will appear at the top of their list.
We’ll pass these in as parameters: “EGYlyiOdggDOaPoTUxaTQobmS6gtiX V12t3k6RQQ2r8X top the name of my card goes here”
Two things to point out in this script:
we put the name of the card at the end so we can just loop through all the remaining words and not have to worry about wrapping the name in quotes to deal with spaces.
since the end game of this is to run from Launch center pro, we want to jump back to Launch Center Pro at the end using it’s x-callback-url
#Add card to List
import urllib2
import urllib
import json
import sys
import webbrowser
arglen = len(sys.argv)
if arglen < 5: raise Exception("Usage: list_trello_lists.py [token] [list_id] [position] [card_name]") name = sys.argv[4] #take care of spaces if arglen > 5:
for i in range(5,arglen):
name = "%s %s" % (name, sys.argv[i])
key = "3e2cd730f3dcccbe15eaf0d39d219a37"
token = sys.argv[1]
args = { 'key': key,
'token': sys.argv[1],
'name': name,
'pos': sys.argv[3],
'idList': sys.argv[2]
}
card_add_url = "https://api.trello.com/1/cards"
try:
data = urllib2.urlopen(card_add_url, urllib.urlencode(args))
except urllib2.HTTPError as inst:
raise Exception("Key or Token incorrect")
#jump back to Launch Center Pro
webbrowser.open("launchpro:")
To run this in Launch Center Pro, Add an Action > Pythonista > Run Script with Arguments. Put in the name of the script, then in arguments, but everything from above except the name: “EGYlyiOdggDOaPoTUxaTQobmS6gtiX V12t3k6RQQ2r8X top,” then hit the button that says input prompt. Now, when you run the script, Launch Center Pro will prompt you for text, enter the name of the card and hit go.
Add as many of these as you want! Just swap out the list ID.
A few months ago I gave a presentation at work about why we moved from SVN to distributed source and git. Totally forgot to put it in a post here. I also had a lot of fun playing with reveal.js for the slides and setting up github pages.
When I switched from eclipse to sublime text 2, the first hotkey I moved over was cmd+d to delete a line. I use it pretty heavily. After using Xcode for a few months it was driving me crazy that it didn’t have delete line as an option under hotkeys. Thanks to stackoverflow for the solve.
To add a new custom key binding, we have to edit the Key Binding plist file:
(close Xcode)
sudo vi /Applications/Xcode.app/Contents/Frameworks/IDEKit.framework/Resources/IDETextKeyBindingSet.plist
Add this text just ABOVE the close of the <dict> at the bottom of this file:
<key>Custom</key>
<dict>
<key>Delete Current Line In One Hit</key>
<string>moveToEndOfLine:, deleteToBeginningOfLine:, deleteToEndOfParagraph:</string>
</dict>
Note that:
This is inside the existing <dict> so there is a </dict></plist> after this
This associates the named action “Delete Current Line In One Hit” to the three key actions in the string. I played around with different options here to get the right combination. For instance, if you try moveToBeginningOfLine, deleteToEndOfLine instead of vice versa, then using it on empty lines will delete the line and the entire next line. Which is unpleasant
Save this and open XCode
Open XCode Preferences
Select Key Bindings
Click on All
In the SEarch box type “Delete” and search for “Delete Current Line in One Hit”
Add your new binding.
I use cmd+d, so I had to map duplicate to something else first
Through the successful completion of the Citrix CCA XenApp Windows Server 2003 exam (1Y0-A23 exam) you can achieve validation of your administration skills with the achievement of a Citrix Certified Administrator (CCA) certification. This exam is the only requirement for achieving the certification, which is a valuable credential to obtain in the IT industry. As more and more enterprises across all sectors or the market utilize Citrix platforms, the XenApp 1Y0-A23 exam is a positive step in your professional development.
Whether you work for a single employer, contract your services to corporate clients, or are a self employed IT professional serving a variety of customers, formally documenting your unique skills and abilities is essential. Passing the Citrix 1Y0-A23 exam is certainly a step in the right direction.
The Citrix 1Y0-A23 exam features 66 questions in ten primary subject areas, including everything from implementation and configuration to troubleshooting and maintenance. A passing score of 60 percent or higher is required for success, and you’ll need to ensure you spend plenty of time and energy preparing for your exam.
Citrix offers formal training in the discipline through online, self paced and instructor led training. Onsite, in person training is also available in some areas. Courses include labs that will allow you to hone your skills and knowledge through hands on application. Additionally, you can utilize other resources available through online prep services such as TestsLive.com, which include tutorials and full length, detailed practice exams. Practice tests are among the most valuable of exam prep activities as they allow you to measure your knowledge attainment and testing readiness prior to scheduling your 1Y0-A23 exam.
By default, WordPress will link directly to an image in the category or post view. In a project I was working on today I wanted to change that. On the category view I wanted the image just to link to the post, and in the post, I didn’t want a link at all. Useful trick I found below:
function change_image_permalink($content){
$format = get_post_format();
//category listing page. link image to post
if (is_single() === FALSE AND $format == 'image'){
$content =
preg_replace(
array('{<a(.*?)(wp-att|wp-content/uploads)[^>]*><img}','{ wp-image-[0-9]*" /></a>}'),
array('<a href="' . get_permalink() . '"><img','" /></a>'),
$content
);
}
//post page. remove link
else if ($format == 'image'){
$content =
preg_replace(
array('{<a(.*?)(wp-att|wp-content/uploads)[^>]*><img}','{ wp-image-[0-9]*" /></a>}'),
array('<img','" />'),
$content
);
}
return $content;
}
add_filter('the_content', 'change_image_permalink');
There are a lot of cases on blogs where once you write the post, the cache for that page doesn’t really have to be updated all that often. Comments can be powered by Disqus so you don’t need to bust the cache every time someone comments. If you make a change to a post, it’s page and any pages that display it (home, category, etc) should be updated automatically anyway; wp-varnish is the best plugin for that btw.
Now, the sidebar. That’s where it can get tricky. On a lot of the content sites I work on, we can cache most pages for days, the backend doesn’t need to keep generating them, the content just lives in varnish. Except for the sidebar. This could have things like “Popular Posts” or “New Posts”. Things that are going to change outside of the context of the post you are currently looking at.
This is where Edge Side Includes (ESI) comes in. For a while, Akamai was the only way to get this behavior, and they are quite expensive. Don’t get me wrong, they are amazing, but you have to be getting serious traffic to need them. Varnish is one of the best caching solutions you can use, especially for WordPress. If you are unsure where to start with Varnish and wordpress, this article is a great starting point. I’v also bookmarked some other articles here.
ESI was introduced in 2.1, and really fleshed out in 3.0 and can be thought of as fragment caching for Varnish. It’s really easy to fix the example I gave above: we want to be able to cache most of the content for 24 hours but refresh just the sidebar every 10 mins. Varnish will do this processing for us, keeping the rest of the page cached, and splicing in the sidebar (and having your webserver process just the sidebar) when it needs to. Most of what I’m going to do below is in the ESI documentation.
We’re going to assume that our theme has a dynamic sidebar called “Sidebar” and that there are cases where we want ESI to be active (production) and some where wordpress should just behave normally (dev). This is what we have before we start thinking about Varnish:
The two varnish tags we are going to use are an esi comment, and an esi:remove tag. These are the switch that will process the page properly whether you have ESI or not. esi:remove will ignore everything between them if ESI is enabled. This is where we put our “normal processing” code. If ESI is not active, this code will run as normal. Inside the esi comment we put the code that we want to run if ESI is enabled. If it is not, the code will be ignored.
Now our sidebar display is ESI ready, but we need to give Varnish an endpoint to hit so it can generate the fragment of the sidebar. So lets create esihandler.php:
Lastly, we’ll have to tell Varnish to cache for different timeframes. A full Varnish config is out of the scope of this post, see the links above for more info. What we need is in the sub vcl_fetch call. Add this at the top:
if (req.url ~ "esihandler.php") {
set beresp.ttl = 10m;
}
else {
set beresp.do_esi = true;
set beresp.ttl = 1440m;
}
And you should be all set. When developing you can use smaller timeframes (10 seconds, and 1min). Drop some logging in to see it in action.
I’m adding drag/drop uploading to the django admin for one of our open source projects called Stager. A blog post about that will follow, it’s not screen-shot ready yet. While doing this I knew we needed a pretty seamless transition after the upload finished, and that we would have to refresh the inline. I didn’t want a full page refresh, so let’s ajax it in.
For these examples just assume that we have a parent CompAdmin which has an model of Comp and an inline called CompSlideInline. We store the instance of the Comp in comp.
from django.template import loader, Context
from django.contrib.admin import helpers
from django.db import transaction
from django.contrib import admin
comp = Comp.objects.get(id=comp_id)
#get the current site
admin_site = admin.site
compAdmin = CompAdmin(Comp, admin_site)
#get all possible inlines for the parent Admin
inline_instances = compAdmin.get_inline_instances(request)
prefixes = {}
for FormSet, inline in zip(compAdmin.get_formsets(request, comp), inline_instances):
#get the inline of interest and generate it's formset
if isinstance(inline, CompSlideInline):
prefix = FormSet.get_default_prefix()
prefixes[prefix] = prefixes.get(prefix, 0) + 1
if prefixes[prefix] != 1 or not prefix:
prefix = "%s-%s" % (prefix, prefixes[prefix])
formset = FormSet(instance=comp, prefix=prefix, queryset=inline.queryset(request))
#get possible fieldsets, readonly, and prepopulated information for the parent Admin
fieldsets = list(inline.get_fieldsets(request, comp))
readonly = list(inline.get_readonly_fields(request, comp))
prepopulated = dict(inline.get_prepopulated_fields(request, comp))
#generate the inline formset
inline_admin_formset = helpers.InlineAdminFormSet(inline, formset,
fieldsets, prepopulated, readonly, model_admin=compAdmin)
#render the template
t = loader.get_template('tabular.html')
c = Context({ 'inline_admin_formset': inline_admin_formset })
rendered = t.render(c)