Fix pdf script

Fix pdf script

############################
# How to generate the PDFs #
############################
# 1. Generate Cover.pdf with latest version date
#    a. Create "ebook" folder in ~/Downloads
#    b. update date in cover.html
#    c. open in safari file:///Users/frank/Sites/ServerlessStackCom/etc/cover.html
#    d. "Export to PDF…"
#    e. Place Cover.pdf in ~/ebook folder
# 2. Ensure "ebook" folder is an option when "Export to PDF…" in Safari
# 3. In terminal, run "osascript pdf.scpt"

set theChaptersStr to "who-is-this-guide-for
what-does-this-guide-cover
how-to-get-help
what-is-serverless
what-is-aws-lambda
why-create-serverless-apps
create-an-aws-account
create-an-iam-user
what-is-iam
what-is-an-arn
configure-the-aws-cli
create-a-dynamodb-table
create-an-s3-bucket-for-file-uploads
create-a-cognito-user-pool
create-a-cognito-test-user
setup-the-serverless-framework
add-support-for-es6-es7-javascript
initialize-the-backend-repo
add-a-create-note-api
add-a-get-note-api
add-a-list-all-the-notes-api
add-an-update-note-api
add-a-delete-note-api
working-with-3rd-party-apis
setup-a-stripe-account
add-a-billing-api
load-secrets-from-env
test-the-billing-api
unit-tests-in-serverless
handle-api-gateway-cors-errors
deploy-the-apis
create-a-cognito-identity-pool
cognito-user-pool-vs-identity-pool
test-the-apis
create-a-new-reactjs-app
initialize-the-frontend-repo
add-app-favicons
setup-custom-fonts
setup-bootstrap
handle-routes-with-react-router
create-containers
adding-links-in-the-navbar
handle-404s
configure-aws-amplify
create-a-login-page
login-with-aws-cognito
add-the-session-to-the-state
load-the-state-from-the-session
clear-the-session-on-logout
redirect-on-login-and-logout
give-feedback-while-logging-in
create-a-custom-react-hook-to-handle-form-fields
create-a-signup-page
create-the-signup-form
signup-with-aws-cognito
add-the-create-note-page
call-the-create-api
upload-a-file-to-s3
list-all-the-notes
call-the-list-api
display-a-note
render-the-note-form
save-changes-to-a-note
delete-a-note
create-a-settings-page
add-stripe-keys-to-config
create-a-billing-form
connect-the-billing-form
setup-secure-pages
create-a-route-that-redirects
use-the-redirect-routes
redirect-on-login
getting-production-ready
what-is-infrastructure-as-code
configure-dynamodb-in-serverless
configure-s3-in-serverless
configure-cognito-user-pool-in-serverless
configure-cognito-identity-pool-in-serverless
deploy-your-serverless-infrastructure
automating-serverless-deployments
setting-up-your-project-on-seed
configure-secrets-in-seed
deploying-through-seed
set-custom-domains-through-seed
test-the-configured-apis
automating-react-deployments
manage-environments-in-create-react-app
create-a-build-script
setting-up-your-project-on-netlify
custom-domain-in-netlify
frontend-workflow
debugging-full-stack-serverless-apps
setup-error-reporting-in-react
report-api-errors-in-react
setup-an-error-boundary-in-react
setup-error-logging-in-serverless
logic-errors-in-lambda-functions
unexpected-errors-in-lambda-functions
errors-outside-lambda-functions
errors-in-api-gateway
wrapping-up
further-reading
translations
giving-back
changelog
staying-up-to-date
best-practices-for-building-serverless-apps
organizing-serverless-projects
cross-stack-references-in-serverless
dynamodb-as-a-serverless-service
s3-as-a-serverless-service
cognito-as-a-serverless-service
share-code-between-services
share-an-api-endpoint-between-services
deploy-a-serverless-app-with-dependencies
environments-in-serverless-apps
structure-environments-across-aws-accounts
manage-aws-accounts-using-aws-organizations
parameterize-serverless-resources-names
deploying-to-multiple-aws-accounts
deploy-the-resources-repo
deploy-the-api-services-repo
manage-environment-related-config
storing-secrets-in-serverless-apps
share-route-53-domains-across-aws-accounts
monitor-usage-for-environments
working-on-serverless-apps
invoke-lambda-functions-locally
invoke-api-gateway-endpoints-locally
creating-feature-environments
creating-pull-request-environments
promoting-to-production
rollback-changes
deploying-only-updated-services
tracing-serverless-apps-with-x-ray
wrapping-up-the-best-practices
api-gateway-and-lambda-logs
debugging-serverless-api-issues
serverless-environment-variables
stages-in-serverless-framework
backups-in-dynamodb
configure-multiple-aws-profiles
customize-the-serverless-iam-policy
mapping-cognito-identity-id-and-user-pool-id
connect-to-api-gateway-with-iam-auth
serverless-nodejs-starter
package-lambdas-with-serverless-bundle
understanding-react-hooks
code-splitting-in-create-react-app
environments-in-create-react-app
deploying-a-react-app-to-aws
create-an-s3-bucket
deploy-to-s3
create-a-cloudfront-distribution
setup-your-domain-with-cloudfront
setup-www-domain-redirect
setup-ssl
deploy-updates
manage-user-accounts-in-aws-amplify
handle-forgot-and-reset-password
allow-users-to-change-passwords
allow-users-to-change-their-email
facebook-login-with-cognito-using-aws-amplify"

