Tag Archives: Windows

HeidiSQL+pLink+putty=Joy

Logo for HeidiSQL, a slick GUI front-end for mySQL

After manually changing a hundred blog posts imported with another theme from “published” to “draft”, I figured it was time to actually look at my WordPress database, since we may wish to do some global link updates,  once we get all of the media imported from another blog.  One of the best tools for this on Windows is the wonderful HeidiSQL program.

My Ubuntu server which hosts mySQL wants an SSL connection to accomplish this, so SSL must be used with HeidiSQL. This is done by using a intermediate program called plink which sits between HeidiSQL and Putty (the terminal program for accessing the Linux command line).

I found an explanation of how to use pLink with HeidiSQL.  However, if you can reach the command line using Putty and an SSL connection on port 22,  then you don’t have to do the first part of the instructions, because you already have the server’s certificate installed on your machine. It was cool to be able to verify this in the Windows registry by looking at the registry key.  And then, I was in.

heidisqlscreen

 

 

Quick Look at Windows 10

Well, I was going to say that the Windows 10 technical preview solves many of the problems that Windows 8 has, including the lack of a start button.

I installed this in a virtual machine both to take a look at 10, but especially to take advantage of updates to Windows PowerShell, which are available only with Windows 8 or later. I’m happy to say the start button is there.

The start button leads to the tiles left over from Windows 8. Maybe this can be re-configured to avoid the tiles? Didn’t Microsoft get the memo that people working on business-class desktop computers DON’T WANT TILES!  At least not the default ones, with videos, the stock market, etc.

OK so you can right-click and delete a tile.  I can imagine configuring this as a standard operation when deploying a new desktop computer to a co-worker.

If you look in the document explorer the new icons are even more cartoon-like than than before. It makes me nostalgic for the old “cartoon-like” icons of Windows XP.

  Sigh.

Odds and Sods: Resurrection, DocBoxes

After much fiddling, I seem to have been able to get my domain techfornonprofits.com to map directly to this blog, which is hosted with bloodspot.com. For a week or two it seemed it was lost in the ether, and I’m still not exactly sure what fix finally was. But, between Google/Blogger, and my domain host at Network Solutions, it looks as if the DNS records have finally got sorted out. Techfornonprofits, the blog was started when the Blogger program was relatively new, before it was purchased by Google. My first entry was in February of 2001 which seems like ancient history now.

I’m trying to sell a few DocBoxes. These are industrial-strength Mini-Itx machines originally sourced from Logic Supply. The have AOpen cases and motherboards, using Intel Celeron chips, with 1 meg of memory, a 60 or 80 Gig hard drive, and a CD or DVD-ROM. I originally had them loaded with Windows XP embedded, or Windows 7 embedded, but have reformatted them to use Xubuntu, which is Ubuntu configured to use the XCFE interface, a lightweight front end which seems to work well with the limited 1 meg of RAM on these machines. The best thing that I liked about this was a stock installation of Xubuntu automatically found the wireless network interface, and my wireless router and my printer. With XP and Windows 7 I had to go rooting around to find drivers for both of these things.

Nothing precludes running the boxes on Windows…I’ve tried it with a stock Windows 7 Professional installation as well as the embedded versions. In their original lives, they were running Windows XP Embedded. The units might have a number of applications:

  • Granny or kiddie workstation 
  • Thin client
  • Industrial controller
  • Process controller
  • Mini file or media server 
  • Lightweight web server  

The picture shows the docbox with a Logitech Orbit camera on top, which was the original configuration. I’m experimenting with how best to advertise and sell these, with a couple options, Craigslist, eBay via Global Garage, a third-party seller, and Do-It-Myself eBay.

PowerShell: Shorten Links with the Bit.ly API

Isn’t it annoying….you have actually go to a web site to shorten your URL!  Here’s how to do it in PowerShell, and you’ll get the shortened URL printed on the command line.

If you save this script in a folder, you can run it by navigating to the script, right-clicking and choosing “Run in PowerShell”.

# Generate shortened URL using the Bitly API 
# To set this up: 
# * You must create an account at Bit.ly, and obtain an $ 
# * authorization token. 
# * Verify your Bit.ly account with an eMail that Bitly 
# * sends to your account. 
# * Obtain an authorization token at: https://bitly.com/a/oauth_apps
# Paste the authorization token here…

