<?xml version="1.0" encoding="UTF-8"?> <rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" ><channel><title>Do Know Evil - A Blog by Tyler Mulligan &#187; Programming</title> <atom:link href="http://www.doknowevil.net/category/computers/software/programming/feed/" rel="self" type="application/rss+xml" /><link>http://www.doknowevil.net</link> <description>Tips and Tricks About Computers, Web Development, Linux, the Internet and the Like</description> <lastBuildDate>Sat, 16 Jul 2011 01:25:35 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.0.5</generator> <item><title>jQuery and jQuery UI in your Grease Monkey scripts.</title><link>http://www.doknowevil.net/2011/07/16/jquery-and-jquery-ui-in-your-grease-monkey-scripts/</link> <comments>http://www.doknowevil.net/2011/07/16/jquery-and-jquery-ui-in-your-grease-monkey-scripts/#comments</comments> <pubDate>Sat, 16 Jul 2011 01:25:35 +0000</pubDate> <dc:creator>Tyler Mulligan</dc:creator> <category><![CDATA[Chromium]]></category> <category><![CDATA[Computers]]></category> <category><![CDATA[DOM]]></category> <category><![CDATA[Firefox]]></category> <category><![CDATA[Google]]></category> <category><![CDATA[Javascript]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[Software]]></category> <category><![CDATA[The Internet]]></category> <category><![CDATA[Web Development]]></category> <category><![CDATA[css]]></category> <category><![CDATA[jQuery]]></category> <category><![CDATA[client-side hack]]></category> <category><![CDATA[control]]></category> <category><![CDATA[fix websites]]></category> <category><![CDATA[grease monkey]]></category> <category><![CDATA[lifehack]]></category> <category><![CDATA[stylish]]></category><guid isPermaLink="false">http://www.doknowevil.net/?p=985</guid> <description><![CDATA[Not all websites are made equal. Unfortunately, some of those websites are ones we&#8217;re required to use. Be it our job, our interests or the undiscovered, web-browsing can be the orgeon trail of the internet. Cultivating the atmosphere to work for us and bringing the right tools along for the journey are essential for survival,]]></description> <content:encoded><![CDATA[<p>Not all websites are made equal.  Unfortunately, some of those websites are ones we&#8217;re required to use.  Be it our job, our interests or the undiscovered, web-browsing can be the <em>orgeon trail</em> of the internet.  Cultivating the atmosphere to work for us and bringing the right tools along for the journey are essential for survival, if you&#8217;re a pioneer.</p><p>I&#8217;m tired of websites that don&#8217;t provide, can&#8217;t provide or will never provide.   I&#8217;ve called in my boys, <a href="https://addons.mozilla.org/en-US/firefox/addon/stylish/" target="_blank" title="create your own css for websites">Stylish</a> and <a href="https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/" target="_blank" title="create your own javascript for websites">Grease Monkey</a> on the front lines.  However, beyond the crazy happenstance that another user might share a solution to your issue on <a href="http://userstyles.org" title="user styles for stylish" target="_blank">userstyles.org</a> or <a href="http://userscripts.org" title="user scripts for grease monkey" target="_blank">userscripts.org</a> you could be left in the cold, without the right tools.  I won&#8217;t go into detail on Stylish in this post but you might not even need it after you see the script.</p><p>Since I&#8217;m already connected with Google every which way in my life, why not pretend like the Internet is a big party and websites are your friends.  Introduce jQuery from Google&#8217;s CDN to other friends (websites) that don&#8217;t already know jQuery and jQuery UI and <em>make it personal</em>.</p><p>That was the driving force behind this <strong>Grease Monkey Script</strong>, which was derived from mashing together <a href="http://strd6.com/2009/02/how-to-load-jquery-ui-css-in-greasemonkey/">strd6&#8242;s script</a> and <a href="http://joanpiedra.com/jquery/greasemonkey/">Joan Piedra&#8217;s script</a> with an update to the latest versions of jQuery and jQuery UI.</p><pre class="brush:javascript">
// ==UserScript==
// @name           jQuery and jQuery UI
// @author         Tyler &quot;-z-&quot; Mulligan
// @version        0.5
// @namespace      http://www.doknowevil.net
// @description    jQuery 1.6.2 and jQuery UI 1.8.4 loaded from google&#039;s CDN with redmond theme.
// @include        http://www.website.com/*
//
// @resource       jQuery               https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js
// @resource       jQueryUI             https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js
//
// @resource       jQueryUICSS          http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/jquery-ui.css
//
// @resource       ui-bg_inset-hard_100_fcfdfd_1x100.png  http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_inset-hard_100_fcfdfd_1x100.png
// @resource       ui-bg_gloss-wave_55_5c9ccc_500x100.png http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_gloss-wave_55_5c9ccc_500x100.png
// @resource       ui-bg_glass_85_dfeffc_1x400.png        http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_glass_85_dfeffc_1x400.png
// @resource       ui-bg_glass_75_d0e5f5_1x400.png        http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_glass_75_d0e5f5_1x400.png
// @resource       ui-bg_inset-hard_100_f5f8f9_1x100.png  http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_inset-hard_100_f5f8f9_1x100.png
// @resource       ui-bg_flat_55_fbec88_40x100.png        http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_flat_55_fbec88_40x100.png
// @resource       ui-bg_glass_95_fef1ec_1x400.png        http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_glass_95_fef1ec_1x400.png
// @resource       ui-icons_469bdd_256x240.png            http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_469bdd_256x240.png
// @resource       ui-icons_469bdd_256x240.png            http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_469bdd_256x240.png
// @resource       ui-icons_d8e7f3_256x240.png            http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_d8e7f3_256x240.png
// @resource       ui-icons_6da8d5_256x240.png            http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_6da8d5_256x240.png
// @resource       ui-icons_217bc0_256x240.png            http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_217bc0_256x240.png
// @resource       ui-icons_f9bd01_256x240.png            http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_f9bd01_256x240.png
// @resource       ui-icons_2e83ff_256x240.png            http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_2e83ff_256x240.png
// @resource       ui-icons_cd0a0a_256x240.png            http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-icons_cd0a0a_256x240.png
// @resource       ui-bg_flat_0_aaaaaa_40x100.png         http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png
// @resource       ui-bg_flat_0_aaaaaa_40x100.png         http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/redmond/images/ui-bg_flat_0_aaaaaa_40x100.png

// ==/UserScript==

var $;