set text item delimiters to "
"

set theChapters to text items of theChaptersStr

########
# Main #
########
downloadPdfs(theChapters)
mergePdfs(theChapters)

##############
# Merge PDFs #
##############
on mergePdfs(theChapters)
  set outputFile to "~/Downloads/ebook/ServerlessStack.pdf"

  set pdfFiles to "~/Downloads/ebook/Cover.pdf"
  repeat with theCurrentChapter in theChapters
    set pdfFiles to pdfFiles & " ~/Downloads/ebook/" & theCurrentChapter & ".pdf"
  end repeat

  do shell script "/System/Library/Automator/Combine\\ PDF\\ Pages.action/Contents/Resources/join.py " & "-o " & outputFile & " " & pdfFiles
end mergePdfs

#################
# Download PDFs #
#################
on downloadPdfs(theChapters)
  repeat with theCurrentChapter in theChapters
    if not(checkFileExist(theCurrentChapter)) then
      downloadPdf(theCurrentChapter)
    end if
  end repeat
end downloadPdfs

on checkFileExist(theChapterName)
  set basePath to POSIX path of (path to home folder) & "Downloads/ebook/"

  tell application "Finder"
    return exists basePath & theChapterName & ".pdf" as POSIX file
  end tell
end checkFileExist

on downloadPdf(theChapterName)
  tell application "System Events"

    tell process "Safari"
      set frontmost to true

      if ((theChapterName as string) is equal to "index") then
        set urlPath to theChapterName
      else
        set urlPath to "chapters/" & theChapterName
      end if
      open location "https://serverless-stack.com/" & urlPath & ".html"

      delay 1

      repeat until menu item "Export as PDF…" of menu "File" of menu bar 1 exists
        delay 0.2
      end repeat
      repeat
        if ((value of menu item "Export as PDF…" of menu "File" of menu bar 1 is enabled) = true)
          exit repeat
        end if
        delay 0.2
      end repeat
      click menu item "Export as PDF…" of menu "File" of menu bar 1

      tell window 1
        repeat until sheet 1 exists
        end repeat

        tell sheet 1
          keystroke theChapterName
          click pop up button "Where:"

          repeat until menu 1 of pop up button "Where:" exists
          end repeat
          click menu item "ebook" of menu 1 of pop up button "Where:"
          click button "Save"
        end tell

      end tell

      delay 2

      click menu item "Close Tab" of menu "File" of menu bar 1

    end tell

  end tell
end downloadPdf

