Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - statmonkey

Pages: [1] 2
1
VSIDO Discussions / Sunflower Issues & Customizations
« on: October 20, 2014, 06:11:34 PM »
For those who are interested this thread for posting customizations, issues, etc. for Sunflower file manager.

[added] quick link to Wiki https://code.google.com/p/sunflower-fm/wiki/WelcomePage

2
I've Got a Life / Essential Android Apps
« on: September 24, 2014, 02:09:33 AM »
In another thread someone mentioned a subject near and dear to my heart, that being book readers. I thought I would start something to see if we could collect favorite apps.  I have three phones, two for hacking around on and one that I use for some of it's intended purposes.  I also have two tablets and a little device I built that is sort of an android media player that I tote around with me when I travel.  So I sort of get into this stuff.

Moon + Reader - I already mentioned it's library management capabilities, which are pretty awesome.  It syncs across devices so wherever you are your book is ready and it also includes a facility to use various dictionaries and wikipedia for quick reference while you are reading.  What I didn't mention is it's ability to nest a cops opds library within the library.  This essentially means that for my own purposes I have complete instant access to my full library wherever I am without having to load the library onto the device.  Fwiw I have a reasonably sized online library and if anyone is interested in having access to it just PM me and I will send you a link.  In MoonReader you can set this as a net library and have it instantly available in the app.  It's pretty nice.

PLEX - I have already mentioned Plex elsewhere as well.  This adds the ability to access and catalogue your stored media.  I am old school so I have about 6 TB of movies and music.  Plex handles this and displays it well.  It's probably worth it for the fact that you can put TED talks on your TV with Chromecast.

Subsonic - Plex is really in home but I want my music with me.  Enter Subsonic which is basically the ability to access my audiobooks and music wherever I am.  It's ability to use the playlists that I have already built in mpd makes it a no-brainer.  It's ability to be accessed anywhere makes it useful.  Note: Does not play well with apache2.

Keepassdroid - With dropbox works to have my pwords anywhere and they are secure

Textra - Personally think this is the best texting/sms there is if you send media or files in your texts

AirDroid and FTP server - these are two apps that make moving junk back and forth between your box and your phone inconsequential.  Really handy when you want to do something in a hurry.

I root everything I own and some of these are probably more than what others may want.

Tasker - Think bash on steroids for your phone.  It has a learning curve but once up and running you can automate about anything.

Titanium Backup - just a must have, especially if you are a rom changer like I am

SMS Backup and Restore - not sure if this requires root but a great little app that backs up your sms to dropbox or drive or even gmail if you want.

TWRP - Makes modding/ROM changing fool proof.

3
General Support / Light DM issues
« on: September 19, 2014, 02:35:40 AM »
I hadn't rebooted for a while ... oh lets say a couple of months :) and when I did lightdm seems to be failing google gives me some bug reports but no answers.  I can start x with no issues logging in and running startx but I see the same issues in my logs and running lightdm in test mode repeats the same error:

