Today’s Regex is used to parse a string for Flickr links and extract the Photo_ID. Once we have the Photo_ID we’re able to create a standard embed code from nearly any Flickr URL.
Supported Links:
The following Regex supports these Flickr links and embed code snippets.
Normal URL : http://www.flickr.com/photos/gambort/6501997531/
Short URL : http://flic.kr/p/aUyrkH
Embed : >a href="http://www.flickr.com/photos/gambort/6501997531/"
title="Skyrim black dragon by gambort, on Flickr"><img
src="http://farm8.staticflickr.com/7004/6501997531_80aa9da91a.jpg"
width="500" height="334" alt="Skyrim black dragon"></a>
****Short Code id needs to be decoded and replaced with the full photo ID****
Again, I’ve broken it up the Regex and commented each line.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | $regexstr = '~ # Match Flickr link and embed code (?:<a [^>]*href=")? # If a tag match up to first quote of src (?: # Group Flickr url https?:\/\/ # Either http or https (?:[\w]+\.)* # Optional subdomains (?: # Group host alternatives. flic\.kr # Either flic.kr | flickr\.com # or flickr.com ) # End Host Group (?:\/photos)? # Optional video sub directory \/[^\/]+\/ # Slash and stuff before Id ([0-9a-zA-Z]+) # $1: PHOTO_ID is numeric [^\s]* # Not a space ) # End group "? # Match end quote if part of src (?:.*></a>)? # Match the end of the a tag ~ix'; |
Usage Example:
This example is more involved than the previous posts because we need to make an API call to get the image URL after we get the Flickr Photo_ID. I’ve also included a Base58 decode function incase the url is the short flic.kr style link.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | function ParseForFlickr($string){ $regexstr = <<REGEX FROM ABOVE>>; require_once('phpFlickr.php'); $f = new phpFlickr("<<Flickr API Key>>"); preg_match_all($regexstr, $string, $matches, PREG_SET_ORDER); //Loop results foreach ($matches as $val) { //If short code decode it if (strpos($val[0], "flic.kr") !== false) { $val[1] = $this->flickrDecode($val[1]); } //make flickr api call with photo id $pinfo = $f->photos_getSizes($val[1]); //Array 3 is the medium 500 size $imgstr = ' <p><img class="upostimg" src="'.$pinfo[3]['source'].'" /></p> '; $string = str_replace($val[0],$imgstr,$string); } return $string; } function flickrDecode($num){ $alphabet = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"; $decoded = 0; $multi = 1; while (strlen($num) > 0) { $digit = $num[strlen($num)-1]; $decoded += $multi * strpos($alphabet, $digit); $multi = $multi * strlen($alphabet); $num = substr($num, 0, -1); } return $decoded; } |
For more Regex see Regex YouTube Parser or Regex Vimeo Parser
Today’s Regex is used to parse a string for Vimeo links and extract the Video_ID. Once we have the Video_ID we’re able to create a standard embed code from Vimeo links.
Supported Links:
The following Regex supports these Vimeo links and embed code snippets.
Normal URL: http://vimeo.com/9669721
Group URL: http://vimeo.com/groups/tvc/videos/32626014
New Embed: <iframe src="http://player.vimeo.com/video/9669721?title=0
&byline=0&portrait=0&color=ffffff" width="400"
height="225" frameborder="0" webkitAllowFullScreen
mozallowfullscreen allowFullScreen > </iframe >
**** Doesn't handle Vimeo's old embed code ****
Again, I’ve broken it up the Regex and commented each line.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | $regexstr = '~ # Match Vimeo link and embed code (?:<iframe [^>]*src=")? # If iframe match up to first quote of src (?: # Group vimeo url https?:\/\/ # Either http or https (?:[\w]+\.)* # Optional subdomains vimeo\.com # Match vimeo.com (?:[\/\w]*\/videos?)? # Optional video sub directory this handles groups links also \/ # Slash before Id ([0-9]+) # $1: VIDEO_ID is numeric [^\s]* # Not a space ) # End group "? # Match end quote if part of src (?:[^>]*></iframe>)? # Match the end of the iframe (?:<p>.*</p>)? # Match any title information stuff ~ix'; |
Usage Example:
This example function takes an input string and uses the above Regex to parse off the Vimeo Video_ID ($1) and add it to $iframestr to create a standard embed code.
1 2 3 4 5 6 | function ParsePostVimeo($string){ $regexstr = <<REGEX FROM ABOVE>>; $iframestr = ' <p><iframe src="http://player.vimeo.com/video/$1?title=0&byline=0&portrait=0" width="500" height="284" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe></iframe></p> '; return preg_replace($regexstr, $iframestr, $string); } |
For more Regex see Regex YouTube Parser
Over the next several days I’m going to post a series of Regex strings. These Regex strings can be used to parse input for different links. I’m using PHP in my examples (you may need to tweak the Regex to work in another language).
Today’s Regex is used to parse a string for YouTube links and extract the Video_ID. Once I have the Video_ID I’m able to create a standard embed code from nearly any YouTube URL.
Supported Links:
The following Regex supports these YouTube links and embed code snippets.
Short URL : http://youtu.be/OxWMsxa5uVk
Normal URL: http://www.youtube.com/watch?v=OxWMsxa5uVk&t=28s
HTTPS URL : https://www.youtube.com/watch?v=OxWMsxa5uVk&feature=g-logo
New Embed : <iframe width="560" height="315" src="http://www.youtube.com/
embed/OxWMsxa5uVk" frameborder="0"
allowfullscreen></iframe>
Old Embed : <object width="1280" height="720"><param name="movie"
value="http://www.youtube.com/v/OxWMsxa5uVk?
version=3&hl=en_US&rel=0"></param>
<param name="allowFullScreen" value="true"></param>
<param name="allowscriptaccess"
value="always"></param><embed
src="http://www.youtube.com/v/OxWMsxa5uVk?version=3&
hl=en_US&rel=0" type="application/x-shockwave-flash"
width="1280" height="720" allowscriptaccess="always"
allowfullscreen="true"> </embed></object>
I won’t spend a lot of time explaining the Regex because I’ve broken it up Regex and commented each line.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | $regexstr = '~ # Match Youtube link and embed code (?: # Group to match embed codes (?:<iframe [^>]*src=")? # If iframe match up to first quote of src |(?: # Group to match if older embed (?:<object .*>)? # Match opening Object tag (?:<param .*</param>)* # Match all param tags (?:<embed [^>]*src=")? # Match embed tag to the first quote of src )? # End older embed code group )? # End embed code groups (?: # Group youtube url https?:\/\/ # Either http or https (?:[\w]+\.)* # Optional subdomains (?: # Group host alternatives. youtu\.be/ # Either youtu.be, | youtube\.com # or youtube.com | youtube-nocookie\.com # or youtube-nocookie.com ) # End Host Group (?:\S*[^\w\-\s])? # Extra stuff up to VIDEO_ID ([\w\-]{11}) # $1: VIDEO_ID is numeric [^\s]* # Not a space ) # End group "? # Match end quote if part of src (?:[^>]*>)? # Match any extra stuff up to close brace (?: # Group to match last embed code </iframe> # Match the end of the iframe |</embed></object> # or Match the end of the older embed )? # End Group of last bit of embed code ~ix'; |
Usage Example:
This example function takes an input string and uses the above Regex to parse off the Video_ID ($1) and add it to $iframestr to create a standard embed code.
1 2 3 4 5 6 | function ParsePostYouTube($string){ $regexstr = <<REGEX FROM ABOVE>>; $iframestr = ' <p><iframe width="500" height="284" src="http://www.youtube.com/embed/$1?wmode=transparent" frameborder="0" allowfullscreen></iframe></p> '; return preg_replace($regexstr, $iframestr, $string); } |
I’m working on a project that uses DataTables a JQuery plug-in that turns ordinary table into dynamic tables. One of the columns includes a list of birthdays. We didn’t want the standard date sorting. We wanted the birthdays to sort primarily by month. Below you will see the custom sort algorithm I came up with to sort our birthdays.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | function sortdatatable(a,b){ //a is blank return 1 to sort after b if(a == '') return 1; //b is blank return 0 no change if(b == '') return 0; //Split dates on / //format expected is mm/dd/yyyy //array 0 is month //array 1 is day //array 1 is year var x = a.split('/'), y = b.split('/'); //Parse month strings to int for comparison var xInt = parseInt(x[0]), yInt = parseInt(y[0]); //If months are the same check days. if(xInt == yInt){ //Parse day strings to int for comparison var x1Int =parseInt(x[1]), y1Int = parseInt(y[1]); //if days are the same check years if(x1Int == y1Int){ //Parse day strings to int for comparison var x2Int = parseInt(x[2]), y2Int = parseInt(y[2]); //if years are the same return 0. //if xInt is smaller than yInt return 1 to sort after y else return -1 return x2Int == y2Int ? 0 : x2Int < y2Int ? 1 : -1; } else { //if xInt is smaller than yInt return 1 to sort after y else return -1 return x1Int < y1Int ? 1 : -1; } } else { //if xInt is smaller than yInt return 1 to sort after y else return -1 return xInt < yInt ? 1 : -1; } } jQuery.fn.dataTableExt.oSort['birthday-asc'] = function(a, b) { return -(sortdatatable(a,b)); }; jQuery.fn.dataTableExt.oSort['birthday-desc'] = function(a, b) { return sortdatatable(a,b); }; |
The meat of the sorting is the sortdatatable function. The algorithm sorts according to descending order. We compare the months first. If the months are the same we compare days and if the days are the same we compare years. If months, days, and years are all the same we return 0 to leave those two items in the same order.
The ascending and descending algorithms are the inverse of each other. So to save space in the JavaScript file we use the same function and return the -(sortdatatable(a,b)) for the ascending sort.
I stumbled across this Silverlight “feature” today. Silverlight’s binding works in a linear order.
1 | <ComboBox SelectedValue="{Binding SelectedHour, Mode=TwoWay}" ItemsSource="{Binding Hours}" /> |
In the above code, selected value isn’t being set on page load. When I change the ComboBox my SelectedHour ViewModel property was being updated with a new value. This let me know that my binding is working. In further debugging I noticed SelectedHour property was being accessed before the Hours property. The binding was trying to set the selected value but the ComboBox was ignoring it because it didn’t have any values. For fun I tired moving ItemSource binding in front of the SelectedValue binding.
1 | <ComboBox ItemsSource="{Binding Hours}" SelectedValue="{Binding SelectedHour, Mode=TwoWay}" /> |
Everything started working perfectly. Now I know to watch the order of my XAML properties in Silverlight.
I’m working on a PHP project that requires human readable, relative date formatting. Below is the PHP function I’m using. The function handles past and future dates.
Sample Future Output :
- 30 seconds to go
- 1 minute to go
- 5 hours to go
- Tomorrow at 2:25pm
- June 30, 2022 5:34pm
Sample Past Output :
- 0 seconds ago
- 32 minutes ago
- 20 hours ago
- Yesterday at 5:26pm
- Monday at 10:28am
- June 25 at 5:23am
- March 30, 2010 at 5:34pm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | public function FormatTime($timestamp) { // Get time difference and setup arrays $difference = time() - $timestamp; $periods = array("second", "minute", "hour", "day", "week", "month", "years"); $lengths = array("60","60","24","7","4.35","12"); // Past or present if ($difference >= 0) { $ending = "ago"; } else { $difference = -$difference; $ending = "to go"; } // Figure out difference by looping while less than array length // and difference is larger than lengths. $arr_len = count($lengths); for($j = 0; $j < $arr_len && $difference >= $lengths[$j]; $j++) { $difference /= $lengths[$j]; } // Round up $difference = round($difference); // Make plural if needed if($difference != 1) { $periods[$j].= "s"; } // Default format $text = "$difference $periods[$j] $ending"; // over 24 hours if($j > 2) { // future date over a day formate with year if($ending == "to go") { if($j == 3 && $difference == 1) { $text = "Tomorrow at ". date("g:i a", $timestamp); } else { $text = date("F j, Y \a\\t g:i a", $timestamp); } return $text; } if($j == 3 && $difference == 1) // Yesterday { $text = "Yesterday at ". date("g:i a", $timestamp); } else if($j == 3) // Less than a week display -- Monday at 5:28pm { $text = date("l \a\\t g:i a", $timestamp); } else if($j < 6 && !($j == 5 && $difference == 12)) // Less than a year display -- June 25 at 5:23am { $text = date("F j \a\\t g:i a", $timestamp); } else // if over a year or the same month one year ago -- June 30, 2010 at 5:34pm { $text = date("F j, Y \a\\t g:i a", $timestamp); } } return $text; } |
The other day I had an interesting problem at work. My new project had a web service call that was pulling metadata off an MS SQL cube. When I started to the the project the call had 6 nested loops that it processing twice. A poster child for inefficiency. Unfortunately looping seems the be the only way to pull metadata from a cube.
By limiting the loops to only the required dimensions and processing everything only once, I was able to get the execution time from 2.5 minutes down to 6 seconds. 6 seconds is still far to long for an on demand call. Luckily the cube metadata doesn’t change frequently. Allowing me to cache the data. Taking the call from 6 seconds down to 200 milliseconds, on all subsequent calls. This is the caching I implemented for the metadata.
Created global private static instance of the HttpRuntime Cache. Allowing anyone calling the service to get the same data from the cache.
1 | private static System.Web.Caching.Cache _cache = HttpRuntime.Cache; |
Next, create a key to use for your cached object. Depending on the data your caching this may need to be more unique than below. Get the object from your global cache using the key. If a non-null comes out of the cache return your cached object.
1 2 3 4 5 6 7 | string key = typeof(<object to cache>).Name; var list = _cache.Get(key) as <object to cache>; if (list != null) { return list; } |
If no object comes out of the cache do your normal data processing. Just before you return your data add it to the cache. Here I’m caching for one day at normal priority.
1 | _cache.Add(key,<object to cache>, null, DateTime.Now.AddDays(1), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, null); |
That’s it! The first call will populate the cache and all other calls will pull from the cache. Super simple and an excellent way to improve your service call performance.
Good Luck!
I had a request to hide the multiple file upload links in SharePoint 2010. After an hour or two of searching for a configuration setting, I got tired and did a simple CSS hack. Granted this doesn’t disable the functionality it only hides links. So users could still work around this if they know the path.
Because SharePoint ignores common web standards and uses Ids with periods I had to escape the Id. CSS will treat the periods as a class declaration if they are not escaped.
To use this simply add the code snippet to your main CSS file or your master page in SharePoint. If this code snippet doesn’t work for you verify that the Id’s are the same in your SharePoint installation.
1 2 3 4 5 | #ctl00_PlaceHolderMain_UploadDocumentSection_ctl03_UploadMultipleLink, #Ribbon\.Documents\.New\.AddDocument\.Menu\.Upload\.UploadMultiple-Menu32 { display: none; } |
I’ve found the best way access initParams throughout your Silverlight Application is to put them in a global static dictionary. This is how I setup my initParms dictionary.
First we need to set an initParams in our ASPX Page:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <div id="silverlightControlHost"> <object width="100%" height="100%" type="application/x-silverlight-2" data="data:application/x-silverlight-2,"> <param name="source" value="ClientBin/initParamsDemo.xap" /> <param name="onError" value="onSilverlightError" /> <param name="background" value="white" /> <param name="minRuntimeVersion" value="3.0.40818.0" /> <param name="autoUpgrade" value="true" /> <param name="initParams" value="ServiceURL=http://localhost:8000/service1.svc" /> < a style="text-decoration: none;" href="http://go.microsoft.com/fwlink/?LinkID=149156&v=3.0.40818.0"> <img style="border-style: none;" src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" /> </a> </object> </div> |
Next we need to create our static dictionary in App.xaml.cs and assign the dictionary in the startup event.
1 2 3 4 5 6 7 | public static IDictionary<string, string> AppParams; private void Application_Startup(object sender, StartupEventArgs e) { this.RootVisual = new MainPage(); AppParams = e.InitParams; } |
When you want to access your param you simply use grab if from the dictionary using the key.
1 | App.AppParams["ServiceURL"] |
We can’t always trust that the initParam is set you should check to make sure it’s in the dictionary before using it.
1 2 3 4 5 6 7 8 | if (App.AppParams.ContainsKey("ServiceURL")) { // Do Something with: App.AppParams["ServiceURL"] } else { // Handle error</code></em></span> } |
My Twitter
- @elementdave is rock'in the mic tonight at the youth auction tonight! 2 hours ago
- Watching the 80's version of Transformers with my 2.5 year old. #goodtimes 9 hours ago
- Hanging out at a lake cabin with friends for the day. 2012/05/19
- P.S.A just because your riding a bike doesn't mean you need skin tight short and shirt. Your not racing right now. 2012/05/19
- @smarkowitz Thanks for following. 2012/05/19
- RT @phpfog: Because you asked for it.... PHP Fog now has cron support. http://t.co/sEZMDkAv Nice... Keep up the good work! 2012/05/18
- Does anyone else find it #ironic that Facebook is buy a company called Karma? http://t.co/Gjdi8Zds 2012/05/18
- Any glimmer of hope you had about your Facebook information being private died today. Facebook is now legal obligated maximize profits. 2012/05/18
- RT @CoffeeScript: Kicksend rewrote their entire web app in one month with a faster, leaner code base featuring CoffeeScript and Backbone ... 2012/05/18
- Glad to see normal investors not getting screwed by driving up $FB prices. It's already overvalued let it stabilize. 2012/05/18
Archives
- December 2011
- October 2011
- August 2011
- June 2011
- April 2011
- March 2011
- February 2011
- December 2010
- November 2010
- October 2010
- August 2010
- June 2010
- May 2010
- April 2010
- March 2010
- February 2010
- January 2010
- December 2009
- November 2009
- October 2009
- September 2009
- August 2009
- July 2009
- June 2009
- May 2009
- April 2009
- March 2009
- February 2009
- January 2009
- December 2008
- November 2008
- September 2007
- July 2007
- June 2007
- April 2007
- March 2007
- February 2007
- January 2007
- December 2006
- November 2006
