Monday, 10 November 2014

iOS7 Syncing problems with DAViCal

Background

A few years ago I installed DAViCAL on my Linux server and we started sharing our personal calendars. It meant having to install & learn the basics of PostgreSQL but it was worth the pain. The initial setup list (available on the DAViCal home page) was easy to follow, and everything worked first time. There are various clients available that use the CalDAV standard, and we soon had it working nicely on various iPhones, iPads and macbooks using iCal. Everything was great!

But then my wife and I upgraded our phones to iOS7, and after a while we became aware that we were no longer seeing each others updates. But as other shared events were still coming through, we knew the calendar server wasn't broken.

We weren't the only ones using iOS7, and I'd already installed the DAViCal version with the headers fix, so I knew it should work. The question was, why was it only effecting just these two phones?


Sorting out the Problem

After randomly trying many solutions others had suggested on the web and getting nowhere, I figured the best thing to do was break down the problem and try and debug it logically.


- Monitor The Problem -

1. The first thing to do is set up your shared calendar in iCal so that the basic operation of the calendar can be checked.
Add all your accounts into iCal


2. Added an entry and monitor the access.log screen to see what actions are being logged.

3. In terminal (or using Putty if you use windows), connect to your Linux server and type..

tail -f access.log

192.168.1.30 - - [10/Nov/2014:19:40:26 +0000] "PUT /davical/caldav.php/private/home/2EC5E2F1-A36E-4C91-A2FF-F8DC514738F7.ics HTTP/1.1" 401 416 "-" "Mac_OS_X/10.9.3 (13D65) CalendarAgent/176.2"
192.168.1.30 - rick [10/Nov/2014:19:40:26 +0000] "PUT /davical/caldav.php/private/home/2EC5E2F1-A36E-4C91-A2FF-F8DC514738F7.ics HTTP/1.1" 204 505 "-" "Mac_OS_X/10.9.3 (13D65) CalendarAgent/176.2"

You can see here it generated two PUT actions. Watch it for a while and you'll also see things like PROPFIND, OPTIONS, REPORT, and DELETE.

4. Once you've got the hang of the sorts of messaging being logged pressed ctrl+c to stop.


- Delete iPhone Account Settings -

5. Now deleted the problem account from Settings > Mail, Contacts, Calendars on your iPhone.


Delete accounts that aren't syncing.

(WARNING : You will lose any entries that haven't been synced, you may want to move them to the local calendar using the Calendar app first!)

6. Open the Calendar app to confirm that all entries on this calendar had gone, and then close it again.


- Clear Sync Tokens on the Database -

7. Back in terminal, enter the following..

su postgres

psql davical

delete from sync_tokens;

\q
exit

(nb. mine said it deleted 60 rows.)

- Add Accounts to iPhone Again -

8. Go back to Settings on your iPhone and add your account back again (use Other > Add CalDAV Account).


Select 'Other' then Add CalDAV Account.


nb, more details can be found here if you've forgotten how to do it.

9. Restart monitoring of the access.log again in terminal.

10. Restart your calendar app and add an entry. As you save, watch the access.log to confirm the phone is writing the event to the server. 

Don't expect events to be synced to iCal, or other devices instantly. It can take 5 minutes or more, even after triggering manual updates. The log entries are enough to know your device is syncing with the server.

Once you have confirmed your device is now syncing correctly (both from and to iCal) you're ready to do the same on the other phone.



Good luck with fixing your problem, and I hope this works for you too.


Tuesday, 7 October 2014

Removing the Repetition in Code (The Array)

Introduction

After spending some time tidying up a predecessor's javascript code I feel the need to document my findings. Any good developer will know all of this stuff, but while I'll go through explaining how to reduce the number of lines in your code, it's worth bearing in mind that we need to balance this with the idea of avoiding obfuscation.  

Obfuscation is the act of creating code that is difficult for humans to understand. Wikipedia suggests this is done deliberately, but I think that sometimes the best intentions go awry.


The Code as I found it

A function had been written to hide a large collection of bitmaps used to indicate validation failures on a web form.

function showimg(imgId,imgAct) {
    a = document.getElementById(imgId);
    if (imgAct == 'show' ) {
        a.style.display='block';
    } else {
        a.style.display='none';
    }
}


This was called in the main processing block in the following way:-

showimg('imgoriginator','hide');
showimg('imgeffectdate','hide');


//....loads more lines like this!!

showimg('entothimg','hide');
showimg('eooimg','hide');


Now if we ignore the fact that the showimg() function isn't very robust (it will generate an error if an object name isn't found in the DOM), it seems like an OK way of doing things.

