• Category Archives Technology
  • See who is logging onto your domain

    I was looking a migration from one domain to another a short while ago. Almost all the users accounts had been migrated over but there were a few hanging on.

    The migration tool wasn’t doing a great job of picking them up so I wrote a small script and added it to group policy for all servers and workstations. Now when someone logs in to the old domain a line is written to the log with their username, computer name and IP address.

    Using this the person responsible for the migration can get through the last few people on the old domain. This has saved a lot of time as before I wrote this th eprocess was very manual.


    Const ForAppending = 8
    Set WshShell = CreateObject("WScript.Shell")
    Set WshNetwork = CreateObject("WScript.Network")
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    Set objFile = objFSO.OpenTextFile("\\ServerName.DomainName.TLD\RemainingComputer\log.txt", ForAppending)
    objFile.WriteLine WshNetwork.ComputerName & "," & WshNetwork.UserName & "," & GetIpAddress
    objFile.Close

    Function GetIPAddress
    strComputer = "."
    Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
    Set IPConfigSet = objWMIService.ExecQuery _
    ("Select IPAddress from Win32_NetworkAdapterConfiguration WHERE IPEnabled = 'True'")

    For Each IPConfig in IPConfigSet
    If Not IsNull(IPConfig.IPAddress) Then
    For i = LBound(IPConfig.IPAddress) to UBound(IPConfig.IPAddress)
    If Not Instr(IPConfig.IPAddress(i), ":") > 0 Then
    strIPAddress = strIPAddress & IPConfig.IPAddress(i) & " "
    End If
    Next
    End If
    Next
    GetIPAddress = strIPAddress
    End Function


  • VBScript to arrange files into folders.

    A few days ago I was presented with just over seven thousand PDF files. I had waited six weeks for these files so I was in a horrid mood when they arrived in one big batch with just ID’s in the file name. I had no way of processing them by customer.

    I had a spreadsheet that had the billing period, the customer name and the bil number in columns A, B and C respectively so I decided to write up a short script to process these files.

    Here’s a cut down version with a little bit removed to protect the various companies involved.


    Set FSO = CreateObject("Scripting.FileSystemObject")
    Set objExcel = CreateObject("Excel.Application")
    Set objWorkbook = objExcel.Workbooks.Open ("D:\Home\Workarea\Invoices_PDF\invoices.xlsx")

    ' Starting at row 2 because row 1 is used for the column headings.
    intRow = 2
    strNewParentPath = "ByETB\"
    strOldParentPath = "Combined\"
    strBasePath = "D:\Home\Workarea\Invoices_PDF\"
    Do Until objExcel.Cells(intRow,1).Value = ""
    strPeriod = ConvertPeriod(objExcel.Cells(intRow, 1).Value)
    strProcessedCompanyName = ConvertCompanyToDirectoryName(objExcel.Cells(intRow, 2).Value)
    strFileName = "billno-" & objExcel.Cells(intRow, 3).Value & ".pdf"
    ' WScript.Echo "Moving " & strOldParentPath & strFileName & " To " & strNewParentPath & strProcessedCompanyName & "\" & strPeriod & "\"

    If NOT (FSO.FolderExists(strBasePath & strNewParentPath & strProcessedCompanyName)) Then
    WScript.echo "Folder " & strBasePath & strNewParentPath & strProcessedCompanyName & " didn't exist."
    FSO.CreateFolder strBasePath & strNewParentPath & strProcessedCompanyName
    End If

    If NOT (FSO.FolderExists(strBasePath & strNewParentPath & strProcessedCompanyName & "\" & strPeriod)) Then
    WScript.echo "Folder " & strBasePath & strNewParentPath & strProcessedCompanyName & "\" & strPeriod & " didn't exist."
    FSO.CreateFolder strBasePath & strNewParentPath & strProcessedCompanyName & "\" & strPeriod
    End If

    WScript.Echo "Copying from: " & strBasePath & strOldParentPath & strFileName & " Copying to: " & strBasePath & strNewParentPath & strProcessedCompanyName & "\" & strPeriod& "\"
    FSO.CopyFile strBasePath & strOldParentPath & strFileName, strBasePath & strNewParentPath & strProcessedCompanyName & "\" & strPeriod& "\"
    intRow = intRow + 1
    Loop
    objExcel.Quit

    Function ConvertCompanyToDirectoryName (CompanyName)
    if CompanyName = "" Then
    WScript.Echo "No ETB Name passed to ConvertCompanyToDirectoryName function"
    Exit Function
    End If

    If InStr(1, CompanyName, "DUBLIN") <> 0 Then
    CompanyName = "Dublin"
    End If

    If InStr(1, CompanyName, "LOUTH") <> 0 Then
    CompanyName = "Louth"
    End If

    If InStr(1, CompanyName, "DONEGAL") <> 0 Then
    CompanyName = "Donegal"
    End If

    If InStr(1, CompanyName, "LIMERICK") <> 0 Then
    CompanyName = "Limerick"
    End If

    If InStr(1, CompanyName, "GALWAY") <> 0 Then
    CompanyName = "Galway"
    End If

    If InStr(1, CompanyName, "CORK") <> 0 Then
    CompanyName = "Cork"
    End If

    If InStr(1, CompanyName, "CARLOW") <> 0 Then
    CompanyName = "Carlow"
    End If

    If InStr(1, CompanyName, "KERRY") <> 0 Then
    CompanyName = "Kerry"
    End If

    If InStr(1, CompanyName, "MEATH") <> 0 Then
    CompanyName = "WestMeath"
    End If

    If InStr(1, CompanyName, "KILDARE") <> 0 Then
    CompanyName = "Kildare"
    End If

    If InStr(1, CompanyName, "TIPPERARY") <> 0 Then
    CompanyName = "Tipperary"
    End If

    If InStr(1, CompanyName, "TIPP") <> 0 Then
    CompanyName = "Tipperary"
    End If

    If InStr(1, CompanyName, "LAOIS") <> 0 Then
    CompanyName = "Laois"
    End If

    If InStr(1, CompanyName, "MONAGHAN") <> 0 Then
    CompanyName = "Monaghan"
    End If

    ' Replace spaces with under lines.
    If InStr(1, CompanyName, " ") <> 0 Then
    CompanyName = Replace(CompanyName, " ", "_")
    End If

    ' Replaces / character with nothing.
    If InStr(1, CompanyName, "/") <> 0 Then
    CompanyName = Replace(CompanyName, "/", "")
    End If

    ConvertCompanyToDirectoryName = CompanyName
    End Function

    Function ConvertPeriod (Period)
    If Period = "" Then
    WScript.Echo "Period passed to ConvertPeriod function is blank."
    Exit Function
    end If

    If Period = "01/01/2016" Then
    Period = "Jan2016"
    End If

    If Period = "01/02/2016" Then
    Period = "Feb2016"
    End If

    If Period = "01/03/2016" Then
    Period = "Mar2016"
    End If

    If Period = "01/04/2016" Then
    Period = "Apr2016"
    End If
    ConvertPeriod = Period
    End Function


  • Error updating iPhone. IOS problems.

    I’ve had problems updating my iPhone from IOS9.1.1 to IOS9.2 since it was released in the middle of December.

    I’ve tried the usual fixes:

    1. Updating from the iPhone as normal. This fails just after verifying the update.
    2. Updating from iTunes. This fails trying to create a backup. IT always says there isn’t enough space on my 2TB hard drive that’s about 50% free.
    3. I even resorted to resetting to factory defaults and installing the update before restoring from an iCloud backup. This gave the same errors as before.
    4. Obviously this is after various resets and trying from different wireless and wired networks on different Internet connections.
    5. I’ve even tried changing my regional settings to see if it was something related to my connectivity to an Irish update repository.

    Today I’m trying something different. I’ve downloaded the firmware for IOS9.2 and I’ve restored using that IPSW file using iTunes.

    Of course this is going to wipe the iPhone again but restoring from an iCloud backup using Doulci activator will get everything back as it was. Excluding WiFi, Email and social network passwords for some reason.

    This is the first time in about six years that I’ve had problems with an IOS upgrade. It’s quite frustrating and disappointing.


  • The Apple Watch with Voiceover review – Day 7

    Someone made a comment a few days ago about the Apple Watch and specifically Voiceover that I found kind of interesting. She said that the Apple watch isn’t like a normal talking watch. A normal talking watch has very slow speech feedback and the volume is static. It also usually chimes before announcing the time to the world. An Apple Watch might not be as discrete but it has a coolness factor at the moment that slightly negates the annoying factor for people around me. I can only hope that lasts. Her point was that the Apple Watch speaks much faster because I have it configured at that speed and if I’m going into an environment that’s quieter I can set the volume of the speech appropriately so that while in a quiet meeting for example it doesn’t shout my notifications out to the world.

    In most reviews of the Apple Watch I’ve read that people get annoyed by the number of notifications. I have to say that I’m not annoyed by them at all. I find that I actually miss most of the notifications that come in to the Apple Watch. This is because the tap is so slight that unless I’m not busy I really won’t notice. The iPhone demands attention but the Apple Watch quietly asks for it.

    I’m a techy. I love all things techy therefore it’s a given that I’ll get to like the Apple Watch but I don’t love it. I don’t see myself feeling naked without the Apple Watch like I do when I forget my phone. Sorry. That’s not quite true. I don’t feel naked without my phone but I feel like I’m missing something important. The Apple Watch isn’t that important to me. Apple announced on Monday that Apple OS version 2 will be out in September or October. I’m really hoping they address the short comings I’ve outlined on this blog in the past week. I’ll be emailing accessibility@apple.com to make sure they are aware of my problems, complaints and annoyances. I can only hope that every other Voiceover user of the Apple Watch does the same thing. If people don’t tell Apple what they are doing wrong they really can’t expect them to fix the problems for the next release.


  • Apple Watch with voiceover review – Day 2

    Day two with the Apple watch was quite uneventful.

    I was working from home so I reached my standing goal and my activity goal but I didn’t get anywhere near reaching my exercise goal. I’m hoping today will be a little better.

    Because I was at home I also didn’t have any problem with being unable to hear the watch due to background noise.

    I spent some time before work learning more about it. I still haven’t figured out how to turn off the noises for Voiceover but I learned that I can increase and decrease the volume reasonably easy. Double tap the screen with two fingers then slide up or down. The problem that I’ve encountered however is that when you release your fingers from the screen the volume can go up or down a bit. It’s not very accurate. It’s also not all that efficient so it can’t be done in a hurry.

    I also noticed that in glances you can move through the items by using the scroll area at the bottom. This is much faster than flicking up and down and then double tapping on next or previous item.

    I’ve enabled digital crown navigation. This can be done by triple tapping with two fingers. I like this method of navigation. Especially for notifications. The problem I have encountered though is when you use it to quickly move down to the last control labelled dismiss voiceover doesn’t always tell you that you’re there. It feels like an unfinished feature.

    I looked through the manual yesterday to try to find a list of Voiceover gestures. I had no success. If they are in a manual, they are well hidden.

    I’m still very irritated by the watch constantly turning on when I move my hand. Obviously I use my hands for everything. Finding things, opening doors, typing, playing music, my guide dog etc. The watch has absolutely no awareness of this though and constantly turns on and off. Each time it turns on Voiceover plays a sound and speaks the time. The problem is, I like this feature but I’d prefer if it was more intelligent. The funny thing is, I’ve read other reviews of the Apple Watch that have complained that the wrist movement isn’t fluid enough. In other words when the reviewers moved their wrist the watch face doesn’t turn on. Maybe this is something Apple have rectified and as a result have made it over sensitive.

    I have liked getting the notifications on my wrist though. Especially for work. I don’t get over loaded so it’s nice to get the important things even when I’ve stepped away or I’m talking to someone.

    Speaking of stepping away, one of the draws of the Apple watch for me is the fitness and activity side of things. I know I need to be more active. This is showing me exactly how much more. It may not be as accurate as dedicated devices on the market but it’s accessible and it’s accurate enough to send me in the right direction.


  • The apple Watch with Voiceover – Day 1

    The Apple watch on my wristI ordered the Apple Watch a few days after it was officially available in April and it arrived yesterday, a bit sooner than I had expected.

    I had tried one in the Apple store in Belfast back in April but the demonstration models didn’t have the ability to enable Voiceover so my conclusion wasn’t definitive on if this was going to be a benefit or not. However, as I like all things techy, I decided to go and buy one regardless.

    I want these reviews to be comprehensive without being too long so let me jump right into it.

    Firstly, there is an offal lot of packaging. I don’t know how Apple is ticking its sustainability box when it has so many little bits of packaging around the watch. It came in a card board box. Inside this was a card board shell which suspended another card board box. Inside this was a plastic box with the watch in the middle. The watch was also wrapped in about four types of plastic from the outside of the box to the strap.

    Fortunately it had plenty of battery when I started with it. It wasn’t at 100% but it was probably around 90. I turned it on, successfully paired it with my phone and within a few minutes the Apple watch was talking and working well. It’s just as well it was a quick process as I got it into my hands at 7:35 and I had to be out by 7:50PM last night.

    The fact I had to go straight out after the watch was configured meant that I didn’t really give myself enough time to get even slightly comfortable with this new user interface. I knew how to check the time, get to glances, open notifications and move around applications but I hadn’t yet customized the watch face or installed the update to 1.01.

    On the up side, bringing the Apple Watch out straight away meant that it was thrown into a real life scenario right out of the box. I had to meet the rest of my family for a big event so the room that we were in was very noisy. This posed a challenge for the Apple Watch from the perspective of a Voiceover user. How do you gain the benefit of the apple watch as a discrete extension of your iPhone when you need to have the volume up so high that everyone in the room can hear it or you need to hold your arm close to your ear like someone doing a type of very weird salute? It was one of the reasons I have a lot of reservations about the Apple watch. I have always hated talking watches with a passion. Do I really want to use one?

    I’m in noisy environments a lot so I’ll explore this potential problem more as the days go on.

    The other problem I had was when we were eating. I’d move my arm and the watch would start talking. It’s very irritating but yet I see the benefit of this feature being enabled when I’m walking. Unfortunately there’s no quick way of disabling this that I know of however I must say that I haven’t bothered reading the manual yet. I probably should have read some of this by now but I generally only read the manual when all else fails.

    I got the opportunity to configure the watch a little more last night when I got back at 1AM. It seems easy enough to use.

    One complaint I have is that voiceover is far too sluggish. Now, that doesn’t mean that it’s very slow to respond, it just means that it’s slower than the phone to respond to flicks and taps. This is probably an unfair comparison to make. The phone has a much more powerful processor but if the screen reader doesn’t respond instantly to gestures the user interface feels sluggish and the experience feels very cumbersome.

    I’m being harsh. This is the first version of the Apple Watch but for the price I’ve paid for it, I demand a certain standard. The Voiceover implementation doesn’t begin to live up to that standard.

    One of my plans when buying the Apple watch was to make my own watch face. This wouldn’t be a visual face, it would use the taptic engine to provide the time in a sequence of vibrations. Unfortunately Apple put a stop to my plan by restricting the development of watch faces.

    One very positive point to the Apple Watch is it is smaller and lighter than my TISSOT TOUCH SILEN-T watch.


  • Answered: MongoDB + PyMongo – Searching within a date range.

    I wrote a short blog post last night when I felt that I couldn’t get any further independently with searching within a Mongo database for data between a date and time range.

    I was highlighting a question that I had posed on Stack overflow.

    Fortunately today when I got home from work very late I found there were two very short and very useful responses.
    Turns out that I was over complicating my approach. The date is actually represented in the Mongo shell as an ISo date but it’s actually a BSON date type.

    So by converting it to a string I was causing the problem in the first place.

    Here’s what I was trying:

    date1 = datetime.datetime.utcnow()-datetime.timedelta(minutes=15)
    date1 = date1.strftime(“%Y-%m-%dT%H:%M:%S.000Z”)
    for cursor in sensors.find({‘Date’:{“$gte”:’ISODate(“‘date1’)”‘}}):

    First line is defining the date and time minus 15 minutes.
    Second line is converting it into the right format.
    Third line is creating the cursor and adding the ISODate(“”) component.

    However, here’s what I should have been doing.

    date1 = datetime.datetime.utcnow()-datetime.timedelta(minutes=15)
    for cursor in sensors.find({‘Date’:{“$gte”: date1}}):

    That simple!

    However, on my travels I found that you can profile a Mongo database.
    Learn about profiling MOngo here
    This turns on profiling:

    db.setProfilingLevel(2)db.setProfilingLevel(0)

    This shows you the entries written to the profile table:

    db.system.profile.find()

    This is the kind of output you can expect from profiling:

    “query”, “ns” : “DatabaseName.CollectionName”, “query” : { “Date” : { “$gte” : “ISODate(\”2014-12-31T12:30:09.000Z\”)” } }, “ntoreturn” : 0, “ntoskip” : 0, “nscanned” : 0, “keyUpdates” : 0, “nreturned” : 0, “responseLength” : 20, “millis” : 1, “client” : “127.0.0.1”, “user” : “” }

    My huge thanks to the people on Stack overflow who helped out.


  • Question: MongoDB + PyMongo – Searching within a date range.

    Here we go again. I blogged about this before but now I’m trying to do it using Python. I don’t know why this is so difficult!

    I had to ask the question on Stack overflow because I’m no closer to solving it.

    When I eventually find the answer or if someone helps, I’ll of course post the solution here. It’s funny, when researching this, I kept finding the blog post I wrote before. Funny but ever so slightly irritating as well because I really don’t need to read wheat I’ve written!

    Updated on 8th January 2015 at 11PM: I have written a second blog post with the answer to this question here.


  • Turning on and off your Christmas tree lights from the Raspberry Pi.

    Thanks to a suggestion from my wife last week, I bought a Energenie socket controller for the Raspberry Pi. This little gadget allows wireless communication to a special socket that plugs into an electrical outlet. When working, this allows you to easily write code that will turn on or off that socket. The pack comes with one transmitter and two receiving sockets but actually, I bought two kits as each socket may be controlled by up to two transmitters and one transmitter may control up to four sockets.

    The reason that I bought this is quite simple. I have a new Raspberry Pi B+ in our living room with RaspBMC to allow us to use the XBMC media center software. we also put up our Christmas tree last weekend so we have the yearly problem of having to reach around quite a large christmas tree to reach the socket to turn off power to the lights every night. As they would say on twitter, it’s a perfect example of a first world problem! I hate that term but I’m getting off the point. Thanks to the RP and the Energenie I can turn on and off our Christmas tree lights remotely without going anywhere near that hard to reach socket.

    The problem of course was, on Wednesday after I spent a short amount of time getting this set up the night before, my wife posted a status to facebook saying, “It’s bad when I’m not technical enough to turn on the christmas tree lights”. Point taken. I set about creating a web interface to allow us to do this from our phones.

    I have never used the Flask Python web micro framework so this was a very new venture for me. the code you see before is my second version. The first one didn’t use views, a config file, templates or flash messages. It worked but it wasn’t as clean. I like to learn to do things properly so I scrapped it and read about how to do this properly. If you are interested in Flask, I really suggest you read this incredibly helplful tutorial by guel Grinberg.
    Here are all the steps. Hopefully I haven’t left anything out. To make this a little more conveenient for you, I’ve also included a package of all the code and graphics you will need to get this running on your own system.

    What you’ll need

    • A Raspberry Pi
    • An Energenie socket

    Getting your environment ready.

    I’m installing this on RaspBMC. This is the Raspberry Pi distribution for XBMC use primarily.
    Update the aptitude repository
    sudo apt-get update
    Install build dependencies.
    apt-get install gcc python-dev
    install the Python GPIO package to gain control of the pins on the Pi.
    cd /tmp
    wget https://pypi.python.org/packages/source/R/RPi.GPIO/RPi.GPIO-0.5.8.tar.gz

    Extract the contents of the archive.
    tar xzvf RPi.GPIO-0.5.8.tar.gz
    cd RPi.GPIO-0.5.8
    sudo python setup.py install

    Change to your home directory and get the Energenie install software from the following address.
    cd
    wget https://energenie4u.co.uk/res/software/ENER002-2PI.py

    Now install this.
    sudo python ENER002-2PI.py
    Make a directory that will hold your project
    cd
    mkdir

    ProjectName}
    cd {ProjectName}

    Get the really fantastic library created by Amy Mather’s. More information can be found here.
    wget https://github.com/MiniGirlGeek/energenie-demo/raw/master/energenie.py
    Get the Python setup tools package.
    sudo apt-get install python-setuptools
    get the Flask micro web framework.
    sudo easy_install flask
    Get the Jinja2 Python template engine.
    sudo easy_install Jinja2
    You now have all the components required to get coding.

    create your app file and directory structure

    The structure is as follows:
    {ProjectName}/
    {ProjectName}/run.py
    {ProjectName}/config.py
    {ProjectName}/energenie.py
    {ProjectName}/apple-touch-icon-120x120-precomposed.png
    {ProjectName}/apple-touch-icon-120x120.png
    {ProjectName}/favicon.png
    {ProjectName}/app/
    {ProjectName}/app/views.py
    {ProjectName}/app/__init__.py
    {ProjectName}/app/static/
    {ProjectName}/app/static/apple-touch-icon-120x120.png
    {ProjectName}/app/static/christmastree.png
    {ProjectName}/app/static/style.css
    {ProjectName}/app/templates/
    {ProjectName}/app/templates/index.html

    The code

    The following section has the code for each file along with a description of what that file is used for.

    run.py

    You will use this file to launch your application.

    from app import app
    app.run(host='0.0.0.0', debug=True) # Set to be accessible over the network with debugging enabled.

    config.py

    The config.py file does as you would expect. It is used to store config variables for the application.
    SECRET_KEY = 'YourSecretKey'
    The secret key is what ever you define. This is used by the flash messaging component.

    app/views.py

    This is the main part of your application. all of the processing happens here.

    # Import statements.
    from flask import render_template, flash
    from app import app
    from energenie import switch_on, switch_off

    # Main page. accessible from http://yourIPAddress:5000/
    @app.route('/')
    def index():
    return render_template('index.html', title='Christmas')

    # Code that is called with http://yourIPAddress:5000/on. This turns on the lights and adds a message to say the lights are on.
    @app.route('/on')
    def on():
    switch_on(1)
    flash('Christmas tree lights on.')
    return render_template('index.html', title='Christmas - Lights On')

    # Code that is called with http://yourIPAddress:5000/off. This turns off the lights and adds a message to say the lights are off.
    @app.route('/blue')
    def off():
    switch_off(1)
    flash('Christmas tree lights off.')
    return render_template('index.html', title='Christmas - Lights Off')

    app/__init__.py

    App initialization. Also includes the definition of the config file and tells flask that we are using views.py.

    from flask import Flask
    app = Flask(__name__)
    app.config.from_object('config')
    from app import views

    app/static/style.css

    You need to put static files into the static directory. The following style sheet definition defines some basic page layout options.

    body {
    margin-top:100px;
    font-size: 30px;
    }

    .red-button-link {
    text-decoration: none;
    padding: 15px 20px;
    background: red;
    color: #FFF;
    -webkit-border-radius: 6px;
    -moz-border-radius: 6px;
    border-radius: 6px;
    border: solid 2px #20538D;
    text-shadow: 0 -2px 0 rgba(0, 0, 0, 0.4);
    -webkit-box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.4), 0 2px 2px rgba(0, 0, 0, 0.2);
    -moz-box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.4), 0 2px 2px rgba(0, 0, 0, 0.2);
    box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.4), 0 2px 2px rgba(0, 0, 0, 0.2);
    -webkit-transition-duration: 0.2s;
    -moz-transition-duration: 0.2s;
    transition-duration: 0.2s;
    -webkit-user-select:none;
    -moz-user-select:none;
    -ms-user-select:none;
    user-select:none;
    }
    .red-button-link:hover {
    background: red;
    border: solid 2px #2A4E77;
    text-decoration: none;
    }
    .red-button-link:active {
    text-decoration: none;
    -webkit-box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.6);
    -moz-box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.6);
    box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.6);
    background: red;
    border: solid 2px #23E5F;
    }

    .green-button-link {
    text-decoration: none;
    padding: 15px 20px;
    background: green;
    color: #FFF;
    -webkit-border-radius: 6px;
    -moz-border-radius: 6px;
    border-radius: 6px;
    border: solid 2px #20538D;
    text-shadow: 0 -2px 0 rgba(0, 0, 0, 0.4);
    -webkit-box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.4), 0 2px 2px rgba(0, 0, 0, 0.2);
    -moz-box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.4), 0 2px 2px rgba(0, 0, 0, 0.2);
    box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.4), 0 2px 2px rgba(0, 0, 0, 0.2);
    -webkit-transition-duration: 0.2s;
    -moz-transition-duration: 0.2s;
    transition-duration: 0.2s;
    -webkit-user-select:none;
    -moz-user-select:none;
    -ms-user-select:none;
    user-select:none;
    }
    .green-button-link:hover {
    background: green;
    border: solid 2px #2A4E77;
    text-decoration: none;
    }
    .green-button-link:active {
    text-decoration: none;
    -webkit-box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.6);
    -moz-box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.6);
    box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.6);
    background: green;
    border: solid 2px #203E5F;
    }

    PNG files

    Add the graphics from the attached zip file if you like but if you would rather use your own, add them to the static folder.

    templates/index.html

    This is the template file. The UI that you will see is defined in this file.





    {{ title }}


    Picture of the Christmas Tree.
    Turn the lights on      Turn the lights off

    {% with messages = get_flashed_messages() %}
    {% if messages %}
    {% for message in messages %}
    {{ message }} {% endfor %}
    {% endif %}
    {% endwith %}




    Download the files required in an archive

    You may download the archive here

    if you would rather not copy and paste the code.