############################
# How to generate the PDFs #
############################
# 1. Generate Cover.pdf with latest version date
#    a. Create "ebook" folder in ~/Downloads
#    b. update date in cover.html
#    c. open in safari file:///Users/frank/Sites/ServerlessStackCom/etc/cover.html
#    d. "Export to PDF…"
#    e. Place Cover.pdf in ~/ebook folder
# 2. Ensure "ebook" folder is an option when "Export to PDF…" in Safari
# 3. In terminal, run "osascript pdf.scpt"

set theChaptersStr to "who-is-this-guide-for
what-does-this-guide-cover
how-to-get-help
what-is-serverless
what-is-aws-lambda
why-create-serverless-apps
create-an-aws-account
create-an-iam-user
what-is-iam
what-is-an-arn
configure-the-aws-cli
create-a-dynamodb-table
create-an-s3-bucket-for-file-uploads
create-a-cognito-user-pool
create-a-cognito-test-user
setup-the-serverless-framework
add-support-for-es6-es7-javascript
initialize-the-backend-repo
add-a-create-note-api
add-a-get-note-api
add-a-list-all-the-notes-api
add-an-update-note-api
add-a-delete-note-api
working-with-3rd-party-apis
setup-a-stripe-account
add-a-billing-api
load-secrets-from-env
test-the-billing-api
unit-tests-in-serverless
handle-api-gateway-cors-errors
deploy-the-apis
create-a-cognito-identity-pool
cognito-user-pool-vs-identity-pool
test-the-apis
create-a-new-reactjs-app
initialize-the-frontend-repo
add-app-favicons
setup-custom-fonts
setup-bootstrap
handle-routes-with-react-router
create-containers
adding-links-in-the-navbar
handle-404s
configure-aws-amplify
create-a-login-page
login-with-aws-cognito
add-the-session-to-the-state
load-the-state-from-the-session
clear-the-session-on-logout
redirect-on-login-and-logout
give-feedback-while-logging-in
create-a-custom-react-hook-to-handle-form-fields
create-a-signup-page
create-the-signup-form
signup-with-aws-cognito
add-the-create-note-page
call-the-create-api
upload-a-file-to-s3
list-all-the-notes
call-the-list-api
display-a-note
render-the-note-form
save-changes-to-a-note
delete-a-note
create-a-settings-page
add-stripe-keys-to-config
create-a-billing-form
connect-the-billing-form
setup-secure-pages
create-a-route-that-redirects
use-the-redirect-routes
redirect-on-login
getting-production-ready
what-is-infrastructure-as-code
configure-dynamodb-in-serverless
configure-s3-in-serverless
configure-cognito-user-pool-in-serverless
configure-cognito-identity-pool-in-serverless
deploy-your-serverless-infrastructure
automating-serverless-deployments
setting-up-your-project-on-seed
configure-secrets-in-seed
deploying-through-seed
set-custom-domains-through-seed
test-the-configured-apis
automating-react-deployments
manage-environments-in-create-react-app
create-a-build-script
setting-up-your-project-on-netlify
custom-domain-in-netlify
frontend-workflow
debugging-full-stack-serverless-apps
setup-error-reporting-in-react
report-api-errors-in-react
setup-an-error-boundary-in-react
setup-error-logging-in-serverless
logic-errors-in-lambda-functions
unexpected-errors-in-lambda-functions
errors-outside-lambda-functions
errors-in-api-gateway
wrapping-up
further-reading
translations
giving-back
changelog
staying-up-to-date
best-practices-for-building-serverless-apps
organizing-serverless-projects
cross-stack-references-in-serverless
dynamodb-as-a-serverless-service
s3-as-a-serverless-service
cognito-as-a-serverless-service
share-code-between-services
share-an-api-endpoint-between-services
deploy-a-serverless-app-with-dependencies
environments-in-serverless-apps
structure-environments-across-aws-accounts
manage-aws-accounts-using-aws-organizations
parameterize-serverless-resources-names
deploying-to-multiple-aws-accounts
deploy-the-resources-repo
deploy-the-api-services-repo
manage-environment-related-config
storing-secrets-in-serverless-apps
share-route-53-domains-across-aws-accounts
monitor-usage-for-environments
working-on-serverless-apps
invoke-lambda-functions-locally
invoke-api-gateway-endpoints-locally
creating-feature-environments
creating-pull-request-environments
promoting-to-production
rollback-changes
deploying-only-updated-services
tracing-serverless-apps-with-x-ray
wrapping-up-the-best-practices
api-gateway-and-lambda-logs
debugging-serverless-api-issues
serverless-environment-variables
stages-in-serverless-framework
backups-in-dynamodb
configure-multiple-aws-profiles
customize-the-serverless-iam-policy
mapping-cognito-identity-id-and-user-pool-id
connect-to-api-gateway-with-iam-auth
serverless-nodejs-starter
package-lambdas-with-serverless-bundle
understanding-react-hooks
code-splitting-in-create-react-app
environments-in-create-react-app
deploying-a-react-app-to-aws
create-an-s3-bucket
deploy-to-s3
create-a-cloudfront-distribution
setup-your-domain-with-cloudfront
setup-www-domain-redirect
setup-ssl
deploy-updates
manage-user-accounts-in-aws-amplify
handle-forgot-and-reset-password
allow-users-to-change-passwords
allow-users-to-change-their-email
facebook-login-with-cognito-using-aws-amplify"

