Monday, October 3, 2016

Save to PDF for Airprint / iPad Pro

I recently purchased an iPad Pro 9.7 which I love (thanks to a supporter for the gift!).

However, one use I really wanted was to be able to save/print web pages to PDF so that I could read and highlight them at my leisure. I found that Notability is the perfect tool for annotating PDFs, but I couldn't find any way to print a webpage as PDF and import it into Notability.

What I would have expected was that I could navigate to an article I wanted to save to Notability as a PDF and then choose "Print" from the browser and choose "Save as PDF" like I can with a Macbook. However, on my iPad Pro, when I go to select printers, it just says "No Airprint Printers Found".

After quite a bit of research, I found this wonderful little workaround that I just have to share:

First, navigate to a webpage / article that you want to save as PDF to Notability (or whatever your favorite PDF annotation app might be). Then choose the little "share" icon at the top of the screen.


Second, from the menu that appears, choose "Print":


Next, you'll get a print dialog that doesn't have any options you want. But there is a gesture you can use to open the document as a PDF that you can save! 


Note that if you choose "Select Printer" there is no way to save as PDF. But, over the red boxed area above, just use a two finger open pinch and it will expand into a save-able document!

After the two finger open pinch, you will see an expanded version of your print preview that you can now click the "share" icon again at the top right and see the options you really wanted in the first place. :) 


I hope this helps you! I couldn't find this information anywhere but found it hinted at in a couple of places. It is intuitive once you know how to do it and adds a tremendous amount of value to one of the primary use cases for me on my iPad Pro.

Enjoy!



Tuesday, November 4, 2014

Copy a database from SQL Server to SQL Server Express

Since Microsoft's SQL Server doesn't support direct database copy from a full SQL Server version to their Express version (why?  who knows, perhaps they felt it would drive sales?) you can't use their GUI tools to copy a database.  You also can't import into Express from an SQL Server Export.

But I did find a way to do it manually.

Step 1: in MS SQL Server Management Studio, right click on the database you want to copy and choose Tasks-->Generate Scripts...

Step 2: Work through the wizard, but if you want to copy the data, take care to click the "Advanced" button on the "Set Scripting Options" step and find "Types of data to script" and choose "Schema and Data".  Finish the wizard and if all goes well it will save an SQL script you can use to reconstitute the database on your Express instance.

Step 3: Copy that sql script somewhere that you can access from the target computer running SQL Server Express.

Step 4: Using MS SQL Management Studio on your target computer, create the database you want to copy the schema and data into.  Create a user with ownership or at least create permissions.  Now, if the database you are copying is small, you can open the file in a query window in Management Studio and run it.  If your file is large, however, that won't work.

Step 5: Once step 4 is complete, then you can use a command line tool to run the sql script.  You will probably need to open the file in something like Notepad++ and tweak the initial USE command to use the database you have created.  You may also need to tweak other things.  Then you can run:

sqlcmd -S .\SQLEXPRESS -U myuser -P SECRETPASSWORD -i My_File_Export.sql


Good luck!

ken.

Tuesday, October 28, 2014

Classic ASP excel export fails with "download was interrupted"

After updating to Internet Explorer 10 (or maybe it was 11) we suddenly started getting an error "File.xls download was interrupted." from our classic ASP data exporter tool.  Finally I found this blog post:

http://blogs.msdn.com/b/ieinternals/archive/2012/07/16/content-length-and-transfer-encoding-validation-in-ie10-download-manager-couldnt-be-downloaded-retry-cancel.aspx

Which led me to understand that there was a problem with the way we had written our export code.

This is what we had:


string strFileName = lblRiverName.Text;
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader("Content-Disposition", "attachment; filename=" + strFileName + ".xls");

Response.Write("...output here...");

Response.Flush();
Response.Close();
Response.End();
After reading the msdn blog post, I see that don't in fact want to call Response.Close(). It also sounded like we shouldn't call Response.End() either. So I commented both of those lines out and traded one problem for another. Now I was getting what seemed to be the initial html of the web page saved into the export file! Very strange. After reading more blogs and docs, I decided that perhaps Response.End() was important after all, contrary to what many folks seemed to say. That did the trick. So in the end all that needed to be done was to comment out the Response.Close():
string strFileName = lblRiverName.Text;
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader("Content-Disposition", "attachment; filename=" + strFileName + ".xls");

Response.Write("...output here...");

Response.Flush();
//Response.Close();
Response.End();
Another win for Microsoft! (tic)

Tuesday, August 5, 2014

Moving average of an average: TSQL

We track water temperature data over a wide variety of locations and want to be able to report a 7 day moving average of the average temperature for a given day.  We're using Microsoft SQL Server 2012 which has nifty OVER and PARTITION functions that help.