The problem I had was that there were 124 of these calls, probably the result of a copy-&-paste frenzy. And while there's nothing actually wrong with doing this, it makes the code difficult to maintain. (and annoys people like me)

Let's say at some stage that we wanted to modify the parameters passed to the showimg() function. All of a sudden we have over a hundred lines to change. It might have started out simple, but now it's a complete pain!


How do we make it better?

The answer is to use an array to hold the image IDs, and then use a loop to process them.

I'd only use it if we get more than a handful of calls because the added complexity would hinder more than it helped. But, with 124 lines it's well worth bother, so first of all we'll define an array and fill it using the data from the original calls:

var imgArr = ['imgoriginator','imgeffectdate','imggroupnumber','imggroupname','imgaccountnumber','imgaccountnumber1','imgaccountnumber2',  'imgaccountnumber3','imgaccountnumber4','imgaccountnumber5','imgbranchname',
'imgtradingname','imgrequestforchange','imgreasonforchange','imgjustrequest','imgaccountmarker','imgremoverrider',
'discat1','overdis1','disthre1','saltarcat1','saltar1','payacc1','payto1','addl1','city1','county1','postcode1','justod1',
'discat2','overdis2','disthre2','saltarcat2','saltar2','payacc2','payto2','addl2','city2','county2','postcode2','justod2',
'discat3','overdis3','disthre3','saltarcat3','saltar3','payacc3','payto3','addl3','city3','county3','postcode3','justod3',
'discat4','overdis4','disthre4','saltarcat4','saltar4','payacc4','payto4','addl4','city4','county4','postcode4','justod4',
'discat5','overdis5','disthre5','saltarcat5','saltar5','payacc5','payto5','addl5','city5','county5','postcode5','justod5',
'discat6','overdis6','disthre6','saltarcat6','saltar6','payacc6','payto6','addl6','city6','county6','postcode6','justod6',
'discat7','overdis7','disthre7','saltarcat7','saltar7','payacc7','payto7','addl7','city7','county7','postcode7','justod7',
'th1','th2','th3','tl1','pt1','pt2','pt3','pl1','qeimg','gskimg','nqeimg','piimg','genimg','zdimg','shimg','pmedimg',
'gslmedimg','hbimg','otherimg','totalaahimg','trigenimg','triplsimg','entothimg','eooimg'];


Then we have a simple 'For' loop:

for (var i = 0; i < imgArr.length; i++){
   showimg(imgArr[i],'hide');
}


... and that's it!

If you need to add further field IDs it's a simple task of adding them to the array definition. There's no need to worry about getting the calls right, they just do the same as all the others.


An Alternative

Some of you will probably have your own ideas about how to improve this code.

One method to remove the array definition altogether requires you modify the web page to set each of the image class names to 'validate',... yes all 124 of them! And then have code that builds the array directly from the DOM..

var imgArr = document.getElementsByClassName('validate');

The loop needs a slight tweak because the array is now an array of tag objects, or we could do away with the showimg() function call and perform the hide within the loop..

for (var i = 0; i < imgArr.length; i++){
   imgArr[i].style.display='none';
}

Can't get much simpler than that, and maintenance is easier still, but it's now not so clear how it works! 


I'll leave you with a joke that Microsoft recently tweeted...

Q: Why did the programmer quit his job?

A: Because he didn't get arrays!

Friday, 6 June 2014

Adding a Second Minecraft Server in Linux

Introduction

We've been using the linux startup script from the minecraft wiki for some time now and generally it works a treat, but recently I've wanted to set up a second service for my two younger sons to play on, away from the highly modified worlds that my oldest son had set up. The script can't cope with two services running at the same time, but with a few tweaks you can run as many as you like. The following instructions create a new game server called Pinga using a service called kidcraft.

Creating the New Minecraft Installation