set text item delimiters to "
"

set theChapters to text items of theChaptersStr

########
# Main #
########
downloadPdfs(theChapters)
mergePdfs(theChapters)

##############
# Merge PDFs #
##############
on mergePdfs(theChapters)
  set outputFile to "~/Downloads/ebook/ServerlessStack.pdf"

  set pdfFiles to "~/Downloads/ebook/Cover.pdf"
  repeat with theCurrentChapter in theChapters
    set pdfFiles to pdfFiles & " ~/Downloads/ebook/" & theCurrentChapter & ".pdf"
  end repeat

  do shell script "/System/Library/Automator/Combine\\ PDF\\ Pages.action/Contents/Resources/join.py " & "-o " & outputFile & " " & pdfFiles
end mergePdfs

#################
# Download PDFs #
#################
on downloadPdfs(theChapters)
  repeat with theCurrentChapter in theChapters
    if not(checkFileExist(theCurrentChapter)) then
      downloadPdf(theCurrentChapter)
    end if
  end repeat
end downloadPdfs

on checkFileExist(theChapterName)
  set basePath to POSIX path of (path to home folder) & "Downloads/ebook/"

  tell application "Finder"
    return exists basePath & theChapterName & ".pdf" as POSIX file
  end tell
end checkFileExist

on downloadPdf(theChapterName)
  tell application "System Events"

    tell process "Safari"
      set frontmost to true

      if ((theChapterName as string) is equal to "index") then
        set urlPath to theChapterName
      else
        set urlPath to "chapters/" & theChapterName
      end if
      open location "https://serverless-stack.com/" & urlPath & ".html"

      delay 1

      repeat until menu item "Export as PDF…" of menu "File" of menu bar 1 exists
        delay 0.2
      end repeat
      repeat
        if ((value of menu item "Export as PDF…" of menu "File" of menu bar 1 is enabled) = true)
          exit repeat
        end if
        delay 0.2
      end repeat
      click menu item "Export as PDF…" of menu "File" of menu bar 1

      tell window 1
        repeat until sheet 1 exists
        end repeat

        tell sheet 1
          keystroke theChapterName
          click pop up button "Where:"

          repeat until menu 1 of pop up button "Where:" exists
          end repeat
          click menu item "ebook" of menu 1 of pop up button "Where:"
          click button "Save"
        end tell

      end tell

      click menu item "Close Tab" of menu "File" of menu bar 1

    end tell

  end tell
end downloadPdf


Windows

Windows

FasdUAS 1.101.10
k
i
I	0resize_app_window

o0app_name

o0win_position

o0win_size
Z=
=
n
1

prun
4

capp
o0app_name
m
boovtrue
O9
O8
k7
r&
J  !
 n"#
"4$

cobj
$m
#o0win_position!%
%n&'
&4(

cobj
(m
'o0win_position
n)*
)1#%

posn
*l #+
+2 #

cwin,
,r'7-.
-J'1//01
0n'+23
24(+4

cobj
4m)*
3o'(0win_size15
5n+/67
64,/8