First I noticed that I need to calculate the average temperature and then calculate the moving average of that value.  It seemed to me what I really wanted was to be able to do the simple average aggregate using a GROUP BY date, and then pipe that resultset to an OVER PARTITION query. 


Here's how I ended up writing it:


WITH DAILY_TEMP_AVG AS
(
 SELECT
  convert(date, ReadingDateTime) as TempDate,
  avg(WaterTemperature) as AvgWaterTemp,
  LocationId
 FROM WaterTemp_VW
 GROUP BY LocationId, convert(date, ReadingDateTime)
)
SELECT
 LocationId,
 TempDate,
 AvgWaterTemp,
 avg(AvgWaterTemp) over (PARTITION by locationid
       ORDER BY TempDate
       ROWS BETWEEN 3 PRECEDING AND 3 FOLLOWING) as theaverage
 FROM DAILY_TEMP_AVG
 WHERE LocationId = 1150
 AND TempDate BETWEEN '6/1/2013' AND '7/1/2013'

Friday, October 25, 2013

Access Denied on Orchard CMS theme files on IIS 7

Today I'm working on moving an Orchard CMS site from an IIS6 server to an IIS7 server.  I copied the folder over to its new home and used "Add Application" to set the folder up.  I added the Application Pool user (use "IIS AppPool\AppPoolName" as the user in the security dialog -- see http://stackoverflow.com/questions/7334216/iis7-permissions-overview-applicationpoolidentity) and voila, everything worked!  Well -- almost everything -- none of my themes' css were showing up.

In the browser network tab I could see that all of the css files were getting a 302 error -- "Access Denied".  Strange!

I found that in the IIS7 Authentication panel, the Anonymous Authentication was set to use the default IIS "IUSR" instead of my application pool identity.  The dialog:

Changing it to "Application pool identity" did the trick!


Friday, August 2, 2013

Crashmapper - creative way to use GIS

Here's a guy who data-scraped NYC provided PDF's in order to have the ability to provide an interactive heat map of New York accidents!  Pretty cool idea and quite a determination.

http://nyc.crashmapper.com/#about

Friday, March 22, 2013

THE GOODs LIFE

In the "old days" (and I mean since Aristotle and his Ethics) kids grew up thinking and wondering about how to live a "good life".  Apparently, everyone only gets one life and since it seems rather a waste to lay down in the end and say, "Well, that was a really rotten life!" and so we might ask: what can be done to have a good one?  That was the kind of question people used to talk about.

Lately (and I mean in the last 70 years or so) it seems everyone has finally agreed on the answer.  The consensus is so complete that almost everyone has entirely stopped asking the question, "How do you live a good life?" because there is no reason to talk about a question that everyone already knows the answer to.  It just isn't all that interesting anymore since everyone agrees on what the "good life" is and how to attain it.

Just ask yourself, "What is the one thing I need to have an awesome life?"

Your answer is probably something like, "Win the lottery!"  Of course, it isn't so much the money you'd be excited about, though for some people, the image of laying on piles of $100 bills as big as a mattress would be downright thrilling.  What you want to win the lottery for is the "stuff" you could get.  It would change your life for the better, wouldn't it?  There's no question!  Of course it would!

If we all know money can buy you the good life, then there's really nothing more to discuss about what the good life actually is or how one can go about living it.  The more important thing is to get busy making some money.

If the question of "How do I live a good life?" has the answer: "Buy it!" then we would talk about things like:

  • Do you have a good job?
  • What kind of phone do you have?
  • How big is your house?
  • What kind of car do you drive?
  • What clothes do you wear?
  • What school did you go to?

"How to help your child be successful" would be all about "How to help your kid get a good job" because, naturally, a better job is more money is more of the good life.

Now, we all would say we know that "money can't buy happiness" (or love for that matter) but when we think about what we actually spend ourselves on and how we measure each other, our actions tell a different story.  Our actions always betray our true beliefs.

The reason we don't talk about the good life is because we can no longer define "good" as a culture.  The word "good" is dangerous ground.  If there is "good" then there must be "bad" and now you're making some kind of moral statement and "Who are you to say your moral system is superior to mine?" becomes the immediate postmodern reaction.  

But that that leaves us with the best we can have is a "pleasureable life" and we're sold the marketing storyboard as the means to attain it.  We just need to put a few more dollars on our credit card and we can get that priceless moment that will truly make us happy and give us the good life, in the non-moral, un-philosophical, and rather un-satisfying sense.

We've given up pursuit of the "good life" for the "goods life".  But I don't think we got a very good deal.