Wednesday, November 21, 2012

Creating a custom image on UIToolbar in MonoTouch


Recently I had to create a custom button for UIToolbar. Specifically, in my case, it was not a button, but a separator. I was very surprised to find out that UIBarButtonItem does not have a height attribute. Turns out there is a workaround to set a customer hight for a UIBarButtonItem. This is what I did:


// Create a custom image of needed hight with a regular button
var customerImageButton = new UIButton (UIButtonType.Custom);
customerImageButton.SetBackgroundImage (UIImage.FromFile 
                   ("Images/separator.png"), UIControlState.Normal);
   
customerImageButton.Frame = new RectangleF (0, 0, 3, 46);

// Initialize new UIBarButtonItem from a custom view - new button
var customerBarButton = new UIBarButtonItem (customerImageButton);

// Make updates to the existing bar
var barButtonList = new List ();

// Update toolbar in xib/story board with custom items
for (var i =0; i< tlbrMainToolbar.Items.Length; i++)  
{  
  if (i == 4)    
  {
      // replace placeholder button with a custom separator
      // In my case it was button 4 
      barButtonList.Add(customerBarButton);   
  }    
  else   
  {   
      barButtonList.Add (tlbrMainToolbar.Items[i]);   
  } 
}

// Set the new button list for the toolbar 
tlbrMainToolbar.Items = barButtonList.ToArray();

Hope this saves someone time!

Thursday, October 18, 2012

More orientation in iOS with MonoTouch

I ran into some interesting orientation distinctions with MonoTouch development. Luckily the good folks at Xamarin were very helpful on their forums.

 Regarding orientation, this is what I learned from Adam Kemp:

There are two kinds of orientation: device orientation UIDeviceOrientation and interface orientation UIInterfaceOrientation. Interface orientation tells you whether it's portrait, portrait upside down, landscape left, or landscape right. Device orientation has more spatial orientations like face up or face down (i.e., how is the user holding the device, rather than what does the screen look like). Device orientation is much more prone to changes even when the interface doesn't change at all (and sometimes the device doesn't know at all, hence the "unknown").

UIDevice.CurrentDevice.Orientation gives you the device orientation.

To get interface orientation you use UIApplication.SharedApplication.StatusBarOrientation.

You can also observe changes to the orientation by adding an observer like this:

   _interfaceNotificationHandle = 
         NSNotificationCenter.DefaultCenter.AddObserver(
            UIApplication.DidChangeStatusBarOrientationNotification, 
            HandleInterfaceOrientationDidChangeNotification); 


And don't forget to unregister (in this case I do it in Dispose(), but for a view you might want to register when the view is added to a window and unregister when it's removed):


public void Dispose() 
{ 
    if (!_disposed) 
    { 
        if (_interfaceNotificationHandle != null) 
        { 
            NSNotificationCenter.DefaultCenter
                .RemoveObserver(_interfaceNotificationHandle); 

            _interfaceNotificationHandle = null; 
        }
        
        _disposed = true; 
         
    } 
}

Wednesday, October 17, 2012

Change orientation automatically with iOS6 and MonoTouch

Orientation and auto rotation in iOS6 with MonoTouch is slightly less obvious then I had hoped. It took me a little while to get it right, so maybe this will help others. To get your app to auto-rotate you will need to make sure you have done the following:

  1. Edited your Info.plist to specify allowed orientations
  2. Make sure you have RootController assigned to your view. Without this auto rotation will not work and you will get a compile time warning - "Application windows are expected to have a root view controller at the end of application launch". 

Do the following in AppDeligate.cs

UIWindow window;

public override bool FinishedLaunching (UIApplication app, 
                                           NSDictionary options)
{
     window = new UIWindow (UIScreen.MainScreen.Bounds);
     
     // change this to your controller
     var cvc = new SomeViewController(); 
     window.RootViewController = cvc; 
   
     // make the window visible
     window.MakeKeyAndVisible ();

     return true;
}


Once you are done with this, you should get auto-rotation!

Next, you can specify allowed orientations (if you want to limit to a specific set) either in AppDeligate.cs (globally) or in your controller level using the following override:

public override UIInterfaceOrientationMask 
                  GetSupportedInterfaceOrientations 
                     (UIApplication application, UIWindow forWindow)
{
  return UIInterfaceOrientationMask.Landscape;
}
Also, on the controller level, you can disable auto rotation all together using the following:

public override bool ShouldAutorotate()
{
         return false;
}

Hope this helps! Leave me a comment if this worked for you.





Thursday, April 5, 2012

Installing memcached on RHEL6 to use with Drupal 7

Recently I decided to switch from memcache to memcached PHP extension to be used with Drupal 7. I followed a great guide from http://www.bxtra.net/articles/2011-03-22/how-to-install-memcached-on-centos-memcached-pecl-update-20110322 but made some modifications to work with RHEL 6 / CentOs 6.
# Get libvent
wget http://monkey.org/~provos/libevent-2.0.10-stable.tar.gz
tar -xvf libevent-2.0.10-stable.tar.gz
cd libevent-2.0.10-stable
./configure;make;make install;

# Get the latest version of libmemcached
wget https://launchpad.net/libmemcached/1.0/1.0.5/+download/libmemcached-1.0.5.tar.gz
tar xvfz libmemcached-1.0.5.tar.gz
cd libmemcached-1.0.5
./configure
make && make install

# Get ZLIB headers
yum install zlib-devel

# Remount /tmp with execute permissions 
mount -o remount,exec /tmp

pecl install memcached

# Revert back to a safer configuration
mount -o remount,noexec /tmp

The last step is to add the extension to /etc/php.d/
extension=memcached.so > /etc/php.d/memcached.ini
Now you can update your settings.php in Drupal to take advantage of all the tweaks:
$conf['memcache_options'] = array(

// Turn off compression, as this takes more CPU cycles than its 
// worth for most users
Memcached::OPT_COMPRESSION => FALSE,
// Turn on consistent distribution, which allows you 
// to add/remove servers easily
Memcached::OPT_DISTRIBUTION => Memcached::DISTRIBUTION_CONSISTENT,
// Highly recommended to enable this option if you want 
// to use consistent hashing
Memcached::OPT_LIBKETAMA_COMPATIBLE => TRUE, 
// Dials down the connection timeout to 50 millisecond
Memcached::OPT_CONNECT_TIMEOUT => 50,
// These are timeouts for the actual send and receive operations sent
// to the Memcached server, this time in microseconds. 
Memcached::OPT_SEND_TIMEOUT => 50000,
Memcached::OPT_RECV_TIMEOUT => 50000,
// A timeout that is used internally for polling the input and output
// streams. This one is back in milliseconds
Memcached::OPT_POLL_TIMEOUT => 50,
// Enable non-blocking sends. This means that PHP immediately regains
// control when sending a value over the wire.
Memcached::OPT_NO_BLOCK => TRUE,
// Nnumber of times to try to connect to a server 
// before ejecting it from a  pool. 
Memcached::OPT_SERVER_FAILURE_LIMIT => 20,
// The number of seconds to wait before trying to add 
// a down server back in to the pool
Memcached::OPT_RETRY_TIMEOUT => 360

);
This is mostly taken from http://blog.roundeights.com/36883753

Wednesday, April 4, 2012

Managing a collection of Apache web servers via Parallel SSH



Recently, I came across something that I considered to be a common problem, with a known solution and hit a snag. I needed to manage some basic operations across 12 Apache Web servers running RHEL6. I wanted to perform basic tasks such as restart Apache and memcache, as well perform some simple management tasks. It turned out to be a challenge, mostly due to lack of documentation. Which is why I'm writing this. Hopefully someone else will find this helpful.

First I downloaded PDSH - http://code.google.com/p/pdsh/wiki/UsingPDSH
wget http://pdsh.googlecode.com/files/pdsh-2.28.tar.bz2
Next untar the archive, of course
tar -xvf pdsh-2.28.tar.bz2
Next we want to configure, build and install PDSH on the system:
cd pdsh-2.28
./configure
make
make install 
Now we have PDSH all built and ready to go. All straight forward thus far, but next things get a touch tricky.
First, you need to define your hostlist file. Let's call it hostlist.txt and put it in /var/pdsh. We need to tell PDSH to use this as the default hostlist file location:
export WCOLL=/var/pdsh/hostlist.txt
Next, you want to edit your host file on the machine and create host names foe every server IP you want to manage:
vim /etc/hosts