cobj
8m-.
7o+,0win_size
.n9:
9146

ptsz
:l14;
;214

cwin
4<

prcs
<o0app_name
m==sevsalis\Macintosh HDBDSystem Events.app
 cuCoreServices0/:System:Library:CoreServices:System Events.app/$System Events.appMacintosh HD-System/Library/CoreServices/System Events.app/>?
>l?@A
@lB
BrCD
CJEEFG
FmGH
Hm(
Do0wide_center_positionAIJ
Il
K
Kr
LM
LJNNOP
OmPQ
Qm	Q
Mo0wide_center_sizeJRS
RlSTU
TlV
VIW0resize_app_windowWXY
XmZZ[[1Password 7Y\]
\o0wide_center_position]^
^o0wide_center_sizeU_`
_la
aIb0resize_app_windowbcd
cmeeffCalendardgh
go0wide_center_positionhi
io0wide_center_size`jk
jl (l
lI (m0resize_app_windowmno
nm!"ppqqFantasticalors
ro"#0wide_center_positionst
to#$0wide_center_sizekuv
ul)1w
wI)1x0resize_app_windowxyz
ym*+{{||Google Chromez}~
}o+,0wide_center_position~
o,-0wide_center_sizev
l2:
I2:0resize_app_window
m34Linear
o450wide_center_position
o560wide_center_size
l;C
I;C0resize_app_window
m<=Mail
o=>0wide_center_position
o>?0wide_center_size
lDR
IDR0resize_app_window
mEFMessages
JFJ
mFG
mGH(
JJN
mJK?
mKLQ
lS[
IS[0resize_app_window
mTU
Music
oUV0wide_center_position
oVW0wide_center_size
l\f
I\f0resize_app_window
m]`
Notes
o`a0wide_center_position
oab0wide_center_size
lgq
Igq0resize_app_window
mhkNotion
okl0wide_center_position
olm~~0wide_center_size
lr|}|
Ir|{z{0resize_app_window
msvPreview
ovwyy0wide_center_positionx
owxww0wide_center_sizexz}|
l}vu
I}tst0resize_app_window
m~Safari
orr0wide_center_positionq
opp0wide_center_sizeqsvu
lon
Imlm0resize_app_window
mSiftie
okk0wide_center_positionj
oii0wide_center_sizejlon
lhg
Ifef0resize_app_window
m
Slack
odd0wide_center_positionc
obb0wide_center_sizecehg
la`
I_^_0resize_app_window
mSpotify
o]]0wide_center_position\
o[[0wide_center_size\^a`
lZY
IXWX0resize_app_window
mTextEdit

	J

mVV
U
mTTU
S
J
mRRQ
mPPQSWZYO
lNM
ILKL0resize_app_window
mTweetbot
J
mJJ I
 mHH(I!G
!J""#$
#mFF?$%E
%mDDQEGKNMOC&'()*C&BA@?B0resize_app_window
A.aevtoappnull****@0wide_center_position?0wide_center_size'>=<+,;>0resize_app_window=:-:-98790app_name80win_position70win_size<+65460app_name50win_position40win_size,32=10/.-
3
capp
2
prun
1
prcs
0
cobj
/
cwin
.
posn
-
ptsz;>*/,e3+*/#k/l/lv*-,FOk/l/lv*-,FUUYh(,.+*/0)
,.aevtoappnull****
.k11@22I33T44_55j66u778899::;;<<==>>??@@AABBCC((+*/0'&%$#"Z!ep{ '&(%0wide_center_position$#Q"0wide_center_size!0resize_app_window ?)lvEOlvEO*m+O*m+O*m+O*m+O*m+O*m+O*lvlvm+O*m+O*am+O*am+O*am+O*am+O*am+O*am+O*am+O*aalvaalvm+O*alvlvm+)DD(*EEQascr
ޭ

FasdUAS 1.101.10
k
i
I	0resize_app_window

o0app_name

o0win_position

o0win_size
Z=
=
n
1

prun
4

capp
o0app_name
m
boovtrue
O9
O8
k7
r&
J  !
 n"#
"4$

cobj
$m
#o0win_position!%
%n&'
&4(

cobj
(m
'o0win_position
n)*
)1#%

posn
*l #+
+2 #

cwin,
,r'7-.
-J'1//01
0n'+23
24(+4

cobj
4m)*
3o'(0win_size15
5n+/67
64,/8

cobj
8m-.
7o+,0win_size
.n9:
9146

ptsz
:l14;
;214

cwin
4<

prcs
<o0app_name
m==sevsalis\Macintosh HDBDSystem Events.app
 cuCoreServices0/:System:Library:CoreServices:System Events.app/$System Events.appMacintosh HD-System/Library/CoreServices/System Events.app/>?
>l?@A
@lB
BrCD
CJEEFG
FmGH
Hm(
Do0wide_center_positionAIJ
Il
K
Kr
LM
LJNNOP
OmPQ
Qm	Q
Mo0wide_center_sizeJRS
RlSTU
TlV
VIW0resize_app_windowWXY
XmZZ[[1Password 7Y\]
\o0wide_center_position]^
^o0wide_center_sizeU_`
_la
aIb0resize_app_windowbcd
cmeeffCalendardgh
go0wide_center_positionhi
io0wide_center_size`jk
jl (l
lI (m0resize_app_windowmno
nm!"ppqqFantasticalors
ro"#0wide_center_positionst
to#$0wide_center_sizekuv
ul)1w
wI)1x0resize_app_windowxyz
ym*+{{||Google Chromez}~
}o+,0wide_center_position~
o,-0wide_center_sizev
l2:
I2:0resize_app_window
m34Linear
o450wide_center_position
o560wide_center_size
l;C
I;C0resize_app_window
m<=Mail
o=>0wide_center_position
o>?0wide_center_size
lDR
IDR0resize_app_window
mEFMessages
JFJ
mFG
mGH(
JJN
mJK?
mKLQ
lS[
IS[0resize_app_window
mTU
Music
oUV0wide_center_position
oVW0wide_center_size
l\f
I\f0resize_app_window
m]`
Notes
o`a0wide_center_position
oab0wide_center_size
lgq
Igq0resize_app_window
mhkNotion
okl0wide_center_position
olm~~0wide_center_size
lr|}|
Ir|{z{0resize_app_window
msvPreview
ovwyy0wide_center_positionx
owxww0wide_center_sizexz}|
l}vu
I}tst0resize_app_window
m~Safari
orr0wide_center_positionq
opp0wide_center_sizeqsvu
lon
Imlm0resize_app_window
mSiftie
okk0wide_center_positionj
oii0wide_center_sizejlon
lhg
Ifef0resize_app_window
m
Slack
odd0wide_center_positionc
obb0wide_center_sizecehg
la`
I_^_0resize_app_window
mSpotify
o]]0wide_center_position\
o[[0wide_center_size\^a`
lZY
IXWX0resize_app_window
mTextEdit

	J

mVV
U
mTTU
S
J
mRRQ
mPPQSWZYO
lNM
ILKL0resize_app_window
mTweetbot
J
mJJ I
 mHH(I!G
!J""#$
#mFF?$%E
%mDDQEGKNMOC&'(C&BAB0resize_app_window
A.aevtoappnull****'@?>)*=@0resize_app_window?<+<+;:9;0app_name:0win_position90win_size>)87680app_name70win_position60win_size*54=3210/
5
capp
4
prun
3
prcs
2
cobj
1
cwin
0
posn
/
ptsz=>*/,e3+*/#k/l/lv*-,FOk/l/lv*-,FUUYh(.,-,-.+
..aevtoappnull****
,k//@00I11T22_33j44u5566778899::;;<<==>>??@@AA**-,-.)('&%$Z#ep{"! )(('0wide_center_position&%Q$0wide_center_size#0resize_app_window"?! +lvEOlvEO*m+O*m+O*m+O*m+O*m+O*m+O*lvlvm+O*m+O*am+O*am+O*am+O*am+O*am+O*am+O*am+O*aalvaalvm+O*alvlvm+ascr
ޭ