Optimize images in CRON job

Google PageSpeed Insights may complain about images being not compressed enough. There are techniques which ensure lossless compression. When using JPG images you may compress them using jpegoptim, which may be run from the command line.

jpegoptim -s /var/www/html/images/*.jpg

The command will go through all jpg images in that folder and will perform lossless compression. The -s parameter will also ensure that all markers (eg. comments and EXIF data) will be removed.

Add music from your SD Card to Windows Media Player library

This solution is good for situations where you don’t have enough space on your hard disc, so you move it to your SD Card and have it plugged to the PC permanently.
You may have noticed that you are unable to select folders inside the SD Card. What you have to do is make the music folder on the SD Card shared (at least with yourself) and then add it to the Windows Media Player from the network share.

Block commit to SVN when Redmine issue is not specified

Redmine allows to reference commits to issues by using keyword refs followed by # and number of the issue. If you want to block user commit to SVN without specifying Redmine issue you can use similar pre-commit hook on SVN. The hook is for Windows version.


@ECHO OFF

REM *************************************************************
REM * this sets the arguments supplied by Subversion *
REM *************************************************************
SET REPOS=%1
SET TXN=%2

REM *************************************************************
REM * define directory paths *
REM * you *must* add any paths for command line tools you plan *
REM * since SVN does not include the Windows %PATH% environment *
REM * variable for security reasons. *
REM * *
REM * DIR - the current hooks directory *
REM * PATH - a user set path of where executables are located *
REM * *
REM *************************************************************
SET DIR=%REPOS%hooks

REM *************************************************************
REM * make sure to add the path to the SendEmail executable *
REM *************************************************************
SET PATH=%PATH%;%DIR%

REM *************************************************************
REM * get comment search for "refs #" *
REM *************************************************************
svnlook log -t "%TXN%" "%REPOS%" | findstr /c:"refs #" > NUL
IF %errorlevel% NEQ 0 GOTO Error

GOTO Success

:Error
ECHO. 1>&2
ECHO Your commit has been blocked because you didn't 1>&2
ECHO specify Redmine issue with refs keyword. 1>&2
ECHO Please write a log message (eg. refs #123) and 1>&2
ECHO then try committing again. -- Thank you Roman 1>&2
EXIT 1

:Success

Hide images from the Plone’s Tabular View

It is easily possible to hide images from the navigation port-let using control panel, but I did not find similar option for the Tabular View when a folder contents is displayed.
So here is the solution I have applied.

  1. Login to Zope Management interface
  2. Go to /…/portal_skins/plone_content and create a custom version of folder_tabular_view
  3. In the customized version of the folder_tabular_view locate “class python:test(oddrow, ‘even’, ‘odd’)” and change it to “class python:test(oddrow, ‘even tr-‘ + item_type_class, ‘odd tr-‘ + item_type_class)
  4. After these changes TR tag of the folder contents table will have an additional CSS class which we can use to hide unwanted content types
  5. Save the changes and edit customized CSS file called ploneCustom.css
  6. Add “.tr-contenttype-image { display: none; }” to hide rows with image content types

HtmlDecode inside SQLCLR without System.Web reference

I grabbed code from the WebUtility class which is available in System.Net of the .NET Framework 4.0. Can be compiled inside .NET 2.0.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
namespace System.Net
{
public static class WebUtility
{
private static class HtmlEntities
{
private static string[] _entitiesList = new string[]
{
""-quot",
"&-amp",
"'-apos",
"<-lt>-gt",
"u00a0-nbsp",
"¡-iexcl",
"¢-cent",
"£-pound",
"¤-curren",
"¥-yen",
"¦-brvbar",
"§-sect",
"¨-uml",
"©-copy",
"ª-ordf",
"«-laquo",
"¬-not",
"­-shy",
"®-reg",
"¯-macr",
"°-deg",
"±-plusmn",
"²-sup2",
"³-sup3",
"´-acute",
"µ-micro",
"¶-para",
"·-middot",
"¸-cedil",
"¹-sup1",
"º-ordm",
"»-raquo",
"¼-frac14",
"½-frac12",
"¾-frac34",
"¿-iquest",
"À-Agrave",
"Á-Aacute",
"Â-Acirc",
"Ã-Atilde",
"Ä-Auml",
"Å-Aring",
"Æ-AElig",
"Ç-Ccedil",
"È-Egrave",
"É-Eacute",
"Ê-Ecirc",
"Ë-Euml",
"Ì-Igrave",
"Í-Iacute",
"Î-Icirc",
"Ï-Iuml",
"Ð-ETH",
"Ñ-Ntilde",
"Ò-Ograve",
"Ó-Oacute",
"Ô-Ocirc",
"Õ-Otilde",
"Ö-Ouml",
"×-times",
"Ø-Oslash",
"Ù-Ugrave",
"Ú-Uacute",
"Û-Ucirc",
"Ü-Uuml",
"Ý-Yacute",
"Þ-THORN",
"ß-szlig",
"à-agrave",
"á-aacute",
"â-acirc",
"ã-atilde",
"ä-auml",
"å-aring",
"æ-aelig",
"ç-ccedil",
"è-egrave",
"é-eacute",
"ê-ecirc",
"ë-euml",
"ì-igrave",
"í-iacute",
"î-icirc",
"ï-iuml",
"ð-eth",
"ñ-ntilde",
"ò-ograve",
"ó-oacute",
"ô-ocirc",
"õ-otilde",
"ö-ouml",
"÷-divide",
"ø-oslash",
"ù-ugrave",
"ú-uacute",
"û-ucirc",
"ü-uuml",
"ý-yacute",
"þ-thorn",
"ÿ-yuml",
"Œ-OElig",
"œ-oelig",
"Š-Scaron",
"š-scaron",
"Ÿ-Yuml",
"ƒ-fnof",
"ˆ-circ",
"˜-tilde",
"Α-Alpha",
"Β-Beta",
"Γ-Gamma",
"Δ-Delta",
"Ε-Epsilon",
"Ζ-Zeta",
"Η-Eta",
"Θ-Theta",
"Ι-Iota",
"Κ-Kappa",
"Λ-Lambda",
"Μ-Mu",
"Ν-Nu",
"Ξ-Xi",
"Ο-Omicron",
"Π-Pi",
"Ρ-Rho",
"Σ-Sigma",
"Τ-Tau",
"Υ-Upsilon",
"Φ-Phi",
"Χ-Chi",
"Ψ-Psi",
"Ω-Omega",
"α-alpha",
"β-beta",
"γ-gamma",
"δ-delta",
"ε-epsilon",
"ζ-zeta",
"η-eta",
"θ-theta",
"ι-iota",
"κ-kappa",
"λ-lambda",
"μ-mu",
"ν-nu",
"ξ-xi",
"ο-omicron",
"π-pi",
"ρ-rho",
"ς-sigmaf",
"σ-sigma",
"τ-tau",
"υ-upsilon",
"φ-phi",
"χ-chi",
"ψ-psi",
"ω-omega",
"ϑ-thetasym",
"ϒ-upsih",
"ϖ-piv",
"u2002-ensp",
"u2003-emsp",
"u2009-thinsp",
"‌-zwnj",
"‍-zwj",
"‎-lrm",
"‏-rlm",
"–-ndash",
"—-mdash",
"‘-lsquo",
"’-rsquo",
"‚-sbquo",
"“-ldquo",
"”-rdquo",
"„-bdquo",
"†-dagger",
"‡-Dagger",
"•-bull",
"…-hellip",
"‰-permil",
"′-prime",
"″-Prime",
"‹-lsaquo",
"›-rsaquo",
"‾-oline",
"⁄-frasl",
"€-euro",
"ℑ-image",
"℘-weierp",
"ℜ-real",
"™-trade",
"ℵ-alefsym",
"←-larr",
"↑-uarr",
"→-rarr",
"↓-darr",
"↔-harr",
"↵-crarr",
"⇐-lArr",
"⇑-uArr",
"⇒-rArr",
"⇓-dArr",
"⇔-hArr",
"∀-forall",
"∂-part",
"∃-exist",
"∅-empty",
"∇-nabla",
"∈-isin",
"∉-notin",
"∋-ni",
"∏-prod",
"∑-sum",
"−-minus",
"∗-lowast",
"√-radic",
"∝-prop",
"∞-infin",
"∠-ang",
"∧-and",
"∨-or",
"∩-cap",
"∪-cup",
"∫-int",
"∴-there4",
"∼-sim",
"≅-cong",
"≈-asymp",
"≠-ne",
"≡-equiv",
"≤-le",
"≥-ge",
"⊂-sub",
"⊃-sup",
"⊄-nsub",
"⊆-sube",
"⊇-supe",
"⊕-oplus",
"⊗-otimes",
"⊥-perp",
"⋅-sdot",
"⌈-lceil",
"⌉-rceil",
"⌊-lfloor",
"⌋-rfloor",
"〈-lang",
"〉-rang",
"◊-loz",
"♠-spades",
"♣-clubs",
"♥-hearts",
"♦-diams"
};
private static Dictionary _lookupTable = WebUtility.HtmlEntities.GenerateLookupTable();
private static Dictionary GenerateLookupTable()
{
Dictionary dictionary = new Dictionary(StringComparer.Ordinal);
string[] entitiesList = WebUtility.HtmlEntities._entitiesList;
for (int i = 0; i < entitiesList.Length; i++)
{
string text = entitiesList[i];
dictionary.Add(text.Substring(2), text[0]);
}
return dictionary;
}
public static char Lookup(string entity)
{
char result;
WebUtility.HtmlEntities._lookupTable.TryGetValue(entity, out result);
return result;
}
}
private static char[] _htmlEntityEndingChars = new char[]
{
';',
'&'
};
public static string HtmlDecode(string value)
{
if (string.IsNullOrEmpty(value))
{
return value;
}
if (value.IndexOf('&') < 0)
{
return value;
}
StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
WebUtility.HtmlDecode(value, stringWriter);
return stringWriter.ToString();
}
public static void HtmlDecode(string value, TextWriter output)
{
if (value == null)
{
return;
}
if (output == null)
{
throw new ArgumentNullException("output");
}
if (value.IndexOf('&') < 0)
{
output.Write(value);
return;
}
int length = value.Length;
int i = 0;
while (i < length)
{
char c = value[i];
if (c != '&')
{
goto IL_110;
}
int num = value.IndexOfAny(WebUtility._htmlEntityEndingChars, i + 1);
if (num <= 0 || value[num] != ';')
{
goto IL_110;
}
string text = value.Substring(i + 1, num - i - 1);
if (text.Length > 1 && text[0] == '#')
{
ushort num2;
if (text[1] == 'x' || text[1] == 'X')
{
ushort.TryParse(text.Substring(2), NumberStyles.AllowHexSpecifier, NumberFormatInfo.InvariantInfo, out num2);
}
else
{
ushort.TryParse(text.Substring(1), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out num2);
}
if (num2 != 0)
{
c = (char)num2;
i = num;
goto IL_110;
}
goto IL_110;
}
else
{
i = num;
char c2 = WebUtility.HtmlEntities.Lookup(text);
if (c2 != '')
{
c = c2;
goto IL_110;
}
output.Write('&');
output.Write(text);
output.Write(';');
}
IL_117:
i++;
continue;
IL_110:
output.Write(c);
goto IL_117;
}
}
}
}