192.168.1.10 devweb1
192.168.1.11 devweb2
192.168.1.12 devweb3
192.168.1.13 devweb4

Next you want to add these host names to your default host file in /var/pdsh/hostlist.txt
vim /var/pdsh/hostlist.txt
devweb1
devweb2
devweb3
devweb4
After this is done, you are almost done. You just have to make sure that you have a user that has key-based authentication set up with the servers that you want to manage. To test that SSH with the user you are planning to use to each one of the boxes and make sure you get in without entering a password:

If your SSH is set up correctly, you are ready to run basic commands in PDSH:
pdsh -R exec -w myuser@devweb[1-4] ssh -l %u %h date

devweb3: Wed Apr  4 14:38:49 CDT 2012
devweb1: Wed Apr  4 14:38:49 CDT 2012
devweb2: Wed Apr  4 14:38:49 CDT 2012
devweb4: Wed Apr  4 14:38:49 CDT 2012

This works, and that's great. Now you want to do something more complicated, such as restart Apache. This is where things get trickier. You need to log in individually to each one of your web servers and edit the SUDO file.
visudo

#Disable tty requirement, so PDSH can use sudo
#Defaults    requiretty

#next add permissions for your users for Apache 
#and Memcache with no password
Cmnd_Alias      APACHE = /etc/init.d/httpd start, 
                         /etc/init.d/httpd stop, 
                         /etc/init.d/httpd restart, 
                         /etc/init.d/httpd graceful

Cmnd_Alias      MEMCACHE = /etc/init.d/memcached restart,
                           /etc/init.d/memcached start, 
                           /etc/init.d/memcached stop

%myusergroup ALL = NOPASSWD: APACHE, MEMCACHE


And now you are good to go! Give the following a shot:
pdsh -R exec -w myuser@devweb[1-4] ssh -l %u %h sudo 
                                        /etc/init.d/httpd restart

Now you can manage a farm of any size very easily. Adjust the numbers in the brackets to make changes to a partial set of servers.

Tuesday, April 5, 2011

CSS Causing a Crash on Webkit Browsers

This absolutely blew my mind today. Turns out a piece of CSS code can cause a 30 second pinwheel and/or crash in Safari and Chrome on a Mac. This is extra crazy, because it works fine on all browsers on a PC, including IE6. At first I thought it was an issue with my JavaScript code or something wrong with JQuery, but after spending a whole boat load of hours on this problem, turns out the culprit was 1 line CSS.

The following line caused crashes and freezes for me: background-size: 100%;

This was set on a div in a code that I inherited.
div.searchFilter {
 background: #FFFFFF url(../images/search_options_bg.png) 0 0 repeat-x;
 width: 762px;
 margin-top: 0;
 display: none;
 border: 1px solid #b6ac9f;
}

I hope this saves someone some agony, because it drove me insane.

Tuesday, March 15, 2011

Sitecore and FieldRenderer

I get work with Sitecore quite a bit, and even though I do like the product itself, my biggest gripe is that the online documentation is sparse and not easily searchable. In particular, I could not find the documentation for FieldRenderer format parameters anywhere. These are extremely useful for formatting Date and Image fields.

First include WebControls namespace to use FieldRenderer:
using Sitecore.Web.UI.WebControls;

Next, use the following overload for the Render method:
FieldRenderer.Render(Item item, string fieldName, string parameters);

As far as the parameters argument goes, this where I had to dig endlessly to figure out the right string every time I use the functionality. Here is the info I was able to come up with, which will hopefully save you some time:

1. Date Formatting, add format= and then formatting string you want to use
FieldRenderer.Render(item, "Date", "format=MM/dd/yyyy")

2. Images - one thing to note, URL format is used to combine parameters together.
FieldRenderer.Render(item, "Date", "w=500&h=700&as=1")

For images the list of options is significantly larger:

w: - Width
h: - Height
mw: - Max Width
mh: - Max Height
la: - Language
vs: - Version
db: - Database
bc: - Background Color
as: - Allow Stretch
sc: - Scale (.33 = 33%)