Monday, 11 September 2017

iPad Won't Start or Charge

The Problem

My son let his ipad run down really low, and then his brother accidentally unplugged it shortly after it had been set to charge. The net result was that the screen went black, then when we plugged it back in to charge we just got the apple logo.



After a few hours it was still the same. It didn't appear to be charging and refused to start.

The solution

I fixed it by putting the ipad into DFU mode and left it plugged into the charger overnight.
  1. Hold the Power Button (3 secs)
  2. Continue holding the power button and also hold the home button (15 secs)
  3. Release the power button while continuing to hold the home button (10 secs)
The ipad screen was black after this, but you'll know it's in DFU mode because when you plug it in you will no longer get the apple logo.

The next day I forced it to shutdown by pressing Power and Home. You should then be able to start it as normal and it will show a 100% charge.

Hopefully this will work for you, good luck.

Tuesday, 18 July 2017

VB - Deploying an Application using Oracle Data Access

Introduction

It's great when you get your application to run in Visual Studio, or even from the compiled files on your PC, but at some stage you're going to want to deploy or share it. This is where I ran into problems with Oracle drivers.

Oracle  Drivers

You set up your Oracle access in VB by selecting the DLL that came with your client software and adding it to the project resources. Here's what mine looked like in Visual Studio..

Assigning the Oracle library as a project resource.
Then add the following imports into your program module..

Imports Oracle.DataAccess.Client
Imports Oracle.DataAccess.Types


But, although you've set your resources correctly, the DLL location and version is likely to be different on other machines you deploy to. So you'll probably to get errors.

You can start to fix this by setting the Copy Local value to be True, and then the DLL file gets bundled into the release folder when you re-compile.

Set Copy Local
But while this might get your locally compiled version working, it's likely that other machines will still have problems with driver compatibility errors.

Typically you'll see something like this..

Oracle.DataAccess.Client.OracleConnection' threw an exception. ---> Oracle.DataAccess.Client.OracleException: The provider is not compatible with the version of Oracle client

Solution

Download the Instant Client Basic Lite files from Oracle and unzip it to your PC. Copy the following library DLL files and put it into the same deploy folder as your executable:-

oci.dll
ociw32.dll
Oracle.DataAccess.dll 
orannzsbb11.dll
oraocci11.dll
oraociicus11.dll
OraOps11w.dll

Hopefully that will get you going.

Friday, 7 July 2017

VB - Connecting to an Oracle Database without using a TNS Entry

Introduction

Connecting to an Oracle database isn't too much of a problem, there's examples everywhere on the web along the following lines..

Dim conn As New OracleConnection()
Dim connstr as String, dataSource as String, userId as String, password as String
dataSource = "dev10g"
userId = "jsmith"
password = "letmein"
connstr = "Data Source=" + dataSource + "; User Id=" + userId + "; Password=" + password + ";"
conn.ConnectionString = connstr
Try
  conn.Open()
Catch ex As Exception
  ' Database connection failed
  conn.Dispose() 'Dispose of the connection
  Exit Sub
End Try


This works ok, but it's not very portable unless everyone that wants to use it sets themselves a TNS entry called "dev10g" in their tnsnames.ora file.

What if we wanted to define the host and port number in the config, and then connect without using TNS?

Connecting to Oracle Directly

In practice all we need to do is alter the connection string to provide the information that the tnsnames.ora would have sent. So the code above doesnt change much.

Dim conn As New OracleConnection()
Dim connstr As String
Dim dbServer As String, dbPort As String, dbServiceName As String
Dim userId As String, password As String

dbServer = "lordv01"
dbPort = "1521"
dbServiceName = "dev10g"
userId = "jsmith"
password = "letmein"
dconnstr = "Data Source=" + dbServer + ":" + dbPort + "/" + dbServiceName + ";User ID=" + userId + ";Password=" + password
conn.ConnectionString = connstr
Try
  conn.Open()
  Catch ex As OracleException
  conn.Dispose() 'Dispose of the connection
  Exit Sub