I wanted it use vanilla Minecraft version 1.5.2, which was the very first version that we tried, but it should work for any version including craftbukkit, or any other modded versions.

1. Make a copy of your existing Minecraft installation.

cp -Rv /opt/minecraft /opt/kidcraft

2. Remove the old world directories (in my case the world was called 'Plop')

rm -R Plop

3. Edit your server.properties file and change the following settings:-
   - server-port : 25566 (the default is 25565 so pick a number that isn't being used)
   -server-name : Pinga (enter your new server name)
   - level-name : Pinga (will be used to name your new world)
   - gamemode : 1 (Creative - my kids don't want to play survival, you can leave this as 0)

Also make sure the other settings are set back if altered from standard.

4. Empty the Ops, Banned-ip, Banned-players and White-list files or delete them (they'll get recreated when you start the server).

5. Start the server up and allow it to create a new world.

6. Check you can connect to it in the game using the Multiplayer option.

7. Close down the server.

Create a New Backup Folder

If you use the backup option then you want to specify a new location for the files so they don't get mixed in with your existing backups. Mine were going into the /DailyBackup/Minecraft folder.

8. Go to your backup folder and create a new sub-directory

cd /DailyBackup
mkdir kidcraft

Modifying the Startup Script

The startup script uses the 'screen' utility as the control mechanism, and this also allows you to access the console if required. You will need to make some changes to the new script so that the commands connect to the correct service.

 9. Copy the startup script

cp /etc/init.d/minecraft /etc/init.d/kidcraft

10. Ensure it can be executed

chmod 755 /etc/init.d/kidcraft

11. Edit the new startup script and modify the following:-
   - WORLD : 'Pinga'
   - MCPATH : '/opt/kidcraft'
   - BACKUPPATH : '/DailyBackup/kidcraft'

12. Then alter the startup line in the mc_start() function

as_user "cd $MCPATH && screen -h $HISTORY -dmS kidcraft $INVOCATION"

13. Repeat stage 12 for the following functions:-
   - mc_saveoff()
   - mc_saveon()
   - mc_stop()
   - mc_command()

14. Save and exit the file.

You should be able to start and stop the new service using this new script in the normal way.

eg. /etc/init.d/kidcraft start

You can also access the console using the following command.

screen -r -S kidcraft

(Nb. use Ctrl + A D to exit)

One more thing..

Nearly forgot,.. if you want to make this server available over the web, don't forget to set up another port forwarding service on your router.

Update

An improved method can be found here http://theperfectbeast.blogspot.co.uk/p/linux-minecraft-server-script.html

Tuesday, 3 June 2014

Minecraft 1.5.2 on Snow Leopard


The Trials of Old Kit

I've pretty much given up trying to get Minecraft running on my old PowerPC Mac Mini (and I don't think I'm alone in that), so I dug out my black Macbook from around 2009. My original problem had been that Apple and Oracle had given up on the PPC processor so OSX was stuck at Leopard and Java with Apples version of 1.5, so I assumed the Macbook with it's intel Core Duo CPU would be easy.

Seems I was wrong again!

Its all about the Java

After installing the Minecraft launcher I initially found it crashed after trying to start the game (just like before). I managed to find a Java update that had been recompiled to NOT stop when it found an old version of the OSX.

With this I was able to get Minecraft working, but only on version 1.6.1 or higher. But my server is 1.5.2 and upgrading wasn't an option. I have a friend who's kids play on an old PC that doesn't like any version later than this because of video driver issues.

Once again, after lots of googling I was unable to find a solution to the problem, it seems that the launcher was broken some time after v1.5.2 and thus later versions just won't work on Snow Leopard.

Shoot the Snow Leopard

I'd always held off upgrading to Lion because it meant losing Rosetta and I'd actually quite liked Snow Leopard. I saw it as a better, more 'sorted' version of Leopard, but as this laptop just wasn't being used anymore I didnt have anything to lose. The upgrade went smoothly and was followed by a 2Gb system update.

After this I started up Minecraft and it just worked (wow) albeit running slightly warm. I then spent a little time tinkering with the video settings in the game to get it running smoothly (turning on advanced OpenGL, setting the Graphics to 'Fancy' and turning off clouds). Everything was running great until I turned off full screen mode to see if it would run cooler. Then it crashed in disgust, refusing to restart.

It took a little trial and error to work out how to fix it, but here's all you need to do:-
  • Set your launcher to use the latest version of the game.
  • Launch the game and then go into the video settings.
  • Switch back to fullscreen mode
  • End the game
  • Switch back to 1.5.2 and relaunch.
Simple enough to fix. I suspect there's some sort of backwards incompatibility with the video drivers and earlier versions of Minecraft. In my experience the world of Java is full of version issues and gotchas. But this is the price you pay for cross platform compatibility.

For a simple looking blocky game it sure does make my laptop run hot.

Thursday, 22 May 2014

Oracle Apex - Adding Region Help

Oracle APEX Help Text

Occasionally at work I build systems using Oracle's Application Express and I find I have to stop the web developer within me from going overboard and solving problems in a non APEX way. We had just completed a new system for managing customer discounts and had asked the system owner to come up with field and page help for the application. After a few days we received a spreadsheet full of descriptions and help for most of the pages, but to my surprise they'd included region help. The latter being something that isn't currently implemented in vanilla APEX.

Just to explain a little for those not conversant in APEX, systems are built from a number of pages, and each page can be essentially a report or form. You can have a mix of these by using regions, but as everything must be in a region anyway it's really a case of adding extra regions. Additionally it can be beneficial to split forms across multiple regions to aid clarity or group by function. The following example shows percentage fields used to capture discount percentages for a customer.

Standard Form Region in APEX.
Item help has already been added to this region and this can be seen by clicking one of the labels. This runs a JQuery function called 'popupFieldHelp' and generates a fancy popup like this example.

Item Help Example.

So far all perfectly normal, there's nothing new here!

Additionally these items appear on the Page Help, grouped together under a section title that matches their region title.

What About Region Help?

So everything was great until we were asked for a region help, but as the requirement was valid I couldn't just discard the idea. But I didn't want to write custom JQuery code because my non-developer colleague may need to update it, and I also wanted it to appear in the page help. Here's what I came up with...

1. Add a 'Display Only' page item to your region and choose a sensible name.

(In our example this will be 'P19_ADDITIONAL_DISCOUNTS_HELP').

2. Set the Label text to reference the region name, to be shown in the page help.

(I used 'Additional Discounts Region' for my label.)

3. Add the help text to the item in the normal way entering your region help text.

4. Move the item so that it is first in the region and run the page.

5. Test your new help text by clicking on the item label, then right click it and copy the link code.

(nb. In Firefox this is 'Copy Link Location' and in Internet Explorer it is 'Copy Shortcut'.)

6. Paste the link code into Notepad (or similar) and you should have something like this..

javascript:popupFieldHelp('3439324541165905','112943106205802')

(nb. The first number is your item number, the second is the session number)

7. Edit the region and alter the title to..

<a class="uHelpLink" href="javascript:popupFieldHelp ('xxxxxxxxx','&APP_SESSION.')">Additional Discounts</a>

Where xxxxxxxxx is your item number that we found in the previous stage.

8. Save and run the page and your title will now show as a link (see image below).

Region Help Linked To Region Title.
9. Click the title link and check it works.

10. Finally edit the page again and set the item to 'Hidden' so that it's label no longer shows in the region.

(nb. The item help box will now be hidden when editing the item, but it's still there and available to page and item popup help functions.)


Update, 20/01/2015 Method adapted for tabular form columns.

Monday, 19 May 2014

Restoring Java 1.6 on a PowerPC Mac


The Problem

The kid's old G4 Mac Mini was superceeded last year by a more modern intel version which has taken over the duties of Web Browsing, Minecraft and StarCraft.

My oldest son used to live and breath Minecraft, but it fell out of favour a few months back and although the new server still runs his creations, it tends to only get used by his old friends. I think he wanted it to be packed with people, but as it's a small private server using a domestic internet connection I argued this wasn't really fair on the rest of us. As time went on it became less about creating and more about minecraft based activities, although there's some pretty amazing creative stuff on there.

It concerned me though that my server investment was being wasted, so I decided to introduce my two younger sons (5 and 7) to a very much simpler version of Minecraft. I added another service on port 25566 using server version 1.5.2, but then I ran into a problem.

My plan was to hook the old PowerPC Mac Mini to my TV and use that as a second machine, so both boys can play at the same time. This should avoid the "waiting for their turn" issues that we frequently get and be more fun for them. But somewhere along the way an Apple update has removed Java 1.6 (for security reasons) and dumped it back to 1.5, and this version won't run later versions of Minecraft or the loader. Apples recommendation, get it from Oracle (we don't supply it anymore)

Between a rock and a hard place.

I'll admit the G4 Mac Mini is getting as little old; I think I bought it in 2006 so a friend could edit his holiday video. It went on to serve as a loan machine for a few years until we finally set it up for the kids. If I'd have waited another 6 months it would have been an Intel version (sighs), but nobody saw the switch to Intel coming.

So guess what, Oracle don't supply a PowerPC version of Java anymore (in fact I'm not sure they ever did, because Apple still supplied it up to 1.6) None of the Apple update links for Java work anymore (archived) and any updates I do find just install later versions of 1.5, and there's little hope of 1.7!

I did manage to find some v1.6 files after the JavaV8 Apple update, but curiously it didnt show up in Java Preferences. Then when I hacked it into use by altering the symbolic links in /system/library/Frameworks/javaVMs/versions it politely informed me that it was the wrong CPU type.

/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Commands/java -version
/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Commands/java: Bad CPU type in executable

So I'm looking at scrapping this machine because it's CPU is not supported anymore, or find a creative way of getting around the problem.

Soylatte or Bust

After a lot more googling I found Soylatte, their site had binaries and after install I ran java -version is proudly reported version 1.7.

Add to your path to get it to run..

export PATH=/usr/local/soylatte16-amd64/bin:$PATH       
(or what ever you called your install dir)

I had high expectations, but this is a Beta Java Developer Kit (JDK), all we want is the Runtime or JRE. Something's not right though because I'm not able to get Minecraft to run and now Java Preferences fails to start.

I went back to googling for answers and ideas, but I didn't find anything new.

So what are my options now?
  • Chuck it in the skip. (buy intel one)
  • Install Linux MintPPC (more investigation required)
  • Replace logic board with Core 2 duo version. (not even sure this will work)

Monday, 31 March 2014

DRM & Copyright

What do you mean it's illegal?


From June 1st it will become *legal* to rip your CDs in the UK.

"What?", I hear you say, "I didn't know it wasn't"

Yeah, that's a common thing I hear because it's an unjust law that nobody pays any attention to. Most see that if you can freely import music into iTunes (or similar) then how can it be illegal. Somehow the music industry managed to sneak that by us. They assumed we'd just roll over and re-buy our content again using whatever download service our phones or music players supported.

Essentially they scared our governments into accepting these measures to protect what they called a fragile economy. Completely ignoring the fact that if they produced a good product at a reasonable price then people would buy it. On top of that they introduced Digital Rights Management (DRM) stopping the consumer from choosing how they used the contents they'd purchased, in addition making it technically impossible (or at most difficult) to make a fair copy.

Anyone investing any time breaching these measures is then clearly a pirate!

Times they are a changing

It's all part of our broken Copyright and Patent system which has now been investigated in the Hargreaves report, and this has identified a number of small reforms. The Intellectual Property Office recently made the following statement..

"The changes make small but important reforms to UK copyright law and aim to end the current situation where minor and reasonable acts of copying which benefit consumers, society and the economy are unlawful"

..And this to include all digital formats, not just music CDs. So the days of device lock-in might be numbered. So all that stuff you bought on your kindle, why not "format shift" it so that any digital e-reader can open it?

This includes DVDs and Bluray discs which is also currently encumbered with strong DRM, so in practice I'm not sure how that's going to work. The changes excludes Computer Software, but it's unclear how things like games could ever be copied to another format that you might own, but I for one would like to make a backup copy of any discs I own so it seems lacking.

Back to Reality

I can't see any time soon that we'll be seeing video discs that don't have DRM and content region restrictions. It's going to take a bigger change in the law before that happens because big business just doesn't want to let the genie out of the bottle. But it's like the blocking of the Pirate Bay web site, it won't stop the small percentage of people from obtaining content via illegal methods, but we all suffer in the mean time!