$OAuthToken=”xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”

$Instructions = “You can paste a long URL into the command line by` right-clicking the mouse.`n”
$Instructions 
$LongURL= Read-Host “Enter or Paste in the Long URL”

# Make the call
$MyURL=Invoke-WebRequest `
-Uri https://api-ssl.bitly.com/v3/shorten `
-Body @{access_token=$OAuthToken;longURL=$LongURL} `
-Method Get

#Get the elements from the returned JSON 

$MyURLjson = $MyURL.Content | convertfrom-json 

# Print out the shortened URL 
$MyURLjson.data.url 

Pause

Powershell: Scripting FTP

Having spent some hours figuring out how to script an FTP transfer, I thought I’d describe my kludge. Maybe someone can suggest a more elegant way.  I’m trying to I’m connect to a FTP server on my Linux box to upload a file.
There are at least three approaches that can be taken:
1. Directly interact with .NET objects
2. Import a Powershell module for FTP
3. Use Powershell to manipulate a command line FTP program, such as the Putty Secure FTP program PSFTP.
I started with the second option recommended on TechNet. Looks great, and I thought that it was semi-official (being from Technet). I was unable to get a connection and I think it may be related to the fact that module apparently doesn’t support SFTP version 2.  There are a couple other quirks with the module… including the fact that the user name and password are passed to the command line as an object.  
By the way, both option 2 and 3 have the same name, PSFTP. 
Option 2 = Powershell FTP 
Option 3 = Putty Secure FTP 
So, I’m on to option 3.  This looks a little more promising.  One gotcha, however, is that calling Putty PSFTP from the Powershell ise, makes the connection but doesn’t return to show the PSFTP prompt. Here’s the command (so far) 
PS> .psftp myaccount@192.168.224.184 -p 22 -pw mypassword -v -2
This command shows that:
The psftp program is located in the current directory.
myaccount@192.168.224.184 – is the login account used for logging into the target machine
192.168.224.185 – is the IP address of the target machine
-p 22 – is port 22, used for Secure FTP
-pw is the password
-v is verbose (upon execution it returns all the steps of the login
-2 is SSL version 2.
Running this from the command line in the ISE gives the following:
  .psftp : Looking up host “192.168.214.184”
At line:1 char:1
+ .psftp myaccount@192.168.224.184 -P 22 -pw mypassword -v -2
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (Looking up host “192.168.224.184”:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError
Connecting to 192.168.224.184 port 22
We claim version: SSH-2.0-PuTTY_Release_0.63
Server version: SSH-2.0-OpenSSH_3.8.1p1
Using SSH protocol version 2
Doing Diffie-Hellman group exchange
Doing Diffie-Hellman key exchange with hash SHA-1
Host key fingerprint is:
ssh-rsa 1024 ce:ec:0d:c2:90:ab:5e:87:12:bf:ba:f9:78:77:89:fb
Initialised AES-256 SDCTR client->server encryption
Initialised HMAC-SHA1 client->server MAC algorithm
Initialised AES-256 SDCTR server->client encryption
Initialised HMAC-SHA1 server->client MAC algorithm
Using username “myaccount”.
Attempting keyboard-interactive authentication
Access granted
Opening session as main channel
Opened main channel
Started a shell/command
Connected to 192.168.214.103
Remote working directory is /ftproot
PS >
If you run this from the ise, it returns the PS command as shown.  
If you run this from a regular powershell command session, it will keep you in the PSFTP session, and you can run use the usual FTP commands….like CD, etc. 
In either case, the way Putty FTP can execute scripted commands is that the script has to live in a separate batch file that is called from the command line.  There doesn’t appear to be a  way to pass commands from Powershell to a running Putty SFTP session.  (hmm.. really?) 
Additioanal points: 
1. I might be able to configure the FTP server running on the Linux box to accept the connection from the PowerShell FTP module. I haven’t investigated that possibility but presumably it would be less secure in terms of encryption.

2. The script above has the name and password in clear text.  Not a best practice. 
3. Various versions of FTP are described on this page.  

Web Services, REST, Shopify and Brightpearl Part I

Part I.

Background:

I am currently working on a project which involves a Shopify online web store, and the Brightpearl Inventory and CRM system. Both of these cloud-based systems have an Application Programmer’s Interface, (API) which provide a programmatic way to query and manipulate the data that has been entered via the normal web interface. They use these APIs to talk to each other and make them available to programmers who want to create custom functionality or plugins for the systems. Communication with these APIs can be done using a REST compatible client written in PHP, Python, Ruby on Rails, or a host of 3rd-generation languages like C# and Visual Basic.
REST stands for Representational State Transfer. This is the most recent flavor of network programming, similar to SOAP, XML, and XML-RPC, and even good old remote procedure calls.

Use-Case:

I’m looking into a way to extract data from the Brightpearl inventory system; I want to query for each day’s purchases and extract the order number, customer name and shipping information. I want to take this information and format it as an .DBF file for use by the UPS WorldShip program. Note that in this example, I’m interested in being a client of an existing web service, and, for the moment I really just need to query the service for existing data, I don’t need to add or delete records on the server.
To start this odyssey, I’m using my Windows workstation. I’m thinking eventually if I need to have a web server for testing (to run PHP or RAILS for example), that I’ll spin that up as a virtual machine using VirtualBox on Windows with Ubuntu Server as my guest OS with a mySQL backend.
The Brighpearl documentation suggests several tools that can be used to send requests to the API. Perverse as it sounds. I found it was helpful to install no less than three add-ons for FoxFire and Chrome to send the API requests, which enabled learning the mechanics of the process a little easier.
For Chrome:
For FireFox:
Each of these three add-ons allow you to send requests to a web server. Each is slightly different. The Chrome add-on includes a parser for JSON data, which is really helpful when you are working with JSON…which is the case with Brightpearl.
Brightpearl also suggests a book from O’Reilly called RESTful Web Services by Leonard Richardson and Sam Ruby. The book was published in 2007, so although it has some useful information, it is somewhat dated. There is nothing about oAuth in it for example.
 
To get started with the Brightpearl API, you have to make sure that your user account is authorized to work with the API. This is done by accessing the “Staff” under Setup, and making sure that there is a green checkmark next to the user’s name in the API access column. 
Get an Authorization Token
Brightpearl requires that you obtain an authorization token prior to accessing any other requests.  The request for the authorization token takes the form of  a POST request  which includes your user name and password in the request payload. The URI of the payload includes two variables,  your brightpearl server location, the name of your BrightPearl account and a Content-Type of text/xml
Content-Type: text/xml
where
use=”US East”
“microdesign”, is the name of your Brightpearl account id
The user name and password are passed as JSON name pairs to the apiAccountCredentials variable:
{

    apiAccountCredentials:{
        emailAddress:”myname@mydomain.com”,
        password:”mypassword”
    }

}
Note that the double quotes enclosing the eMail address and password are also present.
So, if you look at the raw request that is sent, the full request looks like this:
POST https://ws-use.brightpearl.com/microdesign/authorise
Content-Type: text/xml
{
apiAccountCredentials:{
emailAddress:”myname@mydomain.com”,
        password:”mypassword”    }
}
If the request is successful, you’ll receive a hexedicimal number back which is your authorization token.
{“response”:” xxxxxx-xxxxx-xxxxx-xxxxx-xxxx-xxxxxxxxxx”}
Once you have the authorization token, it is used in subsequent requests as a substitute for your user name and password. The token expires after about 30 minutes of inactivity…so you’ll have to issue another authorization request and obtain a new token after that time. 
Once you have gotten the authorization token, you can start making requests. The basic request is a “resource search” which is a query of the Brightpearl data. Resource searches are issued with GET requests, and must include the API version number. The authorization code is sent as a header along with the request. 
 
As a reminder, the authorization request is a POST, and the resource query is a GET.
(More on resource searches in Brightpearl).
GET https://ws-use.brightpearl.com/2.0.0/microdesign/warehouse-service/goods-note/goods-out-search
brightpearl-auth: xxxxxx-xxxxx-xxxxx-xxxxx-xxxx-xxxxxxxxxx
This request returns a list of the current goods-out notes (Brightpearl’s nomenclature for a packing slip or pick-list).
Example with results: 
The folllowing GET request shows the current orders.
brightpearl-auth: xxxxxx-xxxxx-xxxxx-xxxxx-xxxx-xxxxxxxxxx
This returns a list of current orders, in JSON format. The format shows the structure of the data first, and then the actual records.  Note that there are only three orders!
{“response”:{“metaData”:{“resultsAvailable”:3,”resultsReturned”:3,”firstResult”:1,”lastResult”:3,”columns”:[{“name”:”orderId”,”sortable”:true,”filterable”:true,”reportDataType”:”IDSET”,”required”:false},{“name”:”orderTypeId”,”sortable”:true,”filterable”:true,”reportDataType”:”INTEGER”,”referenceData”:[“orderTypeNames”],”required”:false},{“name”:”contactId”,”sortable”:true,”filterable”:true,”reportDataType”:”INTEGER”,”required”:false},{“name”:”orderStatusId”,”sortable”:true,”filterable”:true,”reportDataType”:”INTEGER”,”referenceData”:[“orderStatusNames”],”required”:false},{“name”:”orderStockStatusId”,”sortable”:true,”filterable”:true,”reportDataType”:”INTEGER”,”referenceData”:[“orderStockStatusNames”],”required”:false},{“name”:”createdOn”,”sortable”:true,”filterable”:true,”reportDataType”:”PERIOD”,”required”:false},{“name”:”createdById”,”sortable”:true,”filterable”:true,”reportDataType”:”INTEGER”,”required”:false},{“name”:”customerRef”,”sortable”:true,”filterable”:true,”reportDataType”:”STRING”,”required”:false},{“name”:”orderPaymentStatusId”,”sortable”:true,”filterable”:true,”reportDataType”:”INTEGER”,”referenceData”:[“orderPaymentStatusNames”],”required”:false}],”sorting”:[{“filterable”:{“name”:”orderId”,”sortable”:true,”filterable”:true,”reportDataType”:”IDSET”,”required”:false},”direction”:”ASC”}]},”results”:[[1,1,207,4,3,”2014-09-18T14:15:50.000-04:00″,4,”#1014″,2],[2,1,207,1,3,”2014-09-29T13:20:52.000-04:00″,4,”#1015″,2],[3,1,207,1,3,”2014-09-29T13:25:39.000-04:00″,4,”#1016″,2]]},”reference”:{“orderTypeNames”:{“1″:”SALES_ORDER”},”orderPaymentStatusNames”:{“2″:”PARTIALLY_PAID”},”orderStatusNames”:{“1″:”Draft / Quote”,”4″:”Invoiced”},”orderStockStatusNames”:{“3″:”All fulfilled”}}}
If you use the “Advanced REST Client Application For Chrome, it will decode the above so that it is readable:
{
response:

{
metaData:

{
resultsAvailable3
resultsReturned3
firstResult1
lastResult3
columns:

[

9]

0:  

{
name: “orderId
sortabletrue
filterabletrue
reportDataType: “IDSET
requiredfalse
}
1:  

{
name: “orderTypeId
sortabletrue
filterabletrue
reportDataType: “INTEGER
referenceData:

[

1]

0:  orderTypeNames
requiredfalse
}
2:  

{
name: “contactId
sortabletrue
filterabletrue
reportDataType: “INTEGER
requiredfalse
}
3:  

{
name: “orderStatusId
sortabletrue
filterabletrue
reportDataType: “INTEGER
referenceData:

[

1]

0:  orderStatusNames
requiredfalse
}
4:  

{
name: “orderStockStatusId
sortabletrue
filterabletrue
reportDataType: “INTEGER
referenceData:

[

1]

0:  orderStockStatusNames
requiredfalse
}
5:  

{
name: “createdOn
sortabletrue
filterabletrue
reportDataType: “PERIOD
requiredfalse
}
6:  

{
name: “createdById
sortabletrue
filterabletrue
reportDataType: “INTEGER
requiredfalse
}
7:  

{
name: “customerRef
sortabletrue
filterabletrue
reportDataType: “STRING
requiredfalse
}
8:  

{
name: “orderPaymentStatusId
sortabletrue
filterabletrue
reportDataType: “INTEGER
referenceData:

[

1]

0:  orderPaymentStatusNames
requiredfalse
}
sorting:

[

1]

0:  

{
filterable:

{
name: “orderId
sortabletrue
filterabletrue
reportDataType: “IDSET
requiredfalse
}
direction: “ASC
}
}
results:

[

3]

0:  

[

9]

0:  1
1:  1
2:  207
3:  4
4:  3
5:  2014-09-18T14:15:50.000-04:00
6:  4
7:  #1014
8:  2
1:  

[

9]

0:  2
1:  1
2:  207
3:  1
4:  3
5:  2014-09-29T13:20:52.000-04:00
6:  4
7:  #1015
8:  2
2:  

[

9]

0:  3
1:  1
2:  207
3:  1
4:  3
5:  2014-09-29T13:25:39.000-04:00
6:  4
7:  #1016
8:  2
}
reference:

{
orderTypeNames:

{
1: “SALES_ORDER
}
orderPaymentStatusNames:

{
2: “PARTIALLY_PAID
}
orderStatusNames:

{
1: “Draft / Quote
4: “Invoiced
}
orderStockStatusNames:

{
3: “All fulfilled
}
}
}

A Database for Grant Research

I put together a grants database screen (click to view full size) to consolidate information for funding sources, and to track dates and interactions.

It is definitely an evolving project, but contains the basic information need to contact the funder, the deadline dates involved, the funder’s areas of interest, and the typical range of a grant award.

So far, I’ve been concentrating on foundation funding. Many foundations typically ask for a letter of interest before you put together a full proposal. So, I’ve included multiple date fields, a deadline for a letter of interest, a deadline for a full proposal, and a date when they announce their award.

Originally I thought that this database would be mostly for research, but after working with the online grants database, Grantstation, I think I will reserve this database for funders that I really expect to submit to. Some ideas for future enhancements include:

  • Links to standard “boilerplate” paragraphs that are used in an application. 
  • Links to edit the proposal or letter directly in Word. 
  • Links to the PDFs of the proposal. 
  • Reports that create a grants calendar. 
Before anyone comments that “you should really use X software” for this purpose, I just want to say that I’ve used several in the past, including DonorPerfect and Blackbaud, and evaluated many others. Right now, I’m in the process of rethinking my entire workflow automation from the ground up, and this very lightweight approach is just what I’m looking for. Plus its in FileMaker, so I can run it on my Windows machines at work, or my Macs at home.     

Rebootolator: Execute a Remote Linux Shell Script from Windows

Ok,  so, your mission, should you decide to accept it, is to restart mySQL and Apache on a remote server. This restarts a balky web site hosted by Apache, and also restarts a mySQL server which is used for a back-end for Drupal.

You want to execute this from your Windows computer.

The target computer runs CentOS 5.6 This is an (ancient) Red Hat Linux derivative, running (ancient) mySQL and Apache.

I ended up using PLink called from a Windows .CMD file to execute a bash shell script.  The shell script looks like this:

Rebootolator

#!/bin/bash -p
# Rebootolator – Reboots Apache and mySQL on a target Server
# LK Microdesign June 25, 2014
TERM=”xterm”
export TERM
clear
echo
echo ‘Rebooting Apache and mySQL on myServer’
echo ‘———————————–‘
echo ‘Restarting mySQL’
/etc/init.d/httpd restart
echo ”
echo ‘Restarting the Apache web server.’
/etc/init.d/mysqld restart
echo ‘Reboot procedure completed’


Note this script is not stored on the target server, but simply put in the same folder as the windows cmd file on my windows box.  

Now for the Windows command file: 

Reboot.CMD

:: Batch file to restart services on myServer
:: Restarts mySQL and httpd 
:: Uses the Rebootolator shell script
:: LK/Microdesign August 12, 2014  
@echo off
cls
echo. 
echo.
plink -ssh username@192.168.xxx.xxx -m rebootolator.sh -pw mypass
echo.
echo.

pause >nul | echo Press any key to exit. 

So, lets deconstruct the Windows Reboot.CMD file.
The first four lines are comment lines. Turns out, you can use two colons to preface a comment in Windows, (who knew?) instead of REM.
Line 5 turns off output to the screen.
Line 6 clears the screen.
Line 7 and 8 put in blank lines.
All the work happens on line 9, using the PLINK command. PLINK is the command line version of PUTTY, a free open source terminal program for Windows workstations. Both PLINK and PUTTY are pretty wonderful and highly recommended if you need to access Linux machines from Windows.
-ssh means “use the secure socket layer protocol to log into this machine”
username@192.168.xxx.xxx is a administrator’s account on the target machine,  probably the root account.
-m rebootolator.sh is the name of the shell script (above) that needs to run on the target machine.
-pw mypass is the password for the account used to log into the machine.

Deconstructing the Rebootolator.sh script:
#!/bin/bash -p  just means this is a BASH script
The two commands that actually restart the mySQL server, and the Apache server are: 
/etc/init.d/httpd restart
/etc/init.d/mysqld restart

The rest, (the echo commands) write out what  is happening at the command line. The Term command is my attempt to avoid a harmless error message that occurs when the script starts to execute.

Since I didn’t realize I could host the Rebootolator.sh script in my Windows folder, I originally though I’d have to log into one Linux box, and then execute the script on the target box.  Turned out the whole thing was simpler using PLINK, which is the equivalent of SSH and SSHPASS programs used to access remote machines from the Linux command line.

Alabama Eye Bank runs on FileMaker Pro.

Over at  Tech for Home Healtcare,  I’ve described how the Alabama Eye Bank uses FileMaker Pro to manage the process of receiving donated corneas thorough finding a recipient and scheduling the surgery. It is an amazing application that shows the cross-platform versatility of FileMaker, hosted on Windows servers, and deployed to Mac workstations, iPads, and iPhones.  

Refurbished Desktop Computers

Refurbs are for when you have more time than money. I’m not sure about the exact figure, but in many cases, I think I’ve ended up spending several hours per unit getting a refurbished computer back online after a hard drive failure, or just having to spend hours updating Windows and Office so that I’m confident getting the machine on the network.

We got several “really good deals” from NewEgg, for refurbished Lenovo desktop computers at $214.00. These appeared to be of “office quality”, included Windows 7 Pro, and were nicely finished. Unfortunately, we have had 2/3 of the Western Digital Blue hard drives start to fail at some point. This has created no end of extra heartache for the users and an enormous amount of work for the IT staff.

NewEgg has been fine on returns, however, providing UPS shipping labels, and RMA procedures over the web.

OK….so much for NewEgg.  We’re looking at alternatives.  (we have more time than money).

Techsoup has Dell refurbished computers that are prepared by a third party. For example:


Dell OptiPlex 755 Core 2 Duo Windows 7 Desktop 2.0 Ghz – 2.6 Ghz 
$286.00 
Min of 160Gb drive
Min of 2Gs RAM 
Windows 7 Professional 64 bit. 
Also includes: 
Office 2010
Adobe Flash,Reader 

One advantage here is that if you need licenses for Windows 7 and Office, they are included in the price. You would spend the $286.00 on those if you bought at retail, and maybe quite a lot less if you have a Microsoft Open, agreement. But, it like getting the hardware free.

The Dell Outlet looks promising with several machines in the $315-$390 range which still include Windows 7 as opposed to Windows 8, and have at least 500Gb drives, and 4 Gigs of RAM. These have more up-to-date processors than the Techsoup machines, and are certainly not as old. Most Dell Outlet machines were either not delivered, or were taken back within the warrenty period.

I’ve had solid results with Dell Outlet computers at the workstation and server level; mixed results with standard desktop machines, and a real disaster with older SX-series Optiplexes.  The best seem to be the larger ones; towers or mini-towers. Smaller machines, “mini-desktops” may have suffer from the suboptimal cooling, and the older components may have reached their design end-of-life earlier than those installed in a larger case.

One thing we have often found is that dual monitors are wonderful, and this is something that I would recommend for anyone as a matter of course. If you need an extra monitor card, these can be found from NewEgg starting at around $35.00. Best to wait until you have received the machine, because there can be variations in the slots, and the available adapter space that aren’t evident from the web page.

On the Mac side, I’ve purchased several Macbooks, iPods, iPads, from the Apple Store. These have always worked flawlessly. The Refurb store has a 21.5 inch iMac for $1099, which is the model from September 2013. The cost is only $200 or so less that of a new, similar iMac. It includes 8 gigs of RAM, and 1 terabyte hard drive, and of course the Mavrick OS, and iWork. If you’ve got more money than time, and just want to get to work, this might be the way to go.