End Try


It took me a bit of poking around to find the right syntax, so hopefully someone will find this useful.

Friday, 30 June 2017

VB - Reading a Text Resource File Line by Line

Introduction

I'm not a VB programmer, but recently I needed to build an interface between Oracle and an MDB file, so I had to start getting familiar with Visual Express Studio 2013. I've done a lot of LotusScript in the past so it wasn't a big problem, but some things have proved to be a struggle.

For today's problem, I wanted to store a text file (used as a template) and pragmatically create a new version of it with a new name. It felt like the best thing to do was store the file as a resource, but it wasn't immediately obvious how to do it.

Creating the Resource

You can add a resource to your project as a text file using the Resources section of your project Properties. It's quite simple to access it in your code, in the following way:-

myString = My.Resource.MyTextFile 

But, if you do this then you'll get the whole file as a long text string. I wanted to be able to read it in using StreamReader and write it out line by line. But text files are always treated in this special way, so my method won't work.

The answer is to trick VB into thinking it's opening a binary file (just give it a different extension).

I created my file called inprep.template and moved it into the projects resource folder.

I then dragged it into the Resources page to register it as a project resource.

My new file resource

The VB Code

Here's the code to read the file (one row at a time) and output it to a new file.

Dim template As New MemoryStream(My.Resources.inprep)
Dim file As System.IO.StreamWriter
Dim oRdr As StreamReader = New StreamReader(template)
Try
   file = My.Computer.FileSystem.OpenTextFileWriter("c:\test.txt", False)
   Do While oRdr.Peek() >= 0
      file.WriteLine(oRdr.ReadLine())
   Loop
   oRdr.Close()
   file.Close()
Catch ex As Exception
   Console.WriteLine(ex.Message)
End Try


It's simple enough once you realise that you need to handle it as a binary file.

Friday, 9 December 2016

A Simple Guide to Oracle Data Pump

Introduction

In order to create a test system for one of our customers I needed to copy some schemas from the live oracle database. As the main schema contained a lot of objects, I realised that the best thing to use was Data Pump. Something I'd never used it before.

Oracle Data Pump first appeared in 10g and provided a newer and more flexible alternative to the 'exp' and 'imp' utilities from previous Oracle versions. It's a server based technology so you'll need access to the file directory structure on the database server. That means you'll need to be able to remote connect to both source and target servers.

Running an Export

We're going to start by running a schema export, it's quite straight forward, but we need to ensure that we have a directory object configured in Oracle. You could go ahead and just add one, but it's worth looking to see if there's one already set up that you can use. Log into the source server (in my case Live) and type the following:-

SQL> select directory_name, directory_path from all_directories;

The results should give you a column listing the object name, and a second stating it's actual directory path on disk. It makes sense to choose one where the directory actually exists, and where you have file creations rights, but that should go without saying!

If nothing suitable exists then go ahead and create one, and then grant yourself read and write on it.

You run the export from the operating systems command prompt, here's what I used:-

expdp <my user>/<my password> directory=<my directory object> dumpfile=<my export file>.dmp schemas=<schema to export>

When it runs it will output process to the screen and may take a number of minutes to complete (depending on number of objects and size of tables). If you'd prefer the progress can be sent to a file just by including the following paramater:-

  logfile=<export log>.log

Now if you go to the directory listed in the directory_path you should see your DMP file waiting for you. They can be quite large but normally they zip quite well to make file transfer quicker.

Running an Import

The obvious next step was to copy the dump file over to the target server (in my case the new test system), but don't worry about where to put it just yet. What we need to do again is find an Oracle directory object to use for the import process.

I used the same query as before:-

SQL> select directory_name, directory_path from all_directories;

If a directory object exists then move your dump file into it, or (as before) create your own directory object in Oracle.