// Inject jQuery into page... gross hack... for now...
(function() {
    if (typeof unsafeWindow.jQuery == &#039;undefined&#039;) {
        var head = document.getElementsByTagName(&#039;head&#039;)[0];

        var script = document.createElement(&#039;script&#039;);
        script.type = &#039;text/javascript&#039;;

        var jQuery = GM_getResourceText(&#039;jQuery&#039;);
        var jQueryUI = GM_getResourceText(&#039;jQueryUI&#039;);

        script.innerHTML = jQuery + jQueryUI;
        head.appendChild(script);

    }
    GM_wait();
})();

// Check if jQuery&#039;s loaded
function GM_wait() {
    if (typeof unsafeWindow.jQuery == &#039;undefined&#039;) {
        window.setTimeout(GM_wait, 100);
    } else {
        $ = unsafeWindow.jQuery.noConflict(true);
        addUIStyles();
        letsJQuery();
    }
}

function addUIStyles() {
    var head = document.getElementsByTagName(&#039;head&#039;)[0];
    var resources = {
        &#039;ui-bg_inset-hard_100_fcfdfd_1x100.png&#039;: GM_getResourceURL(&#039;ui-bg_inset-hard_100_fcfdfd_1x100.png&#039;),
        &#039;ui-bg_gloss-wave_55_5c9ccc_500x100.png&#039;: GM_getResourceURL(&#039;ui-bg_gloss-wave_55_5c9ccc_500x100.png&#039;),
        &#039;ui-bg_glass_85_dfeffc_1x400.png&#039;: GM_getResourceURL(&#039;ui-bg_glass_85_dfeffc_1x400.png&#039;),
        &#039;ui-bg_glass_75_d0e5f5_1x400.png&#039;: GM_getResourceURL(&#039;ui-bg_glass_75_d0e5f5_1x400.png&#039;),
        &#039;ui-bg_inset-hard_100_f5f8f9_1x100.png&#039;: GM_getResourceURL(&#039;ui-bg_inset-hard_100_f5f8f9_1x100.png&#039;),
        &#039;ui-bg_flat_55_fbec88_40x100.png&#039;: GM_getResourceURL(&#039;ui-bg_flat_55_fbec88_40x100.png&#039;),
        &#039;ui-bg_glass_95_fef1ec_1x400.png&#039;: GM_getResourceURL(&#039;ui-bg_glass_95_fef1ec_1x400.png&#039;),
        &#039;ui-icons_469bdd_256x240.png&#039;: GM_getResourceURL(&#039;ui-icons_469bdd_256x240.png&#039;),
        &#039;ui-icons_469bdd_256x240.png&#039;: GM_getResourceURL(&#039;ui-icons_469bdd_256x240.png&#039;),
        &#039;ui-icons_d8e7f3_256x240.png&#039;: GM_getResourceURL(&#039;ui-icons_d8e7f3_256x240.png&#039;),
        &#039;ui-icons_6da8d5_256x240.png&#039;: GM_getResourceURL(&#039;ui-icons_6da8d5_256x240.png&#039;),
        &#039;ui-icons_217bc0_256x240.png&#039;: GM_getResourceURL(&#039;ui-icons_217bc0_256x240.png&#039;),
        &#039;ui-icons_f9bd01_256x240.png&#039;: GM_getResourceURL(&#039;ui-icons_f9bd01_256x240.png&#039;),
        &#039;ui-icons_2e83ff_256x240.png&#039;: GM_getResourceURL(&#039;ui-icons_2e83ff_256x240.png&#039;),
        &#039;ui-icons_cd0a0a_256x240.png&#039;: GM_getResourceURL(&#039;ui-icons_cd0a0a_256x240.png&#039;),
        &#039;ui-bg_flat_0_aaaaaa_40x100.png&#039;: GM_getResourceURL(&#039;ui-bg_flat_0_aaaaaa_40x100.png&#039;),
        &#039;ui-bg_flat_0_aaaaaa_40x100.png&#039;: GM_getResourceURL(&#039;ui-bg_flat_0_aaaaaa_40x100.png&#039;)
    };

    var style = document.createElement(&#039;style&#039;);
    style.type = &#039;text/css&#039;;

    var css = GM_getResourceText (&#039;jQueryUICSS&#039;);
    $.each(resources, function(resourceName, resourceUrl) {
        console.log(resourceName + &#039;: &#039; + resourceUrl);
        css = css.replace( &#039;images/&#039; + resourceName, resourceUrl);
    });

    style.innerHTML = css;
    head.appendChild(style);
}

// All your GM code must be inside this function
function letsJQuery() {
    //alert($); // check if the dollar (jquery) function works
    //alert($().jquery); // check jQuery version
    $(&quot;
&lt;div id=&#039;example&#039; class=&#039;flora&#039; title=&#039;This is my title&#039;&gt;I&#039;m in a dialog!&lt;/div&gt;

&quot;).dialog({
        buttons: {
            &quot;Ok&quot;: function() {
                alert(&quot;Ok&quot;);
            },
            &quot;Cancel&quot;: function() {
                $(this).dialog(&quot;close&quot;);
            }
        }
    });
}
</pre><p>I also wanted to use this script with Chromium browser, the open-source version of <a href="http://www.google.com/chrome/" target="_blank">Google Chrome</a>.  I found the <a href="https://chrome.google.com/webstore/detail/dhdgffkkebhmkfjojejmpbldmpobfkfo" target="_blank">TamperMonkey Extension for Chrome</a>. <a href="https://chrome.google.com/webstore/detail/fjnbnpbmkenffdnngjfgmeleoegfcffe" target="_blank">Stylish</a> is also available for Chrome.</p> ]]></content:encoded> <wfw:commentRss>http://www.doknowevil.net/2011/07/16/jquery-and-jquery-ui-in-your-grease-monkey-scripts/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Generating CSS Based on Images, also SEO-Friendly</title><link>http://www.doknowevil.net/2011/02/20/generating-css-based-on-images-also-seo-friendly/</link> <comments>http://www.doknowevil.net/2011/02/20/generating-css-based-on-images-also-seo-friendly/#comments</comments> <pubDate>Sun, 20 Feb 2011 17:19:05 +0000</pubDate> <dc:creator>Tyler Mulligan</dc:creator> <category><![CDATA[Bash]]></category> <category><![CDATA[Computers]]></category> <category><![CDATA[HTML]]></category> <category><![CDATA[Images]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[Python]]></category> <category><![CDATA[Software]]></category> <category><![CDATA[Web Development]]></category> <category><![CDATA[css]]></category> <category><![CDATA[generation]]></category> <category><![CDATA[tricks]]></category><guid isPermaLink="false">http://www.doknowevil.net/?p=977</guid> <description><![CDATA[I&#8217;ve typed out a lot of CSS that&#8217;s focused on using a background image to replace text. I&#8217;ve been using a cross-browser CSS trick that&#8217;s SEO-friendly, I&#8217;m not sure if it&#8217;s documented anywhere. I came upon the solution myself when I was searching for a clever way to do this years ago and it&#8217;s become]]></description> <content:encoded><![CDATA[<p>I&#8217;ve typed out a lot of CSS that&#8217;s focused on using a background image to replace text.  I&#8217;ve been using a cross-browser CSS trick that&#8217;s SEO-friendly, I&#8217;m not sure if it&#8217;s documented anywhere.  I came upon the solution myself when I was searching for a clever way to do this years ago and it&#8217;s become the standard method for me.  However, I dislike the tedious task of typing out the CSS and referencing the image pixels and at work, I don&#8217;t want my developers wasting that time either.</p><p>I figured it&#8217;d be best to come up with a simple solution, so I started coding something out in bash and it worked:</p><pre class="brush:bash">#!/bin/bash
# css.sh - generate common css and html
# Tyler Mulligan (z@interwebninja.com)
# Last Update: 02/16/2011
# MIT License

create_block_image() {
    feh -lr ${1:-.} | awk &#039;{ print $3&quot; &quot;$4&quot; &quot;$8 }&#039; | sed &#039;1d&#039; | while read l; do N=$((N+1));
        cbi_css $l
    done
    feh -lr ${1:-.} | awk &#039;{ print $3&quot; &quot;$4&quot; &quot;$8 }&#039; | sed &#039;1d&#039; | while read l; do N=$((N+1));
        cbi_html_a $l
    done
    feh -lr ${1:-.} | awk &#039;{ print $3&quot; &quot;$4&quot; &quot;$8 }&#039; | sed &#039;1d&#039; | while read l; do N=$((N+1));
        cbi_html_div $l
    done
}
cbi_css() {
    f=${3##*/}
    echo &quot;#${f%.*} {
    display: block;
    background: url(&#039;$3&#039;) no-repeat 0 0;
    width: 0;
    height: $2px;
    padding-left: $1px;
    overflow: hidden;
}&quot;
}
cbi_html_a() {
    f=${3##*/}
    echo &quot;&lt;a href=\&quot;#\&quot; id=\&quot;${f%.*}\&quot; alt=\&quot;$f\&quot; title=\&quot;$f\&quot;&gt;${f%.*}&lt;/a&gt;&quot;
}
cbi_html_div() {
    f=${3##*/}
    echo &quot;
&lt;div id=\&quot;${f%.*}\&quot;&gt;&lt;/div&gt;

&quot;
}

s=$1; shift; case $s in
  --image-block|--cbi|-i) create_block_image $@;;
  *) help help;;
esac</pre><p>Which ouputs something like:</p><pre class="brush:bash">
z@zygon:~/scripts/css$ ./css.sh -i img/
#dumbtubes-fav {
    display: block;
    background: url(&#039;img/dumbtubes-fav.png&#039;) no-repeat 0 0;
    width: 0;
    height: 14px;
    padding-left: 16px;
    overflow: hidden;
}
#submit_new {
    display: block;
    background: url(&#039;img/submit_new.png&#039;) no-repeat 0 0;
    width: 0;
    height: 106px;
    padding-left: 244px;
    overflow: hidden;
}
#dumbtubes-logo {
    display: block;
    background: url(&#039;img/dumbtubes-logo.png&#039;) no-repeat 0 0;
    width: 0;
    height: 70px;
    padding-left: 274px;
    overflow: hidden;
}
&lt;a href=&quot;#&quot; id=&quot;dumbtubes-fav&quot; alt=&quot;dumbtubes-fav.png&quot; title=&quot;dumbtubes-fav.png&quot;&gt;dumbtubes-fav&lt;/a&gt;
&lt;a href=&quot;#&quot; id=&quot;submit_new&quot; alt=&quot;submit_new.png&quot; title=&quot;submit_new.png&quot;&gt;submit_new&lt;/a&gt;
&lt;a href=&quot;#&quot; id=&quot;dumbtubes-logo&quot; alt=&quot;dumbtubes-logo.png&quot; title=&quot;dumbtubes-logo.png&quot;&gt;dumbtubes-logo&lt;/a&gt;
&lt;div id=&quot;dumbtubes-fav&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;submit_new&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;dumbtubes-logo&quot;&gt;&lt;/div&gt;
</pre><p>To explain the way this CSS works, it uses the padding-left as the actual width, setting the width 0 and then pushes whatever content you have out of view using overflow:hidden to hit it from view.  This makes it easy for search engines, keeping your HTML clean and CSS simple.</p><p>The bash script relies of &#8220;feh&#8221; a lightweight image viewer for linux that outputs a list of images and their dimensions.  It also generates some sample HTML to quickly drop in and modify.</p><p>This is not an elegant solution and I&#8217;m not happy with the fact that it relies on feh.  I&#8217;ve been slowly getting into python and I was amazed at how fast I was able to recreate this script in Python.</p><pre class="brush:python">#!/usr/bin/python
# css.py - generate common css and html
# Tyler Mulligan (z@interwebninja.com)
# Last Update: 02/17/2011
# MIT License
from PIL import Image
import sys
import os.path

CSS_FORMAT = &quot;&quot;&quot;#%s {\n\
    display: block;\n\
    background: url(&#039;%s&#039;) no-repeat 0 0;\n\
    height: %spx;\n\
    width: 0;\n\
    padding: %spx;\n\
    overflow: hidden;\n\
}\n&quot;&quot;&quot;

HTML_A_FORMAT = &quot;&quot;&quot;&lt;a href=&quot;#&quot; id=&quot;%s&quot; alt=&quot;%s&quot; title=&quot;%s&quot;&gt;%s&lt;/a&gt;\n&quot;&quot;&quot;
HTML_DIV_FORMAT = &quot;&quot;&quot;
&lt;div id=&quot;%s&quot;&gt;%s&lt;/div&gt;

\n&quot;&quot;&quot;

css=&quot;&quot;
html_a=&quot;&quot;
html_div=&quot;&quot;
for tf in os.listdir(sys.argv[1]):
    f = os.path.join(sys.argv[1],tf)
    if os.path.isfile(f) == True :
        img = Image.open(f)
        fid = os.path.splitext(tf)[0]
        (width, height) = img.size[0:2]
        css += CSS_FORMAT % (fid,f,height,width)
        html_a += HTML_A_FORMAT % (fid,f,fid,fid)
        html_div += HTML_DIV_FORMAT % (fid,fid)

print css
print html_a
print html_div </pre><p>This is just the basic idea, I didn&#8217;t spend more than 15 minutes on this rewrite, it does what I need it to do so far.  It was suggested by friends if I make it any bigger, to look into a templating engine, such as mako.  I hope this script can be useful to someone :). PS, HTML_DIV_FORMAT should be on one line, not sure why my syntax highlighter is trying to put it on 3.</p> ]]></content:encoded> <wfw:commentRss>http://www.doknowevil.net/2011/02/20/generating-css-based-on-images-also-seo-friendly/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Tips for Using Bash in the Linux Terminal &#8211; Part 1</title><link>http://www.doknowevil.net/2010/10/23/tips-for-using-bash-in-the-linux-terminal-part-1/</link> <comments>http://www.doknowevil.net/2010/10/23/tips-for-using-bash-in-the-linux-terminal-part-1/#comments</comments> <pubDate>Sat, 23 Oct 2010 10:13:05 +0000</pubDate> <dc:creator>Tyler Mulligan</dc:creator> <category><![CDATA[Bash]]></category> <category><![CDATA[Computers]]></category> <category><![CDATA[Linux]]></category> <category><![CDATA[OSX]]></category> <category><![CDATA[Operating Systems]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[Software]]></category> <category><![CDATA[Ubuntu]]></category> <category><![CDATA[cli]]></category> <category><![CDATA[shortcuts]]></category> <category><![CDATA[terminal]]></category> <category><![CDATA[tips]]></category><guid isPermaLink="false">http://www.doknowevil.net/?p=687</guid> <description><![CDATA[Introduction Bash is the default shell in the terminal on many Linux and UNIX based operating system, such as Ubuntu or Mac OS X. I&#8217;ve mentioned commandlinefu.com before as a great reference for learning some neat tricks with the terminal. I&#8217;ve gained a lot from the site and a few others, such as the Advanced]]></description> <content:encoded><![CDATA[<h2>Introduction</h2><p>Bash is the default shell in the terminal on many Linux and UNIX based operating system, such as Ubuntu or Mac OS X.  I&#8217;ve mentioned <a href="http://www.commandlinefu.com" title="learn to be a terminal master">commandlinefu.com</a> before as a great reference for learning some neat tricks with the terminal.  I&#8217;ve gained a lot from the site and a few others, such as the <a href="http://tldp.org/LDP/abs/html/" target="_blank">Advanced Bash Scripting Guide</a> and <a href="http://wiki.bash-hackers.org" target="_blank">the bash hackers wiki</a>.  I wanted to share some of the tips I use most often, combined with other information that I&#8217;ve compiled through my use of the terminal.</p><p>I think I should mention that I&#8217;ve been using more applications in the terminal recently.  Some people view this as backwards but I argue just the opposite.  Limiting the amount of times I need to use the mouse and the number of keystrokes I need to make drastically increases my efficiency.  Many bash applications are designed around single keystrokes, layered hotkeys and edit &#8220;modes&#8221;.  GUIs have their place but many of my tasks can be completely more accurately and consistently via the terminal.</p><p>With that said, lets dive in.</p><h2>The Basics</h2><h3>Hotkeys</h3><p>Moving:<br /> <b>Ctrl + a</b> -> Go to the beginning of the line you are currently typing on.<br /> <b>Ctrl + e</b> -> Go to the end of the line you are currently typing on<br /> <b>Alt + f</b> -> Move cursor forward one word on the current line.<br /> <b>Alt + b</b> -> Move cursor backward one word on the current line.</p><p>Editing:<br /> <b>Ctrl + u</b> -> Clears from before the cursor position. If you are at the end of the line, clears the entire line.<br /> <b>Ctrl + k</b> -> Clear from after the cursor. If you are at the beginning of the line, clears the entire line.<br /> <b>Ctrl + w</b> -> Delete the word before the cursor.<br /> <b>Ctrl + h</b> -> Same as backspace.<br /> <b>Ctrl + t</b> -> Swap the last two characters before the cursor.<br /> <b>Esc + t</b> -> Swap the last two words before the cursor.</p><p>Other:<br /> <b>Ctrl + l</b> -> Clear screen (same as clear command).<br /> <b>Ctrl + c</b> -> Kill the current command or process.<br /> <b>Ctrl + z</b> -> Puts whatever you are running into a suspended background process, fg to restore it.<br /> <b>Ctrl + d</b> -> Exit the current shell.</p><p>Oddly, unlike many terminal applications, Bash hotkeys don&#8217;t make a lot of sense to me.  There are very few that are &#8220;intuitive&#8221;.</p><h3>History</h3><p>Press the <b>up arrow for the last command</b> or:</p><p><b>!!</b> &#8212; repeat last command</p><pre class="brush:bash">echo &quot;hello&quot;
!!
</pre><p>Outputs:</p><pre class="brush:bash">z@zentury:~$ echo &quot;hello&quot;
hello
z@zentury:~$ !!
echo &quot;hello&quot;
hello</pre><p><b>ctrl+r</b> is one of the best ways to search through your history.  it will initialize a reverse search as you type.  To go to the next result, press ctrl+r again</p><h2>Advanced</h2><h3>History Expansion/Modification</h3><p>!:0 &#8212; will repeat the first token</p><pre class="brush:bash">cd ~
ls -la
!:0
</pre><p>!:1-3 &#8212; defining a range: 1-3 will repeat the 2nd to 4th tokens (count starts at 0).  It&#8217;s important to note that double quotes will group tokens together.</p><pre class="brush:bash">echo &quot;hello there&quot; &amp;&amp; ls ~
!:3-4</pre><p>!!:s/find/replace/ &#8212; will allow you to replace a part of the command</p><pre class="brush:bash">echo &quot;hello there&quot;
!!:s/hello/hi/</pre><p>Outputs:</p><pre class="brush:bash">z@zentury:~$ echo &quot;hello there&quot;
hello there
z@zentury:~$ !!:s/hello/hi/
echo &quot;hi there&quot;
hi there
</pre><p><i>OR even shorter:</i></p><p>^find^replace</p><pre class="brush:bash">echo &quot;hello there&quot;
^hello^hi</pre><p>Outputs:</p><pre class="brush:bash">z@zentury:~$ echo &quot;hello there&quot;
hello there
z@zentury:~$ ^hello^hi
echo &quot;hi there&quot;
hi there
</pre><h3>Sequences and Pattern Expansion</h3><p>Typically in a Linux or UNIX environment you have access to a command line tool name &#8220;seq&#8221; which <a href="http://www.doknowevil.net/2009/08/15/generating-sequences-of-numbers-or-characters-with-bash/" target="_blank">gone over before</a>.  However, it&#8217;s good to know that bash has built-in sequence expansion and you don&#8217;t need to rely on seq.</p><pre class="brush:bash">echo {a..z}
a b c d e f g h i j k l m n o p q r s t u v w x y z</pre><p>by defining a start and end character with the &#8216;..&#8217; in between, we tell bash to fill in the rest and echo a list for us.  Those are all lowercase, what if you wanted uppercase? simple:</p><pre class="brush:bash">echo {A..Z}
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z</pre><p>Or both, with a few extra characters in the mix:</p><pre class="brush:bash">echo {A..z}
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [  ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z</pre><p>It doesn&#8217;t always have to be a-z though,</p><pre class="brush:bash">echo {A..G}
A B C D E F G</pre><p>This also works with numbers:</p><pre class="brush:bash">echo {0..9}
0 1 2 3 4 5 6 7 8 9
echo {0..100}
0 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 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100</pre><p>Descending as well as ascending</p><pre class="brush:bash">echo {9..0}
9 8 7 6 5 4 3 2 1 0</pre><p>Echo a specific set</p><pre class="brush:bash">echo {1,4,6,9}
1 4 6 9</pre><p>Applying it</p><h4>Quickly backup a file</h4><pre class="brush:bash">touch file1.txt
cp file1.txt{,.bak}
ls
file1.txt file1.txt.bak</pre><p>explanation: the first parameter is empty, the second is .bak, this expands to >> cp file1.txt file1.txt.bak << and creates the copy</p><h4>Convert an image type</h4><p>If you have image magick installed, you can convert file types pretty easy using this same concept:</p><pre class="brush:bash">sudo apt-get install imagemagick</pre><p>(To install on Ubuntu)</p><pre class="brush:bash">convert file.{jpg,png}</pre><h4>Permutations</h4><pre class="brush:bash">echo {a..c}{a..c}{a..c}
aaa aab aac aba abb abc aca acb acc baa bab bac bba bbb bbc bca bcb bcc caa cab cac cba cbb cbc cca ccb ccc</pre><h2>Stay tuned for Part 2</h2><p>These are some pretty common techniques I use to reduce the amount of typing and thinking required to complete a task in the terminal.  Stay tuned for part 2 and <a href="http://www.commandlinefu.com/commands/by/zed" target="_blank">check out some of my creative usages at commandlinefu.com</a>.<br /> -</p> ]]></content:encoded> <wfw:commentRss>http://www.doknowevil.net/2010/10/23/tips-for-using-bash-in-the-linux-terminal-part-1/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Customizing Colors for Your .bashrc</title><link>http://www.doknowevil.net/2010/10/21/customizing-colors-for-your-bashrc/</link> <comments>http://www.doknowevil.net/2010/10/21/customizing-colors-for-your-bashrc/#comments</comments> <pubDate>Thu, 21 Oct 2010 08:20:35 +0000</pubDate> <dc:creator>Tyler Mulligan</dc:creator> <category><![CDATA[Application Management]]></category> <category><![CDATA[Bash]]></category> <category><![CDATA[Command Line]]></category> <category><![CDATA[Computers]]></category> <category><![CDATA[Javascript]]></category> <category><![CDATA[Linux]]></category> <category><![CDATA[OSX]]></category> <category><![CDATA[Operating Systems]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[Software]]></category> <category><![CDATA[open source]]></category> <category><![CDATA[colors]]></category> <category><![CDATA[customization]]></category> <category><![CDATA[ps1]]></category> <category><![CDATA[Ubuntu]]></category><guid isPermaLink="false">http://www.doknowevil.net/?p=830</guid> <description><![CDATA[I&#8217;m working on organizing my dotfiles and part of that process has led me to clean up the way I address colors. I came across a few good sources, for .bashrc colors and decided it&#8217;d be better to create my own. I would like to have used the ones I found on the Arch wiki]]></description> <content:encoded><![CDATA[<p>I&#8217;m working on organizing my <a title="dot files for linux and unix bashrc, bash_aliases and application configuration files" href="http://github.com/z/dotfiles" target="_blank">dotfiles</a> and part of that process has led me to clean up the way I address colors.  I came across a <a title="for bashrc colors" href="http://tldp.org/LDP/abs/html/sample-bashrc.html" target="_blank">few good sources</a>, <a title="few good sources" href="http://wiki.archlinux.org/index.php/Color_Bash_Prompt" target="_blank">for .bashrc colors</a> and decided it&#8217;d be better to create my own.  I would like to have used the ones I found on the Arch wiki but the aliases were a bit odd to me.  They also break consistency as you scroll down.  I&#8217;m not sure if this is due to it being a collaborative wiki or it&#8217;s a way to teach multiple syntaxes/approaches.  In either case I figured the aliases weren&#8217;t as &#8220;standard&#8221; as I thought they might be in that world.</p><p>So I decided to copy them the best of the bunch into geany and modify them with regular expressions.  I used column selection to speed up some of the tasks, such as Title Case formatting and typing the prefixes.</p><pre class="brush:bash"># define colors
Black=&#039;\e[0;30m&#039;    # Black / Regular
Red=&#039;\e[0;31m&#039;      # Red
Green=&#039;\e[0;32m&#039;    # Green
Yellow=&#039;\e[0;33m&#039;   # Yellow
Blue=&#039;\e[0;34m&#039;     # Blue
Purple=&#039;\e[0;35m&#039;   # Purple
Cyan=&#039;\e[0;36m&#039;     # Cyan
White=&#039;\e[0;37m&#039;    # White

BBlack=&#039;\e[1;30m&#039;   # BBlack / Bold
BRed=&#039;\e[1;31m&#039;     # BRed
BGreen=&#039;\e[1;32m&#039;   # BGreen
BYellow=&#039;\e[1;33m&#039;  # BYellow
BBlue=&#039;\e[1;34m&#039;    # BBlue
BPurple=&#039;\e[1;35m&#039;  # BPurple
BCyan=&#039;\e[1;36m&#039;    # BCyan
BWhite=&#039;\e[1;37m&#039;   # BWhite

UBlack=&#039;\e[4;30m&#039;   # UBlack / Underline
URed=&#039;\e[4;31m&#039;     # URed
UGreen=&#039;\e[4;32m&#039;   # UGreen
UYellow=&#039;\e[4;33m&#039;  # UYellow
UBlue=&#039;\e[4;34m&#039;    # UBlue
UPurple=&#039;\e[4;35m&#039;  # UPurple
UCyan=&#039;\e[4;36m&#039;    # UCyan
UWhite=&#039;\e[4;37m&#039;   # UWhite

BGBlack=&#039;\e[40m&#039;    # BGBlack - background
BGRed=&#039;\e[41m&#039;      # BGRed
BGGeeen=&#039;\e[42m&#039;    # BGGreen
BGYellow=&#039;\e[43m&#039;   # BGYellow
BGBlue=&#039;\e[44m&#039;     # BGBlue
BGPurple=&#039;\e[45m&#039;   # BGPurple
BGCyan=&#039;\e[46m&#039;     # BGCyan
BGWhite=&#039;\e[47m&#039;    # BGWhite

NC=&#039;\e[0m&#039;          # Text Reset / No Color</pre><p>Here is a test case:</p><pre class="brush:bash">for c in {,B,U,BG}{Black,Red,Green,Yellow,Blue,Purple,Cyan,White}; do echo -e ${!c}$c${NC}; done; echo -e &quot;${NC}&quot;</pre><p>Here is the same test case without the aliases</p><pre class="brush:bash">for c in {0,1,4}\;{30..37} {40..47}; do echo -e \\e[${!c}${c}m${c}m\\e[0m; done;</pre><p>Here's a PS1 you can try it with</p><pre class="brush:bash">PS1=&quot;${debian_chroot:+($debian_chroot)}\[${BWhite}\]\u\[${NC}\]\[${Yellow}\]@\[${White}\]\h\[${NC}\]:\[${BBlue}\]\w\[${NC}\]$ &quot;</pre><p>I plan to use these quite often as I build out my .bash_aliases but the most immediate use you might find useful is the PS1 generation tool I&#8217;ve setup an alpha of <a href="http://interwebninja.com/ps1-o-matic">http://interwebninja.com/ps1-o-matic/</a></p><p><a href='http://www.doknowevil.net/wp-content/uploads/2010/10/ps1-o-matic-0.5.ogv'>ps1-o-matic-0.5 video in action</a></p><p><img src="http://www.doknowevil.net/wp-content/uploads/2010/10/screenshot383-300x29.png" alt="" title="screenshot383" width="300" height="29" class="alignnone size-medium wp-image-842" /><br /> <img src="http://www.doknowevil.net/wp-content/uploads/2010/10/screenshot384-300x30.png" alt="" title="screenshot384" width="300" height="30" class="alignnone size-medium wp-image-841" /><br /> <img src="http://www.doknowevil.net/wp-content/uploads/2010/10/screenshot386-300x28.png" alt="" title="screenshot386" width="300" height="28" class="alignnone size-medium wp-image-839" /><br /> <img src="http://www.doknowevil.net/wp-content/uploads/2010/10/screenshot387-300x41.png" alt="" title="screenshot387" width="300" height="41" class="alignnone size-medium wp-image-838" /></p><p>Below is a screenshot of how I&#8217;m revising the script to use only javascript objects rather than relying on html inputs to store values:<br /> <a href="http://www.doknowevil.net/wp-content/uploads/2010/10/screenshot394.png"><img src="http://www.doknowevil.net/wp-content/uploads/2010/10/screenshot394-1024x581.png" alt="" title="screenshot394" width="1024" height="581" class="alignnone size-large wp-image-866" /></a></p><p>I&#8217;m currently at the point where I&#8217;m using jquery ui&#8217;s draggable and sortable to allow segments to be moved around but I have nothing worth sharing yet.  Stay tuned, I&#8217;ll be checking the source into <a href="http://github.com/z" target="_blank">my github account</a> soon.</p> ]]></content:encoded> <wfw:commentRss>http://www.doknowevil.net/2010/10/21/customizing-colors-for-your-bashrc/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <enclosure url="http://www.doknowevil.net/wp-content/uploads/2010/10/ps1-o-matic-0.5.ogv" length="4806169" type="video/ogg" /> </item> <item><title>MySQL and Python &#8211; The Problems and [Some] Solutions</title><link>http://www.doknowevil.net/2010/10/15/mysql-and-python-the-problems-and-some-solutions/</link> <comments>http://www.doknowevil.net/2010/10/15/mysql-and-python-the-problems-and-some-solutions/#comments</comments> <pubDate>Fri, 15 Oct 2010 22:22:59 +0000</pubDate> <dc:creator>Tyler Mulligan</dc:creator> <category><![CDATA[Computers]]></category> <category><![CDATA[MySQL]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[Python]]></category> <category><![CDATA[Software]]></category> <category><![CDATA[bugs]]></category> <category><![CDATA[caveats]]></category> <category><![CDATA[parameterization]]></category> <category><![CDATA[suggestions]]></category><guid isPermaLink="false">http://www.doknowevil.net/?p=826</guid> <description><![CDATA[Intro I&#8217;m still relatively new to Python. I dabble once in a while. Usually when I catch myself writing something overly complicated in bash. I figured doing MySQL from a Python script would be easier and better implemented in Python. Well, I was in for a few surprises I&#8217;d like to share with others looking]]></description> <content:encoded><![CDATA[<h2>Intro</h2><p>I&#8217;m still relatively new to Python.  I dabble once in a while.  Usually when I catch myself writing something overly complicated in bash.  I figured doing MySQL from a Python script would be easier and better implemented in Python.  Well, I was in for a few surprises I&#8217;d like to share with others looking to integrate with MySQL in Python before you encounter the same problems I did.</p><h2>Getting on with it</h2><p>As a Python noob, it made sense to me to use the python-mysqldb module.  It &#8220;works&#8221; but not well.  Read through the [working] code below and see if you can find the problem and how I circumvented it.</p><pre class="brush:python">#!/bin/python
# Tyler Mulligan (tyler@doknowevil.net)
# MySQL the WRONG way in Python
import MySQLdb

def connection_settings():
    global DB_ADMIN, DB_ADMIN_PASSWORD, DB_NAME, DB_HOST, DB_USER, DB_PASSWORD
    DB_ADMIN=&quot;root&quot;
    DB_ADMIN_PASSWORD=&quot;local&quot;
    DB_NAME=&quot;foobardb&quot;
    DB_HOST=&quot;localhost&quot;
    DB_USER=&quot;foobar&quot;
    DB_PASSWORD=&quot;local&quot;

def run_admin_sql():
    conn = MySQLdb.Connection(host=DB_HOST, user=DB_ADMIN, passwd=DB_ADMIN_PASSWORD)
    cursor = conn.cursor()

    #cursor.execute(&quot;DROP USER %s@%s&quot;, (DB_USER, DB_HOST))
    #cursor.execute(&quot;DROP DATABASE %s&quot; % DB_NAME)

    cursor.execute(&quot;CREATE USER %s@%s IDENTIFIED BY %s&quot;, (DB_USER, DB_HOST, DB_PASSWORD))
    cursor.execute(&quot;CREATE DATABASE %s&quot; % DB_NAME)
    cursor.execute(&quot;GRANT USAGE ON %s.* TO %s@%s IDENTIFIED BY &#039;%s&#039;&quot; % (DB_NAME, DB_USER, DB_HOST, DB_PASSWORD))
    cursor.execute(&quot;GRANT ALL PRIVILEGES ON *.* to %s@%s IDENTIFIED BY %s&quot;, (DB_USER, DB_HOST, DB_PASSWORD))

    cursor.close()
    conn.close()

    conn = MySQLdb.Connection(db=DB_NAME, host=DB_HOST, user=DB_USER, passwd=DB_PASSWORD)
    cursor = conn.cursor()

    cat_table_sql = &quot;&quot;&quot;CREATE TABLE cats
    (
    `id` int(3) unsigned NOT NULL AUTO_INCREMENT,
    `name` varchar(50) NOT NULL,
    `age` int(2) NOT NULL,
    `type` int(2) NOT NULL,
    PRIMARY KEY (`id`)
    )&quot;&quot;&quot;

    cursor.execute(cat_table_sql)
    cursor.execute(&quot;INSERT INTO cats (name, age, type) VALUES (%s, %s, %s)&quot;, (&quot;fluffy&quot;, 5, 1))
    cursor.execute(&quot;INSERT INTO cats (name, age, type) VALUES (%s, %s, %s)&quot;, (&quot;meow meow&quot;, 6, 1))
    cursor.execute(&quot;INSERT INTO cats (name, age, type) VALUES (%s, %s, %s)&quot;, (&quot;purrfect&quot;, 3, 1))

    cursor.execute(&quot;SELECT * FROM cats&quot;)

    results = cursor.fetchall()
    cursor.close()
    conn.close()
    return results

connection_settings()
print run_admin_sql()</pre><p>The problem is parameterization.  The python-mysqldb module sucks at it.  It&#8217;s glaringly obvious when you look at the follow snippet and how I worked around it.</p><pre class="brush:python">
cursor.execute(&quot;CREATE USER %s@%s IDENTIFIED BY %s&quot;, (DB_USER, DB_HOST, DB_PASSWORD)) # GOOD
cursor.execute(&quot;CREATE DATABASE %s&quot; % DB_NAME) # BAD NEWS BEARS
cursor.execute(&quot;CREATE DATABASE %s&quot;, (DB_NAME)) # but the module won&#039;t support this
</pre><p>The difference, is that the first implementation uses the module&#8217;s parameterization to escape the variables that are passed to it, making it safe.  The second is using Python&#8217;s string formatter which means I&#8217;d have to do all the escaping and sanitization prior, which is obviously more dangerous and annoying.</p><p>The MySQLdb docs bury this little note, &#8220;Parameter placeholders can only be used to insert column values. They can not be used for other parts of SQL, such as table names, statements, etc.&#8221;</p><p>You can implement it this way but you&#8217;ll be wasting your time.  There are better modules out there to make up for this one&#8217;s shortcomings. <a href="http://packages.python.org/oursql/" target="_blank">OurSQL</a> and <a href="http://www.sqlalchemy.org/" target="_blank">SQLAlchemy</a> were the two libraries recommended to me in #python on irc.freenode.org.  I will make another post when I develop the same example above using one of these libraries.</p> ]]></content:encoded> <wfw:commentRss>http://www.doknowevil.net/2010/10/15/mysql-and-python-the-problems-and-some-solutions/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Random gnome-terminal profiles (themes) in Ubuntu</title><link>http://www.doknowevil.net/2010/09/30/random-gnome-terminal-profiles-themes-in-ubuntu/</link> <comments>http://www.doknowevil.net/2010/09/30/random-gnome-terminal-profiles-themes-in-ubuntu/#comments</comments> <pubDate>Thu, 30 Sep 2010 23:20:02 +0000</pubDate> <dc:creator>Tyler Mulligan</dc:creator> <category><![CDATA[Application Management]]></category> <category><![CDATA[Bash]]></category> <category><![CDATA[Command Line]]></category> <category><![CDATA[Computers]]></category> <category><![CDATA[GNOME]]></category> <category><![CDATA[Linux]]></category> <category><![CDATA[Operating Systems]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[Software]]></category> <category><![CDATA[Window Management]]></category><guid isPermaLink="false">http://www.doknowevil.net/?p=794</guid> <description><![CDATA[Introduction Does it ever confuse you if you have too many terminals open at once that look alike? Perhaps you&#8217;re just looking to express your personality or tickle your brain. In any case, if you&#8217;re using the terminal in ubuntu a lot, you may be interested in having random profiles (colors / settings). The concept]]></description> <content:encoded><![CDATA[<h2>Introduction</h2><p>Does it ever confuse you if you have too many terminals open at once that look alike?  Perhaps you&#8217;re just looking to express your personality or tickle your brain.  In any case, if you&#8217;re using the terminal in ubuntu a lot, you may be interested in having random profiles (colors / settings).</p><p>The concept of the method is pretty simple, define a hotkey that launches a script that picks a random profile you&#8217;ve created and then open the terminal with that profile as a parameter.</p><h2>Prerequisites</h2><p>- Compiz or other hotkey script that will allow you to link to a .sh file<br /> - gnome-terminal<br /> - bash</p><h2>Getting Started</h2><p>You can figure out what Profiles you have by going to <strong>Edit > Profiles</strong> in gnome-terminal.  You likely only have one, &#8220;Default&#8221;, unless you&#8217;re already actively using terminal profiles.  If you only have one, you should create a few, maybe 3 or 4 right now and play with the colors a bit. <strong>Important, don&#8217;t include spaces in the names of the profiles</strong></p><h2>The Script</h2><p>Create a file in your scripts folder (or create a directory if you don&#8217;t have one):</p><pre class="brush:bash">
mkdir ~/scripts
touch ~/scripts/gnome-terminal.sh &amp;&amp; chmod +x ~/scripts/gnome-terminal.sh
gedit ~/scripts/gnome-terminal.sh
</pre><p>Paste the following replacing the Profile names with those of your own (delimited by spaces) and change the number 4 to that of the :</p><pre class="brush:bash">
#!/bin/bash
p=( Default Delta Psi Sigma )
gnome-terminal --window-with-profile ${p[$((RANDOM%${#p[@]}))]}
</pre><p>That ugly looking bit right here is a calculation between a random number (<strong>echo RANDOM</strong>) and the size of the array (<strong>${#p[@]}</strong>), &#8220;random&#8221; % &#8220;length of array&#8221;.  Where % means mod, or remainder of the division. (examples: 7%4 = 3; 6%4 = 2; 5%4 = 1; 4 % 4 = 0; 4 % 3 = 1; 321%321= 0).</p><p>To illustrate more, play with this code:</p><pre class="brush:bash">r=$RANDOM; echo $r; echo $((r % 4))</pre><p>This is how we get a random index value for the array. This value is nested inside the array ${p[r]}, where r is the random, within bounds, array index.  That array then corresponds with a name of our profile and we pass it as a paramater to gnome-terminal with &#8220;&#8211;window-with-profile&#8221;.  So using my define array above, if the random index were &#8220;1&#8243;, &#8220;Delta&#8221; would be echoed.  If the index were &#8220;0&#8243;, Default would be.</p><h2>The Setup</h2><p>Now, I use compiz with the commands plugin, setting my &#8220;command line 0&#8243; to <strong>~/scripts/./gnome-terminal.sh</strong> and my &#8220;run command 0&#8243; under my key bindings tab to <strong>ctrl+alt+t</strong>, but you can associate this script with anything you&#8217;d like to kick it off.  A shortcut icon for example.</p><p>May this inspire you to understand, extend and share.</p> ]]></content:encoded> <wfw:commentRss>http://www.doknowevil.net/2010/09/30/random-gnome-terminal-profiles-themes-in-ubuntu/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Restricting a user&#8217;s shell permissions on Ubuntu Server 10.04 with lshell</title><link>http://www.doknowevil.net/2010/09/27/lshell-restricting-a-users-shell-permissions-on-ubuntu-server-10-04/</link> <comments>http://www.doknowevil.net/2010/09/27/lshell-restricting-a-users-shell-permissions-on-ubuntu-server-10-04/#comments</comments> <pubDate>Mon, 27 Sep 2010 23:19:37 +0000</pubDate> <dc:creator>Tyler Mulligan</dc:creator> <category><![CDATA[Bash]]></category> <category><![CDATA[Command Line]]></category> <category><![CDATA[Linux]]></category> <category><![CDATA[Operating Systems]]></category> <category><![CDATA[Ubuntu]]></category> <category><![CDATA[open source]]></category> <category><![CDATA[access control]]></category> <category><![CDATA[application permissions]]></category> <category><![CDATA[backups]]></category> <category><![CDATA[game servers]]></category> <category><![CDATA[limited users]]></category> <category><![CDATA[lshell]]></category> <category><![CDATA[security]]></category><guid isPermaLink="false">http://www.doknowevil.net/?p=785</guid> <description><![CDATA[As described by apt-cache, the method which I usually begin a package search for in a Ubuntu Server 10.04 environment: z@zentury ~$ apt-cache search lshell lshell - restricts a user&#039;s shell environment to limited sets of commands This is an extremely useful way to restrict a Linux users capabilities. Alternative shells, such as rssh, limit]]></description> <content:encoded><![CDATA[<p>As described by apt-cache, the method which I usually begin a package search for in a Ubuntu Server 10.04 environment:</p><pre class="brush:bash">z@zentury ~$ apt-cache search lshell
lshell - restricts a user&#039;s shell environment to limited sets of commands
</pre><p>This is an extremely useful way to restrict a Linux users capabilities.  Alternative shells, such as rssh, limit you to toggle a specific set of applications, (scp, sftp, cvs, svn, rsync or rdist).  A limited shell is helpful for reasons such as backups or game/application servers where you know/want the user to be able to execute only a specific set of actions. You can however, consider other reasons for restricting users on a Linux based machine.</p><p>A <a href="http://lshell.ghantoos.org/Use%20case" target="_blank">typical use case is provided in the lshell wiki</a>.</p><p>Ubuntu also provides a default in <strong>etc/lshell.conf</strong>, which serves as a good example:</p><pre class="brush:bash"># lshell.py configuration file
#
# $Id: lshell.conf,v 1.20 2009/06/09 19:53:46 ghantoos Exp $

[global]
##  log directory (default /var/log/lshell/ )
logpath         : /var/log/lshell/
##  set log level to 0, 1, 2 or 3  (0: no logs, 1: least verbose)
loglevel        : 2
##  configure log file name (default is %u i.e. username.log)
#logfilename     : %y%m%d-%u

[default]
##  a list of the allowed commands or &#039;all&#039; to allow all commands in user&#039;s PATH
allowed         : [&#039;ls&#039;,&#039;echo&#039;,&#039;cd&#039;,&#039;ll&#039;]

##  a list of forbidden character or commands
forbidden       : [&#039;;&#039;, &#039;&amp;&#039;, &#039;|&#039;,&#039;`&#039;,&#039;&gt;&#039;,&#039;&lt;&#039;, &#039;$(&#039;, &#039;${&#039;]

##  number of warnings when user enters a forbidden value before getting
##  exited from lshell
warning_counter : 2

##  command aliases list (similar to bash’s alias directive)
aliases         : {&#039;ll&#039;:&#039;ls -l&#039;, &#039;vi&#039;:&#039;vim&#039;}

##  a value in seconds for the session timer
#timer           : 5

##  list of path to restrict the user &quot;geographicaly&quot;
#path            : [&#039;/home/bla/&#039;,&#039;/etc&#039;]

##  set the home folder of your user. If not specified the home_path is set to
##  the $HOME environment variable
#home_path       : &#039;/home/bla/&#039;

##  update the environment variable $PATH of the user
#env_path        : &#039;:/usr/local/bin:/usr/sbin&#039;

##  allow or forbid the use of scp (set to 1 or 0)
#scp             : 1

##  allow of forbid the use of sftp (set to 1 or 0)
#sftp            : 1

##  list of command allowed to execute over ssh (e.g. rsync, rdiff-backup, etc.)
#overssh         : [&#039;ls&#039;, &#039;rsync&#039;]

##  logging strictness. If set to 1, any unknown command is considered as
##  forbidden, and user&#039;s warning counter is decreased. If set to 0, command is
##  considered as unknown, and user is only warned (i.e. *** unknown synthax)
#strict          : 1

##  force files sent through scp to a specific directory
#scpforce        : &#039;/home/bla/uploads/&#039;
</pre><p>If this looks like something you would like to be able to do, you can install it with apt-get:</p><pre class="brush:bash">z@zentury ~$ apt-get install lshell</pre><p>You can change a current user to have the limited shell with the following command:</p><pre class="brush:bash">sudo chsh -s /usr/bin/lshell backupbot</pre><p>You can add a new user with a limited shell with the following command (-m creates the home directory):</p><pre class="brush:bash">sudo useradd -m -s /usr/bin/lshell backupbot</pre><p>A <a href="http://lshell.ghantoos.org/Configuration" target="_blank">more detailed configuration guide can be found here</a></p> ]]></content:encoded> <wfw:commentRss>http://www.doknowevil.net/2010/09/27/lshell-restricting-a-users-shell-permissions-on-ubuntu-server-10-04/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Python Multi-head X (Nvidia TwinView / Dual Monitor) Development Notes</title><link>http://www.doknowevil.net/2010/07/05/python-multi-head-x-nvidia-twinview-dual-monitor-development-notes/</link> <comments>http://www.doknowevil.net/2010/07/05/python-multi-head-x-nvidia-twinview-dual-monitor-development-notes/#comments</comments> <pubDate>Mon, 05 Jul 2010 23:29:24 +0000</pubDate> <dc:creator>Tyler Mulligan</dc:creator> <category><![CDATA[Application Management]]></category> <category><![CDATA[Computers]]></category> <category><![CDATA[Linux]]></category> <category><![CDATA[Operating Systems]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[Python]]></category> <category><![CDATA[Software]]></category><guid isPermaLink="false">http://www.doknowevil.net/?p=745</guid> <description><![CDATA[Preface The following development notes were written after researching the underlying handling of dual monitors in the X window system on Linux. I&#8217;ve included a code snippet that I built to help demonstrate behavior and create a proof of concept to show I can determine which monitor a window is on using only python and]]></description> <content:encoded><![CDATA[<h2>Preface</h2><p>The following development notes were written after researching the underlying handling of dual monitors in the <a href="http://en.wikipedia.org/wiki/X_Window_System" target="_blank">X window system</a> on Linux. I&#8217;ve included a code snippet that I built to help demonstrate behavior and create a proof of concept to show I can determine which monitor a window is on using only python and no statically set coordinates.</p><h2>Introduction</h2><p>I mentioned in my previous post that I&#8217;m using an nVidia video card with &#8220;<a href="http://www.nvidia.com/object/feature_twinview.html" target="_blank">TwinView</a>&#8221; software that outputs my video as if it were one screen, which it technically is, one X screen.  This means that the distinction between monitors is not mapped in the X tree, it&#8217;s handled by the window manager. Unlike <a href="http://en.wikipedia.org/wiki/Xinerama" target="_blank">Xinerama</a>, which has an x session per monitor and stitches them together.  Xinerama, however, has is being deprecated in favor of <a href="http://en.wikipedia.org/wiki/RandR" target="_blank">RandR</a> but regardless, TwinView is my choice and is not an option for me to change to.</p><p>With all of that said, the decision to bridge python to c that interfaces with compiz is a deadend and would be better implemented based on the new 0.9.0 C++ api.  It would be nice to be able to return a list of windows from a &#8220;monitor&#8221; object.  However, that&#8217;s beyond my current scope.  I was able to whip up some python that to show that implementing the monitor management in python using the gtk module isn&#8217;t /that/ hacky.  I emphasize because I read some posts that claimed window decorations could be an issue in accurate calculations.</p><h2>Some Code</h2><p>Read the comment on line 2. <a href="http://www.pygtk.org/docs/pygtk/" target="_blank">Learn more about pygtk here</a></p><pre class="brush:python">
#!/usr/bin/python
# Print some information about the X environment, the monitor setup, currently active window and cursor position
import gtk.gdk

screen = gtk.gdk.screen_get_default()
print &quot;X default screen size: %d x %d&quot; % (screen.get_width(), screen.get_height())
print &quot;xid of root window: %d&quot; % screen.get_root_window().xid

monitors = int(screen.get_n_monitors())
print &quot;== %d monitors ==&quot; % monitors
for m in range(0, monitors):
    print &quot; - geometry of monitor %d: %s&quot; % (m, screen.get_monitor_geometry(m))

window = screen.get_active_window()
win_x, win_y, win_w, win_h, win_bit_depth = window.get_geometry()
print &quot;active window on monitor: %d&quot; % screen.get_monitor_at_point((win_x+(win_w/2)),(win_y+(win_h/2)))
print &quot;window geometry (x,y,w,h): %d, %d, %d, %d&quot; % (win_x,win_y,win_w,win_h)

display = gtk.gdk.display_get_default()
pointer = display.get_pointer()
print &quot;cursor position (x, y): %d, %d&quot; % (pointer[1], pointer[2])
print &quot;cursor on monitor: %d&quot; % screen.get_monitor_at_point(pointer[1],pointer[2])</pre><p>thanks to those in #compiz-dev and #python on freenode who helped me come around to create this snippet.  I hope it will help others looking to develop for multi-head setups in Linux.  Please let me know if I missed anything or did something incorrectly, this is new territory for me.</p> ]]></content:encoded> <wfw:commentRss>http://www.doknowevil.net/2010/07/05/python-multi-head-x-nvidia-twinview-dual-monitor-development-notes/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Compiz 0.9.0 Released &#8211; Completely Rewritten in C++</title><link>http://www.doknowevil.net/2010/07/04/compiz-0_9_0-released-completely-rewritten-in-c-plus-plus/</link> <comments>http://www.doknowevil.net/2010/07/04/compiz-0_9_0-released-completely-rewritten-in-c-plus-plus/#comments</comments> <pubDate>Mon, 05 Jul 2010 02:44:16 +0000</pubDate> <dc:creator>Tyler Mulligan</dc:creator> <category><![CDATA[Application Management]]></category> <category><![CDATA[Compiz]]></category> <category><![CDATA[Computers]]></category> <category><![CDATA[Desktop Mods]]></category> <category><![CDATA[Linux]]></category> <category><![CDATA[Operating Systems]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[Software]]></category> <category><![CDATA[open source]]></category><guid isPermaLink="false">http://www.doknowevil.net/?p=738</guid> <description><![CDATA[I was doing some in depth research / code hacking regarding the support of multi-headed output (dual monitors) on Linux. I won&#8217;t get into details but my video is being output to my monitors as &#8220;one screen&#8221; with a virtual distinctions handled by the window manager. Because of this, figuring out which of the monitors]]></description> <content:encoded><![CDATA[<p>I was doing some in depth research / code hacking regarding the support of multi-headed output (dual monitors) on Linux.  I won&#8217;t get into <a href="http://forum.compiz.org/viewtopic.php?f=89&#038;t=13362" title="managing windows across dual monitors in compiz?">details</a> but my video is being output to my monitors as &#8220;one screen&#8221; with a virtual distinctions handled by the window manager.  Because of this, figuring out which of the monitors you are on isn&#8217;t as straight forward as you might think.  Originally I was looking for a way to access the c functions in compiz through python but that point is now moot (likely for the better).</p><p>The <a href="http://lists.freedesktop.org/archives/compiz/2010-July/003429.html">first unstable release of the Compiz 0.9 series</a>, completely rewritten in C++.  As said, this &#8220;brings a whole new developer API, splits rendering into plugins, switches the buildsystem from automake to cmake and brings minor functionality improvements. This release represents the first developer and tester preview of what will eventually make the 0.10.x stable series. Please note that as such, it is not yet ready for general use as there are a number of known  ssues, regressions and incomplete functionality.&#8221;</p><p>Here is a <b>SLIGHTLY DATED</b> graph I got <a href="http://santiance.com/2009/10/compiz-code-comparison/">from Santiance.com</a>.</p><p><a href="http://www.doknowevil.net/wp-content/uploads/2010/07/compiz_comparison_chart.png"><img src="http://www.doknowevil.net/wp-content/uploads/2010/07/compiz_comparison_chart.png" alt="" title="compiz_comparison_chart" width="776" height="449" class="alignnone size-full wp-image-739" /></a></p><p>This is a really interesting turning point for the project and I&#8217;m glad I came across this while doing my research for multi-head handling in compiz. Knowing where the future lies could drastically change where I put my efforts in developing to support them.</p> ]]></content:encoded> <wfw:commentRss>http://www.doknowevil.net/2010/07/04/compiz-0_9_0-released-completely-rewritten-in-c-plus-plus/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>New Python eBook, Much Better, Down and Dirty</title><link>http://www.doknowevil.net/2010/07/01/new-python-ebook-much-better-down-and-dirty/</link> <comments>http://www.doknowevil.net/2010/07/01/new-python-ebook-much-better-down-and-dirty/#comments</comments> <pubDate>Fri, 02 Jul 2010 00:50:14 +0000</pubDate> <dc:creator>Tyler Mulligan</dc:creator> <category><![CDATA[Books]]></category> <category><![CDATA[Computers]]></category> <category><![CDATA[Python]]></category> <category><![CDATA[Software]]></category><guid isPermaLink="false">http://www.doknowevil.net/?p=729</guid> <description><![CDATA[Some friends recommended a book that&#8217;s a quicker pace with some better programming practices. Learn Python The Hard way (or quick way :-P). It reads more like a walk-through tutorial / quick reference and gives you easily repeatable programming practices that will get you a stronger feel for the language. It&#8217;s probably best used in]]></description> <content:encoded><![CDATA[<p>Some friends recommended a book that&#8217;s a quicker pace with some better programming practices. <a href="http://learnpythonthehardway.org/index" target="_blank">Learn Python The Hard way</a> (or quick way :-P). It reads more like a walk-through tutorial / quick reference and gives you easily repeatable programming practices that will get you a stronger feel for the language.  It&#8217;s probably best used in combination with the <a href="http://docs.python.org/" target="_blank">Python Documentation</a>.  Also, a fair warning, <a href="http://oppugn.us/posts/1272050135.html">Dive Into Python has war declared against it</a>.</p> ]]></content:encoded> <wfw:commentRss>http://www.doknowevil.net/2010/07/01/new-python-ebook-much-better-down-and-dirty/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> </channel> </rss>
<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk
Page Caching using disk (enhanced)
Object Caching 962/1060 objects using disk

Served from: www.doknowevil.net @ 2012-02-04 03:55:39 -->