Quote
*** Error in `lightdm': double free or corruption (fasttop): 0x00007f6f371e8ab0

Has anyone else seen this or does anyone have a hint to a solution?

Thanks

4
General Support / Chromecasting issues
« on: September 07, 2014, 03:19:42 AM »
I usually just broadcast stuff from apps on my phone but of late have been wanting to watch certain videos from websites, well to be honest I want to watch live horse races when my horses run and they are only broadcast on certain sites so I have to use chrome.  But alas and alack I can't get chrome to play them.  Has anyone had anyluck using vlc or anything to chromecast websites or local videos over?   Plex?  Any recommendations at all?

Seems as if I am the only one who is interested in this.  But in case someone comes along before this all changes:

1. I can't seem to get google remote desktop to work - keeps asking me to reinstall
         It requires a reboot.  This is the only known method for casting hidden streams that some providers us, well other than deconstructing the page and hijacking the stream :)

2. Chromium doesn't see VLC at all in the options pages?
      True enough.  VLC is working for a straight streamcast extension but so far no good.  It seems Chrome will work but alas chromium does not use the same parsing methods so extension fails to load
3. I can play the videos in firefox but can't get them to the TV?
      False.  I can get some videos streams to work but these are the standard file formats etc. that I could just download and stream myself.
4. Does Roku do this???
      No Roku faces the same issues.  It is about content control really. 

Below I will add in what has worked for me.

5
VSIDO Discussions / Runit vs systemd placeholder
« on: September 06, 2014, 05:28:53 PM »
This is just a placeholder folder for comments/ideas/links regarding runit.  I am looking forward to having a go at it this week as time permits (bit of another pject need to finish up).  Also this does not preclude that runit is a solution or an answer I would hope that if there are other suggestions people will start similar threads.

Currently I am starting with this thread as recommended by a friend http://smarden.org/runit/

6
Since tomorrow I head to the track and probably won't be on for a while I wanted to post at least one more of these fwiw how to things.  This one is as much for myself as a reminder as anything else.

If you are using gparted or fdisk to format large drives you are going to have problems. This is due to fdisk having a 2TB partition limitation. There are several different ways to overcome this Debian can handle larger partitions, the Linux kernel and GNU tools can use the larger partitions once created, but to me the easiest method for getting that initial partition created requires using parted.  This method works because parted allows the gpt partition table that fdisk does not.

Why would you do this?

Fixing this issue using the command line is fast and relatively easy, it also helps you to be familiar with the command line tools for partitioning should you have drive issues.  I also feel like I have more control, the command line offers several options that GUI disk managers do not.

How technical is this job?

There is nothing in here that should give even the most basic user a problem.  A little common sense and some patience to make sure you get it right.  This method does involve working with disks so you need to be careful to get the right disk and understand that you will be deleting whatever is on the disk since you are formatting it.

What is covered?

We will walk through using parted and some of its commands, creating labels and mkfs all from the command line.

What do you need?

A command line, a hard disk connected externally, parted and a terminal.

What are the steps?

  • Get parted
  • Find the disk
  • Understanding using parted
  • Format the disk
  • Get our reserved space back

Steps

Get parted

We will be using parted for this operation so fire up your cli and run:

Code: [Select]
sudo apt-get parted
Find the right disk

I use a fairly standard External SATA USB Cradle to attach and communicate to the system.  Once the drive is in the bay and the USB connected we need to make sure we know where the system has placed the device.  Since we'll need to be root to run parted open up a terminal and login in as root.  There are several ways to check where the drive is but the simplest to me is just run dmesg and you get a list of drive activity as part of the summary (assuming you just plugged the drive in).  In my case the newest attached drive is /dev/sdm.

Code: [Select]
dmesg | tail -5
You should see something like this:
Quote
[69229.559950]  sdm: unknown partition table
[69229.560655] sd 27:0:0:0: [sdm] Very big device. Trying to use READ CAPACITY(16).
[69229.562168] sd 27:0:0:0: [sdm] No Caching mode page present
[69229.562172] sd 27:0:0:0: [sdm] Assuming drive cache: write through
[69229.562175] sd 27:0:0:0: [sdm] Attached SCSI disk

So now that we know where our drive is we can open parted.

Using Parted

Before starting with parted it doesn't hurt to refresh what  parted is.  Parted works similarly but not the same as fdisk and if you are familiar with fdisk you are certainly going to have no issues with parted.  Just running the command parted will give you the parted environment and you can see a listing of "help" which shows commands that you can run with parted. 

For example:

Code: [Select]
parted -a optimal /dev/sdm
would show the partitions on device sdm and the command print would list out the physical information on the drive.  Unlike fdisk parted doesn't need a separate tool set to format and label it's all included.

Code: [Select]
mkfs #partition #fs-type
will tell parted to create whatever file system you have for #fs-type on #partition and if you make any mistakes you run

Code: [Select]
rm #partition
and it will remove #partition.  To exit parted all you have to do is type:

Code: [Select]
quit
One of the flaws in the parted documentation is that it doesn't lay out using gpt partition tables or even using ext4, ext3 or btrfs. This is annoying since there is a simple work around but then again if it was corrected we would not need this how to. All of these things can be done with parted.  The actual partition type you use is incidental to the process, for our example we will use ext4 but recognize it can be about any file-system we want.

Formatting the disk

To create a single, large partition from the command line using parted and our disk on /dev/sdm we will start by creating the gpt label. Due to the issues about parted not knowing internally about ext4 we will do this outside of the parted environment.  In other words we will call parted from the command line as part of the executable.

Code: [Select]
parted -a optimal /dev/sde mklabel gpt
Parted will helpfully warn you:

Quote
Warning: The existing disk label on /dev/sdm will be destroyed and all data on
this disk will be lost. Do you want to continue?
Yes/No?

Select yes, we want to rewrite the disk label. Next I need to set up the partition with

Code: [Select]
parted -a optimal /dev/sdm mkpart -- primary ext4 1 -1
Parted will now tell you that you need to update your fstab. This is fine information but not relevant for our external drive. If you are working with a drive on your system just make note that you need to fix your fstab later and move on. What the above command is saying is that we want a primary partition on partition one of /dev/sdm. What you need to recognize is that we now have a partition to work with and not just a device. That means that the remaining commands will use /sdm1 which is the partition and not /sdm which is the device. It's a subtle but important difference. We can now format our partition.

Code: [Select]
mkfs.ext4 -L 'External' /dev/sdm1
What we are saying here is format to ext4 and label External our device at /dev/sdm1. Our system responds with:
Quote
mke2fs 1.42.8 (20-Jun-2013)
Filesystem label=External
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
183148544 inodes, 732566272 blocks
36628313 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=4294967296
22357 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,
102400000, 214990848, 512000000, 550731776, 644972544

Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

All well and good except ... see that line "36628313 blocks (5.00%) reserved for the super user"?  On a small drive it's not important but on a 3 TB drive 5% is a significant amount of space.  This default 5% is reserved for the system as a failsafe.  It was originally intended (when we had small drives) to stop the drive becoming unusable when full.  It's never stopped me from over filling a drive by the way and seems pretty worthless.  Since this is an external drive only used for storage I don't really care.  I probably would never use the whole drive but it makes me crazy to be forfeiting so much space, so let's fix that.

Get our reserved space back

We don't need to have 5% reserved, 1% would be plenty and it's doubtful we are going to fill this whole thing up anyway.  So we have one more command to run:

Code: [Select]
sudo tune2fs -m 1 /dev/sdm1
Our terminal tells us:
Quote
Setting reserved blocks percentage to 1% (7325662 blocks)
So we know we now have 1% reserved and not 5%.

Summary

This should all go pretty fast, I think it takes me about 5 minutes to do the step by step process, being careful.  Since I use Spacefm it sees the drive automatically and I can begin dropping things into it from the moment I click on it. Given how easy this is I don't ever waste my time with the GUI apps like disk manager or gparted, I just fire up the cli and go. Enjoy your new large drive!

7
Feedback & Suggestions / Fave Apps or Apps I add after installing VSIDO
« on: January 06, 2014, 02:01:04 AM »
I always add:
roxterm
Version: 2.7.2-1
Installed-Size: 62
Maintainer: Tony Houghton <h@realh.co.uk>
Architecture: all
Depends: roxterm-gtk3 (>= 2.7.2-1)
Benefits: many but you can set the term to warn on command finish or keep open on finish, great for debugging scripts, etc.  It's just a term emulator but it's features bring some things to the table not available elsewhere.

Also clipit
       bashburn
       keepassx
       numlockx
which I am sure everyone is familiar with. Not really essential but would save me a few apt-gets



8
How To's / Watch a folder for changes and perform an action
« on: December 21, 2013, 08:54:03 PM »
This is kind of a script/How To but think it fits best here.  Mods can move it if I have misplaced it.  It's another one of my adventures into the obscure.  I have to confess that this looks a little intimidating, it is really not.  I have just tried to be detailed and precise to make it easier.

Recently I have played around with Incron "http://inotify.aiken.cz/?section=incron&amp;page=about&amp;lang=en" the reason being that I was looking for a way to automatically watch a file or folder and take some action.  What I wanted to watch was the folder that my music was in and then run a command or a script to re-index my play list as kind of proof of concept. The problem I ran into was that Incron is not able to handle recursive watching, it can only watch a file or a folder not a tree.  This will explain how I solved my problem and I think opens up a fair amount of possibilities.

A couple of caveats.  I am not a python coder, I am barely a bash scriptwriter.  I have borrowed liberally and tried to credit where I got the ideas and if anyone sees a better way to do this I would love to hear it.  One problem I have not solved is watching multiple folders to run different jobs.  I have a couple of ideas of how to go about it but haven't got that far.  For now this offers a solution to my problem and perhaps someone will find it useful.

Why Would you do this?

Linux offers lots of ways to manage syncing folders and running programs (like cron) automatically but all use time as the parameter and that is inefficient for folders that change seldom and that you only want something to happen when an event takes place.  Inotify and Incron have potential but limitations and this method really has none.  If, you wanted to have your git files uploaded and committed every time you changed something in the git tree this concept would work.  In fact you could also do this for an upload if you locally develop websites for example and want to automatically upload your files when a change happened and not at a certain time every day or week.

It is fairly simple, powerful and straightforward.  For any of the following "events" you can do an action.  That action is defined as: anything from a command to a full-blown script or opening an application.  If you can conceive it in the framework it can be done.

supported events from the original README:

  •    'access' - File was accessed (read) (*)
        'attribute_change' - Metadata changed (permissions, timestamps, extended attributes, etc.) (*)
       'write_close' - File opened for writing was closed (*)
       'nowrite_close' - File not opened for writing was closed (*)
       'create' - File/directory created in watched directory (*)
       'delete' - File/directory deleted from watched directory (*)
       'self_delete' - Watched file/directory was itself deleted
       'modify' - File was modified (*)
       'self_move' - Watched file/directory was itself moved
       'move_from' - File moved out of watched directory (*)
       'move_to' - File moved into watched directory (*)
       'open' - File was opened (*)
       'all' - Any of the above events are fired
       'move' - A combination of 'move_from' and 'move_to'
       'close' - A combination of 'write_close' and 'nowrite_close'

How Technical?

I find python a bit enigmatic but, as far as any real technical knowledge for anyone doing these steps it is not much.  The heavy lifting is really done by a python script and the configuration file is pretty basic. I have tried to cut any excess configuration to keep it simple.  All you really need is python installed and a couple of helpers, a terminal and a basic understanding of file structure, some command line skills and a text editor.

What is not covered?

I won't go into detail about how the python script actually works or the daemon initiator. If you are interested in any of the background information it's best if you read the sources of where I got the templates for this project.  These are as follows:

There are some other places I picked up ideas here and there but unfortunately I have become a bit muddled on what I learned to do this and what I already knew.  Apologies to anyone who is not credited.

What do I need?

You will need python 2.7 or higher, and the pyinotify library.  The pyinotify library is just a python event notifier that works off inotify.

In Ubuntu (and Debian) you can install these with:

Code: [Select]
sudo apt-get install python python-pyinotify
For Vsido users these are probably already installed.  It is also possible you will need python-argparser but again I think most distro's have argpaser. If not, python-argparser is in the Debian repo's and you can apt-get it.

What Are the Steps

Download the package

Read the README

Place the files in the correct places/Create structure

Edit the ini file

Make sure you have the proper permissions

Initiate the daemon

Test your event and reaction

Autostart the daemon


Assumptions in this how to?

We will assume that you have a folder that holds your music and that the structure is:

Code: [Select]
/Music/Artist/Album
Or something similarly hierarchical that has several layers.  We will also assume that you have a playlists folder in ...

Code: [Select]
~/.mpd/playlists
 and that you have a find command or some script you want to run.  For our purposes I am going to use a detailed command to show the power of our tool but you could use any command or script.

Steps

Download the package

Download the package either here as a tar or from the project page:
https://sourceforge.net/p/watchmonkey/code/ci/master/tree/
https://sourceforge.net/projects/watchmonkey/files/

Read the README

Ok, this isn't realistic but understand that everything that is here in this how-to is pretty much in the README.  I would like to apologize for the name of the scripts by the way but any name I could think of was already taken. Forgive me. :)

Set up your structure

Move to wherever you downloaded the files in a terminal.  We will need to create a folder and copy some files around. First we need somewhere to put our python script.  So create a folder called watcher in /usr/local/bin (as root for all the following):

Code: [Select]
mkdir /usr/local/bin/watcher
Next copy into the watcher folder two files.

Code: [Select]
cp watchmonkey.py README /usr/local/bin/watcher/
Make sure that watchmonkey.py is executable

Code: [Select]
chmod u+x /usr/local/bin/watcher/watchmonkey.py
Next copy over the daemon file watchmonkey.sh to /etc/init.d/

Code: [Select]
cp watchmonkey.sh /etc/init.d/watchmonkey.sh
Make sure that watchmonkey.sh is executable

Code: [Select]
chmod u+x /etc/init.d/watchmonkey.sh
Set up and edit the configuration file

Now we need to work with our configuration file .watchmonkey.ini. Copy it to the $USER directory as the user (exit root in the terminal)

Code: [Select]
cp .watch.ini ~/
Now we open that file in our favorite text editor.

Code: [Select]
geany ~/.watchmonkey.ini
There are two lines you have to change.  They are lines 25 and 67.  They are simple as follows:

  • Line 25 is the path to your music folder in my case I want to watch my Jazz folder for changes.  So I enter here:

Code: [Select]
watch=/mnt/Jukebox/Music/Jazz
You would replace /mnt/Jukebox/Music/Jazz with whatever path you want to watch
  • Line 67 is the command you want to run.  It really can be anything for example:
Code: [Select]
echo "something changed" >  ~/mywatchedfolder.txt
for our example mine is going to thoroughly go through and make a playlist and I enter:

Code: [Select]
command=find /mnt/Jukebox/Music/Jazz -type f -name "*.mp3" -or -name "*.ogg" -or -name "*.flac" -or -name "*.m4a" > /home/stat/.mpd/playlists/JazzIndex.m3u
You would of course want to change the folder you are watching and the playlist name.  Again this is just a proof of concept.

There are some other lines you might want to check out:

The next is line 48 that sets what you want to watch. The parameters are described in lines 27-43 and can just be separated by comma's. The default is create,delete.
Line 52 allows you to set what folders in the tree or files to exclude and the same rules apply.
Line 55 allows you to set whether you want the folder watched recursively or not. Default is true
Line 58 will offer you the option of autoadd new subdirectories. Default is true
For our test we can leave these alone.


Check permissions

Check your permissions one more time and make sure the files are in the proper places:

Code: [Select]
ls -als /usr/local/bin/watcher/watchmonkey.py #should be executable
Code: [Select]
ls -als /etc/init.d/watchmonkey.sh should be executable
Code: [Select]
ls -als ~/.watcher.ini should be owned by user
Initiate the daemon

Initially we will just start the daemon from the command line and test it as a daemon. (as root)

Code: [Select]
/etc/init.d/watchmonkey.sh start
Code: [Select]
/etc/init.d/watchmonkey.sh status
This should return something like:

Starting watchmonkey.sh (via systemctl): watchmonkey.service.


and respectively:

watchmonkey.service - LSB: watch files or folder as defined
Loaded: loaded (/etc/init.d/watchmonkey.sh)
Active: active (exited) since Sat 2013-12-21 02:17:55 CST; 6s ago
Process: 2085 ExecStart=/etc/init.d/watchmonkey.sh start (code=exited, status=0/SUCCESS)
Dec 21 02:17:55 kurtvsido systemd: Starting LSB: watch files or folder as defined...
Dec 21 02:17:55 kurtvsido systemd: Started LSB: watch files or folder as defined.


So far so good (I hope)

Test your event and action
If you have followed my example testing is pretty simple.  Lets just go to our music directory.  In my case thats /mnt/Jukebox/Music/Jazz and add an mp3 file. It doesn't really have to be one but just have the watcher think it is one.  So ...

Code: [Select]
touch /mnt/Jukebox/Music/Jazz/watchmonkey.mp3
we can test this a couple of ways first:

Code: [Select]
tail -5 /var/log/syslog | tac
Should show you something like this:

Dec 21 02:17:55 kurtvsido systemd: Started LSB: watch files or folder as defined.
Dec 21 02:17:55 kurtvsido watchmonkey.sh: Starting system watchmonkey daemon:.
Dec 21 02:17:55 kurtvsido systemd: Starting LSB: watch files or folder as defined...
...


or

Code: [Select]
grep "watchmonkey.mp3" ~/.mpd/playlists/JazzIndex.m3u
Should return something like:

/mnt/Jukebox/Music/Jazz/watchmonkey.mp3


Autostarting the daemon

If you like what you see you can autostart the daemon with

Code: [Select]
sudo update-rc.d watchmonkey.sh defaults enable
Switching enable with disable will remove it from autostart.

Also remember that you should not edit the config file .watchmonkey.ini while the daemon is running. Always run:

Code: [Select]
sudo /etc/init.d/watchmonkey.sh stop
Then change the ini and restart it with the start command.  Reload is not very reliable.  On systemd setups see the README

Summary

I realized a couple of things once I got this working. First that to monitor more than one folder or file I would need separate daemons.  I am researching this but if anyone has any ideas or better python knowledge let me know.  Since jobs are defined in the ini file I should be able to code it to look at whether there are more than one job in the python script.  That is a big TODO.  The second thing is that this (to me) is really useful.  I actually have changed my initial usage to using it for git and auto committing, etc. using a script.  I have it working to check my git folders. Run a commit generically and then upload the files automatically all from a simple bash script using gpg.  I am in hopes that someone finds it useful and at the least interesting.  I have a feeling that I can find something better for remote work but am still researching that one.

Happy watchmonkeying!

9
How To's / Securely using mutt with multiple Gmail Accounts
« on: November 20, 2013, 05:32:43 AM »
In my continuing search for obscure things that no one besides myself wants to know here is a little mutt love.  It is also another demonstration of the power of my favorite distro - everything you need is part of the standard install and is there waiting for you when you need it.  One more hat tip to Vsido, great job all!

Why do this?
I like mutt, its easy to use and configure and if I want I can always log to the browser window to get mails.  Personally though, I rarely do as mutt can do everything I need in a light, text based interface.  As always because it's there and can be done. 

Who would do it?
Well, anyone who feels the same way I do or anyone looking to streamline their email handling and save some time over the long run.  Mutt can be configured with boxes in much the way your gmail accounts are and if you have multiple accounts as I do using mutt with multiple accounts switching between accounts is much easier and faster. 

How skilled do you need to be?
Really about the only "skill" required is a solid understanding of the command line and a little patience.

What is required?
  • Nano, vim, emacs, any cli document app
    mutt
    a gmail account or two
    your username and password
    gpg
All of these are standard with Vsido so you should have to do nothing for that distro.  For others YMMV.

Steps
  • Set up secure password file
    Set up your .muttrc with your specific account info
    Add some html handling
    Remove the temp password file (unsecured version)
    Mutt away!


Setting up your password file

There are several ways to do this.  Ultimately this solution (provided here) is not without it's flaws. A really capable hacker, one who is capable of getting control of your box could take advantage of the temp file handling used here and get access to your account info.  For that matter anyone who could figure out your control password could access pgp.  In other words if you are a heinous worry wart this won't be secure enough for you.  For my purposes it provides enough that I am unconcerned.  If you desire more then you probably have a better understanding of PGP than I do and know how to use shred and a temp drive in ram.  I don't see the need for that level of tin hatted-ness. Ok, flame away. 

For security we will be setting up an encrypted file for your passwords. For my examples I will be using my old favorite nano but any similar app will work.
To start with we will need to generate a gpg key to secure our passwords file.  To do this (you should already have gpg installed if you are on Vsido)
   
Code: [Select]
gpg --gen-keyThis will start the key generation process and it will prompt a few questions.  Accept the default (DSA + RSA) and then accept the maximum keylength.  It will then ask you the validity period of the key (if you are planning on a public key it should be for a finite period) I am the only one on my box (I hope) so I just chose a key period that would not expire.  Once this is done it will start asking you for several other pieces of info.  Like your name, email and maybe some comments and in the end will ask you for a pass phrase. You can put whatever you want in any of this but it is best that you fill it out correctly and use a good pass phrase.   You will need the name you entered in the very next step as well as that pass phrase when you use mutt so don't forget who you are or what your pass phrase is.  As always use something you can remember and that is secure :)
For more tips and tricks on gpg check out http://nixtricks.wordpress.com/2009/10/04/introduction-to-encryption-of-files-using-gpg/ which is where I learned this. Note some of it is out of date but the basic concepts are correct

We will need a place to put this file and for my purposes I will use a folder called .encrypt like so:
   
Code: [Select]
cd ~
Code: [Select]
mkdir .encrypt
Code: [Select]
cd .encrypt
Code: [Select]
nano .gmpassIn that file enter the following:
Gmail1 yourfirstpassword
Gmail2 yoursecondpassword
Gmail3 yourthirdpassword
etc. as you need and then save the file
Now we can encrypt the file with:
   
Code: [Select]
gpg --encrypt --recipient 'Your Name' .gmpassWhat we are saying here is use gpg to encrypt the file .gmpass  I would suggest that you don't delete the original file .gmpass quite yet.  Just in case you made an error somewhere you can keep it around for reference.

Great, we now have an encrypted gmail password file.  Next you will need to create a file in the .encrypt folder called .tmp otherwise our temp storing of messages won't work.  Once it is there it will immediately be overwritten when you run mutt, so no worries. Create that file now with
   
Code: [Select]
touch ~/.encrypt/.tmp
Setting Up Mutt
For the most part mutt should be ready to go. Next we have to set up a folder called .mutt in your home folder to put the cache headers in.
Code: [Select]
mkdir ~/.muttMutt itself should not need any outside help (like procmail, fetchmail, etc) and all we have to do is edit and create the .muttrc  Since this file is a little extensive I used geany to do it but nano or vim will work as well.  The first section until the macros is all you need to worry about adjusting.  I have attempted to put some notes in to make it easier to see.  It really only takes a few minutes.  Clearly the password section requires you to adjust according to where you put your pass file and what you named it but the rest is simple.  Just make sure the password paths are correct.

Code: [Select]
#-----------#
# Passwords #
#-----------#
# remember our passwords file .gmpass?  Well these lines find it and decrypt it using gpg. Important note the my_ part of each of these is
# critical so don't leave it out, it must be "set my_etcetera .......
set my_tmpsecret=`gpg2 -o ~/.encrypt/.tmp -d ~/.encrypt/.gmpass.gpg`
set my_gpass1=`awk '/Gmail1/ {print $2}' ~/.encrypt/.tmp`
set my_gpass2=`awk '/Gmail2/ {print $2}' ~/.encrypt/.tmp`
set my_gpass3=`awk '/Gmail3/ {print $2}' ~/.encrypt/.tmp`
set my_del=`rm -f ~/.encrypt/.tmp`
 
#---------------#
# Account Hooks #
#---------------#
# What you are replacing in here is "user#acct that is it the rest stays the same for each of the three accounts
# all we are doing here is creating hooks to get the mail and stay in contact with gmail.  Ummm, don't try this with yahoo :)
account-hook . "unset imap_user; unset imap_pass; unset tunnel" # unset first!
account-hook        "imaps://user1stacct@imap.gmail.com/" "\
    set imap_user   = user1stacct@gmail.com \
        imap_pass   = $my_gpass1"
account-hook        "imaps://user2ndacct@imap.gmail.com/" "\
    set imap_user   = user2ndacct@gmail.com \
        imap_pass   = $my_gpass2"
account-hook        "imaps://user3rdacct@imap.gmail.com/" "\
    set imap_user   = user3rdacct@gmail.com \
        imap_pass   = $my_gpass3"
 
#-------------------------------------#
# Folders, mailboxes and folder hooks #
#-------------------------------------#
# In this section you are changing the user#acct and Your Name and that is it. You could monkey with the folder locations as you wish

# Setup for user1:
set folder          = imaps://user1stacct@imap.gmail.com/
mailboxes           = +INBOX =[Gmail]/Drafts =[Gmail]/'Sent Mail' =[Gmail]/Spam =[Gmail]/Trash
set spoolfile       = +INBOX
folder-hook         imaps://user1stacct@imap.gmail.com/ "\
    set folder      = imaps://user1stacct@imap.gmail.com/ \
        spoolfile   = +INBOX \
        postponed   = +[Gmail]/Drafts \
        record      = +[Gmail]/'Sent Mail' \
        from        = 'Your Name <user1stacct@gmail.com> ' \
        realname    = 'Your Name' \
        smtp_url    = smtps://user1stacct@smtp.gmail.com \
        smtp_pass   = $my_gpass1"
 
# Setup for user2:
set folder          = imaps://user2ndacct@imap.gmail.com/
mailboxes           = +INBOX =[Gmail]/Drafts =[Gmail]/'Sent Mail' =[Gmail]/Spam =[Gmail]/Trash
set spoolfile       = +INBOX
folder-hook         imaps://user2ndacct@imap.gmail.com/ "\
    set folder      = imaps://user2ndacct@imap.gmail.com/ \
        spoolfile   = +INBOX \
        postponed   = +[Gmail]/Drafts \
        record      = +[Gmail]/'Sent Mail' \
        from        = 'Your Name <user2ndacct@gmail.com> ' \
        realname    = 'Your Name' \
        smtp_url    = smtps://user2ndacct@smtp.gmail.com \
        smtp_pass   = $my_gpass2"
       
# Setup for user3:
set folder          = imaps://user3rdacct@imap.gmail.com/
mailboxes           = +INBOX =[Gmail]/Drafts =[Gmail]/'Sent Mail' =[Gmail]/Spam =[Gmail]/Trash
set spoolfile       = +INBOX
folder-hook         imaps://user3rdacct@imap.gmail.com/ "\
    set folder      = imaps://user3rdacct@imap.gmail.com/ \
        spoolfile   = +INBOX \
        postponed   = +[Gmail]/Drafts \
        record      = +[Gmail]/'Sent Mail' \
        from        = 'Your Name <user3rdacct@gmail.com> ' \
        realname    = 'Your Name' \
        smtp_url    = smtps://user3rdacct@smtp.gmail.com \
        smtp_pass   = $my_gpass3"
 
#--------#
# Macros #
#--------#
macro index <F1> "y12<return><return>" # jump to mailbox number 12 (user1 inbox)
macro index <F2> "y6<return><return>"  # jump to mailbox number 6 (user2 inbox)
macro index <F3> "y18<return><return>"  # jump to mailbox number 18 (user3 inbox)
# Below requires added script separate from mutt for more info see the section on opening HTML files in a browser
macro index <F10> "<copy-message>/tmp/mutttmpbox\n<enter><shell-escape>~/bin/viewhtmlmail.py\n" "View HTML in browser"
macro pager <F10> "<copy-message>/tmp/mutttmpbox\n<enter><shell-escape>~/bin/viewhtmlmail.py\n" "View HTML in browser"
#-----------------------#
# Gmail-specific macros #
#-----------------------#
# to delete more than 1 message, just mark them with "t" key and then do "d" on them
macro index d ";s+[Gmail]/Trash<enter><enter>" "Move to Gmail's Trash"
# delete message, but from pager (opened email)
macro pager d "s+[Gmail]/Trash<enter><enter>"  "Move to Gmail's Trash"
# undelete messages
macro index u ";s+INBOX<enter><enter>"         "Move to Gmail's INBOX"
macro pager u "s+INBOX<enter><enter>"          "Move to Gmail's INBOX"
 
#-------------------------#
# Misc. optional settings #
#-------------------------#
# Check for mail every minute for current IMAP mailbox every 1 min
set timeout         = 60
# Check for new mail in ALL mailboxes every 2 min
set mail_check      = 120
# keep imap connection alive by polling intermittently (time in seconds)
set imap_keepalive  = 300
# allow mutt to open new imap connection automatically
unset imap_passive
# store message headers locally to speed things up
# (the ~/.mutt folder MUST exist! Arch does not create it by default)
set header_cache    = ~/.mutt/hcache
# sort mail by threads
set sort            = threads
# and sort threads by date
set sort_aux        = last-date-received

color normal white default
color hdrdefault brightcyan default
color signature green default
color attachment brightyellow default
color quoted green default
color quoted1 white default
color tilde blue default

The color stuff  at the end I haven't really played with so if anyone out there has a better idea let me know.  I read a couple of ways to do the password files btw but could not make sense of them.  I know this way works so there you have it.

HTML
If you would like to get some html abilities then create a file called .mailcap in the user's root like this:
Code: [Select]
nano ~/.mailcapand enter this line:
   text/html; elinks -dump %s ; copiousoutput
You can substitute lynx if that is your preference. I will either add to this or create another post about html processing.  The mutt devs seem to have toyed with some things without my knowledge and my old python scripts aren't working at the moment.

Opening HTML files in a browser
Good news!  This function can be easily done thanks to Akkana and this post http://shallowsky.com/blog/tech/email/mutt-viewing-html-mail.html.  The bottom line is as follows.  Download the script from git hub here https://github.com/akkana/scripts/blob/master/viewhtmlmail Save it as viewhtmlmail.py in your ~/bin folder and make it executable. Then copy the following two lines and place them in the macro's section of your .muttrc
Code: [Select]
macro index <F10> "<copy-message>/tmp/mutttmpbox\n<enter><shell-escape>~/bin/viewhtmlmail.py\n" "View HTML in browser"
Code: [Select]
macro pager <F10> "<copy-message>/tmp/mutttmpbox\n<enter><shell-escape>~/bin/viewhtmlmail.py\n" "View HTML in browser"make the file ~/bin/viewhtmlmail.py executable with chmod +x and then when you press F10 with an open html mail it will open in firefox/iceweasel.

Remove our temp file
Let's not forget the unsecured file we created earlier.  We can just wipe it away with
Code: [Select]
rm ~/.encrypt/.gmpassSince I am thinking of it, there is no need to get nervy about wiping this out.  Should you later add or delete accounts writing a new file and re-running the command
Code: [Select]
gpg --encrypt --recipient 'Your Name' .gmpass will allow you to overwrite the gpg file.

Fire Up Mutt
When you start mutt, PGP will ask you for your passphrase.  It should also show you that it is checking the encrypted file and getting the info out after that.  Then, if all went well you should see mutt going online to get your email.  Oops, it's possible that your fist screen is empty or you don't see the mails for your online accounts?  Well that is because of the mailboxes.  If you followed my rc they will all be nicely tucked away in their own little homes.  Your machine and local stuff will come into the main box and the rest of this stuff will be accessible (most simply) by your macro's.  If you press F1 you will briefly see a list of accounts and it will open the first set of inboxes as designated by the macro.  It should then take you to that mailbox.  If you know mutt you will have no issues and if you don't just press the ? key where advised and start to explore.  It can do it all and mutt is in the true unix tradition of something that does it's thing and does it very very well.

Just to be thorough let's pull apart our macro:
      macro index <F1> "y12<return><return>" # jump to mailbox number 12 (user1 inbox)
What this is saying is that pressing F1 will take you to the 12th mailbox which will be the inbox for user1. If you look above at the boxes we created earlier and look at the way the folders are laid out in mutt it will be pretty clear how and why the macros are set to 6 and 12. Hint:you can use the y key and the c key in certain locations to prowl around the folders.

Local Mail
So where did our local mail go?  Well unless you set up boxes for it it will be in /var/mail/$USER.  I did monkey with this and found it ... "interesting" in other words I didn't like the results. I guess I have just become comfy with /var/mail/$USER.  I did just go ahead and leave it in the standard folder /var/mail/$USER. I use this box a lot for scripts and testing so I would rather lose my gmail than it.  This means that to get to it I have to use "C" and type in the path.  I personally have no issues with this but YMMV.

Glib-Object-CRITICAL -- UPDATE - RESOLVED
At lease for the moment there is a fix for this.  I no longer have this error after running the following as root:
Code: [Select]
apt-get install pinentry-curses pinentry-gtk2 pinentry-qt4 signing-party
You are most likely going to see the following:
Code: [Select]
(pinentry:22868): GLib-GObject-CRITICAL **: Object class GtkSecureEntry doesn't implement property 'editing-canceled' from interface 'GtkCellEditable'This error from what I can understand was "fixed" in git a couple of years ago but still has not been applied.  Don't ask me I just work here :-X.
This statement is still true. Git has pinentry 0.83 and Debian is still using pinentry 0.81.1 so much for Sid and cutting edge :) I have not yet found a work around and if anyone has any ideas let me know.  It seems to stem from pgp not finding or knowing where to look for pinentry-gtk2It is incidental if annoying and doesn't harm anything.  If I come up with a fix or anyone out there does I will add it.   

Summation
I hope someone finds this useful.  For me personally I have been doing my mail like this for some time and find it extremely effective.  I rarely use the browser for mail and that keeps my distractions to a minimum.  Well, not totally true I have tendency to be distracted by anything I find interesting, but you get my drift.  The real point here is once again, Vsido has "everything" that is needed to do what many would consider a somewhat sophisticated process and what I would consider essential.  Happy Vsido-ing.



10
General Support / Systemd issues
« on: November 12, 2013, 10:47:42 PM »
I am considering rebuilding systemd from the scratch and applying my own patches.  Before I jump down that rabbit hole I was interested if anyone else is seeing the same things that I am and if they had a subsequent fix.  Here is my issue:

A few updates ago I encountered errors when doing an update that I am pretty sure are coming from systemd and the way it controls inits.  These have expanded today and are "Errors encountered while processing:
     console-tools
     console-setup-linux
     console-setup
Is anyone else seeing this?  Are you ignoring them or is there something that can be done to correct them? Maybe it is local to my system and if that is the case I would appreciate knowing.  Thanks.

11
How To's / Using dpkg-deb to remake a package
« on: November 08, 2013, 05:40:51 AM »
Vsido has some great tools that might be unknown to many users.  One of these hidden gems is dpkg-deb. What dpkg-deb does is allows you to create your own packaged version of an application that already exists as a deb.  It's very simple to use and for anyone wishing to have more control over not just what is on your system but how it actually works it offers some real value.  I will be using dmenu as an example since I recently did this for myself and I hope that it gives you some idea of the functionality of this tool.  Before I start a hat tip to VastOne for starting me on this path, it's been very interesting and enlightening.

Why would you do this?

If, for example there were some incidental changes you made to some package that the Debian devs had not seen fit to include or if you don't like the structure that a package installs by default.  Maybe you want to add features, move file locations, etc.

How technical do you need to be?


Not very, assuming you aren't trying to rebuild essential packages. A basic understanding of file structures, command lines, text editors and you are on your way.

What is not covered here?

I am not going to cover building a deb from source, this is only about repackaging.  Debian offers a great many ways to skin the cat and this is just one of them.  If you are interested in others (most of which are already in our favorite distro) a quick search will present you with some of the options.

What do I need?

Not much. I am pretty sure dpkg-deb is installed by default or by Vsido-welcome in the package building section. If not you can use apt-get to grab it.  So fire up your terminal and play along.

What are the steps?

   Make your project file structure
       Download the deb you want to repackage
   Dis-assemble/extract the deb package
   Copy in your changes/adjustments
   Adjust the version number
   Build your package
   Remove the old package
   Install the new
   Enjoy your customized Linux

What is assumed?

It's going to be assumed that you have made modifications to the way the package functions already.  What I mean by that is this: Let's say you made modifications to dmenu, for example adding in a script you like or altering dmenu_run in some way.  You don't want to use the Debian version because it doesn't consider these changes and you would like to keep them with you in the future and you want to be able to package suckless-tools quickly if they get updated.  You don't have to build it from scratch again, once your modifications are made you are ready to go.

Set Up Your Structure
Download the deb you want to alter and put it in the top-level folder where you are going to repackage. In our case http://ftp.us.debian.org/debian/pool/main/s/suckless-tools/suckless-tools_38-2_amd64.deb
and I put it in the folder project. Decide where you want the project and (you can see the structure of the folders below the commands)
   
Code: [Select]
mkdir projectNow move to the /project folder.
   
Code: [Select]
cd ~/projectand we can start the real work.
   
Code: [Select]
mkdir -p extract/DEBIAN
Code: [Select]
mkdir buildYour structure should be as follows:
   project
      extract
      extract/Debian
      build
      
Extract Your Package
Once that is in place we can extract the packages:
   
Code: [Select]
dpkg-deb -x suckless-tools_38-2_amd64.deb  extract/      #our package
   
Code: [Select]
dpkg-deb -e suckless-tools_38-2_amd64.deb  extract/   
What you will now have is a full file structure showing all the "pieces of a deb package". If you look in the DEBIAN folder you will see the information for control that discusses maintainer, etc. If you look in the overall extract folder you will see where the actual application will install itself.  In this case:
   usr/bin
   usr/share #primarily documentation
This makes (for consistency and understanding) the path look like this:
        project
             extract
                 DEBIAN
                 usr
                     bin
                     share

Apply Your Changes

All well and good but now we need to apply our changes.  This means removing the files we are replacing or moving them were we want them, or even adding to them. For our example we want to replace dmenu_run and add a file dmenu_myscript.  So simply remove dmenu_run from the folder /project/usr/bin in the packaging structure.  You can add or change structure here as well.  As an example we'll put them both in /usr/local/sbin since their our scripts now.  We need to create that structure.  So move to the usr folder in extract

   
Code: [Select]
cd extract/usr
Code: [Select]
mkdir -p usr/local/bin
and copy your files into that folder. The only thing you need to be sure of is you get all the changes you made where you want them.  The package program will assume that everything you want to do is in the right place.  This is regardless of what you want to do. For example: If you made changes to dmenu like applying a patch, you would swap out your version for the Debian version in the folder bin or you could even move it to a different folder to be installed there.  Whatever path you set under extract will be the path under the root folder (/) when installed on your system.

Document Your Changes and Keep Track
I would also point out that there must be a file "control" in the folder extract/DEBIAN or dpkg-deb will fail. I am pointing this out because ... well the latest version of suckless-tools is put togther incorrectly and has control in the root folder.  I only caught it after a build failure.

I would suggest that you edit the control file in the DEBIAN folder and change the version number to something other than the Debian original. For example suckless-tools is 38-2 on Debian and in the line "Version"I changed it to 38-2-1 to keep them straight. So open the file control that you find in the folder DEBIAN under extract with your favorite text editor and change the line that starts
   Version: 38-2 #just change 38-2 to what you want, e.g. 38-2-1
If you look you will see a place for notes down below.  If you would like to make some comments so you remember what you did, this is the place.  When you are done save the file and move on.

Build Your Package

Now we just move back to our top level folder and build it
   
Code: [Select]
cd /project
Code: [Select]
dpkg-deb -b extract/ build/   
When it completes,check your build directory you should see your new package called suckless-tools_38-2-1_amd64.deb

Install Your Package
Now just uninstall suckless-tools if you haven't already and run
Code: [Select]
s dpkg -i suckless-tools_38-2-1_amd64.deb to install your personalized version.  I would suggest holding the suckless-tools package as well to keep it from being overwritten by apt.

Congratulations you have a little deb file all your very own :)

12
General Support / Dmenu and scripts
« on: October 12, 2013, 07:40:42 AM »
I have been playing around with dmenu (you know reading the arch forums, stealing the stuff and then with half and idea of what I am doing trying to run things and having them explode).  Specifically I am wondering how you can get dmenu to call a script that runs in a terminal from a hot key call.  Like this SUP+S pulls up dmenu and then somescript is selected then ... crickets.  Shouldn't I be able to get the script to run or do I have to do all this in the terminal?  Very late at night for me so if this is stupid don't hammer me but did I miss in the configuration somewhere or am I off on the concept of dmenu completely?

13
Scripts / Best of Bash functions
« on: October 02, 2013, 02:48:49 PM »
Maybe this should be a new thread. My apologies if so. [edit- split off as new thread for you, thnx for suggesting that. - Digit]

With the recent posts on aliases I thought there might be some value in keeping with this thread to post something on functions and .bashrc.  My .bashrc is at present about 300 lines and use it for much more than just making sure my paths are right, etc.  I won't post the whole thing it includes a very detailed bash completion section which accounts for most of the size.  It also uses several functions which I am always looking to add so maybe this will prompt someone to post their favorites.  Functions work similarly to aliases except you can do a lot more with them.  I have three main functions which I use a ton:
Code: [Select]
# function to swap two files with each other:
#   swap file1.txt file2.txt this is used as shown with things like swap .conkyrc .conkyold etc.
function swap() # Swap 2 filenames around, if they exist
{ #(from Uzi's bashrc).
local TMPFILE=tmp.$$

[ $# -ne 2 ] && echo "swap: 2 arguments needed" && return 1
[ ! -e $1 ] && echo "swap: $1 does not exist" && return 1
[ ! -e $2 ] && echo "swap: $2 does not exist" && return 1

mv "$1" $TMPFILE
mv "$2" “$1″
mv $TMPFILE "$2"
}
if you play with it a little you will get the point. 

The next two are find functions with the second one allowing you to perform some action on what it finds.  SpaceFM has this feature but I really use the terminal far more than SpaceFM.
Code: [Select]
# Find a file with a pattern in name:
#  ff string.*
function ff() { find . -type f -iname '*'$*'*' -ls ; }

# Find a file with pattern $1 in name and Execute $2 on it:
#  fe string.* cmd
function fe()
{ find . -type f -iname '*'${1:-}'*' -exec ${2:-file} {} \; ; }

This last one is really my favorite.  It passes the $USERS bash history to root under su.  I always forget how to use !! correctly (not sure why, probably due to the fact I am an idiot) but frequently I type some command or set and then realize I should have been root.  This function fixes that issue and more.  It essentially is the core for some other things as well.  I created functions using this model to pass my aliases, etc.  It is written to work only under su not sudo su (for reasons that should be obvious) and I might be the only fool who runs root as root but I get a little old school I guess.  Anyway I use this and its little brothers fairly often and it has saved me a lot of work.  If you read it you will pretty quickly see how it could be adapted for sudo su with a few adjustments.  Most of you are much more intuitive than I am so I'll let you sort that out.
Code: [Select]
# set a function using su to have USER history available to root ONLY as su
# this also passes ICEauthority and vi history (which I seldom use)
# please remember the \ are only there to make it look nice as line ends
function su () {
    local SUUSER=root
    local ORIGU=$USER
    local ORIGG=`groups | awk '{print $1}'`
    if [[ $# -gt 0 ]] ; then
        local char=`echo $1 | cut -c 1`
        if [[ "$char" == '-' ]] ; then
            /bin/su $*
            return $?
        else
            local SUUSER=$1
        fi
    fi
    #append recent history to the history file
    history -a
    /bin/su ${SUUSER} -c "env USER=${SUUSER} HOME=${HOME} ${SHELL}; \
          [ -f ${HOME}/.ICEauthority ] \
          && chown $ORIGU:$ORIGG ${HOME}/.ICEauthority ${HOME}/.viminfo"
    # Clear the history list by deleting all the entries.
    history -c
    # Read the contents of the history file and use them as the current history.
    history -r
}
Disclaimer: I didn't write these originally.  I lifted them from those who have gone before me and later added children off them that do similar functions.  I do think they provide a good template of just some of the way you can use functions in bash and get more out of your bash environment.  BTW yes you can pass these to scripts and use them there as well.  Anyone out there use functions?  I would love to see them and hope this sparks something or helps someone.


14
Scripts / Best of Bash Links
« on: September 29, 2013, 07:53:05 PM »
I hold bash in the highest regard.  I more than love it I luuuurrrrvvvee it.  I was thinking that with all bash can do we should probably have a little go to of places to get more on bash.  There really is so much there I don't think anyone could know it all.  I have one page in particular that I refer to fairly often and thought I would post it and perhaps others will find it useful or can add to the list.

http://samrowe.com/wordpress/advancing-in-the-bash-shell/

If you are interested in doing more with bash.  I highly recommend this short read.  Tons of good stuff in there I frequently forget.

15
Zenity & Yad / redeye type adjustment
« on: September 27, 2013, 08:43:34 AM »
OK, good to hear.  Above I mentioned that you can essentially drag and drop to make new scripts and here is an example.  Pretty simple but still relatively useful.  By essentially slightly altering the initial zenity call we can change the back up script from file selection to yes/no and make our little script adjust our monitor warmth (this is just a bastardization of redeye btw).
Code: [Select]
#!/bin/bash
#==========================================================================
# TITLE: redeye type adjustment
# AUTHOR:Statmonkey
#
# USAGE: redeye $1 as in redeye night or redeye day
# DESCRIPTION:  Automatically adjusts the screen to night mode for reduced eye strain
# Requires redeye             
# DATE: LAST UPDATED 4/30/13 to change the settings to greater variance
#==========================================================================
###############################################
# Define Variables:
###############################################
zenity --question --title="Redeye" --text="Set screen for ..." --ok-label="Night" --cancel-label="Day"

redeye=$?
if [ "$redeye" -eq "0" ] ; then
   xrandr | sed -n 's/ connected.*//p' | xargs -n1 -tri xrandr --output {} --brightness 0.7 --gamma 2:3:4
else
   xrandr | sed -n 's/ connected.*//p' | xargs -n1 -tri xrandr --output {} --brightness 1 --gamma 1:1:1
fi

I actually do use this frequently as I tend to sit at the box a little too much every day/night/week/month/year

Pages: [1] 2