Before running the import we need to connect as sysdba and create the empty schema in the test system.


SQL> create user newschema identified by pwd4newschema;
 

(NB. The "Identified By" parameter is the password.)

Finally at the command prompt run the import command:-

impdp <my user>/<my password> DIRECTORY=<my directory object> DUMPFILE=<my export file>.dmp

Again the progress will be reported to the screen. Scan through it and check you don't get any errors. I had some dependancy issues because two other schemas referenced in the packaged functions where missing. If this happens to you, copy the missing references and recompile your packages.

Wednesday, 7 September 2016

QR Code Treasure Hunt for kids

Introduction

Like many, I found the introduction of QR codes quite an intriguing idea. A simple pattern of squares which could be scanned with your smartphone and take you to a webpage or display a block of text.

It wasn't long before I started seeing these alongside museum exhibitions enabling visitors to see additional information, and this in turn has tended to drive public wifi access.

Anyway, my kids think these things are magical.


QR Code with a URL (Area 5.1 Cartoon)


Let's have a Treasure Hunt

One rainy day after the kids had been scanning QR codes on the back of the MagPi magazine I told them about my idea for using QR codes for a treasure hunt. They'd heard of this activity (although not with QR Codes) and were keen to try it, but getting decent clues seemed to be a bit of a problem for them. We googled a few websites that gave some examples, but we weren't impressed. I was sure I could do better.

So I hatched the idea to write my own clues and run a treasure hunt for them about the house and garden.


Building the Clues

There's various ways you can go about creating clues, but care should be taken to ensure you pitch the difficulty level right. You don't want them getting it too quickly, but it should force them to reason it out with a bit of thought. I decided to make mine rhyme and I used the http://www.rhymezone.com/ site to help me.

Here's a few of my examples:-
  • Mirrored Bathroom Cabinet: I’m a cupboard shiny and white, I reflect the world from this clean height. 
  • Door Mat: Stand on me, I won’t get sore, you’ll often find me by the door. 
  • Bike Shed: I’m never too sleepy, but I’m always two tired. In my wooden house your clue can be acquired. 
  • Nut Basket: At christmas time just get snacking, a basket of these will get you cracking. 

Try to include objects from all over the house and garden, including things from their rooms as well as everyday objects. Aim to have at least a dozen, and if you think your clue might be too hard, have a 2nd clue handy. (Before you go much further, review these with another person to ensure you have gauged the level correctly)

Generating QR Codes

Now you have your clues ready, the next step is to convert them into codes. The easiest way to do this is using one of the online webservices. (I used http://www.qr-code-generator.com/ which worked quite well, but it added a bit of a delay between downloads. This could be reduced by refreshing the page every half a dozen or so.)

The one thing I did notice is that longer clues increased the density of the pattern.

OK, once you've finished you should have a load of image files (make sure you unzip them if your chosen service compresses them). Next I added mine into iPhoto (because I use a Mac) and this enabled me to produce a contact sheet (you select it from the printing page). This was just an easy way of getting multiple QR images onto one sheet of paper so they didnt turn out huge when printed. You could manually add them into a word document, or similar if you want.


My QR Code contact sheet
Once printed, cut them into individual squares. Here's where it gets tricky, you'll want your phone handy with your favourite bar code reader (I was using RedLaser on the iphone).


Setting up the Treasure Hunt

I got into a real mess here and ended up with clues leading round in circles, so do yourself a favour and work out the route beforehand. Work through systematically using your phone to read each code. It took me about half an hour to set up 14 clues, so make sure your kids are out of the way, or busy. (Mine were playing Minecraft)

Then I left the first clue lying around where they could find it, and they took the bait. It was great fun watching them running about, trying different ideas and occasionally even working together. An hour later they reached the end where I'd left them each a packet of smarties.


Thursday, 25 February 2016

Oracle APEX - Updating data in a report using AJAX

Overview

I have a simple report showing hundreds of rows of config type information which I wanted to be able to alter quickly. I don't want to open each row in a form, or have to submit a tabular form to update any changes,.. it's all too slow.

What I want instead is a checkbox type column in the report which when clicked causes an AJAX request will be fired off to the server, which in turn runs an update query.

Sounds simple enough!

Setting up the Report

Let's start by looking at the report..
 


I've added a column called 'Ignore' which looks like a radio field/item. When clicked this will run an update to toggle the value in the database table.

Here's SQL that creates this in the report (notice I'm using a graphic of a radio button instead or a HTML form elements).

CASE WHEN sm.method = '3' THEN
         '<img name='||sd.personkey||' src="#IMAGE_PREFIX#pkt_rb_chk.gif" title="Ignored, click to remove" onclick="clicked(this)">'
       ELSE
         '<img name='||sd.personkey||' src="#IMAGE_PREFIX#pkt_rb.gif" title="Click to ignore" onclick="clicked(this)">'
       END ignore,

My database table stores an ignore as a '3' in the 'method' column. And, the reason why I'm using images is because I wanted to store the record key against the images using its name attribute. (It simplifies the javascript.)

Adding the Javascript

Next I added the following code to the Function and Global Variable Declaration on the report page. It uses some handy JQuery functions to make the code easier.

function clicked(obj){
  var personkey = obj.name;
  var img = obj.src.replace(/http:+\/.+\/+/,'');
  var checked;
  if (img == 'pkt_rb.gif') {
    checked = 1;
    var match = $(obj).closest('td').prev('td').text();
    if (match == 'Automatic' || match == 'Manual'){
      // Prompt for confirmation..
      var msg=confirm("This action will remove the current match, continue?");
      if (msg!=true){
        return;
      }
    }
  }
  else { checked = 0; }
  var ajax = new htmldb_Get(null,$v('pFlowId'),
            'APPLICATION_PROCESS=ToggleIgnore',0);
  ajax.addParam('x01',personkey);
  ajax.addParam('x02',checked);
  ajax.get();
  ajax = null;
  $(obj).closest('td').next('td').text('');
  if (checked == 1){
    $(obj).closest('td').prev('td').text('Ignore');
    obj.src = obj.src.replace(/.gif$/,'') + '_chk.gif';
  }
  else {
    $(obj).closest('td').prev('td').text('-');
    obj.src = obj.src.replace(/_chk.gif$/,'') + '.gif';
  }
}

The function takes the image object and uses a regular expression to find out the image name, and thus whether it's selected or not. (This gives us the initial 'ignore' status) We throw up a confirmation box if ignore is being set and then we start the AJAX call.

The AJAX call uses an APEX standard function called html_Get. This handles the request, the parameters you need to pass, and any browser variations. In our example we don't have any values being returned to the browser, but it would be easy to handle this by altering the 'get' command.

var gReturn = ajax.get();
// then do something with this value 

The final stage is to alter the radio image, and its hover-over text. Again we use a regular expression to alter the image name.

Next we need the back-end code that updates the table.

Adding an Application Process

You possibly noticed the AJAX function above is calling an Application Process called 'ToggleIgnore'.

So I created this Application Process using the name 'ToggleIgnore' and used the following anonymous block of PL/SQL code.

DECLARE
  l_person_key varchar2(20);
  l_checkbox varchar2(1);
BEGIN
  wwv_flow_api.set_security_group_id;
  l_person_key := apex_application.g_x01;
  l_checkbox := apex_application.g_x02;
  // Update the table
  switchboard_pkg.set_ignore(
    p_personkey => l_person_key,
    p_checked   => l_checkbox
  );
END;

The parameters are passed into p_personkey and p_checked, and in my example I've stored the update code in a packaged procedure. (It simply runs an update, but you shouldn't need me to go through that part).

Hopefully that's enough to help you get started building your own custom AJAX update methods.