]> BookStack Code Mirror - website/commitdiff
Merge branch 'master' of git://github.com/ChromatixAU/bookstackapp-website into Chrom...
authorDan Brown <redacted>
Sat, 14 Mar 2020 13:07:50 +0000 (13:07 +0000)
committerDan Brown <redacted>
Sat, 14 Mar 2020 13:07:50 +0000 (13:07 +0000)
168 files changed:
config.toml
content/blog/1k-stars-and-v0-19-0.md [new file with mode: 0644]
content/blog/beta-bugfix-release-v0-17-4.md
content/blog/beta-release-v0-18-0.md [new file with mode: 0644]
content/blog/beta-release-v0-20-0.md [new file with mode: 0644]
content/blog/beta-release-v0-20-1.md [new file with mode: 0644]
content/blog/beta-release-v0-21-0.md [new file with mode: 0644]
content/blog/beta-release-v0-22-0.md [new file with mode: 0644]
content/blog/beta-release-v0-23-0.md [new file with mode: 0644]
content/blog/beta-release-v0-24-0.md [new file with mode: 0644]
content/blog/beta-release-v0-25-0.md [new file with mode: 0644]
content/blog/beta-release-v0-25-1.md [new file with mode: 0644]
content/blog/beta-release-v0-25-2.md [new file with mode: 0644]
content/blog/beta-release-v0-25-5.md [new file with mode: 0644]
content/blog/beta-release-v0-26-0.md [new file with mode: 0644]
content/blog/beta-release-v0-27-0.md [new file with mode: 0644]
content/blog/beta-release-v0-28-0.md [new file with mode: 0644]
content/blog/beta-security-release-v0-18-5.md [new file with mode: 0644]
content/docs/admin/_index.md [new file with mode: 0644]
content/docs/admin/backup-restore.md
content/docs/admin/cache-session-config.md
content/docs/admin/commands.md
content/docs/admin/debugging.md
content/docs/admin/hacking-bookstack.md [new file with mode: 0644]
content/docs/admin/installation.md
content/docs/admin/language-config.md [new file with mode: 0644]
content/docs/admin/ldap-auth.md
content/docs/admin/multi-instance.md
content/docs/admin/other-config.md [new file with mode: 0644]
content/docs/admin/pdf-rendering.md
content/docs/admin/saml2-auth.md [new file with mode: 0644]
content/docs/admin/security.md
content/docs/admin/social-auth.md [deleted file]
content/docs/admin/subdirectory-setup.md [new file with mode: 0644]
content/docs/admin/third-party-auth.md [new file with mode: 0644]
content/docs/admin/updates.md
content/docs/admin/upload-config.md [new file with mode: 0644]
content/docs/admin/upload-limits.md [deleted file]
content/docs/admin/utf8mb4-upgrade.md
content/docs/admin/visual-customisation.md
content/docs/user/_index.md [new file with mode: 0644]
content/docs/user/content-overview.md
content/docs/user/markdown-editor.md
content/docs/user/organising-content.md
content/docs/user/reusing-content.md
content/docs/user/searching.md
content/docs/user/wysiwyg-editor.md
gulpfile.js
package-lock.json [new file with mode: 0644]
package.json
readme.md
static/images/2017/09/bookstack_mobile_sidebar.mp4 [new file with mode: 0644]
static/images/2017/09/comments.png [new file with mode: 0644]
static/images/2017/09/page_design_new.png [new file with mode: 0644]
static/images/2017/09/page_design_old.png [new file with mode: 0644]
static/images/2017/12/analytics-growth-2017.png [new file with mode: 0644]
static/images/2017/12/book-grid-view.png [new file with mode: 0644]
static/images/2017/12/progress-indicator.mp4 [new file with mode: 0644]
static/images/2018/02/book-grid-updates.png [new file with mode: 0644]
static/images/2018/02/drawio-support.mp4 [new file with mode: 0644]
static/images/2018/04/insert-video.mp4 [new file with mode: 0644]
static/images/2018/05/maintenance.png [new file with mode: 0644]
static/images/2018/05/sidebar-updates.png [new file with mode: 0644]
static/images/2018/07/bookstack-discord-login.png [new file with mode: 0644]
static/images/2018/07/bookstack-quick-edit.mp4 [new file with mode: 0644]
static/images/2018/09/bookshelves.mp4 [new file with mode: 0644]
static/images/2018/09/bookshelves_copy_permissions.png [new file with mode: 0644]
static/images/2018/09/revision_delete.png [new file with mode: 0644]
static/images/2018/09/wysiwyg_rtl_support.png [new file with mode: 0644]
static/images/2019/01/header_signup_link.png [new file with mode: 0644]
static/images/2019/01/header_users_link.png [new file with mode: 0644]
static/images/2019/01/minio_s3_policy.png [new file with mode: 0644]
static/images/2019/03/codeblock_lua_powershell.png [new file with mode: 0644]
static/images/2019/05/admin_page_cleanup.png [new file with mode: 0644]
static/images/2019/05/book_sort_buttons.png [new file with mode: 0644]
static/images/2019/05/breadcrumb_navigation.png [new file with mode: 0644]
static/images/2019/05/design_update_mobile.png [new file with mode: 0644]
static/images/2019/05/design_update_mobile_editing.png [new file with mode: 0644]
static/images/2019/05/image_selection_changes.png [new file with mode: 0644]
static/images/2019/05/listing_sort.png [new file with mode: 0644]
static/images/2019/05/permission_toggle_all.png [new file with mode: 0644]
static/images/2019/05/profile_page_changes.png [new file with mode: 0644]
static/images/2019/05/search_page_changes.png [new file with mode: 0644]
static/images/2019/05/shelf_create_book.png [new file with mode: 0644]
static/images/2019/05/shelves_list.png [new file with mode: 0644]
static/images/2019/05/smart_breadcrumbs.png [new file with mode: 0644]
static/images/2019/05/toggle_details.png [new file with mode: 0644]
static/images/2019/08/header_accessibility.mp4 [new file with mode: 0644]
static/images/2019/08/invite_flow_email.png [new file with mode: 0644]
static/images/2019/08/invite_flow_option.png [new file with mode: 0644]
static/images/2019/08/page_templates.mp4 [new file with mode: 0644]
static/images/2019/08/page_templates.png [new file with mode: 0644]
static/images/2020/02/api-docs.png [new file with mode: 0644]
static/images/2020/02/api-token-generation.png [new file with mode: 0644]
static/images/2020/02/api-user-tokens.png [new file with mode: 0644]
static/images/2020/02/bookstack-saml.png [new file with mode: 0644]
static/images/2020/02/bookstack-test-email.png [new file with mode: 0644]
static/images/2020/02/crowdin-overview.png [new file with mode: 0644]
static/images/2020/02/test-emails.png [new file with mode: 0644]
static/images/2020/02/text-overrides.png [new file with mode: 0644]
static/images/2020/02/theme-colors.png [new file with mode: 0644]
static/images/blog-cover-images/book-aaron-burden.jpg [new file with mode: 0644]
static/images/blog-cover-images/books-eugenio-mazzone.jpg [new file with mode: 0644]
static/images/blog-cover-images/books-maarten-van-den-heuvel.jpg [new file with mode: 0644]
static/images/blog-cover-images/books-radu-marcusu.jpg [new file with mode: 0644]
static/images/blog-cover-images/bookshelf-chuttersnap.jpg [new file with mode: 0644]
static/images/blog-cover-images/bookshelf-giammarco-boscaro.jpg [new file with mode: 0644]
static/images/blog-cover-images/bookshop-john-michael-thomson.jpg [new file with mode: 0644]
static/images/blog-cover-images/drawing-sergey-zolkin.jpg [new file with mode: 0644]
static/images/blog-cover-images/flat-books-patrick-tomasso.jpg [new file with mode: 0644]
static/images/blog-cover-images/lock-jason-blackeye.jpg [new file with mode: 0644]
static/images/blog-cover-images/locks-ruben-bagues.jpg [new file with mode: 0644]
static/images/blog-cover-images/mountains-eberhard-grossgasteiger.jpg [new file with mode: 0644]
static/images/blog-cover-images/paint-andrian-valeanu.jpg [new file with mode: 0644]
static/images/blog-cover-images/shelves-michael-d-beckwith.jpg [new file with mode: 0644]
static/images/blog-cover-images/stars-kristopher-roller.jpg [new file with mode: 0644]
static/images/blog-cover-images/winter-annie-spratt.jpg [new file with mode: 0644]
static/images/dan.jpg
themes/bookstack/layouts/_default/single.html
themes/bookstack/layouts/blog/single.html
themes/bookstack/layouts/index.html
themes/bookstack/layouts/partials/footer.html
themes/bookstack/layouts/partials/header.html
themes/bookstack/layouts/partials/icon/discord.svg [new file with mode: 0644]
themes/bookstack/layouts/partials/icon/language.svg [new file with mode: 0644]
themes/bookstack/layouts/partials/icon/lock.svg [new file with mode: 0644]
themes/bookstack/layouts/partials/icon/markdown.svg [new file with mode: 0644]
themes/bookstack/layouts/partials/list-blog-post.html
themes/bookstack/layouts/partials/mailchimp.html
themes/bookstack/layouts/partials/menu_admin_docs.html
themes/bookstack/layouts/section/docs.html
themes/bookstack/sass/_blog.scss
themes/bookstack/sass/_codemirror.scss [new file with mode: 0644]
themes/bookstack/sass/_header.scss
themes/bookstack/sass/_html.scss
themes/bookstack/sass/_text.scss
themes/bookstack/sass/styles.scss
themes/bookstack/static/images/bookstack-hero-screenshot.jpg [new file with mode: 0644]
themes/bookstack/static/images/bookstack-hero-screenshot.png [deleted file]
themes/bookstack/static/images/screenshots/book-overview.png
themes/bookstack/static/images/screenshots/book-sorting.png
themes/bookstack/static/images/screenshots/books-view.png
themes/bookstack/static/images/screenshots/image-manager.png
themes/bookstack/static/images/screenshots/page-edit.png
themes/bookstack/static/images/screenshots/page-view.png
themes/bookstack/static/images/screenshots/profile-edit-view.png [deleted file]
themes/bookstack/static/images/screenshots/profile-page.png [new file with mode: 0644]
themes/bookstack/static/images/screenshots/search.png
themes/bookstack/static/images/screenshots/settings-view.png
themes/bookstack/static/images/screenshots/thumb_book-overview.png
themes/bookstack/static/images/screenshots/thumb_book-sorting.png
themes/bookstack/static/images/screenshots/thumb_books-view.png
themes/bookstack/static/images/screenshots/thumb_image-manager.png
themes/bookstack/static/images/screenshots/thumb_page-edit.png
themes/bookstack/static/images/screenshots/thumb_page-view.png
themes/bookstack/static/images/screenshots/thumb_profile-edit-view.png [deleted file]
themes/bookstack/static/images/screenshots/thumb_profile-page.png [new file with mode: 0644]
themes/bookstack/static/images/screenshots/thumb_search.png
themes/bookstack/static/images/screenshots/thumb_settings-view.png
themes/bookstack/static/js/script.js
themes/bookstack/static/libs/codemirror/LICENSE [new file with mode: 0644]
themes/bookstack/static/libs/codemirror/codemirror.min.js [new file with mode: 0644]
themes/bookstack/static/libs/codemirror/modes.js [new file with mode: 0644]
themes/bookstack/static/libs/highlight/LICENSE [deleted file]
themes/bookstack/static/libs/highlight/README.md [deleted file]
themes/bookstack/static/libs/highlight/highlight.pack.js [deleted file]
themes/bookstack/static/libs/highlight/styles/atom-one-light.css [deleted file]
yarn.lock [deleted file]

index 21a3c5113a689d3fd5644210e5377bdba805b538..ec398298cfd47b4d0eb43eaf12459c88b35becd0 100644 (file)
@@ -2,6 +2,14 @@ languageCode = "en-gb"
 title = "BookStack"
 baseurl = "https://bookstackapp.com/"
 theme="bookstack"
+enableGitInfo=true
+
+[markup]
+  defaultMarkdownHandler = "goldmark"
+  [markup.goldmark]
+    [markup.goldmark.renderer]
+      unsafe = true
+      xHTML = true
 
 [permalinks]
   post = "/blog/:slug/"
diff --git a/content/blog/1k-stars-and-v0-19-0.md b/content/blog/1k-stars-and-v0-19-0.md
new file mode 100644 (file)
index 0000000..c137247
--- /dev/null
@@ -0,0 +1,84 @@
++++
+categories = ["Releases", "News"]
+tags = ["Releases", "News"]
+title = "1000 Stars and Beta Release v0.19"
+date = 2017-12-10T17:00:00Z
+author = "Dan Brown"
+image = "/images/blog-cover-images/stars-kristopher-roller.jpg"
+description = "Another BookStack milestone with 1000 GitHub stars. In addition we have v0.19 bringing Book cover images along with other nice additions"
+draft = false
++++
+
+Before 2017 is up we have managed to hit [1000 stars](https://github.com/BookStackApp/BookStack/stargazers) on GitHub! This reflects the continued growing momentum that the project has experienced over time considering the 500 star milestone was only passed in March of this year.
+
+Throughout 2017 there's been a growing amount of community contributions to the project in various forms which includes making pull requests, creating issues and supporting on existing issues. A massive thanks to everyone that's made such a contribution since it's great to see people that care about a project like this. A special thanks in particular to [@Abijeet](https://github.com/Abijeet) and [@lommes](https://github.com/lommes) who have both been very active in responding to issues and making contributions.
+
+As always, I like to keep project information as open as possible. Here's a graph showing website activity since Jan 2016, When the website was first set up:
+
+![Google Analytics 2017 Website Growth](/images/2017/12/analytics-growth-2017.png)
+
+Through the second half of this year we've seen a good degree of growth which I hope to see continue through 2018. A dynamic public dashboard of these stats can [be found here](https://datastudio.google.com/reporting/0B_agEsqREhl6T1BiMV9PTlhzblU) if you want to have a deeper look.
+
+## Beta Release v0.19 
+
+As an early winter holiday gift we bring you BookStack v0.19. The main features of this release have primarily been from community pull requests which is fantastic. Here are the handy links for updating: 
+
+* [Update instructions](https://www.bookstackapp.com/docs/admin/updates)
+* [GitHub release page](https://github.com/BookStackApp/BookStack/releases/tag/v0.19.0)
+
+If you haven't updated since v0.18.0 it's worth reading the bugfix notes from [the last post here](/blog/beta-security-release-v0-18-5/) since there are some important changes to take notice of.
+
+For those that did update to v0.18.5 please note that I accidentially did not merge changes for that release so any updates that were meant to be in v0.18.5 won't actually take effect until you update to v0.19.0. Apologies for that. 
+
+#### Requirements Change
+
+For this release we've updated the framework that BookStack is built upon, Laravel, to version 5.5 which requires PHP 7. Therefore BookStack now requires PHP 7.0 or greater. If you are on PHP 5 then you won't be able to run or install the new version of BookStack and will need to upgrade to a newer PHP version before you update BookStack. PHP 7 brings great speed enhancements over PHP 5 as well as many new features to improve development and maintenance.
+
+#### Book Cover Art and Grid Display
+
+It's now possible to assign cover art for your books. To display this new art a grid view has been added to the Books view:
+
+![Books Grid View](/images/2017/12/book-grid-view.png)
+
+This provides a much more visual experience that can allow you to quickly identify different Books. A setting is available in your user preferences to change view type. Depending on feedback we could look to roll this out to other entity types (Chapters/Pages) if found to be useful. 
+
+A big thanks to [@bharadwajag](https://github.com/bharadwajag), [@nileshdeepak](https://github.com/nileshdeepak) and [@AbijeetP](https://github.com/AbijeetP) for their combined work to achieve this great result.
+
+#### Comment Disabling
+
+Comments were added to v0.18 which is great where an extra, BookStack specific, layer of communication is required but there are many instances where communication would be done outside of the system or even instances where it's only used by a single person.
+To support those scenarios an option to disable comments has been added to the settings view. This will completely hide all parts of the commenting system. Thanks once again to [@AbijeetP](https://github.com/AbijeetP) for implementing this feature.
+
+#### Okta Authentication
+
+For companies that use Okta to manage authentication, You can now set up Okta sign-in on BookStack. Details on setting this up can be found at the [bottom of this page](/docs/admin/third-party-auth/#okta). Thanks you [@lommes](https://github.com/lommes) for adding this functionality.
+
+#### Page Navigation Indicator
+
+Just want to highlight a new subtle UI feature added in this release. When scrolling within a page the page navigation menu will highlight any headers within view to make it easier to track your position when reading a page:
+
+<video src="/images/2017/12/progress-indicator.mp4" controls></video>
+
+Thanks you once more to [@AbijeetP](https://github.com/AbijeetP) for implementing this feature.
+
+#### Full List of Changes
+
+* Added book cover art and grid display view. Thanks to [@bharadwajag, @nileshdeepak and @AbijeetP](https://github.com/BookStackApp/BookStack/pull/494). ([#181](https://github.com/BookStackApp/BookStack/issues/181), [#494](https://github.com/BookStackApp/BookStack/pull/494))
+* Added ability to disable comments. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/593). ([#593](https://github.com/BookStackApp/BookStack/pull/593), [#541](https://github.com/BookStackApp/BookStack/issues/541)) 
+* Added Okta authentication option. Thanks to [@lommes](https://github.com/BookStackApp/BookStack/pull/598). ([#598](https://github.com/BookStackApp/BookStack/pull/598))
+* Added page navigation highlighting on page scroll. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/580). ([#580](https://github.com/BookStackApp/BookStack/pull/580), [#466](https://github.com/BookStackApp/BookStack/issues/466))
+* Updated Laravel framework to 5.5. ([#590](https://github.com/BookStackApp/BookStack/issues/590))
+* Added `CTRL+Enter` shortcut to "Save and continue" when editing a page. ([#604](https://github.com/BookStackApp/BookStack/issues/604))
+* Fixed WYSIWYG rendering issues when in fullscreen mode. ([#605](https://github.com/BookStackApp/BookStack/issues/605))
+* Updated custom head content to also function within the WYSIWYG editor. ([#562](https://github.com/BookStackApp/BookStack/issues/562))
+* Set up a simple tool to assist with translation management. ([#373](https://github.com/BookStackApp/BookStack/issues/373))
+* Added way to specify trusted proxies. ([#146](https://github.com/BookStackApp/BookStack/issues/146))
+
+
+### Next Steps
+
+To be honest, I've not yet chosen the next set of features for the next release. I'm planning to revamp the icon system soon to be fully svg based which will hopefully lead to faster loading, sharper rendering and better icons. This idea is part of providing wider customisation enhancement. I'd also like to continue improving upon some of the design changes from the last release.
+
+----
+
+<span style="font-size: 0.8em;opacity:0.8;">Header Image Credits: &nbsp; <a style="background-color:black;color:white;text-decoration:none;padding:4px 6px;font-family:-apple-system, BlinkMacSystemFont, &quot;San Francisco&quot;, &quot;Helvetica Neue&quot;, Helvetica, Ubuntu, Roboto, Noto, &quot;Segoe UI&quot;, Arial, sans-serif;font-size:12px;font-weight:bold;line-height:1.2;display:inline-block;border-radius:3px;" href="https://unsplash.com/@krisroller?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge" target="_blank" rel="noopener noreferrer" title="Download free do whatever you want high-resolution photos from Kristopher Roller"><span style="display:inline-block;padding:2px 3px;"><svg xmlns="http://www.w3.org/2000/svg" style="height:12px;width:auto;position:relative;vertical-align:middle;top:-1px;fill:white;" viewBox="0 0 32 32"><title>unsplash-logo</title><path d="M20.8 18.1c0 2.7-2.2 4.8-4.8 4.8s-4.8-2.1-4.8-4.8c0-2.7 2.2-4.8 4.8-4.8 2.7.1 4.8 2.2 4.8 4.8zm11.2-7.4v14.9c0 2.3-1.9 4.3-4.3 4.3h-23.4c-2.4 0-4.3-1.9-4.3-4.3v-15c0-2.3 1.9-4.3 4.3-4.3h3.7l.8-2.3c.4-1.1 1.7-2 2.9-2h8.6c1.2 0 2.5.9 2.9 2l.8 2.4h3.7c2.4 0 4.3 1.9 4.3 4.3zm-8.6 7.5c0-4.1-3.3-7.5-7.5-7.5-4.1 0-7.5 3.4-7.5 7.5s3.3 7.5 7.5 7.5c4.2-.1 7.5-3.4 7.5-7.5z"></path></svg></span><span style="display:inline-block;padding:2px 3px;">Kristopher Roller</span></a></span>
index 4447200329c7bc4de1b82260b1da59f325141456..473490379731cf870c294cb058b052d8795b2ca0 100644 (file)
@@ -20,7 +20,7 @@ Here are some details on the changes made over the last month:
 As part of v0.17 a database change was included to add support for Emoji.
 To achieve this the encoding used in the database was changed upon upgrade.
 This upgrade caused issues for many users so has therefore now been removed. This can instead
-be done manually by [following the documentation here](/admin/ut8mb4-support/).
+be done manually by [following the documentation here](/docs/admin/ut8mb4-support/).
 
 ### Editor Shortcut Updates
 
diff --git a/content/blog/beta-release-v0-18-0.md b/content/blog/beta-release-v0-18-0.md
new file mode 100644 (file)
index 0000000..5f44fdb
--- /dev/null
@@ -0,0 +1,112 @@
++++
+categories = ["Releases"]
+tags = ["Releases"]
+title = "Beta Release v0.18.0"
+date = 2017-09-10T18:00:00Z
+author = "Dan Brown"
+image = "/images/blog-cover-images/bookshelf-chuttersnap.jpg"
+description = "BookStack v0.18 released with an updated design, more customization options and a commenting system"
+slug = "beta-release-v0-18-0"
+draft = false
++++
+
+We're now over two years into the life of BookStack and to celebrate we have a new release, v0.18. This release unexpectedly grew in scope during
+development but it brings a good bunch of highly-requested features along with the biggest design change since October 2015.
+
+* [Update instructions](https://www.bookstackapp.com/docs/admin/updates)
+* [GitHub release page](https://github.com/BookStackApp/BookStack/releases/tag/v0.18.0)
+
+
+
+### Design Changes
+
+As features have built up the existing design was becoming cluttered. There was little visual separation between different sections and
+a lack of consistency in how pages were laid out. In this release the design has evolved to tackle these issues. Here's a before and after of the page view:
+
+**Before**
+
+![Page Design Old](/images/2017/09/page_design_old.png)
+
+**After**
+
+![Page Design New](/images/2017/09/page_design_new.png)
+
+As you can see, The new design visually separates the page content and the page meta data. The sidebar has been moved to the left to prevent scrolling issues
+and the content within is now clearly labelled and spaced. When scrolling on a page, the sidebar will now not jump around as much such preventing visual distraction.
+
+The header bar height has been reduced to put more focus on the content. The action overflow menu is now labelled to be clearer.
+The old default font has been replaced with system fonts which provide a more native feel and also help to reduce load times. 
+
+On mobile, The sidebar will now remain to the side but be hidden and expandable rather than just jumping below the page content:
+
+<video src="/images/2017/09/bookstack_mobile_sidebar.mp4" controls/>
+
+Overall I'm hoping the design changes will be welcome but if they cause any issues please let me know by [creating an issue on GitHub](https://github.com/BookStackApp/BookStack/issues).
+
+### Commenting System
+
+Feedback is crucial to writing good documentation. Since the start of the year [@Abijeet](https://github.com/BookStackApp/BookStack/pull/261) has been doing some great work on adding comments to BookStack.
+You can now find comments at the bottom of pages. Comments are displayed chronologically and are given an ID which can be used as a reference and allows comments to be directly linked to.
+
+Depending on permissions you can add, delete, edit and even reply to comments. Markdown is supported within comments to allow more advanced formatting.
+
+![BookStack Comment System](/images/2017/09/comments.png)
+
+Upon update ensure you update role permissions to allow users to work with comments.
+
+### Custom Homepage
+
+The option to change the homepage has become a highly requested feature so, with the design changes taking place, it seemed like a good idea to add in this feature.
+In the settings area you can now select any page to show as the homepage. Once set, The existing lists on the homepage will move into a sidebar.
+This homepage will show to all users regardless of permissions set.
+
+<div style='position:relative;padding-bottom:73%'><iframe src='https://gfycat.com/ifr/WetOblongCamel?autoplay=0' frameborder='0' scrolling='no' width='100%' height='100%' style='position:absolute;top:0;left:0;' allowfullscreen></iframe></div>
+
+&nbsp;
+
+In addition, The default homepage has been cleaned up a little by extending the 'Recently Updated Pages' list and removing the 'Recently Created' list as they 
+usually had a lot of overlap. 
+
+### Language Updates 🇮🇹 🇩🇪 🇯🇵
+
+With this release we have more content translated thanks, yet again, to awesome people on GitHub.
+[Thanks to @cipi1965](https://github.com/BookStackApp/BookStack/pull/501) Italian is now a language option.
+Improvements & updates to German and Japanese translations have been made by [@timoschwarzer](https://github.com/BookStackApp/BookStack/pull/474) and [@msaus](https://github.com/BookStackApp/BookStack/pull/483).
+
+### Full List of Changes
+
+
+* Added commenting system (Thanks to [@Abijeet, #261](https://github.com/BookStackApp/BookStack/pull/261), [#47](https://github.com/BookStackApp/BookStack/issues/47)).
+* Large project-wide design revamp ([#480](https://github.com/BookStackApp/BookStack/issues/480)).
+* Switch all fonts to use system fonts ([#423](https://github.com/BookStackApp/BookStack/issues/423)).
+* Added Italian Translations ([#501, Thanks to @cipi1965](https://github.com/BookStackApp/BookStack/pull/501)).
+* Updated German Translations ([#474, Thanks to @timoschwarzer](https://github.com/BookStackApp/BookStack/pull/474)).
+* Updated Japanese Translations ([#483, Thanks to @msaus](https://github.com/BookStackApp/BookStack/pull/483)).
+* Improved customization options:
+  * Added setting for a custom homepage to be set ([#372](https://github.com/BookStackApp/BookStack/issues/372), [#126](https://github.com/BookStackApp/BookStack/issues/126)).
+  * Made it possible to override codemirror (Code block) theme ([#455](https://github.com/BookStackApp/BookStack/issues/455)).
+  * Added docs instructions for overriding BookStack fonts ([#423](https://github.com/BookStackApp/BookStack/issues/423)).
+* Converted most of the angular code to Vue.JS or vanilla JS.
+* Updated some views to support better cross-language pluralization ([#417](https://github.com/BookStackApp/BookStack/issues/417)).
+* Fixed design bug with long attachment names ([#460](https://github.com/BookStackApp/BookStack/issues/460)).
+* Fixed issue with markdown callout shortcut producing bad HTML ([#470](https://github.com/BookStackApp/BookStack/issues/470)).
+* Fixed broken quick-save shortcut in WYSIWYG editor ([#467](https://github.com/BookStackApp/BookStack/issues/467)).
+
+### Next Steps
+
+As part of v0.18 a fair bit of time was dedicated to migrating a lot of the AngularJS code.
+For v0.19 the aim is to remove angular completely which will achieve a large reduction in the production JS file size and keep the codebase consistent.
+
+Since comments were added I think notifications will start to become more requested since it's difficult to know when someone has replied to your comment.
+Therefore this may be further developed or at least planned out during the next release cycle. It's a challenging feature to implement though
+as care will need to be take in regards to performance and installation complexity.
+
+[Some great work](https://github.com/BookStackApp/BookStack/pull/494) has been going on to add book cover art and a grid display option so I'll be looking to merge
+that in for the next release.
+
+Laravel, the PHP framework BookStack is built on, has released version 5.5 recently so we'll look to upgrade to this soon. This will mean a PHP version requirement change to PHP7.
+It's advised to move to PHP7 now if you have not already, even just for the performance benefits.
+
+----
+
+<span style="font-size: 0.8em;opacity:0.8;">Header Image Credits: &nbsp; <a style="background-color:black;color:white;text-decoration:none;padding:4px 6px;font-family:-apple-system, BlinkMacSystemFont, &quot;San Francisco&quot;, &quot;Helvetica Neue&quot;, Helvetica, Ubuntu, Roboto, Noto, &quot;Segoe UI&quot;, Arial, sans-serif;font-size:12px;font-weight:bold;line-height:1.2;display:inline-block;border-radius:3px;" href="https://unsplash.com/@chuttersnap?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge" target="_blank" rel="noopener noreferrer"><span style="display:inline-block;padding:2px 3px;"><svg xmlns="http://www.w3.org/2000/svg" style="height:12px;width:auto;position:relative;vertical-align:middle;top:-1px;fill:white;" viewBox="0 0 32 32"><title></title><path d="M20.8 18.1c0 2.7-2.2 4.8-4.8 4.8s-4.8-2.1-4.8-4.8c0-2.7 2.2-4.8 4.8-4.8 2.7.1 4.8 2.2 4.8 4.8zm11.2-7.4v14.9c0 2.3-1.9 4.3-4.3 4.3h-23.4c-2.4 0-4.3-1.9-4.3-4.3v-15c0-2.3 1.9-4.3 4.3-4.3h3.7l.8-2.3c.4-1.1 1.7-2 2.9-2h8.6c1.2 0 2.5.9 2.9 2l.8 2.4h3.7c2.4 0 4.3 1.9 4.3 4.3zm-8.6 7.5c0-4.1-3.3-7.5-7.5-7.5-4.1 0-7.5 3.4-7.5 7.5s3.3 7.5 7.5 7.5c4.2-.1 7.5-3.4 7.5-7.5z"></path></svg></span><span style="display:inline-block;padding:2px 3px;">chuttersnap</span></a></span>
diff --git a/content/blog/beta-release-v0-20-0.md b/content/blog/beta-release-v0-20-0.md
new file mode 100644 (file)
index 0000000..6d9e35f
--- /dev/null
@@ -0,0 +1,100 @@
++++
+categories = ["Releases"]
+tags = ["Releases"]
+title = "Beta Release v0.20.0"
+date = 2018-02-11T18:00:00Z
+author = "Dan Brown"
+image = "/images/blog-cover-images/drawing-sergey-zolkin.jpg"
+description = "The first release of 2018 is a big one with Draw.IO support, authenticated Images, new languages and new auth options"
+slug = "beta-release-v0-20-0"
+draft = false
++++
+
+Here we have the first release of 2018 and it's a chunky one! Not only do we have draw.io integration but thanks to a range of contributors we have extra languages and authentication options. Additionally, In this release we are testing options for theming as well as authenticated image access.
+
+* [Update instructions](https://www.bookstackapp.com/docs/admin/updates)
+* [GitHub release page](https://github.com/BookStackApp/BookStack/releases/tag/v0.20.0)
+
+### Draw.io Integration
+
+Often when creating documentation there are some things that are much better explained as drawings rather than text hence why drawing support had been requested a few times for BookStack. Creating our own solution is a bit too much work for a project like BookStack to take on but in this release I'm pleased to introduce Draw.io integration as a solution for creating drawings.
+
+Previously you could create a drawing on draw.io then export it as an image to then upload into BookStack but this user flow is clunky and slow. Now there's a drawing button in both the WYSIWYG and Markdown editors that will load in draw.io and create drawings without leaving BookStack.
+
+<video src="/images/2018/02/drawio-support.mp4" controls></video>
+
+When you save the drawing it will be uploaded to BookStack. You can then continue editing the image by double-clicking the drawing from the page editor.
+
+There are a couple of things to note with the current implementation. Updating a drawing will overwrite the file in BookStack instantly. Even if you don't save the page the drawing will be updated. In addition, There is no current way to delete drawings. In the near future we plan to implement some level of 'drawing manager' which will allow drawing versioning and deletion control. If you expect a high level of drawings to be created and you're low on disk space you may want to disable draw.io support for now. 
+
+The Draw.io integration can be disabled from your `.env` file by setting `DRAWIO=false` or `DISABLE_EXTERNAL_SERVICES=true`.
+
+### Chinese and Swedish Language Support
+
+Our language support grows with v0.20 adding support for both simplified Chinese and Swedish thanks to [@yuezhihan](https://github.com/BookStackApp/BookStack/pull/696) and [@marcusforsberg](https://github.com/BookStackApp/BookStack/pull/679).
+
+For anyone wishing to help with adding or updating translations, Details of doing so can be found in the [project readme](https://github.com/BookStackApp/BookStack#translations). The readme details the use of a helper script to speed up the process of finding missing or unused translations.
+
+### GitLab and Twitch Authentication Options
+
+Thanks to [@jozefbalun](https://github.com/BookStackApp/BookStack/pull/691) and [@moutonnoireu](https://github.com/BookStackApp/BookStack/pull/684) we now respectively have GitLab and Twitch authentication options. The GitLab option supports both GitLab.com and self-hosted options.
+
+[Details on authentication options can be found here](/docs/admin/third-party-auth/)
+
+### Book Grid Enhancements
+
+The last BookStack release included the new grid view for the books page. Since then, Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/635), Switching between the grid and list view has been made more intuitive and now only requires clicking the appropriate link situated on the left of the header bar. The old user-profile option for this has been removed accordingly. In addition, The book grid will now properly align to provide a cleaner grid format:
+
+![Book Grid Updates](/images/2018/02/book-grid-updates.png)
+
+### Authenticated Image Access
+
+Previously images could not be secured behind authentication like page content itself due to performance concerns. With this release authenticated image access is being trialled. This prevents image access to anyone not logged in if your instance is not publicly accessible. On larger instances and on pages with many images there could still be performance concerns so use this feature with caution.
+
+[Details on enabling this option can be found here](/docs/admin/security#image-authentication).  
+
+### Groundwork for Theming
+
+Some initial work for support custom views and themes has been added. BookStack is built on Laravel and therefore uses [blade template files](https://laravel.com/docs/5.5/blade) for rendering page content. This new system allows you to selectively override any blade view file that BookStack uses without altering any original BookStack code.
+
+***Note that this feature is very early-on in it's implementation and using it in a production environment is not advised at this time.***
+
+After updating, You'll find a `themes` folder in the top-folder-level of your BookStack install. Within this folder you can create a folder, 'my-custom-theme' for example, to house your view overrides. Within your `.env` file you can then set `APP_THEME=my-custom-theme`. When loading a view BookStack will then look in your specified theme folder before then defaulting to the stock BookStack views. The view will need to match the name and folder structure as those within the `resources/views/` directory.
+
+In a future release I plan to go over the views and considerably clean them up to make things more consistent, modular and easier to override. This cleanup will cause breakages to existing themes so create themes with caution for now.
+
+### Full List of Changes
+
+* Added Draw.io integration. ([#632](https://github.com/BookStackApp/BookStack/pull/632), [#66](https://github.com/BookStackApp/BookStack/issues/66), [#619](https://github.com/BookStackApp/BookStack/issues/619))
+* Added language - Swedish. Thanks to [@marcusforsberg](https://github.com/BookStackApp/BookStack/pull/679). ([#679](https://github.com/BookStackApp/BookStack/pull/679))
+* Added language - Simplified Chinese(zh-CN). Thanks to [@yuezhihan](https://github.com/BookStackApp/BookStack/pull/696). ([#696](https://github.com/BookStackApp/BookStack/pull/696))
+* Added GitLab authentication. Thanks to [@jozefbalun](https://github.com/BookStackApp/BookStack/pull/691). ([#691](https://github.com/BookStackApp/BookStack/pull/691), [#476](https://github.com/BookStackApp/BookStack/issues/476), [#349](https://github.com/BookStackApp/BookStack/issues/349))
+* Added Twitch authentication. Thanks to [@moutonnoireu](https://github.com/BookStackApp/BookStack/pull/684). ([#684](https://github.com/BookStackApp/BookStack/pull/684), [#680](https://github.com/BookStackApp/BookStack/issues/680))
+* Added ability to secure images behind authentication. ([#665](https://github.com/BookStackApp/BookStack/pull/665))
+* Added button to allow quick switching between grid and list book views. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/635). ([#635](https://github.com/BookStackApp/BookStack/pull/635), [#613](https://github.com/BookStackApp/BookStack/issues/613))
+* Added utility command to delete all users from the system. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/621). ([#621](https://github.com/BookStackApp/BookStack/pull/621), [#579](https://github.com/BookStackApp/BookStack/issues/579))
+* Added utility command to add an admin user. ([#609](https://github.com/BookStackApp/BookStack/issues/609))
+* Added '.env' option to set default books view. ([#675](https://github.com/BookStackApp/BookStack/issues/675))
+* Updated book sort operation to check permission of all involved entities before sorting. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/651). ([#651](https://github.com/BookStackApp/BookStack/pull/651))
+* Updated books 'Grid' view so it now uses CSS grid so books align in height. ([#701](https://github.com/BookStackApp/BookStack/issues/701))
+* Standardised PHP code to follow PSR-2. ([#649](https://github.com/BookStackApp/BookStack/issues/649))
+* Corrected the example configuration for okta auth. Thanks to [@lommes](https://github.com/BookStackApp/BookStack/pull/692). ([#692](https://github.com/BookStackApp/BookStack/pull/692))
+* Fixed long code block lines going off the page on PDF exports. ([#676](https://github.com/BookStackApp/BookStack/issues/676))
+* Fixed long text pushing out the view width on mobile devices when viewing books and chapters. ([#669](https://github.com/BookStackApp/BookStack/issues/669))
+* Fixed bug causing markdown editor preview to collapse. ([#658](https://github.com/BookStackApp/BookStack/issues/658))
+* Fixed bug causing page to refresh when clicking search in the image manager. ([#697](https://github.com/BookStackApp/BookStack/issues/697))
+* Fixed styling issue preventing code editor save button from showing on smaller-screen devices. ([#650](https://github.com/BookStackApp/BookStack/issues/650))
+* Fixed error thrown when user accesses an attachment without permission. ([#681](https://github.com/BookStackApp/BookStack/issues/681))
+* Fixed font-size difference between list types in comments. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/644). ([#644](https://github.com/BookStackApp/BookStack/pull/644), [#643](https://github.com/BookStackApp/BookStack/issues/643))
+* Fixed content includes to not break code structure if targeting a table or list. ([#640](https://github.com/BookStackApp/BookStack/issues/640))
+
+
+### Next Steps
+
+As mentioned in the article above a 'Drawing Manager', similar to the 'Image Manager', would be a good addition. Maybe also some kind of 'Image/Drawing Cleanup' functionality would be good at this stage to find unused drawings and images on larger instances.
+
+For other features please ensure you add a 'Thumbs-up' reaction on the parent post of any GitHub issue for desired features as it's a really helpful way to identify the most requested features.
+
+----
+
+<span style="font-size: 0.8em;opacity:0.8;">Header Image Credits: &nbsp; <a style="background-color:black;color:white;text-decoration:none;padding:4px 6px;font-family:-apple-system, BlinkMacSystemFont, &quot;San Francisco&quot;, &quot;Helvetica Neue&quot;, Helvetica, Ubuntu, Roboto, Noto, &quot;Segoe UI&quot;, Arial, sans-serif;font-size:12px;font-weight:bold;line-height:1.2;display:inline-block;border-radius:3px;" href="https://unsplash.com/@szolkin?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge" target="_blank" rel="noopener noreferrer" title="Download free do whatever you want high-resolution photos from Sergey Zolkin"><span style="display:inline-block;padding:2px 3px;"><svg xmlns="http://www.w3.org/2000/svg" style="height:12px;width:auto;position:relative;vertical-align:middle;top:-1px;fill:white;" viewBox="0 0 32 32"><title>unsplash-logo</title><path d="M20.8 18.1c0 2.7-2.2 4.8-4.8 4.8s-4.8-2.1-4.8-4.8c0-2.7 2.2-4.8 4.8-4.8 2.7.1 4.8 2.2 4.8 4.8zm11.2-7.4v14.9c0 2.3-1.9 4.3-4.3 4.3h-23.4c-2.4 0-4.3-1.9-4.3-4.3v-15c0-2.3 1.9-4.3 4.3-4.3h3.7l.8-2.3c.4-1.1 1.7-2 2.9-2h8.6c1.2 0 2.5.9 2.9 2l.8 2.4h3.7c2.4 0 4.3 1.9 4.3 4.3zm-8.6 7.5c0-4.1-3.3-7.5-7.5-7.5-4.1 0-7.5 3.4-7.5 7.5s3.3 7.5 7.5 7.5c4.2-.1 7.5-3.4 7.5-7.5z"></path></svg></span><span style="display:inline-block;padding:2px 3px;">Sergey Zolkin</span></a></span>
diff --git a/content/blog/beta-release-v0-20-1.md b/content/blog/beta-release-v0-20-1.md
new file mode 100644 (file)
index 0000000..15dae6b
--- /dev/null
@@ -0,0 +1,60 @@
++++
+categories = ["Releases"]
+tags = ["Releases"]
+title = "Beta Release v0.20.1"
+date = 2018-03-25T16:00:00Z
+author = "Dan Brown"
+image = "/images/blog-cover-images/books-maarten-van-den-heuvel.jpg"
+description = "Release v0.20.1 is here with a great number of fixes, updates and improvements as well as a good deal of change behind the scenes"
+slug = "beta-release-v0-20-1"
+draft = false
++++
+
+Today we release BookStack v0.20.1. Although this update does not include any major new features it bundles up some big behind-the-scenes changes along with a great deal of fixes and updates. 
+
+* [Update instructions](https://www.bookstackapp.com/docs/admin/updates)
+* [GitHub release page](https://github.com/BookStackApp/BookStack/releases/tag/v0.20.1)
+
+### Image Improvements
+
+Previously you could upload GIF images but, due to resizing, they would not remain in their animated state once in the page. [Abijeet](https://github.com/BookStackApp/BookStack/pull/755) has now fixed this so you can go ahead and litter your pages with animated cat GIFs.
+
+In addition to the Gifs, [Abijeet](https://github.com/BookStackApp/BookStack/pull/754) has also fixed many image manager upload issues, in both function and design, to make the image management experience better.
+
+### Icon Overhaul
+
+Previously BookStack used an icon font, thanks to the [material design iconic font](http://zavoloklom.github.io/material-design-iconic-font/icons.html), which worked nice for quick development. Unfortunately though an icon font is hard to customise and limits the icons available to use.
+
+We have now migrated to fully using SVG icons. Things will generally look the same since we're using the same Google Material Design icon set but thanks to being SVG they should now appear sharper, pages will load quicker and the icons will no longer 'flash' into the view. They can also be easily overridden on an individual basis via [theming](/blog/beta-release-v0-20-0/#groundwork-for-theming).
+
+### Updated Translations
+
+Thanks to [@msaus](https://github.com/BookStackApp/BookStack/pull/761), [@Alwaysin](https://github.com/BookStackApp/BookStack/pull/753), [@cipi1965](https://github.com/BookStackApp/BookStack/pull/743), [@artur-trzesiok](https://github.com/BookStackApp/BookStack/pull/718) and [@leomartinez](https://github.com/BookStackApp/BookStack/pull/709) we now have updated, more complete translations for Japanese, French, Italian, Polish & Spanish Argentinian.  
+
+### Full List of Changes
+
+* GIF images now animate as expected. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/755). ([#755](https://github.com/BookStackApp/BookStack/pull/755),[#223](https://github.com/BookStackApp/BookStack/issues/223))
+* Improved image manager uploader user-experience with many fixes and tweaks. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/754). ([#754](https://github.com/BookStackApp/BookStack/pull/754),[#741](https://github.com/BookStackApp/BookStack/issues/741))
+* Added toggle-able JavaScript escaping on page render. ([#575](https://github.com/BookStackApp/BookStack/issues/575))
+* Updated book/page/chapter create urls to prevent conflicting with entity names. ([#758](https://github.com/BookStackApp/BookStack/issues/758))
+* Updated all icons to SVG in a way that can be override via theming. ([#704](https://github.com/BookStackApp/BookStack/pull/704))
+* Updated dependencies so the project works correcting after installing with composer install --no-dev. ([#742](https://github.com/BookStackApp/BookStack/issues/742))
+* Update to Japanese translations. Thanks to [@msaus](https://github.com/BookStackApp/BookStack/pull/761). ([#761](https://github.com/BookStackApp/BookStack/pull/761))
+* Update to French translations. Thanks to [@Alwaysin](https://github.com/BookStackApp/BookStack/pull/753). ([#753](https://github.com/BookStackApp/BookStack/pull/753),[#752](https://github.com/BookStackApp/BookStack/pull/752))
+* Update to Italian translations. Thanks to [@cipi1965](https://github.com/BookStackApp/BookStack/pull/743). ([#743](https://github.com/BookStackApp/BookStack/pull/743))
+* Update to Polish translations. Thanks to [@artur-trzesiok](https://github.com/BookStackApp/BookStack/pull/718). ([#718](https://github.com/BookStackApp/BookStack/pull/718))
+* Update to 'Spanish Argentina' translations. Thanks to [@leomartinez](https://github.com/BookStackApp/BookStack/pull/709). ([#709](https://github.com/BookStackApp/BookStack/pull/709))
+* Added ability to configure email sender name. Thanks to [@duncanbarnes](https://github.com/BookStackApp/BookStack/pull/711). ([#711](https://github.com/BookStackApp/BookStack/pull/711))
+* Added CACHE_PREFIX to the .env.example file. Thanks to [@pataar](https://github.com/BookStackApp/BookStack/pull/714). ([#714](https://github.com/BookStackApp/BookStack/pull/714))
+* Updated form styling to be little cleaner.
+* Improved search efficiency, by reducing required DB queries, and tweak search scoring to weight entities. Books > Chapters > Pages 
+* Converted CSS/JS build system to webpack.
+* Fixed page preview text showing whitespace causing a lot of wasted space in listings. ([#739](https://github.com/BookStackApp/BookStack/issues/739))
+* Fixed issue where app logo would not load when using secure local images. ([#725](https://github.com/BookStackApp/BookStack/issues/725))
+* Fixed incorrect cursor position after pasting an image in the Markdown editor. ([#751](https://github.com/BookStackApp/BookStack/issues/751))
+* Fixed markdown editor resizing with long strings. Thanks to [@BackwardSpy](https://github.com/BookStackApp/BookStack/pull/716). ([#716](https://github.com/BookStackApp/BookStack/pull/716),[#715](https://github.com/BookStackApp/BookStack/issues/715))
+* Fixed error that could occur due to search results clashing with Vue syntax. 
+
+----
+
+<a style="background-color:black;color:white;text-decoration:none;padding:4px 6px;font-family:-apple-system, BlinkMacSystemFont, &quot;San Francisco&quot;, &quot;Helvetica Neue&quot;, Helvetica, Ubuntu, Roboto, Noto, &quot;Segoe UI&quot;, Arial, sans-serif;font-size:12px;font-weight:bold;line-height:1.2;display:inline-block;border-radius:3px;" href="https://unsplash.com/@mvdheuvel?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge" target="_blank" rel="noopener noreferrer" title="Download free do whatever you want high-resolution photos from Maarten van den Heuvel"><span style="display:inline-block;padding:2px 3px;"><svg xmlns="http://www.w3.org/2000/svg" style="height:12px;width:auto;position:relative;vertical-align:middle;top:-1px;fill:white;" viewBox="0 0 32 32"><title>unsplash-logo</title><path d="M20.8 18.1c0 2.7-2.2 4.8-4.8 4.8s-4.8-2.1-4.8-4.8c0-2.7 2.2-4.8 4.8-4.8 2.7.1 4.8 2.2 4.8 4.8zm11.2-7.4v14.9c0 2.3-1.9 4.3-4.3 4.3h-23.4c-2.4 0-4.3-1.9-4.3-4.3v-15c0-2.3 1.9-4.3 4.3-4.3h3.7l.8-2.3c.4-1.1 1.7-2 2.9-2h8.6c1.2 0 2.5.9 2.9 2l.8 2.4h3.7c2.4 0 4.3 1.9 4.3 4.3zm-8.6 7.5c0-4.1-3.3-7.5-7.5-7.5-4.1 0-7.5 3.4-7.5 7.5s3.3 7.5 7.5 7.5c4.2-.1 7.5-3.4 7.5-7.5z"></path></svg></span><span style="display:inline-block;padding:2px 3px;">Maarten van den Heuvel</span></a>
diff --git a/content/blog/beta-release-v0-21-0.md b/content/blog/beta-release-v0-21-0.md
new file mode 100644 (file)
index 0000000..a03772a
--- /dev/null
@@ -0,0 +1,81 @@
++++
+categories = ["Releases"]
+tags = ["Releases"]
+title = "Beta Release v0.21.0"
+date = 2018-04-22T17:00:00Z
+author = "Dan Brown"
+image = "/images/blog-cover-images/bookshelf-giammarco-boscaro.jpg"
+description = "Beta Release v0.21 is here with video embed support, better tags and the ability to copy pages. There's also a new official BookStack team member!"
+slug = "beta-release-v0-21-0"
+draft = false
++++
+
+A new version of BookStack is here. Version 0.21 improves upon a number of existing features in addition to bringing its own new capabilities to BookStack. If you are updating to this release from v0.20.0 or before it's also worth reviewing the [hefty update v0.20.1](/blog/beta-release-v0-20-1/) which included a good number of fixes and improvements itself.
+
+* [Update instructions](https://www.bookstackapp.com/docs/admin/updates)
+* [GitHub release page](https://github.com/BookStackApp/BookStack/releases/tag/v0.21.0)
+
+### New Team Member
+
+Before we dive into the depths of the new features in this release I'd like to announce that BookStack team has grown a little bit. [Abijeet](https://github.com/Abijeet) is now an official maintainer of BookStack. Abijeet has contributed on a good number of features now and pretty much every recent release includes features or improvements provided by Abieet. In addition, he frequently helps with GitHub issues.
+
+By being an official maintainer he now has the ability to contribute quicker and to manage issues easier without me jumping in. Welcome Abijeet.  
+
+### Media Embed Support
+
+For this release Abijeet has added media embedding to the WYSIWYG editor. This makes it really easy to include videos and media from other websites in your pages. Here's a quick preview of how easy embedding a YouTube video is: 
+
+<video src="/images/2018/04/insert-video.mp4" controls></video>
+
+For those that prefer the Markdown editor, You already have the ability to insert HTML directly in the editor so you can directly insert any embed code from external sources.
+
+### Page Copying
+
+It's now possible to directly copy a page. You can find a new 'Copy' option in the 'More' menu at the top-right when viewing a page. When copying you'll have the option to change the name and alter the destination of the copied page. To be able to copy a page the user will need 'create' permissions for the book or chapter the page is to be copied into.
+
+### Tag System Update
+
+Previously you could only apply tags to pages but this has now been rolled out to books and chapters. This can be found in the edit view of both. These tags can be searched upon just as you currently can with pages.
+
+### Configurable Robots.txt
+
+The `robots.txt` file of a website tells web crawlers, such as Google's page indexer, whether your site should be crawled and indexed. Previously in BookStack this was set to always allow web crawlers. This file has now been made dynamic and will change depending on the "Allow public viewing?" setting.
+
+Alternatively you can force the value of the `robots.txt` by setting `ALLOW_ROBOTS=false`, or `ALLOW_ROBOTS=true`, in the `.env` file. This will take priority over the "Allow public viewing?" setting. 
+
+If you want to customise the contents of this file you are able to do this, without editing BookStack source files, via the theme override system.
+
+### Language Support
+
+Thanks to [@jasoncheng7115](https://github.com/BookStackApp/BookStack/pull/780) we now have traditional Chinese as a language option in BookStack. Upon this addition, the following languages have been updated:
+
+* Spanish - Thanks to [@moucho](https://github.com/BookStackApp/BookStack/pull/783).
+* 'Spanish Argentina' - Thanks to [@leomartinez](https://github.com/BookStackApp/BookStack/pull/806).
+* German - Thanks to [@abno85](https://github.com/BookStackApp/BookStack/pull/798).
+* Japanese - Thanks to [@msaus](https://github.com/BookStackApp/BookStack/pull/767).
+
+### Full List of Changes
+
+* Added the ability to insert videos via the WYSIWYG editor. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/768). ([#768](https://github.com/BookStackApp/BookStack/pull/768)[#266](https://github.com/BookStackApp/BookStack/issues/266)
+* Added the ability to copy a page. ([#673](https://github.com/BookStackApp/BookStack/issues/673))
+* Rolled out tag system to chapters and books. ([#121](https://github.com/BookStackApp/BookStack/issues/121))
+* Updated export image processing to include images when using "local_secure" option. ([#786](https://github.com/BookStackApp/BookStack/issues/786))
+* Robots.txt file is now dynamic and configurable. ([#779](https://github.com/BookStackApp/BookStack/issues/779))
+* Added traditional Chinese translations. Thanks to [@jasoncheng7115](https://github.com/BookStackApp/BookStack/pull/780). ([#780](https://github.com/BookStackApp/BookStack/pull/780))
+* Updated Spanish translations. Thanks to [@moucho](https://github.com/BookStackApp/BookStack/pull/783). ([#783](https://github.com/BookStackApp/BookStack/pull/783))
+* Updated 'Spanish Argentina' translations. Thanks to [@leomartinez](https://github.com/BookStackApp/BookStack/pull/806). ([#806](https://github.com/BookStackApp/BookStack/pull/806))
+* Updated German translations. Thanks to [@abno85](https://github.com/BookStackApp/BookStack/pull/798). ([#798](https://github.com/BookStackApp/BookStack/pull/798))
+* Updated Japanese translations. Thanks to [@msaus](https://github.com/BookStackApp/BookStack/pull/767). ([#767](https://github.com/BookStackApp/BookStack/pull/767))
+* Updated 'Reset Password' flow with newer design ([#800](https://github.com/BookStackApp/BookStack/issues/800))
+* Fixed issue where old books would not update with cover image on save. ([#773](https://github.com/BookStackApp/BookStack/issues/773))
+* Added proper permission checking when moving pages and chapters ([cdb1c7ef](https://github.com/BookStackApp/BookStack/commit/cdb1c7ef88a0054c46ba9eb040464bdea274b095))
+
+### Next Steps
+
+For this release I was hoping to bring in proper revision control for drawings to finish that feature off but I did not find the time so that will be my focus for the next release. I believe Abijeet may be looking to add the 'All Books' listing as a homepage option.
+
+For other features please ensure you add a 'Thumbs-up' reaction on the parent post of any GitHub issue for desired features as it's a really helpful way to identify the most requested features.
+
+----
+
+<span style="font-size: 0.8em;opacity:0.8;">Header Image Credits: &nbsp; <a style="background-color:black;color:white;text-decoration:none;padding:4px 6px;font-family:-apple-system, BlinkMacSystemFont, &quot;San Francisco&quot;, &quot;Helvetica Neue&quot;, Helvetica, Ubuntu, Roboto, Noto, &quot;Segoe UI&quot;, Arial, sans-serif;font-size:12px;font-weight:bold;line-height:1.2;display:inline-block;border-radius:3px;" href="https://unsplash.com/@giamboscaro?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge" target="_blank" rel="noopener noreferrer" title="Download free do whatever you want high-resolution photos from Giammarco Boscaro"><span style="display:inline-block;padding:2px 3px;"><svg xmlns="http://www.w3.org/2000/svg" style="height:12px;width:auto;position:relative;vertical-align:middle;top:-1px;fill:white;" viewBox="0 0 32 32"><title>unsplash-logo</title><path d="M20.8 18.1c0 2.7-2.2 4.8-4.8 4.8s-4.8-2.1-4.8-4.8c0-2.7 2.2-4.8 4.8-4.8 2.7.1 4.8 2.2 4.8 4.8zm11.2-7.4v14.9c0 2.3-1.9 4.3-4.3 4.3h-23.4c-2.4 0-4.3-1.9-4.3-4.3v-15c0-2.3 1.9-4.3 4.3-4.3h3.7l.8-2.3c.4-1.1 1.7-2 2.9-2h8.6c1.2 0 2.5.9 2.9 2l.8 2.4h3.7c2.4 0 4.3 1.9 4.3 4.3zm-8.6 7.5c0-4.1-3.3-7.5-7.5-7.5-4.1 0-7.5 3.4-7.5 7.5s3.3 7.5 7.5 7.5c4.2-.1 7.5-3.4 7.5-7.5z"></path></svg></span><span style="display:inline-block;padding:2px 3px;">Giammarco Boscaro</span></a></span>
diff --git a/content/blog/beta-release-v0-22-0.md b/content/blog/beta-release-v0-22-0.md
new file mode 100644 (file)
index 0000000..396a2a5
--- /dev/null
@@ -0,0 +1,82 @@
++++
+categories = ["Releases"]
+tags = ["Releases"]
+title = "Beta Release v0.22.0"
+date = 2018-05-28T10:00:00Z
+author = "Dan Brown"
+image = "/images/blog-cover-images/bookshop-john-michael-thomson.jpg"
+description = "BookStack v0.22 brings a new homepage option in addition to changes to the drawing system and general design tweaks."
+slug = "beta-release-v0-22-0"
+draft = false
++++
+
+BookStack v0.22 is here with a much requested homepage option in addition to changes to the drawing system and improvements. Let's get into it: 
+
+
+* [Update instructions](https://www.bookstackapp.com/docs/admin/updates)
+* [GitHub release page](https://github.com/BookStackApp/BookStack/releases/tag/v0.22.0)
+
+
+### Books Homepage Option
+
+Setting the '/books' view as the homepage was the most-requested issue we had so [@Abijeet](https://github.com/BookStackApp/BookStack/pull/830) went ahead and built this in as a new setting. Just like the '/books' view a grid or list layout can be selected. This homepage view will still differ slightly in comparison to the '/books' page since the sidebar items will remain more focused on the user's activity rather than additional categories of books. The new setting can be found in the 'App Settings' section of BookStack under 'Application Homepage' as a toggle switch.
+
+### Sidebar Design Changes
+
+The sidebar when viewing pages was beginning to get a little crowded, Especially when the page had both tags assigned and permissions set. This has now been cleaned up to be much more compact with new tag styling. The permissions are now shown in a more efficient manner within the details panel. The difference in space-efficiency can be seen the comparison below:
+
+![BookStack sidebar design changes](/images/2018/05/sidebar-updates.png)
+
+
+### Ubuntu 18.04 Install Script
+
+With the recent release of Ubuntu LTS 18.04, Bionic Beaver, A new install script has been put together. Details of the script and how to run it [can be found here](/docs/admin/installation/#ubuntu-1804).
+
+In comparison to the Ubuntu 16.04 script, This version now installs PHP-7.2 instead of PHP-7.0 and Apache2 is used instead of Nginx. The change to apache was done in the hopes of ensuring that BookStack plays nicer with other web-based packages such as phpMyAdmin and Let’s Encrypt.
+
+### Drawing Changes
+
+Previously when updating a drawing the source file would be completely overwritten. In addition, there was no way to delete a drawing in the system.
+This has now been changed so that new images are created upon updating instead of being overwritten. This ensures that drawing changes are now versioned correctly alongside page updates.
+
+This change does mean that more image files will be created and stored by BookStack. For one-off drawing deletions, or re-naming, you can now access a 'Drawing Manager' from the drawing-icon dropdown in the WYSIWYG editor or by shift-clicking the 'Insert Drawing' action in the markdown editor. To handle bulk image cleanup a new action has been added in the new 'Maintenance' area: 
+
+### Maintenance Area
+
+A new maintenance area has been added to sit alongside settings. This area will expand to hold all common operations an admin might want to perform. Currently it only includes the ability to clean-up images:
+
+![BookStack Maintenance Area](/images/2018/05/maintenance.png)
+
+The clean-up images action provides a way to remove old, unused images from the system. It will search for uploaded gallery images and drawings that cannot be found within page content. It will also search within page revisions although you have the ability to ignore them to clean even more images.
+
+### Language Support
+
+This release includes updates to the German, Spanish and Swedish translations thanks respectively to [@vriic](https://github.com/BookStackApp/BookStack/pull/851), [@moucho](https://github.com/BookStackApp/BookStack/pull/846), [@marcusforsberg](https://github.com/BookStackApp/BookStack/pull/802).
+
+
+### Full List of Changes
+
+* Added setting to set the Books view as the homepage. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/830). ([#615](https://github.com/BookStackApp/BookStack/issues/615),[#830](https://github.com/BookStackApp/BookStack/pull/830))
+* Updated German translations. Thanks to [@vriic](https://github.com/BookStackApp/BookStack/pull/851). ([#851](https://github.com/BookStackApp/BookStack/pull/851))
+* Updated Spanish translations. Thanks to [@moucho](https://github.com/BookStackApp/BookStack/pull/846). ([#846](https://github.com/BookStackApp/BookStack/pull/846))
+* Updated Swedish translations. Thanks to [@marcusforsberg](https://github.com/BookStackApp/BookStack/pull/802). ([#802](https://github.com/BookStackApp/BookStack/pull/802))
+* Ubuntu 18.04 install script now available. ([#850](https://github.com/BookStackApp/BookStack/issues/850))
+* Updated tag and details design in sidebar to be more compact and cleaner. ([#838](https://github.com/BookStackApp/BookStack/issues/838))
+* Drawings now create new image records instead of overwriting existing content. ([#837](https://github.com/BookStackApp/BookStack/pull/837), [#770](https://github.com/BookStackApp/BookStack/issues/770))
+* Added new 'Maintenance' area to settings with option to clean-up images. ([#837](https://github.com/BookStackApp/BookStack/pull/837))
+* Updated design of image manager and fixed search-cancel button to not always clear all images shown. ([#837](https://github.com/BookStackApp/BookStack/pull/837))
+* Updated back-to-top button to not show on not scrollable pages such as the edit view. ([#824](https://github.com/BookStackApp/BookStack/issues/824))
+* Added `.env` option to set Secure/HTTPS only cookies. ([#817](https://github.com/BookStackApp/BookStack/issues/817))
+* Updated link attaching to allow any link types, Not only links matching a set pattern. ([#812](https://github.com/BookStackApp/BookStack/issues/812))
+* Updated `Secure Images` setting to not alter names of uploaded images, Only their paths.
+* Fixed relative CSS references causing WKHTML PDF exports to fail. Now callout icons will show in exports. ([#796](https://github.com/BookStackApp/BookStack/issues/796))
+* Fixed issue with c-like languages not highlighting correctly in code blocks. ([#849](https://github.com/BookStackApp/BookStack/issues/849))
+* Fixed design bug causing search icon to overlap input in header. ([#859](https://github.com/BookStackApp/BookStack/issues/859))
+
+### Next Steps
+
+For the next release I'll have another think about the best way to [remove Composer as a dependency](https://github.com/BookStackApp/BookStack/issues/161) for installs and updates. Ideally I want to ensure the process is as simple as possible while remaining secure. Additionally I may start to have a proper think about the best solution for [adding another level to the organisation hierarchy](https://github.com/BookStackApp/BookStack/issues/95) as that's currently highly-requested.
+
+----
+
+<span style="font-size: 0.8em;opacity:0.8;">Header Image Credits: &nbsp; <a style="background-color:black;color:white;text-decoration:none;padding:4px 6px;font-family:-apple-system, BlinkMacSystemFont, &quot;San Francisco&quot;, &quot;Helvetica Neue&quot;, Helvetica, Ubuntu, Roboto, Noto, &quot;Segoe UI&quot;, Arial, sans-serif;font-size:12px;font-weight:bold;line-height:1.2;display:inline-block;border-radius:3px;" href="https://unsplash.com/@svqmedia?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge" target="_blank" rel="noopener noreferrer" title="Download free do whatever you want high-resolution photos from John Michael Thomson"><span style="display:inline-block;padding:2px 3px;"><svg xmlns="http://www.w3.org/2000/svg" style="height:12px;width:auto;position:relative;vertical-align:middle;top:-1px;fill:white;" viewBox="0 0 32 32"><title>unsplash-logo</title><path d="M20.8 18.1c0 2.7-2.2 4.8-4.8 4.8s-4.8-2.1-4.8-4.8c0-2.7 2.2-4.8 4.8-4.8 2.7.1 4.8 2.2 4.8 4.8zm11.2-7.4v14.9c0 2.3-1.9 4.3-4.3 4.3h-23.4c-2.4 0-4.3-1.9-4.3-4.3v-15c0-2.3 1.9-4.3 4.3-4.3h3.7l.8-2.3c.4-1.1 1.7-2 2.9-2h8.6c1.2 0 2.5.9 2.9 2l.8 2.4h3.7c2.4 0 4.3 1.9 4.3 4.3zm-8.6 7.5c0-4.1-3.3-7.5-7.5-7.5-4.1 0-7.5 3.4-7.5 7.5s3.3 7.5 7.5 7.5c4.2-.1 7.5-3.4 7.5-7.5z"></path></svg></span><span style="display:inline-block;padding:2px 3px;">John Michael Thomson</span></a></span>
diff --git a/content/blog/beta-release-v0-23-0.md b/content/blog/beta-release-v0-23-0.md
new file mode 100644 (file)
index 0000000..10a6d7f
--- /dev/null
@@ -0,0 +1,78 @@
++++
+categories = ["Releases"]
+tags = ["Releases"]
+title = "Beta Release v0.23.0"
+date = 2018-07-29T15:00:00Z
+author = "Dan Brown"
+image = "/images/blog-cover-images/book-aaron-burden.jpg"
+description = "BookStack v0.23 brings quicker editing, Discord login, LDAP group syncing and much more"
+slug = "beta-release-v0-23-0"
+draft = false
++++
+
+Quicker editing, better LDAP integration and Discord login are now here with BookStack v0.23 along with a good set of fixes and improvements.
+I must admit this release comes a little later than expected due to an unusually warm English summer making working conditions in my home office exhausting
+but luckily we've had a good number of code contributions to keep things moving.
+
+* [Update instructions](https://www.bookstackapp.com/docs/admin/updates)
+* [GitHub release page](https://github.com/BookStackApp/BookStack/releases/tag/v0.23.0)
+
+
+### Team Updates
+
+To start things off I'd like to welcome [lommes](https://github.com/lommes) as an official member of the BookStack team.
+This is to recognise the valuable help that lommes has been providing by responding to issues on GitHub in addition to the multiple pull requests they've created to add new features.
+
+### Page Section Quick-Edit
+
+On large pages it can be quite cumbersome to find a section you'd like to edit; then go into edit mode; then find you need to scroll back down in the editor to find your particular section that needs to change.
+Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/875) you can now directly select almost any section when viewing a page and have the editor jump directly to that section. This works for both WYSIWYG and markdown editor users.
+
+To quickly edit a section simply highlight the text show the pop-over, then click the edit icon. This video shows how it works:
+
+<video src="/images/2018/07/bookstack-quick-edit.mp4" muted="true" controls></video>
+
+### LDAP Group Sync
+
+Those using LDAP to manage user access to BookStack will be delighted to know that you can now sync LDAP groups to user roles. A massive thanks to [@brennanmurphy](https://github.com/BookStackApp/BookStack/pull/911) for working on this feature.
+
+This sync will match LDAP group names to BookStack role names and automatically add users to the correct groups upon login. You can optionally configure this sync to also remove users from non-matching groups. If your LDAP group need to be different to your BookStack role name there's a new 'External Authentication IDs' field visible when you edit a role while LDAP is enabled. Names entered here will override the default role-name matching behaviour.
+
+Details on setting up group sync can be found in the [updated LDAP documentation](/docs/admin/ldap-auth/#ldap-group-sync).
+
+### Discord Login Option
+
+![BookStack Discord Login](/images/2018/07/bookstack-discord-login.png)
+
+Thanks to [@lommes](https://github.com/BookStackApp/BookStack/pull/904) it is now possible to use Discord as an login option. Details on setting this up can be found in the [updated third party authentication](/docs/admin/third-party-auth/#discord) documentation.
+
+### Language Support
+
+As usual, This release includes a round of translation updates. French, German, Brazilian Portuguese, Spanish Argentinian & Spanish translations have been updated. A big thanks to GitHub users @nicobubulle, @alex2702, @DeehSlash, @leomartinez and @moucho for contributing updates.
+
+### Full List of Changes
+
+* Added LDAP group sync. Thanks to [@brennanmurphy](https://github.com/BookStackApp/BookStack/pull/911). ([#911](https://github.com/BookStackApp/BookStack/pull/911))
+* Added Discord as social login provider. Thanks to [@lommes](https://github.com/BookStackApp/BookStack/pull/904). ([#904](https://github.com/BookStackApp/BookStack/pull/904), [#903](https://github.com/BookStackApp/BookStack/issues/903))
+* Added ability to select a particular section of a page to edit. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/875). ([#875](https://github.com/BookStackApp/BookStack/pull/875))
+* Added copy icon & functionality to codeblocks ([#858](https://github.com/BookStackApp/BookStack/issues/858))
+* Updated French translations. Thanks to [@nicobubulle](https://github.com/BookStackApp/BookStack/pull/933). ([#933](https://github.com/BookStackApp/BookStack/pull/933))
+* Updated German notification translations. Thanks to [@alex2702](https://github.com/BookStackApp/BookStack/pull/925). ([#925](https://github.com/BookStackApp/BookStack/pull/925))
+* Updated Brazilian Portuguese translations. Thanks to [@DeehSlash](https://github.com/BookStackApp/BookStack/pull/918). ([#918](https://github.com/BookStackApp/BookStack/pull/918))
+* Updated 'Spanish Argentina' translations. Thanks to [@leomartinez](https://github.com/BookStackApp/BookStack/pull/886). ([#886](https://github.com/BookStackApp/BookStack/pull/886))
+* Updated Spanish translations. Thanks to [@moucho](https://github.com/BookStackApp/BookStack/pull/865). ([#865](https://github.com/BookStackApp/BookStack/pull/865))
+* Updated dates shown in the image-manager to be much cleaner. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/907). ([#907](https://github.com/BookStackApp/BookStack/pull/907))
+* Fixed permission bug causing page create to fail within chapter if lacking permissions to view the parent book. ([#912](https://github.com/BookStackApp/BookStack/issues/912))
+* Fixed issue with code not wrapping on revision page. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/906). ([#906](https://github.com/BookStackApp/BookStack/pull/906), [#888](https://github.com/BookStackApp/BookStack/issues/888))
+* Fixed error notification briefly showing on initial load. ([#897](https://github.com/BookStackApp/BookStack/issues/897))
+* Fixed incorrect and confusing attachment deletion behaviour. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/892). ([#892](https://github.com/BookStackApp/BookStack/pull/892), [#884](https://github.com/BookStackApp/BookStack/issues/884))
+* Fixed undefined error when clicking on link under page navigation. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/874). ([#874](https://github.com/BookStackApp/BookStack/pull/874), [#873](https://github.com/BookStackApp/BookStack/issues/873))
+
+### Next Steps
+
+Last month I set out a proposal of what 'Bookshelves' may look like within BookStack. [This proposal can be seen here](https://github.com/BookStackApp/BookStack/issues/95#issuecomment-399753699).
+Feedback so far has been positive with no major objections so Bookshelves will be the main focus for the next release. If you have any thoughts on the proposal feel free to comment on that GitHub issue.
+
+----
+
+<span style="font-size: 0.8em;opacity:0.8;">Header Image Credits: &nbsp; <a style="background-color:black;color:white;text-decoration:none;padding:4px 6px;font-family:-apple-system, BlinkMacSystemFont, &quot;San Francisco&quot;, &quot;Helvetica Neue&quot;, Helvetica, Ubuntu, Roboto, Noto, &quot;Segoe UI&quot;, Arial, sans-serif;font-size:12px;font-weight:bold;line-height:1.2;display:inline-block;border-radius:3px" href="https://unsplash.com/@aaronburden?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge" target="_blank" rel="noopener noreferrer" title="Download free do whatever you want high-resolution photos from Aaron Burden"><span style="display:inline-block;padding:2px 3px"><svg xmlns="http://www.w3.org/2000/svg" style="height:12px;width:auto;position:relative;vertical-align:middle;top:-1px;fill:white" viewBox="0 0 32 32"><title>unsplash-logo</title><path d="M20.8 18.1c0 2.7-2.2 4.8-4.8 4.8s-4.8-2.1-4.8-4.8c0-2.7 2.2-4.8 4.8-4.8 2.7.1 4.8 2.2 4.8 4.8zm11.2-7.4v14.9c0 2.3-1.9 4.3-4.3 4.3h-23.4c-2.4 0-4.3-1.9-4.3-4.3v-15c0-2.3 1.9-4.3 4.3-4.3h3.7l.8-2.3c.4-1.1 1.7-2 2.9-2h8.6c1.2 0 2.5.9 2.9 2l.8 2.4h3.7c2.4 0 4.3 1.9 4.3 4.3zm-8.6 7.5c0-4.1-3.3-7.5-7.5-7.5-4.1 0-7.5 3.4-7.5 7.5s3.3 7.5 7.5 7.5c4.2-.1 7.5-3.4 7.5-7.5z"></path></svg></span><span style="display:inline-block;padding:2px 3px">Aaron Burden</span></a></span>
diff --git a/content/blog/beta-release-v0-24-0.md b/content/blog/beta-release-v0-24-0.md
new file mode 100644 (file)
index 0000000..7204e9d
--- /dev/null
@@ -0,0 +1,114 @@
++++
+categories = ["Releases"]
+tags = ["Releases"]
+title = "Beta Release v0.24.0"
+date = 2018-09-24T11:00:00Z
+author = "Dan Brown"
+image = "/images/blog-cover-images/shelves-michael-d-beckwith.jpg"
+description = "Bookshelves arrive in BookStack v0.24 along with a treasure chest of other features, fixes and updates"
+slug = "beta-release-v0-24-0"
+draft = false
++++
+
+Need a way to categorise your Books? Well BookStack v0.24 is the release for you bringing Bookshelves along with a host of other notable features such as revision removals, social authentication auto-registration and Arabic support.
+
+**Please Note, Due to required re-working of some settings you may have to re-apply any homepage options you've previously set upon updating to v0.24. See the update instructions page linked below for further info.**
+
+* [Update instructions](https://www.bookstackapp.com/docs/admin/updates)
+* [GitHub release page](https://github.com/BookStackApp/BookStack/releases/tag/v0.24.0)
+
+
+### Bookshelves
+
+Bookshelves have now been added as a new layer to the organisation system. Bookshelves offer a way to group and categorise books. A single bookshelf can contain multiple books and a single book can be contained in multiple bookshelves.
+
+<video src="/images/2018/09/bookshelves.mp4" muted="true" controls></video>
+
+This is only the initial functional implementation of bookshelves. Currently the interface for bookshelves is very similar to that for books and chapters. As part of a bigger design update we'll be looking to make bookshelves more unique in respect to their functionality and design.
+
+As with books, bookshelves can have custom permissions set upon them but they differ in the fact the permissions won't cascade down to child items as they do with books & chapters. This is due to fact a book can be in multiple bookshelves. Instead, within the permissions view for the shelf, you have the option to copy the shelf permission settings to all child books:
+
+![Copy Bookshelf Permissions](/images/2018/09/bookshelves_copy_permissions.png)
+
+### Page Revision Updates
+
+Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/1008) it's now possible to remove particular revisions. This can be useful if you ever need to remove sensitive information that was part of a previous page version without having to delete all revision history in the system.
+
+![Copy Bookshelf Permissions](/images/2018/09/revision_delete.png)
+
+A new configuration option has also been added to control the amount of revisions kept by BookStack. Previously there was a limit of 50 versions enforced. This remains the default but it is now possible to increase or even remove this limit by setting the following in your `.env` file:
+
+```bash
+# Set the revision limit to 100
+REVISION_LIMIT=100
+
+# Alternatively, You can set to 'false' to disable the limit altogether. 
+REVISION_LIMIT=false
+```
+
+
+### Social Auto-Registration & Auto-Email-Confirmation
+
+Previously, to register in the system, you'd need to visit the register page and select your login option, you were not able to register via the login page. This also required registrations to be enabled and prevented social registration if using LDAP as your authentication option.
+
+With this release it's now possible to configure, per authentication option, if users should be auto-registered upon login in the event they do not already have an account. This allows a much smoother sign-up process. It's also possible to automatically mark emails as confirmed for particular authentication options if you trust the service to provide the correct email address. Domain restrictions will still be respected, if set, for both of these options.
+
+[Details on configuring these options can be found here.](/docs/admin/third-party-auth/#automatic-registration-email-confirmation)
+
+### Arabic and Right-to-Left Text Support
+
+This release brings quite a notable addition to BookStack's language support. Thanks to [@kmoj86](https://github.com/BookStackApp/BookStack/pull/945) Arabic is now a language choice. This is the first right-to-left language in BookStack so some functionality has been added to support right-to-left text.
+
+The WYSIWYG editor will now default it's text direction based on your language setting. In addition, If a right-to-left language is in use then additional toolbar options will show to provide control over text direction:
+
+![wysiwyg_rtl_support.png](/images/2018/09/wysiwyg_rtl_support.png)
+
+Bullet-point styles have been updated to ensure they display correctly when displayed in a right-to-left manner and page content should show in the correct direction depending on the text detected within.
+
+Note, Right-to-left text support is in its early stages so there's likely to be further updates needed. Please feel free to raise any issues found on GitHub.
+
+### Additional Language Updates
+
+Once again, We've received a whole load of translations by wonderful people. Here are the languages that have received updates and their contributors:
+
+🇪🇸 &nbsp; Spanish - Thanks to [@moucho](https://github.com/BookStackApp/BookStack/pull/1025). <br>
+🇩🇪 &nbsp; German - Thanks to [@vriic](https://github.com/BookStackApp/BookStack/pull/983). <br>
+🇷🇺 &nbsp; Russian - Thanks to [@mullinsmikey](https://github.com/BookStackApp/BookStack/pull/1002). <br>
+🇧🇷 &nbsp; Brazilian Portuguese - Thanks to [@DeehSlash](https://github.com/BookStackApp/BookStack/pull/986). <br>
+
+
+### Full List of Changes
+
+* Added bookshelves, A level above books. ([#947](https://github.com/BookStackApp/BookStack/pull/947), [#1023](https://github.com/BookStackApp/BookStack/issues/1023), [#95](https://github.com/BookStackApp/BookStack/issues/95))
+* Added ability to remove particular revisions. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/1008). ([#1008](https://github.com/BookStackApp/BookStack/pull/1008), [#784](https://github.com/BookStackApp/BookStack/issues/784))
+* Added social auto-registration option. <br> Thanks to [@ibrahimennafaa](https://github.com/BookStackApp/BookStack/pull/966). ([#966](https://github.com/BookStackApp/BookStack/pull/966), [#574](https://github.com/BookStackApp/BookStack/issues/574), [#572](https://github.com/BookStackApp/BookStack/issues/572), [#477](https://github.com/BookStackApp/BookStack/issues/477))
+* Added Arabic language and initial RTL language support. Thanks to [@kmoj86](https://github.com/BookStackApp/BookStack/pull/945). ([#945](https://github.com/BookStackApp/BookStack/pull/945), [#939](https://github.com/BookStackApp/BookStack/issues/939))
+* Added ability to scroll past the end in the Markdown editor. ([#1020](https://github.com/BookStackApp/BookStack/issues/1020))
+* Updated default cookie name and made configurable via .env file. ([#1018](https://github.com/BookStackApp/BookStack/issues/1018))
+* Updated revision limit to be configurable. ([#1004](https://github.com/BookStackApp/BookStack/issues/1004))
+* Updated export templates to include custom styles. ([#981](https://github.com/BookStackApp/BookStack/issues/981))
+* Updated database migrations so MyISAM engine is never forced and so that fulltext index support is not required. ([#726](https://github.com/BookStackApp/BookStack/issues/726))
+* Updated Spanish translations. Thanks to [@moucho](https://github.com/BookStackApp/BookStack/pull/1025). ([#1025](https://github.com/BookStackApp/BookStack/pull/1025), [#1021](https://github.com/BookStackApp/BookStack/pull/1021))
+* Updated German translations. Thanks to [@vriic](https://github.com/BookStackApp/BookStack/pull/983). ([#983](https://github.com/BookStackApp/BookStack/pull/983), [#1026](https://github.com/BookStackApp/BookStack/pull/1026))
+* Updated Russian translations. Thanks to [@mullinsmikey](https://github.com/BookStackApp/BookStack/pull/1002). ([#1002](https://github.com/BookStackApp/BookStack/pull/1002))
+* Updated Brazilian Portuguese translations. Thanks to [@DeehSlash](https://github.com/BookStackApp/BookStack/pull/986). ([#986](https://github.com/BookStackApp/BookStack/pull/986))
+* Fixed chapter content dropdown acting unreliably. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/1009). ([#1009](https://github.com/BookStackApp/BookStack/pull/1009), [#960](https://github.com/BookStackApp/BookStack/issues/960))
+* Fixed duplicate role attachment database error that could occur on LDAP group sync. ([#1003](https://github.com/BookStackApp/BookStack/issues/1003))
+* Fixed issue in WYSIWYG editor where the "No color" option would disappear or not be present. ([#999](https://github.com/BookStackApp/BookStack/issues/999))
+* Fixed issue where code block content may be hidden by the copy button. ([#980](https://github.com/BookStackApp/BookStack/issues/980))
+* Fixed issue in WYSIWYG where it could be hard to escape a blockquote section. ([#961](https://github.com/BookStackApp/BookStack/issues/961))
+* Fixed hardcoded English text in search page. ([#864](https://github.com/BookStackApp/BookStack/issues/864))
+* Fixed issue causing Safari to download items as .dms files. Thanks to [@ajvolin](https://github.com/ajvolin). ([#581](https://github.com/BookStackApp/BookStack/issues/581))
+
+
+### Next Steps
+
+As mentioned above, The Bookshelves implementation has been functionality focused for this release so I'll be thinking about how to bring in a unique Bookshelf design to make them more effective in use. I'm sure we'll also see some further thoughts and requests as people start to use Bookshelves.  
+
+To support the implemented, but not documented, themeing system I'd like to revamp and clean-up all views used by the system. This would probably tie in with fleshing-out the Bookshelf design work as part of a bigger design update which also enhances mobile support.
+
+To support future back-end features such as notifications, exports and API support I'd like to refactor a chunk of the existing code that deals with shelves, books, pages & chapters to make such future developments easier. This will probably be my own focus for the next couple of weeks. 
+
+----
+
+<span style="font-size: 0.8em;opacity:0.8;">Header Image Credits: &nbsp; <a style="background-color:black;color:white;text-decoration:none;padding:4px 6px;font-family:-apple-system, BlinkMacSystemFont, &quot;San Francisco&quot;, &quot;Helvetica Neue&quot;, Helvetica, Ubuntu, Roboto, Noto, &quot;Segoe UI&quot;, Arial, sans-serif;font-size:12px;font-weight:bold;line-height:1.2;display:inline-block;border-radius:3px" href="https://unsplash.com/@michael_david_beckwith?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge" target="_blank" rel="noopener noreferrer" title="Download free do whatever you want high-resolution photos from Michael D Beckwith"><span style="display:inline-block;padding:2px 3px"><svg xmlns="http://www.w3.org/2000/svg" style="height:12px;width:auto;position:relative;vertical-align:middle;top:-1px;fill:white" viewBox="0 0 32 32"><title>unsplash-logo</title><path d="M20.8 18.1c0 2.7-2.2 4.8-4.8 4.8s-4.8-2.1-4.8-4.8c0-2.7 2.2-4.8 4.8-4.8 2.7.1 4.8 2.2 4.8 4.8zm11.2-7.4v14.9c0 2.3-1.9 4.3-4.3 4.3h-23.4c-2.4 0-4.3-1.9-4.3-4.3v-15c0-2.3 1.9-4.3 4.3-4.3h3.7l.8-2.3c.4-1.1 1.7-2 2.9-2h8.6c1.2 0 2.5.9 2.9 2l.8 2.4h3.7c2.4 0 4.3 1.9 4.3 4.3zm-8.6 7.5c0-4.1-3.3-7.5-7.5-7.5-4.1 0-7.5 3.4-7.5 7.5s3.3 7.5 7.5 7.5c4.2-.1 7.5-3.4 7.5-7.5z"></path></svg></span><span style="display:inline-block;padding:2px 3px">Michael D Beckwith</span></a></span>
diff --git a/content/blog/beta-release-v0-25-0.md b/content/blog/beta-release-v0-25-0.md
new file mode 100644 (file)
index 0000000..77aff7e
--- /dev/null
@@ -0,0 +1,115 @@
++++
+categories = ["Releases"]
+tags = ["Releases"]
+title = "Beta Release v0.25.0"
+date = 2019-01-12T22:45:00Z
+author = "Dan Brown"
+image = "/images/blog-cover-images/flat-books-patrick-tomasso.jpg"
+description = "BookStack in 2019 starts with v0.25 which a chunk of improvements. BookStack now has over 2000 stars on GitHub!"
+slug = "beta-release-v0-25-0"
+draft = false
++++
+
+2019 is here and to kick it off we have BookStack v0.25. This release does not contain any major new features
+but instead is focused on making improvements to existing systems within BookStack.
+
+* [Update instructions](https://www.bookstackapp.com/docs/admin/updates)
+* [GitHub release page](https://github.com/BookStackApp/BookStack/releases/tag/v0.25.0)
+
+
+**Please Note, During this release cycle it was found that page content includes could leak their content as preview text to users
+that don't have permission to view the included content. It's recommended to re-save any pages that included other page content that's restricted to ensure included text is not shown in page preview text.**
+
+### Header Changes
+
+The header bar has received a few tweaks this release. First of all, A sign-up link will now be
+shown to public guest users that are not yet logged in, if registration is enabled:
+
+![Header Signup Link](/images/2019/01/header_signup_link.png)
+
+For users that have permission to manage other users, but do not have permission
+to alter system settings, a link to the Users admin area will now show instead of "Settings":
+
+![Header Users Link](/images/2019/01/header_users_link.png)
+
+Thanks to [@qianmengnet](https://github.com/BookStackApp/BookStack/pull/1146) & [@cw1998](https://github.com/BookStackApp/BookStack/pull/1119) for these improvements. 
+
+### Example Environment File Changes
+
+The default `.env.example` file has received some changes. It has been cut down from 89 lines
+to only 31 lines and that includes some better comments. It now only contains common configuration
+that's needed to get initially set-up.
+
+A `.env.example.complete` file is now included as a reference to all the possible options that
+are available along with their default settings. Options can be copied from this as required.
+
+### Custom Avatar Service
+
+BookStack has had built-in [Gravatar](https://en.gravatar.com/) support for a while to enable 
+unique user profile images upon user creation. This system has been revamped so the URL used to 
+fetch an avatar can be customized as required. This allows you to customize the URL used for gravatar
+or you can instead use a different avatar service altogether. For example, By setting the below option 
+in your `.env` file you can instead use libravatar:
+
+```bash
+AVATAR_URL=https://seccdn.libravatar.org/avatar/${hash}?s=${size}&d=identicon
+```
+
+The following variables can be used in this setting which will be populated by BookStack when used:
+
+* `${email}` - The user's email address, URL encoded.
+* `${hash}` - MD5 hashed copy of the user's email address.
+* `${size}` - BookStack's ideal requested image size in pixels.
+
+Thanks to [@Vinrobot](https://github.com/BookStackApp/BookStack/pull/1111) for working to implement this feature.
+
+### Language Updates
+
+As always we've had a good deal of community contributions to bring new and updated translations.
+In this release we have:
+
+* Added Ukrainian translations. Thanks to [@Mant1kor](https://github.com/BookStackApp/BookStack/pull/1183).
+* Added German informal translations. Thanks to [@ezzra](https://github.com/BookStackApp/BookStack/pull/1159).
+* Updated Polish translations. Thanks to [@vasiliev123](https://github.com/BookStackApp/BookStack/pull/1180).
+
+Additionally, included in BookStack v0.24.1 & v0.24.2 we had:
+
+* Added Korean translations. Thanks to [@limkukhyun](https://github.com/BookStackApp/BookStack/pull/1066).
+* Updated Brazilian Portuguese translations. Thanks to [@DeehSlash](https://github.com/BookStackApp/BookStack/pull/1034).
+* Updated Chinese translations. Thanks to [@qianmengnet](https://github.com/BookStackApp/BookStack/pull/1109).
+* Updated French translations. Thanks to [@TheLastOperator](https://github.com/BookStackApp/BookStack/pull/1098).
+* Updated Traditional Chinese translations. Thanks to [@kejjang](https://github.com/BookStackApp/BookStack/pull/1088).
+* Updated 'Spanish Argentina' translations. Thanks to [@leomartinez](https://github.com/BookStackApp/BookStack/pull/1117).
+* Updated German translations. Thanks to [@CliffyPrime](https://github.com/BookStackApp/BookStack/pull/1072).
+
+### Full List of Changes
+
+* Added Ukrainian translations. Thanks to [@Mant1kor](https://github.com/BookStackApp/BookStack/pull/1183). ([#1183](https://github.com/BookStackApp/BookStack/pull/1183))
+* Added German informal translations. Thanks to [@ezzra](https://github.com/BookStackApp/BookStack/pull/1159). ([#1159](https://github.com/BookStackApp/BookStack/pull/1159), [#890](https://github.com/BookStackApp/BookStack/issues/890))
+* Updated Polish translations. Thanks to [@vasiliev123](https://github.com/BookStackApp/BookStack/pull/1180). ([#1180](https://github.com/BookStackApp/BookStack/pull/1180))
+* Updated Spanish translation formatting. Thanks to [@moucho](https://github.com/BookStackApp/BookStack/pull/1197). ([#1197](https://github.com/BookStackApp/BookStack/pull/1197))
+* Added proper escaping to LDAP authentication variables. ([#1163](https://github.com/BookStackApp/BookStack/issues/1163))
+* Added anchor links to user profile sections and added "Register" to header for guest users. Thanks to [@qianmengnet](https://github.com/BookStackApp/BookStack/pull/1146). ([#1146](https://github.com/BookStackApp/BookStack/pull/1146))
+* Added configurable timeout for file & image uploads. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/1133). ([#1133](https://github.com/BookStackApp/BookStack/pull/1133), [#876](https://github.com/BookStackApp/BookStack/issues/876))
+* Added system to prevent the last admin from removing themselves as an admin. ([#1124](https://github.com/BookStackApp/BookStack/issues/1124))
+* Added link to manage users in header if user has permission to do so but does not have permission to change system settings. Thanks to [@cw1998](https://github.com/BookStackApp/BookStack/pull/1119). ([#1119](https://github.com/BookStackApp/BookStack/pull/1119), [#1110](https://github.com/BookStackApp/BookStack/issues/1110))
+* Added support for custom avatar provider. Thanks to [@Vinrobot](https://github.com/BookStackApp/BookStack/pull/1111). ([#1111](https://github.com/BookStackApp/BookStack/pull/1111))
+* Added option to disable LDAPS Certificate Validation. Thanks to [@christophert](https://github.com/BookStackApp/BookStack/pull/1096).  ([#1065](https://github.com/BookStackApp/BookStack/issues/1065))
+* Added testing coverage to user avatar fetching. ([#1193](https://github.com/BookStackApp/BookStack/issues/1193))
+([#1096](https://github.com/BookStackApp/BookStack/pull/1096))
+* Updated times in page exports to use absolute time formats instead of relative formats.
+* Updated "Move" operations so that "Delete" permissions are required on the item being moved. ([#1200](https://github.com/BookStackApp/BookStack/issues/1200))
+* Updated page preview/search system to prevent leaks in included content when permissions are set on included content. ([#1178](https://github.com/BookStackApp/BookStack/issues/1178))
+* Re-enabled missing plaintext copies on system-generated emails. ([#1182](https://github.com/BookStackApp/BookStack/issues/1182))
+* Improved 'SQL' code block highlighting. ([#1181](https://github.com/BookStackApp/BookStack/issues/1181))
+* Simplified ".env.example" file and created full example version. ([#1205](https://github.com/BookStackApp/BookStack/pull/1205))
+* Fixed WYSIWYG editor issue that could reset cursor position on code block click. ([#1162](https://github.com/BookStackApp/BookStack/issues/1162)).
+
+### Next Steps
+
+Throughout this last release cycle I've been playing with a new design based upon a lot of feedback
+provided via issues on GitHub. You can see preview along with the goals of this design update [on the pull request](https://github.com/BookStackApp/BookStack/pull/1153). This will be my personal primary focus for the time being.
+
+----
+
+<span style="font-size: 0.8em;opacity:0.8;">Header Image Credits: &nbsp; <a style="background-color:black;color:white;text-decoration:none;padding:4px 6px;font-family:-apple-system, BlinkMacSystemFont, &quot;San Francisco&quot;, &quot;Helvetica Neue&quot;, Helvetica, Ubuntu, Roboto, Noto, &quot;Segoe UI&quot;, Arial, sans-serif;font-size:12px;font-weight:bold;line-height:1.2;display:inline-block;border-radius:3px" href="https://unsplash.com/@impatrickt?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge" target="_blank" rel="noopener noreferrer" title="Download free do whatever you want high-resolution photos from Patrick Tomasso"><span style="display:inline-block;padding:2px 3px"><svg xmlns="http://www.w3.org/2000/svg" style="height:12px;width:auto;position:relative;vertical-align:middle;top:-2px;fill:white" viewBox="0 0 32 32"><title>unsplash-logo</title><path d="M10 9V0h12v9H10zm12 5h10v18H0V14h10v9h12v-9z"></path></svg></span><span style="display:inline-block;padding:2px 3px">Patrick Tomasso</span></a></span>
diff --git a/content/blog/beta-release-v0-25-1.md b/content/blog/beta-release-v0-25-1.md
new file mode 100644 (file)
index 0000000..098a4ae
--- /dev/null
@@ -0,0 +1,43 @@
++++
+categories = ["Releases"]
+tags = ["Releases"]
+title = "Beta Release v0.25.1"
+date = 2019-01-20T16:30:00Z
+author = "Dan Brown"
+image = "/images/blog-cover-images/winter-annie-spratt.jpg"
+description = "v0.25.1 patches some bugs in addition to bringing support for s3 compatible services"
+slug = "beta-release-v0-25-1"
+draft = false
++++
+
+Soon after the v0.25 release last weekend we have the v0.25.1 patch release to fix some bugs, add support for s3 compatible services and to prepare for the upcoming 
+removal of the Google Plus API.
+
+* [Update instructions](https://www.bookstackapp.com/docs/admin/updates)
+* [GitHub release page](https://github.com/BookStackApp/BookStack/releases/tag/v0.25.1)
+
+
+### Google Sign-in Changes
+
+Google [have announced](https://developers.google.com/+/api-shutdown) the shut-down of Google+ API's which is what BookStack was using for it's Google authentication option.
+The API's are due to be shut down on March the 7th, With API failures starting from January the 28th.
+
+In this release the API calls made no longer make use of the Google+ API so all you'll need to do is to update your BookStack instance to continue using the Google sign-in option. You should be able to continue using the same OAuth credentials as before.
+
+### S3 Compatible Service Support
+
+This release introduces some configuration changes that make it possible to use BookStack with s3 compatible services such as Minio or Ceph (With a s3-compatible gateway). 
+Details of this can be found [in the docs here](/docs/admin/upload-config/#non-amazon-s3-compatible-services).
+
+### Full List of Changes
+
+* Updated revision listing so dates can show localised if the relevant locale is installed on the host system. ([#1214](https://github.com/BookStackApp/BookStack/issues/1214))
+* Added support for s3 compatible storage services such as Minio. ([#1195](https://github.com/BookStackApp/BookStack/issues/1195), [#1192](https://github.com/BookStackApp/BookStack/issues/1192))
+* Updated Google authentication to not use Google+ API. ([#1190](https://github.com/BookStackApp/BookStack/issues/1190))
+* Fixed "Rubber banding" effect when scrolling in certain conditions when comments were disabled. ([#1218](https://github.com/BookStackApp/BookStack/issues/1218))
+* Fixed isssue causing only show a single page to show when using Firefox's print option. ([#1211](https://github.com/BookStackApp/BookStack/issues/1211))
+
+
+----
+
+<span style="font-size: 0.8em;opacity:0.8;">Header Image Credits: &nbsp; <a style="background-color:black;color:white;text-decoration:none;padding:4px 6px;font-family:-apple-system, BlinkMacSystemFont, &quot;San Francisco&quot;, &quot;Helvetica Neue&quot;, Helvetica, Ubuntu, Roboto, Noto, &quot;Segoe UI&quot;, Arial, sans-serif;font-size:12px;font-weight:bold;line-height:1.2;display:inline-block;border-radius:3px" href="https://unsplash.com/@anniespratt?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge" target="_blank" rel="noopener noreferrer" title="Download free do whatever you want high-resolution photos from Annie Spratt"><span style="display:inline-block;padding:2px 3px"><svg xmlns="http://www.w3.org/2000/svg" style="height:12px;width:auto;position:relative;vertical-align:middle;top:-2px;fill:white" viewBox="0 0 32 32"><title>unsplash-logo</title><path d="M10 9V0h12v9H10zm12 5h10v18H0V14h10v9h12v-9z"></path></svg></span><span style="display:inline-block;padding:2px 3px">Annie Spratt</span></a></span>
diff --git a/content/blog/beta-release-v0-25-2.md b/content/blog/beta-release-v0-25-2.md
new file mode 100644 (file)
index 0000000..de49f27
--- /dev/null
@@ -0,0 +1,61 @@
++++
+categories = ["Releases"]
+tags = ["Releases"]
+title = "Project Roadmap & Beta Release v0.25.2"
+date = 2019-03-10T13:45:00Z
+author = "Dan Brown"
+image = "/images/blog-cover-images/mountains-eberhard-grossgasteiger.jpg"
+description = "We have another patch release for BookStack v0.25 to fix bugs, update translations & to add some new configuration options."
+slug = "beta-release-v0-25-2"
+draft = false
++++
+
+We have another patch release for BookStack v0.25 to fix bugs, update translations & to add some new configuration options. We now also have a project roadmap to provide some visibility of where the BookStack is going.
+
+* [Update instructions](https://www.bookstackapp.com/docs/admin/updates)
+* [GitHub release page](https://github.com/BookStackApp/BookStack/releases/tag/v0.25.2)
+
+### Project Roadmap
+
+Visibility of BookStack's direction was becoming increasingly requested as more people get involved with the project. To provide some insight into the development plan, a new section has been added to the project readme to outline a high-level roadmap for BookStack:
+
+**[BookStack Roadmap](https://github.com/BookStackApp/BookStack#road-map)**
+
+Additionally, the release process has been detailed to provide insight into how BookStack releases are organised and how releases are versioned:
+
+
+**[BookStack Release Process](https://github.com/BookStackApp/BookStack#release-versioning--process)**
+
+
+### Code Block Updates
+
+Code blocks in BookStack have been updated to provide syntax highlighting for two new popular languages: Lua & PowerShell.
+
+![CodeBlock LUA PoweShell](/images/2019/03/codeblock_lua_powershell.png)
+
+### Language Updates
+
+* German translations now include translations for shelves. Thanks to [@Xiphoseer](https://github.com/BookStackApp/BookStack/pull/1272). ([#1272](https://github.com/BookStackApp/BookStack/pull/1272)).
+* Dutch translations will now show the current password hint information. Thanks to [@maantje](https://github.com/BookStackApp/BookStack/pull/1314). ([#1314](https://github.com/BookStackApp/BookStack/pull/1314))
+
+### Full List of Changes
+
+* Added PowerShell code highlighting to code blocks. Thanks to [@christophert](https://github.com/BookStackApp/BookStack/pull/1263). ([#1263](https://github.com/BookStackApp/BookStack/pull/1263), [#1040](https://github.com/BookStackApp/BookStack/issues/1040))
+* Added LUA code highlighting to code blocks. ([#1223](https://github.com/BookStackApp/BookStack/issues/1223))
+* Added LDAP option to set a custom "Display Name" property. Thanks to [@dfanara](https://github.com/BookStackApp/BookStack/pull/1317). ([#1317](https://github.com/BookStackApp/BookStack/pull/1317), [#1306](https://github.com/BookStackApp/BookStack/issues/1306))
+* Added possibility to set a password for Redis connections. ([#1283](https://github.com/BookStackApp/BookStack/issues/1283))
+* Updated front-end file upload size limit to be configurable. ([#1293](https://github.com/BookStackApp/BookStack/issues/1293))
+* Updated Dutch translations for the password hint. Thanks to [@maantje](https://github.com/BookStackApp/BookStack/pull/1314). ([#1314](https://github.com/BookStackApp/BookStack/pull/1314))
+* Updated image paste/drop uploads to properly set page relations so image permissions are active. ([#1287](https://github.com/BookStackApp/BookStack/issues/1287))
+* Updated German translations to include translations for shelves. Thanks to [@Xiphoseer](https://github.com/BookStackApp/BookStack/pull/1272). ([#1272](https://github.com/BookStackApp/BookStack/pull/1272))
+* Updated permissions checked for "Page Copy" function to be more accurate to what permissions are actually required. Thanks to [@mark-james](https://github.com/BookStackApp/BookStack/pull/1202). ([#1202](https://github.com/BookStackApp/BookStack/pull/1202), [#1199](https://github.com/BookStackApp/BookStack/issues/1199))
+* Updated permissions checked for the "Shelves" header item to be visible. Now takes into account custom shelve-level permissions. ([#1201](https://github.com/BookStackApp/BookStack/issues/1201))
+* Fixed bug where using alignment properties could break tables. ([#1284](https://github.com/BookStackApp/BookStack/issues/1284))
+* Fixed issue where default system language would not be reflected when viewing another user's profile. ([#1316](https://github.com/BookStackApp/BookStack/issues/1316))
+* Fixed issue where image-manager tooltips could be cut-off. Thanks to [@Abijeet](https://github.com/BookStackApp/BookStack/pull/1238). ([#1238](https://github.com/BookStackApp/BookStack/pull/1238), [#1186](https://github.com/BookStackApp/BookStack/issues/1186))
+
+
+
+----
+
+<span style="font-size: 0.8em;opacity:0.8;">Header Image Credits: &nbsp; <a style="background-color:black;color:white;text-decoration:none;padding:4px 6px;font-family:-apple-system, BlinkMacSystemFont, &quot;San Francisco&quot;, &quot;Helvetica Neue&quot;, Helvetica, Ubuntu, Roboto, Noto, &quot;Segoe UI&quot;, Arial, sans-serif;font-size:12px;font-weight:bold;line-height:1.2;display:inline-block;border-radius:3px" href="https://unsplash.com/@eberhardgross?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge" target="_blank" rel="noopener noreferrer" title="Download free do whatever you want high-resolution photos from eberhard grossgasteiger"><span style="display:inline-block;padding:2px 3px"><svg xmlns="http://www.w3.org/2000/svg" style="height:12px;width:auto;position:relative;vertical-align:middle;top:-2px;fill:white" viewBox="0 0 32 32"><title>unsplash-logo</title><path d="M10 9V0h12v9H10zm12 5h10v18H0V14h10v9h12v-9z"></path></svg></span><span style="display:inline-block;padding:2px 3px">eberhard grossgasteiger</span></a></span>
diff --git a/content/blog/beta-release-v0-25-5.md b/content/blog/beta-release-v0-25-5.md
new file mode 100644 (file)
index 0000000..cfa328b
--- /dev/null
@@ -0,0 +1,64 @@
++++
+categories = ["Releases"]
+tags = ["Releases"]
+title = "Beta Security Releases v0.25.[3,4,5] & Our Security Process"
+date = 2019-03-24T20:15:00Z
+author = "Dan Brown"
+image = "/images/blog-cover-images/locks-ruben-bagues.jpg"
+description = "Over the last week some security issues have been raised regarding file uploads. BookStack v0.25.3, v0.25.4 & v0.25.5 have been released to cover these issues, in addition to bringing some translation updates."
+slug = "beta-release-v0-25-5"
+draft = false
++++
+
+Over the last week some security issues have been raised regarding file uploads. BookStack v0.25.3, v0.25.4 & v0.25.5 have been released to cover these issues, in addition to bringing some translation updates.
+
+* [Update instructions](https://www.bookstackapp.com/docs/admin/updates)
+* GitHub release pages:
+    * [v0.25.3](https://github.com/BookStackApp/BookStack/releases/tag/v0.25.3)
+    * [v0.25.4](https://github.com/BookStackApp/BookStack/releases/tag/v0.25.4)
+    * [v0.25.5](https://github.com/BookStackApp/BookStack/releases/tag/v0.25.5)
+
+### Security Issues Found
+
+First of all, A massive thanks to [@inc0x0](https://twitter.com/inc0x0) for raising these security issues and providing guidance.
+
+It was found that BookStack could possibly accept PHP files via the image upload endpoint which could then be called externally to perform malicious activity. This is particularly an issue in environments where untrusted users have the necessary permissions to upload images. BookStack v0.25.3 was released to directly cover this scenario.
+
+In the same manner as above it was found that PHP files, with a non-standard PHP extensions such as `.phtml`, could be uploaded and then executed on some web-servers. BookStack v0.25.4 added a file-extension whitelist to only allow expected image file types to be uploaded to BookStack.
+
+Although not so common, Some web-servers can utilise files with double extensions, such as `.php.en`. BookStack v0.25.5 was released to prevent images with multiple extensions from being uploaded. In addition, v0.25.5 will also use random file names for attachment files for extra security. 
+
+Please consider that malicious exploitation of this vulnerability may have allowed access to other files on your server that the PHP process has access to, Including your BookStack `.env` file, so consider updating any passwords or keys if you think this had a possibility of being exploited on your instance. The vulnerable image upload endpoints would require a user to log-in by default but if your instance contained untrusted users or if permissions were changed to allow uploads by any visitors then please consider that this may have been exploited.
+
+### Security Process Updates
+
+When enacting upon the above security issues I noticed that the processes for security concerns could be improved. Details of how to report a sensitive security issue can now be found in the [project readme](https://github.com/BookStackApp/BookStack/tree/master#security).
+
+For the purpose of notifying admins on security issues, A new mailing list has been created which you can [subscribe to here](http://eepurl.com/glIh8z). 
+
+### Translations
+
+BookStack v0.25.5 includes the following translation updates:
+
+* Added Czech translations. Thanks to [@cima](https://github.com/BookStackApp/BookStack/pull/1347). ([#1347](https://github.com/BookStackApp/BookStack/pull/1347))
+* Updated russian translations . Thanks to [@agvol](https://github.com/BookStackApp/BookStack/pull/1348). ([#1348](https://github.com/BookStackApp/BookStack/pull/1348))
+* Updated 'Spanish Argentina' translations. Thanks to [@leomartinez](https://github.com/BookStackApp/BookStack/pull/1327). ([#1327](https://github.com/BookStackApp/BookStack/pull/1327))
+
+### Full List of Changes
+
+These releases contain the following fixes and changes:
+
+* Added Czech translations. Thanks to [@cima](https://github.com/BookStackApp/BookStack/pull/1347). ([#1347](https://github.com/BookStackApp/BookStack/pull/1347))
+* Updated russian translations . Thanks to [@agvol](https://github.com/BookStackApp/BookStack/pull/1348). ([#1348](https://github.com/BookStackApp/BookStack/pull/1348))
+* Updated 'Spanish Argentina' translations. Thanks to [@leomartinez](https://github.com/BookStackApp/BookStack/pull/1327). ([#1327](https://github.com/BookStackApp/BookStack/pull/1327))
+* Added prevention for PHP files via the image upload endpoint.
+* Added whitelist for the extensions on uploaded image files to prevent other, malicious, filetypes being uploaded.
+* Prevented image files with multiple extensions being uploaded via the image upload endpoint.
+* Updated attachment storage to use random file names to help prevent attacks via file name.
+
+
+
+
+----
+
+<span style="font-size: 0.8em;opacity:0.8;">Header Image Credits: &nbsp; <a style="background-color:black;color:white;text-decoration:none;padding:4px 6px;font-family:-apple-system, BlinkMacSystemFont, &quot;San Francisco&quot;, &quot;Helvetica Neue&quot;, Helvetica, Ubuntu, Roboto, Noto, &quot;Segoe UI&quot;, Arial, sans-serif;font-size:12px;font-weight:bold;line-height:1.2;display:inline-block;border-radius:3px" href="https://unsplash.com/@rubavi78?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge" target="_blank" rel="noopener noreferrer" title="Download free do whatever you want high-resolution photos from Rubén Bagüés"><span style="display:inline-block;padding:2px 3px"><svg xmlns="http://www.w3.org/2000/svg" style="height:12px;width:auto;position:relative;vertical-align:middle;top:-2px;fill:white" viewBox="0 0 32 32"><title>unsplash-logo</title><path d="M10 9V0h12v9H10zm12 5h10v18H0V14h10v9h12v-9z"></path></svg></span><span style="display:inline-block;padding:2px 3px">Rubén Bagüés</span></a></span>
diff --git a/content/blog/beta-release-v0-26-0.md b/content/blog/beta-release-v0-26-0.md
new file mode 100644 (file)
index 0000000..d8b06ae
--- /dev/null
@@ -0,0 +1,202 @@
++++
+categories = ["Releases"]
+tags = ["Releases"]
+title = "Beta Release v0.26.0"
+date = 2019-05-06T17:00:00Z
+author = "Dan Brown"
+image = "/images/blog-cover-images/paint-andrian-valeanu.jpg"
+description = "A design update comes to BookStack which includes a whole bunch of user experience improvements and much better mobile usability"
+slug = "beta-release-v0-26-0"
+draft = false
++++
+
+After a long development cycle BookStack v0.26 is finally here, bringing a refreshed design that includes new
+functionality while providing a much better mobile experience.
+
+* [Update instructions](https://www.bookstackapp.com/docs/admin/updates)
+* [GitHub release page](https://github.com/BookStackApp/BookStack/releases/tag/v0.26.0)
+
+
+Before jumping into all the changes, there's a few things to note before upgrading:
+
+**Internet Explorer Support**
+
+IE11 Support has now been dropped. We *may* support any critical issues for view-only scenarios otherwise please use a modern browser.
+
+**Translations**
+
+Since many interfaces and lines of text have been updated, It may take a little while for some translations to catch-up. Expect to see more English text than usual if you're using a non-English language option.
+
+**Images**
+
+Due to changes how images are handled, as detailed below, some types of images may become inaccessible. Old logo images will be deleted upon change. Unused Book & Shelf cover images, in addition to user profile images, will be become inaccessible after the update so you may want to delete them before upgrading.
+
+**Security**
+
+On previous versions of BookStack it was possible for users to insert JavaScript via the Markdown editor using *"on\*"* html event attributes. These will now be removed on page render unless you have set *ALLOW_CONTENT_SCRIPTS=true*. If untrusted users have access to your BookStack instance you may want to scan for " on" in the html column of the pages table to identify any malicious intent. Thanks to [@Xiphoseer](https://github.com/Xiphoseer) for reporting.
+
+### Design Update
+
+Design changes have been applied to every single view in BookStack. The aims of this design update were as follows:
+
+- Improve design consistency and feature usage throughout application.
+- Improve the mobile experience.
+- Provide a more modern, less "stock", feel.
+- Clean-up the current colour-scheme for easier future customizability.
+- Lessen the usage of glaring book/chapter & page colours.
+- Look to add UI efficiency tweaks.
+
+I'm happy to say I think we've managed to meet all those initial aims.
+Here's a dig into many of the changes:
+
+#### Mobile Experience
+
+The core mobile experience has been a main focus for this update.
+Previously BookStack would kind of respond to work on smaller devices but a lot of vertical space would be used and the interface would look very busy.
+
+*v0.25 on the left, v0.26 on the right.*
+
+<img src="/images/2019/05/design_update_mobile.png" class="no-border" alt="Design update mobile changes">
+
+The header has now been updated to properly collapse down on mobile to reduce used vertical space.
+The old side drawer, containing extra details of the current view, has instead changed to a tabbed interface to save on precious horizontal space.
+
+The editing experience has been reworked to ensure its usable on mobile:
+
+*v0.25 on the left, v0.26 on the right.*
+
+<img src="/images/2019/05/design_update_mobile_editing.png" class="no-border" alt="Design update mobile editing changes">
+
+Unfortunately, there are still issues with being able to edit page content on iOS, which we will continue to look into, but editing now appears to be fully functional on Android devices.
+
+#### Shelf Improvements
+
+This design update provided an opportunity to look at how shelves could become more unique & functional.
+To start with, the shelves list view has been overhauled:
+
+![Shelves listing](/images/2019/05/shelves_list.png)
+
+For each shelf shown, contained books are listed below in columns, somewhat imitating real-life bookshelves, allowing quick visibility of their contents.
+
+To speed up the creation flow, A "New Book" button is now available when viewing a shelf to accelerate the creation process:
+
+![Create book from shelf](/images/2019/05/shelf_create_book.png)
+
+This reduces the number of steps needed to create a new book within a shelf from about 6 steps to just 2.
+Thanks to [@cw1998](https://github.com/BookStackApp/BookStack/pull/1366) for adding this feature.
+
+For ease of navigation, breadcrumbs will now display the current shelf you navigated through:
+
+![Smarter breadcrumbs with shelves](/images/2019/05/smart_breadcrumbs.png)
+
+If BookStack thinks you've navigated via a shelf, the leftmost breadcrumb will show as the shelf overview page otherwise it will default back to the book overview page.
+
+#### Navigation Enhancements
+
+Some navigational enhancements have been applied to allow more efficient traversal of your content in BookStack.
+For the books and shelves list pages, it's now possible to sort the lists by name, created date or updated date:
+
+![Books and shelves list sorting](/images/2019/05/listing_sort.png)
+
+You can change the ordering of the sort to be ascending or descending by clicking the arrow that sits beside the sort drop-down.
+
+In addition to the inclusion of shelves, as mentioned above, breadcrumbs have been powered up with more navigation abilities.
+You can now click the arrows between the crumbs to jump to other items at that level of the hierarchy:
+
+![Breadcrumb Navigation](/images/2019/05/breadcrumb_navigation.png)
+
+You can even search within the drop-downs to quickly find items at each level.
+This addition provides an easy way to quickly jump between higher levels of the hierarchy without even needing to leave the current page.
+
+#### Improved Admin Experience
+
+On the administration side of things, all options and views have received a much needed clean-up.
+Settings are now much better organised and spaced out. Additional hint text has been added where needed to provide extra information & context for various options.
+
+![Admin Page Cleanup](/images/2019/05/admin_page_cleanup.png)
+
+Handling permissions could often be laborious task due to the amount of checkboxes you may have to toggle.
+On such pages, "Toggle All" links have been added for super-quick permission checking:
+
+![Permission Toggles](/images/2019/05/permission_toggle_all.png)
+
+#### Image Selection Changes
+
+For simplicity, and enhanced security, the process for selecting some types of images has changed.
+Profile images, app logo images and book/shelf cover images are now directly selected instead of opening in the image manager.
+
+![Direct Image Selection](/images/2019/05/image_selection_changes.png)
+
+
+#### Book Sort Helpers
+
+To make it easier to sort a book, helpful buttons have been added to perform common sorting operations.
+You can sort by name in addition to created or updated date.
+There are also buttons to move chapters to the start or end of the book.
+For the name & date sort operations, you can press the button a second time to run the sort in the opposite direction.
+
+![Book Sort Helpers](/images/2019/05/book_sort_buttons.png)
+
+#### Profile Page Enhancements
+
+The user profile page has received a few tweaks.
+User-created shelves now show alongside the other content types.
+Links have been added to the "Recently Created" headings for quick searching of content created by the shown user.
+
+![Profile Page Changes](/images/2019/05/profile_page_changes.png)
+
+#### Toggle Details Button
+
+The "Toggle Details" button, shown on the homepage, will now remember its last state so you don't have to click it every time if you prefer details to be visible.
+
+![Toggle Details](/images/2019/05/toggle_details.png)
+
+#### Search Page
+
+The result list on the search page is now a little more compact for efficiency.
+Pages & chapters in the results will now show their parent book, and chapter if applicable, to provide additional context as to where that item sits within your content structure.
+
+![Search Page Crumb](/images/2019/05/search_page_changes.png)
+
+### Full List of Changes
+
+
+* Updated the application design for better mobile functionality and improved general UX. ([#1153](https://github.com/BookStackApp/BookStack/pull/1153))
+* Updated how profile, system & cover images are set & added extra permission checks on image actions.  ([#1410](https://github.com/BookStackApp/BookStack/pull/1410), [#1307](https://github.com/BookStackApp/BookStack/issues/1307), [#1128](https://github.com/BookStackApp/BookStack/issues/1128))
+* Added the possibility to create a book directly within a shelf. Thanks to [@cw1998](https://github.com/BookStackApp/BookStack/pull/1366). ([#1366](https://github.com/BookStackApp/BookStack/pull/1366), [#1260](https://github.com/BookStackApp/BookStack/issues/1260))
+* Added sign-up link to login form and fixed differing name validation on sign-up. Thanks to [@cw1998](https://github.com/BookStackApp/BookStack/pull/1395). ([#1395](https://github.com/BookStackApp/BookStack/pull/1395), [#1239](https://github.com/BookStackApp/BookStack/issues/1239))
+* Added code block syntax highlight for OCaml, Haskell, Rust. Thanks to [@XVilka](https://github.com/BookStackApp/BookStack/pull/1344). ([#1344](https://github.com/BookStackApp/BookStack/pull/1344))
+* Updated page content script escaping logic to strip inline JS event attributes. Thanks to [@Xiphoseer](https://github.com/Xiphoseer) for reporting.
+* Updated revision restore to require confirmation and changed the method from GET so it's less likely to be accidentally triggered. ([#1321](https://github.com/BookStackApp/BookStack/issues/1321))
+* Updated shortcut used for markdown drawing manager to be cross-platform. ([#1228](https://github.com/BookStackApp/BookStack/issues/1228))
+* Updated Swedish translations. Thanks to [@Hambern](https://github.com/BookStackApp/BookStack/pull/1417). ([#1417](https://github.com/BookStackApp/BookStack/pull/1417))
+* Fixed issue where duplicate ID's could sometimes break pages. ([#1393](https://github.com/BookStackApp/BookStack/issues/1393))
+* Fixed issue where user role assignments were not remembered, for roles with a dot in the name, on validation failure. Thanks to [@cw1998](https://github.com/BookStackApp/BookStack/pull/1392). ([#1392](https://github.com/BookStackApp/BookStack/pull/1392), [#1325](https://github.com/BookStackApp/BookStack/issues/1325))
+* Fixed issue where the port would be ignored if a full LDAP server URI was used. ([#1386](https://github.com/BookStackApp/BookStack/pull/1386), [#1278](https://github.com/BookStackApp/BookStack/pull/1278))
+* Dropped IE11 support. ([#1164](https://github.com/BookStackApp/BookStack/issues/1164))
+
+### Next Steps
+
+Since this release includes a lot of design changes I expect there to be a good few fixes, improvements and translation updates to implement over the coming weeks.
+
+**JavaScript Organisation**
+
+I may start having an experimental dig into a new way to organise the JavaScript code BookStack uses.
+BookStack currently bundles pretty much all the JavaScript into single file.
+With the dropping of IE, I'd like to look at going a bit old-school, with most of the JS code being directly on the page and only have a few core global libraries bundled up.
+This would bring the benefit of allowing admins & developers to directly modify parts of the JS without having to install tools or re-bundle the code.
+
+**REST API Authentication**
+
+Once the current redesign has settled, focus will be on the next roadmap item: The REST API.
+In preparation for this, I've opened up a proposal for the primary authentication method to implement which can be found [here on GitHub](https://github.com/BookStackApp/BookStack/issues/1414). This is so any issues or recommendations can be discussed ahead of time since I don't want to rush the choice of authentication.
+
+**Templating**
+
+For the next release I thought it'd be good to look at a highly requested documentation-focused request: Templating. I've put a proposal together [in this comment on GitHub](https://github.com/BookStackApp/BookStack/issues/129#issuecomment-460412403).
+It's a fairly simplistic implementation idea but should provide a benefit to users without having that much extra code/functionality to manage.
+Would be good to get an idea if the proposal would meet people's needs.
+
+----
+
+<span style="font-size: 0.8em;opacity:0.8;">Header Image Credits: &nbsp; <a style="background-color:black;color:white;text-decoration:none;padding:4px 6px;font-family:-apple-system, BlinkMacSystemFont, &quot;San Francisco&quot;, &quot;Helvetica Neue&quot;, Helvetica, Ubuntu, Roboto, Noto, &quot;Segoe UI&quot;, Arial, sans-serif;font-size:12px;font-weight:bold;line-height:1.2;display:inline-block;border-radius:3px" href="https://unsplash.com/@freephotocc?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge" target="_blank" rel="noopener noreferrer" title="Download free do whatever you want high-resolution photos from Andrian Valeanu"><span style="display:inline-block;padding:2px 3px"><svg xmlns="http://www.w3.org/2000/svg" style="height:12px;width:auto;position:relative;vertical-align:middle;top:-2px;fill:white" viewBox="0 0 32 32"><title>unsplash-logo</title><path d="M10 9V0h12v9H10zm12 5h10v18H0V14h10v9h12v-9z"></path></svg></span><span style="display:inline-block;padding:2px 3px">Andrian Valeanu</span></a></span>
diff --git a/content/blog/beta-release-v0-27-0.md b/content/blog/beta-release-v0-27-0.md
new file mode 100644 (file)
index 0000000..892be81
--- /dev/null
@@ -0,0 +1,193 @@
++++
+categories = ["Releases"]
+tags = ["Releases"]
+title = "Beta Release v0.27.0"
+date = 2019-08-31T13:00:00Z
+author = "Dan Brown"
+image = "/images/blog-cover-images/books-eugenio-mazzone.jpg"
+description = "BookStack v0.27 brings faster building with Page Templates, A more accessible interface, a new user invitation flow and much more "
+slug = "beta-release-v0-27-0"
+draft = false
++++
+
+BookStack v0.27 is now available which adds page templates, a new user invitation flow, a more accessible interface and a bunch of under-the-hood changes to provide a better user & developer experience. 
+
+* [Update instructions](https://www.bookstackapp.com/docs/admin/updates)
+* [GitHub release page](https://github.com/BookStackApp/BookStack/releases/tag/v0.27.0)
+
+### Page Templating
+
+It's now possible to define page templates that can be used to speed up and standardise the creation & modification of page content:
+
+<video src="/images/2019/08/page_templates.mp4" muted="true" controls onclick="this.paused ? this.play() : this.pause()"></video>
+
+Templates are simply pages that have been marked as a template in the editor sidebar. Once marked as a template it will show as an available template to any other users that have view permissions of that page template. Clicking the template "card" will replace the your existing editor content, if any, with the page template content. There are also buttons to insert the template content at the top or bottom of your page. Alternatively, It is possible to drag the template "card" into a specific area of the the editor. These actions work in both the default WYSIWYG editor and markdown editor. 
+
+![Page Templates](/images/2019/08/page_templates.png)
+
+Since templates are essentially just specially-marked pages, templates can be organised within books and chapters like any other page. An approach many admins may want to take is to create a new "Templates" book with restricted permissions so anyone can view, and therefore use them as templates, but only certain members can edit. A new "Manage page templates" role permission is now available to designate which roles have the ability to mark a page as a template.
+
+### Accessibility
+
+Accessibility on the web is important yet it is often overlooked; It was definitely something I overlooked in BookStack. For this release I have invested some time learning how we can make BookStack easier to use for those with disabilities. Here's an overview of what's changed:
+
+- Default colors in BookStack have become darker, now meeting WCAG Level A standards, for better readability.
+- Interactive components such as dropdowns, modals & slide-downs can now used properly without a mouse:
+
+<video src="/images/2019/08/header_accessibility.mp4" muted="true" controls onclick="this.paused ? this.play() : this.pause()"></video>
+
+- Descriptions have been set for many elements where context relies upon sight.
+- Main layout HTML tags have been updated to better indicate the purpose of various sections of a page.
+- Styles have been updated to ensure it remains clear which element on the page has focus.
+- Icons have been tagged so they're not mistaken for content. 
+
+There's still some work to be done, especially when it comes to the page editors, but this release marks a good start in making the project accessible to all. The project [readme on GitHub](https://github.com/BookStackApp/BookStack/#-accessibility) has been updated with the accessibility standards we're aiming for along with some details to show that we're open to issues regarding accessibility.
+
+### New User Invitation Flow
+
+A new way to onboard users to BookStack has been implemented. When creating a user, a new option is available to send the user an invite email:
+
+![Invite Flow Option](/images/2019/08/invite_flow_option.png)
+
+This option is selected by default; Unticking it will show the password fields if you'd prefer set the password manually yourself. The new user will then receive an email which will take them on a flow to set their own password and gain access to your BookStack instance. 
+
+![Invite Flow Email](/images/2019/08/invite_flow_email.png)
+
+This new flow should enable admins to onboard new users in a more efficient and secure manner compared to creating accounts then having to share the password via other means.
+
+### Docker Development Environment
+
+To make it easier to get started with BookStack development work, A docker-compose setup has been added to the project. This setup will start a database, start the app and build the JavaScript & CSS assets on change. Note that this is designed for development use only, Not a way to run BookStack for actual use.
+
+Details on using this docker development environment can be [found in the readme here](https://github.com/BookStackApp/BookStack#-development-using-docker).
+
+Thanks to [@timoschwarzer](https://github.com/BookStackApp/BookStack/pull/1504) for this feature.
+
+### Under-the-Hood Changes
+
+This release includes a lot of under-the-hood changes that work towards a more efficient system in addition to a cleaner codebase. 
+
+##### jQuery Removal
+
+On the front-end, jQuery has been removed and any of the jQuery-reliant libraries that we were using have been swapped to either native elements or lean alternatives. This means that if you have added any jQuery dependant custom code you'll also need to bring in the jQuery library yourself too.
+
+##### App Colours
+
+The way many theme colors are implemented has been revised to use CSS variables. This makes it much easier to customize the colors used for pages, chapters, books & shelves. This is an example of a customizing these colors, which can be placed directly in the "Custom HTML Head Content" setting in BookStack:
+
+```html
+<style>
+    :root {
+        --color-page: #a242d7;
+        --color-page-draft: #cfb732;
+        --color-chapter: #db5382;
+        --color-book: #534ecb;
+        --color-bookshelf: #3eeaf0;
+    }
+</style>
+```
+
+##### URL System Rewrite
+
+The system used to generate URLs has been re-written to better extend the Laravel framework instead of overriding it. The changes here should lead to more reliable URL generation, especially in situations where BookStack redirects you to locations you had visited or tried to visit before (Login redirects or back buttons).
+
+##### Framework Configuration Folder Move
+
+BookStack previously had the folder `config/` which contained internal framework configuration that was only intended to be modified by BookStack, not by end users of BookStack. This folder has been moved to `app/Config/` so it's not instantly visible on install to help avoid confusion in where configuration changes should be made.
+
+##### Separate Images and Attachment File Store
+
+The file storage system has been updated to allow images and attachments to be stored in separate locations. You can use the below new `.env` options to configure this otherwise the `STORAGE_TYPE` option will still control both by default.
+
+```bash
+ # Image storage system to use 
+ # Defaults to the value of STORAGE_TYPE if unset. 
+ # Accepts the same values as STORAGE_TYPE. 
+ STORAGE_IMAGE_TYPE=local 
+  
+ # Attachment storage system to use 
+ # Defaults to the value of STORAGE_TYPE if unset. 
+ # Accepts the same values as STORAGE_TYPE although 'local' will be forced to 'local_secure'. 
+ STORAGE_ATTACHMENT_TYPE=local_secure 
+```
+
+##### Front-End Translation System Restructure
+
+The way translated text is passed to dynamic JavaScript elements has changed so that these are inject directly into the page, instead of there being a background request to `/translations` on each page load. 
+
+##### Markdown Editor Display
+
+The markdown editor preview display has been re-written so that content is rendered within a sandboxed iframe that does not execute JavaScript. This is to help prevent malicious user-inserted JavaScript from running when the editor is opened.
+
+### Translations
+
+Big thanks to members of the community for supplying translations. Since the original v0.26 release we have received the following translation updates:
+
+##### New Languages
+
+* Hungarian. Thanks to [@miles75](https://github.com/BookStackApp/BookStack/pull/1554).
+
+##### Updated Languages
+
+* French. Thanks to [@lucaguindani](https://github.com/BookStackApp/BookStack/pull/1485).
+* German. Thanks to [@danielroehrig-mm](https://github.com/BookStackApp/BookStack/pull/1561).
+* Brazilian Portuguese. Thanks to [@DeehSlash](https://github.com/BookStackApp/BookStack/pull/1534).
+* Swedish. Thanks to [@Hambern](https://github.com/BookStackApp/BookStack/pull/1433).
+* Dutch. Thanks to [@NootoNooto](https://github.com/BookStackApp/BookStack/pull/1437).
+* Russian. Thanks to [@kostefun](https://github.com/BookStackApp/BookStack/pull/1443).
+
+### Discord
+
+Thanks to [@TimmKroe](https://github.com/BookStackApp/BookStack/issues/1442) A BookStack Discord server has been created here:
+
+https://discord.gg/ztkBqR2
+
+If you want to chat about BookStack or want to ask something without creating a GitHub issue feel free to jump into the server.
+
+### Full List of Changes
+
+* Reviewed accessibility of BookStack to move towards WCAG 2.0 Support. ([#1320](https://github.com/BookStackApp/BookStack/issues/1320), [#1476](https://github.com/BookStackApp/BookStack/issues/1476))
+* Added page templating functionality. ([#129](https://github.com/BookStackApp/BookStack/issues/129), [#1527](https://github.com/BookStackApp/BookStack/pull/1527))
+* Added the ability to send a new user a sign-up link where the user can set their own password. ([#316](https://github.com/BookStackApp/BookStack/issues/316))
+* Added docker development environment. Thanks to [@timoschwarzer](https://github.com/BookStackApp/BookStack/pull/1504). ([#1504](https://github.com/BookStackApp/BookStack/pull/1504))
+* Added the ability to set seperate storage types for Images and Attachments. ([#1302](https://github.com/BookStackApp/BookStack/issues/1302))
+* Added Hungarian translations. Thanks to [@miles75](https://github.com/BookStackApp/BookStack/pull/1554). ([#1554](https://github.com/BookStackApp/BookStack/pull/1554), [#1573](https://github.com/BookStackApp/BookStack/pull/1573))
+* Added notice to the "Custom HTML Head Content" setting to advise it does not apply while on the settings page. ([#1144](https://github.com/BookStackApp/BookStack/issues/1144))
+* Updated entity permissions table so it's hidden unless custom permissions are enabled to prevent confusion. Thanks to [@timoschwarzer](https://github.com/BookStackApp/BookStack/pull/1505). ([#1505](https://github.com/BookStackApp/BookStack/pull/1505))
+* Updated French translations. Thanks to [@lucaguindani](https://github.com/BookStackApp/BookStack/pull/1485). ([#1485](https://github.com/BookStackApp/BookStack/pull/1485))
+* Updated German translations. Thanks to [@danielroehrig-mm](https://github.com/BookStackApp/BookStack/pull/1561). ([#1561](https://github.com/BookStackApp/BookStack/pull/1561))
+* Updated Brazilian Portuguese translations. Thanks to [@DeehSlash](https://github.com/BookStackApp/BookStack/pull/1534). ([#1534](https://github.com/BookStackApp/BookStack/pull/1534))
+* Updated HTML code of base templates with locale definition. Thanks to [@kostasdizas](https://github.com/BookStackApp/BookStack/pull/1486). ([#1486](https://github.com/BookStackApp/BookStack/pull/1486))
+* Updated the debug bar so it does not show unless explicitly enabled. ([#1508](https://github.com/BookStackApp/BookStack/issues/1508))
+* Updated entity colors so they can be easily overridden.
+* Updated page navigation so full headings are included in the output but then truncated via CSS which can be overridden. ([#1206](https://github.com/BookStackApp/BookStack/issues/1206))
+* Updated markdown editor to render the preview in a sandboxed iframe that does not run JavaScript.  ([#1531](https://github.com/BookStackApp/BookStack/issues/1531)).
+* Re-wrote URL generation system to avoid incorrect redirects occurring during certain actions such as login and list view change. ([#1536](https://github.com/BookStackApp/BookStack/issues/1536), [#1459](https://github.com/BookStackApp/BookStack/issues/1459))
+* Made it possible to run phpunit via the composer-installed copy. ([#1555](https://github.com/BookStackApp/BookStack/issues/1555))
+* Moved 'config' directory into 'app' directory to avoid confusion. ([#1506](https://github.com/BookStackApp/BookStack/issues/1506))
+* Redesigned front-end translation system to prevent an addition HTTP call on each page load. ([#1258](https://github.com/BookStackApp/BookStack/issues/1258))
+* Fixed issue causing main menu to be hidden by the page editor at certain widths. ([#1556](https://github.com/BookStackApp/BookStack/issues/1556))
+* Fixed missing word in social account description text. Thanks to [@bjubes](https://github.com/BookStackApp/BookStack/pull/1517). ([#1517](https://github.com/BookStackApp/BookStack/pull/1517))
+* Fixed print CSS to work with the recent design changes. ([#1472](https://github.com/BookStackApp/BookStack/issues/1472))
+* Fixed sidebar layout issues on mid-level screen sizes. ([#1434](https://github.com/BookStackApp/BookStack/issues/1434))
+* Fixed issue that prevented scrolling in the WYSIWYG editor on iOS devices. ([#1058](https://github.com/BookStackApp/BookStack/issues/1058))
+* Fixed issue where multi-byte characters would not render correctly in the sidebar. ([#1172](https://github.com/BookStackApp/BookStack/issues/1172))
+* Fixed incorrect page navigation indentation. ([#542](https://github.com/BookStackApp/BookStack/issues/542))
+* Removed use of babel and css autoprefixer from dev build system for faster builds. ([#1468](https://github.com/BookStackApp/BookStack/issues/1468))
+* Removed jQuery and replaced jQuery-based libraries.
+
+### Framework & PHP Version Change
+
+Just as an advanced warning we'll likely be upgrading Laravel, the framework used in BookStack, to version 6 which will cause a change in the PHP version requirement for BookStack. The minimum required version of PHP will be 7.2 compared to the current minimum requirement of 7.0.5. We'll be putting some documentation together to help manage this change but it will likely mean some manual config changes for many BookStack users. [Discussion about this can be found here](https://github.com/BookStackApp/BookStack/issues/1600).
+
+### Next Steps
+
+Version v0.28 will start the work to implement the API, which is the next item on the [Road Map](https://github.com/BookStackApp/BookStack#%EF%B8%8F-road-map) to tackle. Don't expect full API completion, It'll be more about setting the underlying framework & systems to support it along with maybe a single set of endpoints so we can essentially release a preview to get feedback before expanding it out fully.
+
+An initial SAML auth implementation has been provided by [@Xiphoseer](https://github.com/BookStackApp/BookStack/pull/1576) so that will be reviewed and hopefully merged in for the next release.
+
+I've been thinking about migrating the application styles from SCSS to standard CSS within blade template files. You can [find my thinking on this here](https://github.com/BookStackApp/BookStack/issues/1607). This idea would then be to do something similar in the future with the JavaScript code-base to really open up the customization and tweakability opportunities to those that desire it.
+
+----
+
+<span style="font-size: 0.8em;opacity:0.8;">Header Image Credits: &nbsp; <a style="background-color:black;color:white;text-decoration:none;padding:4px 6px;font-family:-apple-system, BlinkMacSystemFont, &quot;San Francisco&quot;, &quot;Helvetica Neue&quot;, Helvetica, Ubuntu, Roboto, Noto, &quot;Segoe UI&quot;, Arial, sans-serif;font-size:12px;font-weight:bold;line-height:1.2;display:inline-block;border-radius:3px" href="https://unsplash.com/@eugi1492?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge" target="_blank" rel="noopener noreferrer" title="Download free do whatever you want high-resolution photos from Eugenio Mazzone"><span style="display:inline-block;padding:2px 3px"><svg xmlns="http://www.w3.org/2000/svg" style="height:12px;width:auto;position:relative;vertical-align:middle;top:-2px;fill:white" viewBox="0 0 32 32"><title>unsplash-logo</title><path d="M10 9V0h12v9H10zm12 5h10v18H0V14h10v9h12v-9z"></path></svg></span><span style="display:inline-block;padding:2px 3px">Eugenio Mazzone</span></a></span>
diff --git a/content/blog/beta-release-v0-28-0.md b/content/blog/beta-release-v0-28-0.md
new file mode 100644 (file)
index 0000000..5075d52
--- /dev/null
@@ -0,0 +1,250 @@
++++
+categories = ["Releases"]
+tags = ["Releases"]
+title = "Beta Release v0.28.0"
+date = 2020-02-03T21:00:00Z
+author = "Dan Brown"
+image = "/images/blog-cover-images/books-radu-marcusu.jpg"
+description = "Our first 2020 release arrives with some great new features such as an initial API implementation and SAML2 authentication alongside further new customisation options"
+slug = "beta-release-v0-28-0"
+draft = false
++++
+
+Our first 2020 release arrives with some great new features such as an initial API implementation and SAML2 authentication alongside further new customisation options.
+
+* [Update instructions](https://www.bookstackapp.com/docs/admin/updates)
+* [GitHub release page](https://github.com/BookStackApp/BookStack/releases/tag/v0.28.0)
+
+**This release increases the minimum supported PHP version from 7.0.5 to 7.2. Please view the "Update instructions" page above for more details.**
+
+### Initial REST API Implementation
+
+The foundations for the API have been constructed as part of this release. This is intended to be a limited trial to ensure the core work and API formats function as required, so only a limited set of endpoints that cover basic "book" CRUD operations are available at this time.
+
+A new "Access system API" role permission has been added to BookStack which, when assigned to a user, enables access to the API docs and endpoints while also showing the following API tokens section on the user profile screen:
+
+![API User Tokens](/images/2020/02/api-user-tokens.png)
+
+New API tokens can be generated with a custom name, to help label the use of the token, in addition to an expiry date.
+Once created, the token ID and the token secret will be provided. The token secret is hashed in the database so is only shown to the user once.
+
+![API Token Generation](/images/2020/02/api-token-generation.png)
+
+These tokens details can then be used as a HTTP header in API requests to authenticate.
+API requests will have the same permissions as those that belong to the user which generated the token used for the request.
+
+Documentation for the API, including authentication details, can be found built-in to your BookStack instance at the `/api/docs` endpoint.
+The "Access system API" permission is required to view the documentation so ensure you've assigned that before trying to access.
+
+![API Docs](/images/2020/02/api-docs.png)
+
+We'll be extending the available endpoints in future releases.
+I've created an issue on GitHub to collect feedback, regarding the API implementation, so that we can capture any issues or important required changes early on. 
+[This can be found here](https://github.com/BookStackApp/BookStack/issues/1852).
+
+
+### SAML2 Authentication
+
+A SAML2 authentication option is now available to provide a seamless single-sign-on experience.
+Massive thanks to [@Xiphoseer](https://github.com/Xiphoseer) for getting this started.
+This can be used instead of the default Email & Password authentication and it works much like the existing LDAP authentication system.
+
+![BookStack SAML2 Authentication](/images/2020/02/bookstack-saml.png)
+
+A range of options are available to configure the SAML2 authentication, including the option to sync BookStack roles with groups from your Identity Provider.
+You can choose the attributes to use for details, such as email & id, and SAML single-logout is supported.
+
+[Details of configuring your instance to use SAML2 can be found here](/docs/admin/saml2-auth/).
+
+### Theme Colour Customisation
+
+As part of release v0.27 we made the application theme colours more accessible by making them CSS variables. 
+Thanks to [@james-geiger](https://github.com/james-geiger)'s efforts, these have now been made into easy-to-change options within the settings area of BookStack:
+
+![BookStack theme color customisation](/images/2020/02/theme-colors.png)
+
+### Test Email Sending
+
+Email sending could be a tricky aspect to debug in BookStack, made harder by the fact it was difficult to find a way
+to trigger an email send. A new section in the maintenance area of BookStack, thanks to [@timoschwarzer](https://github.com/timoschwarzer), helps alleviate
+this difficulty by allowing you to send test emails at the press of a button:
+
+![BookStack Test Email Sending](/images/2020/02/test-emails.png)
+
+This option will force a test email to be sent out as shown below:
+
+![BookStack Test Email Example](/images/2020/02/bookstack-test-email.png)
+
+### Override Translation Text
+
+It's now possible to override BookStack translation text, used for the BookStack interface, without having to alter
+the original BookStack files:
+
+![BookStack Translation Text Overrides](/images/2020/02/text-overrides.png)
+
+Overrides can be done on a per-translation basis and are performed via the theme system.
+Details of the theme system and the use of text content overrides can be [found in the docs here](/docs/admin/hacking-bookstack/#text-content).
+
+### Under-the-Hood Changes
+
+##### Laravel & PHP
+
+Many changes have taken place to the core code for this release cycle. 
+We've updated the version of Laravel, the framework BookStack is built upon, from 5.5 to 6.12.
+This enforced a change in the minimum supported version of PHP from 7.0.5 to 7.2.
+
+##### Core Refactor
+
+To support the introduction of the API many of the core logic files have been refactored to be simpler and easier to share across front-end and API routes.
+The inclusion of SAML2 authentication prompted a revision of how authentication is handled leading to a cleaner, more consistent approach with better testing coverage.
+
+##### Editor Events
+
+Some editor events are now emitted for both the WYSIWYG and markdown editors. 
+This allows those with some JavaScript knowledge to listen to such events to gain a reference to the underlying configuration and libraries used enabling greater modification opportunities without needing to edit core BookStack code.
+
+[Details of these events can be found here](/docs/admin/hacking-bookstack/#bookstack-editor-events).
+
+### Translations
+
+##### New Translation Management
+
+During this release cycle we have started to use [crowdin](https://crowdin.com/project/bookstack) to help manage translations.
+Massive thanks to crowdin for letting us use the platform for free.
+
+![BookStack Translation Text Overrides](/images/2020/02/crowdin-overview.png)
+
+Crowdin provides a friendly user interface in addition to other great features such as auto-suggestions and change control which makes 
+translation management much easier and ensures better quality of translations overall. 
+
+This effectively negates the need for a translator to be familiar with git and/or GitHub which is a great benefit since it lowers the technical barrier for language contributions.
+
+##### Translation Updates
+
+A big thanks to the following crowdin members for providing the following translation updates:
+
+* Rodrigo Saczuk Niz (rodrigoniz) - _Portuguese, Brazilian_
+* 叫钦叔就好 (254351722) - _Chinese Traditional; Chinese Simplified_
+* aekramer - _Dutch_
+* cipi1965 - _Italian_
+* Mykola Ronik (Mantikor) - _Ukrainian_
+* JachuPL - _Polish_
+* m0uch0 - _Spanish_
+* milesteg - _Hungarian_
+* Beenbag - _German_
+* furkanoyk - _Turkish_
+* nutsflag - _French_
+* Lett3rs - _Danish_
+* Julian (julian.henneberg) - _German; German Informal_
+* Maxim Zalata (zlatin) - _Russian; Ukrainian_
+* 3GNWn - _Danish_
+* dbguichu - _Chinese Simplified_
+* Randy Kim (hyunjun) - _Korean_
+* Francesco M. Taurino (ftaurino) - _Italian_
+* DanielFrederiksen - _Danish_
+* Finn Wessel (19finnwessel6) - _German_
+* Leonardo Mario Martinez (leonardo.m.martinez) - _Spanish, Argentina_
+
+Also a big thanks to the following GitHub members for providing the following translation updates:
+
+* [@johnroyer](https://github.com/BookStackApp/BookStack/pull/1819) - Traditional Chinese 
+* [@artskoczylas](https://github.com/BookStackApp/BookStack/pull/1804) - Polish
+* [@dellamina](https://github.com/BookStackApp/BookStack/pull/1762) - Italian
+* [@qianmengnet](https://github.com/BookStackApp/BookStack/pull/1797) - Simplified Chinese 
+* [@jzoy](https://github.com/BookStackApp/BookStack/pull/1791) - Simplified Chinese
+* [@ististudio](https://github.com/BookStackApp/BookStack/pull/1734) - Korean
+* [@qligier](https://github.com/BookStackApp/BookStack/pull/1695) - French
+* [@leomartinez](https://github.com/BookStackApp/BookStack/pull/1681) - Spanish Argentina
+* [@oykenfurkan](https://github.com/BookStackApp/BookStack/pull/1660) - Turkish
+* [@kostefun](https://github.com/BookStackApp/BookStack/pull/1646) - Russian
+* [@ezzra](https://github.com/BookStackApp/BookStack/pull/1503) - German
+
+### Copy Shelf Permissions Command
+
+A new command is available as of v0.28 which copies the permission settings of a shelf to all child books:
+
+```bash
+# Copy the permission settings of a specified, or all, shelf to their child books
+php artisan bookstack:copy-shelf-permissions --all
+php artisan bookstack:copy-shelf-permissions --slug=my_shelf_slug
+```
+
+Many users requested the ability for books to auto-inherit shelf permissions, which is unfortunately unavailable
+at this time to the complications where books can be in multiple shelves.
+This new command provides a way to semi-emulate that scenario. If desired, you could run the command as a daily cron-job on your system.
+
+### Full List of Changes
+
+##### Additions
+
+* Added a baseline API implementation. ([#1414](https://github.com/BookStackApp/BookStack/issues/1414), [#1826](https://github.com/BookStackApp/BookStack/pull/1826))
+* Added SAML2 authentication option. Thanks to [@Xiphoseer](https://github.com/BookStackApp/BookStack/pull/1576). ([#1787](https://github.com/BookStackApp/BookStack/pull/1787), [#1576](https://github.com/BookStackApp/BookStack/pull/1576), [#276](https://github.com/BookStackApp/BookStack/issues/276))
+* Added ability to override translations with custom text using the theme system. ([#1749](https://github.com/BookStackApp/BookStack/pull/1749))
+* Added the ability to customise application theme colours in settings. Thanks to [@james-geiger](https://github.com/BookStackApp/BookStack/pull/1723). ([#1723](https://github.com/BookStackApp/BookStack/pull/1723), [#1380](https://github.com/BookStackApp/BookStack/issues/1380))
+* Added ability to send test e-mails. Thanks to [@timoschwarzer](https://github.com/BookStackApp/BookStack/pull/1719). ([#1719](https://github.com/BookStackApp/BookStack/pull/1719), [#1696](https://github.com/BookStackApp/BookStack/issues/1696))
+* Added Pascal support for content code blocks. Thanks to [@albergoniSivaf](https://github.com/BookStackApp/BookStack/pull/1730). ([#1730](https://github.com/BookStackApp/BookStack/pull/1730))
+* Added support INI syntax in code editor. Thanks to [@c0shea](https://github.com/BookStackApp/BookStack/pull/1667). ([#1667](https://github.com/BookStackApp/BookStack/pull/1667), [#1648](https://github.com/BookStackApp/BookStack/issues/1648))
+* Added event hooks for core editor setup actions. ([#1721](https://github.com/BookStackApp/BookStack/issues/1721))
+* Added a "Cascade Shelf Permissions" command to copy shelf permission to books. ([#1091](https://github.com/BookStackApp/BookStack/issues/1091))
+* Added ability to fullscreen markdown editor and improved mobile layout. ([#1675](https://github.com/BookStackApp/BookStack/issues/1675))
+
+##### Updates
+
+* Updated focus outline to be a sensible width and consistent across browsers. ([#1738](https://github.com/BookStackApp/BookStack/issues/1738))
+* Updated page deletion flow so the user lands on the parent chapter if existing. ([#1715](https://github.com/BookStackApp/BookStack/issues/1715))
+* Updated book-create-cancel flow to return to shelf if that's the origin. Thanks to [@cw1998](https://github.com/BookStackApp/BookStack/pull/1687). ([#1687](https://github.com/BookStackApp/BookStack/pull/1687), [#1662](https://github.com/BookStackApp/BookStack/issues/1662))
+* Updated collapsible form sections to auto-open if containing validation errors. ([#1693](https://github.com/BookStackApp/BookStack/issues/1693))
+* Updated LDAP functionality to fetch gravatar upon registration. Thanks to [@philjak](https://github.com/BookStackApp/BookStack/pull/1746). ([#1746](https://github.com/BookStackApp/BookStack/pull/1746))
+* Updated the login fields to autofocus on visit. Thanks to [@almandin](https://github.com/BookStackApp/BookStack/pull/1584). ([#1584](https://github.com/BookStackApp/BookStack/pull/1584))
+* Updated PHP code block syntax highlighting to detect, and highlight, PHP code without opening <?php tags. ([#1557](https://github.com/BookStackApp/BookStack/issues/1557))
+* Updated registration settings to indicate non-used settings when LDAP/SAML is active and removed confusing overriding behaviour. ([#1541](https://github.com/BookStackApp/BookStack/issues/1541))
+* Updated image upload handling to prevent generated thumbnails being used if larger than original image. ([#1751](https://github.com/BookStackApp/BookStack/issues/1751))
+* Updated LDAP authentication to allow the attribute, that's stored and used as a unique identifier, to be configurable. ([#592](https://github.com/BookStackApp/BookStack/issues/592))
+* Updated notifications to show a close icon. Thanks to [@SoarinFerret](https://github.com/BookStackApp/BookStack/pull/1845). ([#1845](https://github.com/BookStackApp/BookStack/pull/1845), [#1525](https://github.com/BookStackApp/BookStack/issues/1525))
+* Updated maintenance page to link to GitHub release page. Thanks to [@DeftNerd](https://github.com/BookStackApp/BookStack/pull/1462). ([#1462](https://github.com/BookStackApp/BookStack/pull/1462))
+* Updated codeblocks so white-space is not trimmed. ([#1771](https://github.com/BookStackApp/BookStack/issues/1771))
+
+##### Translations
+
+* Updated Traditional Chinese translations. Thanks to [@johnroyer](https://github.com/BookStackApp/BookStack/pull/1819). ([#1819](https://github.com/BookStackApp/BookStack/pull/1819))
+* Updated Polish translations. Thanks to [@artskoczylas](https://github.com/BookStackApp/BookStack/pull/1804). ([#1804](https://github.com/BookStackApp/BookStack/pull/1804))
+* Updated Italian translations. Thanks to [@dellamina](https://github.com/BookStackApp/BookStack/pull/1762). ([#1762](https://github.com/BookStackApp/BookStack/pull/1762))
+* Updated Simplified Chinese translations. Thanks to [@qianmengnet](https://github.com/BookStackApp/BookStack/pull/1797) and [@jzoy](https://github.com/BookStackApp/BookStack/pull/1791). ([#1797](https://github.com/BookStackApp/BookStack/pull/1797), [#1791](https://github.com/BookStackApp/BookStack/pull/1791))
+* Updated Korean translations. Thanks to [@ististudio](https://github.com/BookStackApp/BookStack/pull/1734). ([#1734](https://github.com/BookStackApp/BookStack/pull/1734))
+* Updated French translations. Thanks to [@qligier](https://github.com/BookStackApp/BookStack/pull/1695). ([#1695](https://github.com/BookStackApp/BookStack/pull/1695))
+* Updated 'Spanish Argentina' translations. Thanks to [@leomartinez](https://github.com/BookStackApp/BookStack/pull/1681). ([#1681](https://github.com/BookStackApp/BookStack/pull/1681))
+* Updated Turkish translations. Thanks to [@oykenfurkan](https://github.com/BookStackApp/BookStack/pull/1660). ([#1660](https://github.com/BookStackApp/BookStack/pull/1660))
+* Updated Russian translations. Thanks to [@kostefun](https://github.com/BookStackApp/BookStack/pull/1646). ([#1646](https://github.com/BookStackApp/BookStack/pull/1646))
+* Updated German translations. Thanks to [@ezzra](https://github.com/BookStackApp/BookStack/pull/1503). ([#1503](https://github.com/BookStackApp/BookStack/pull/1503))
+* Updated translations for: Portuguese, Brazilian; Chinese Traditional; Chinese Simplified; Dutch; Italian; Ukrainian; Polish; Spanish; Hungarian; German; Turkish; French; Danish; German Informal; Russian; Korean; Spanish, Argentina. Thanks to [Crowdin Users](https://github.com/BookStackApp/BookStack/blob/master/.github/translators.txt).
+
+##### Maintenance
+
+* Upgraded framework to Laravel 6. Thanks to [@timoschwarzer](https://github.com/timoschwarzer) and [@JtheBAB](https://github.com/JtheBAB) for assisting with this. ([#1641](https://github.com/BookStackApp/BookStack/pull/1641), [#1600](https://github.com/BookStackApp/BookStack/issues/1600))
+* Setup Crowdin to manage translations. ([#1261](https://github.com/BookStackApp/BookStack/issues/1261))
+* Refactored entity repository code & refactored core controllers. ([#1690](https://github.com/BookStackApp/BookStack/pull/1690))
+* Aligned authentication service functionality, config & behaviour. ([#1866](https://github.com/BookStackApp/BookStack/pull/1866))
+
+##### Fixes
+
+* Fixed issue where base64 images would paste as text. ([#1697](https://github.com/BookStackApp/BookStack/issues/1697))
+* Fixed issue where pasted images would not auto upload in some circumstances. ([#1651](https://github.com/BookStackApp/BookStack/issues/1651))
+* Fixed issue where code block content would be hidden until clicked. ([#1672](https://github.com/BookStackApp/BookStack/issues/1672))
+* Fixed a possible middleware exception. Thanks to [@abublihi](https://github.com/BookStackApp/BookStack/pull/1793). ([#1793](https://github.com/BookStackApp/BookStack/pull/1793))
+* Fixed issue where a shelf image may not be assigned properly. Thanks to [@philjak](https://github.com/BookStackApp/BookStack/pull/1735). ([#1735](https://github.com/BookStackApp/BookStack/pull/1735))
+* Fixed missing git dependency in developer docker setup. Thanks to [@ammardev](https://github.com/BookStackApp/BookStack/pull/1698). ([#1698](https://github.com/BookStackApp/BookStack/pull/1698))
+* Fixed issue where inline code blocks could overrun the page and cut-off. Thanks to [@james-geiger](https://github.com/BookStackApp/BookStack/pull/1587). ([#1587](https://github.com/BookStackApp/BookStack/pull/1587), [#1575](https://github.com/BookStackApp/BookStack/issues/1575))
+* Fixed missing translations for "actions". Thanks to [@ezzra](https://github.com/BookStackApp/BookStack/pull/1502). ([#1502](https://github.com/BookStackApp/BookStack/pull/1502))
+
+
+### Next Steps
+
+Over the next couple of releases I'll be taking any API feedback into account and deploying a wider set of endpoints.
+That will be my core focus although I'll likely also look to align & review how we track activity in BookStack
+so this can be used for other opportunities such as webhooks, feeds, notifications & audit logs.
+
+As said above, if you have any feedback on the API implementation [I'd love to hear it here](https://github.com/BookStackApp/BookStack/issues/1852).
+
+----
+
+<span style="font-size: 0.8em;opacity:0.8;">Header Image Credits: &nbsp; <a style="background-color:black;color:white;text-decoration:none;padding:4px 6px;font-family:-apple-system, BlinkMacSystemFont, &quot;San Francisco&quot;, &quot;Helvetica Neue&quot;, Helvetica, Ubuntu, Roboto, Noto, &quot;Segoe UI&quot;, Arial, sans-serif;font-size:12px;font-weight:bold;line-height:1.2;display:inline-block;border-radius:3px" href="https://unsplash.com/@radu_marcusu?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge" target="_blank" rel="noopener noreferrer" title="Download free do whatever you want high-resolution photos from Radu Marcusu"><span style="display:inline-block;padding:2px 3px"><svg xmlns="http://www.w3.org/2000/svg" style="height:12px;width:auto;position:relative;vertical-align:middle;top:-2px;fill:white" viewBox="0 0 32 32"><title>unsplash-logo</title><path d="M10 9V0h12v9H10zm12 5h10v18H0V14h10v9h12v-9z"></path></svg></span><span style="display:inline-block;padding:2px 3px">Radu Marcusu</span></a></span>
diff --git a/content/blog/beta-security-release-v0-18-5.md b/content/blog/beta-security-release-v0-18-5.md
new file mode 100644 (file)
index 0000000..0108569
--- /dev/null
@@ -0,0 +1,58 @@
++++
+categories = ["Releases"]
+tags = ["Releases"]
+title = "Beta Security Release v0.18.5 + Other Bugfix Releases"
+date = 2017-11-11T19:01:00Z
+author = "Dan Brown"
+image = "/images/blog-cover-images/lock-jason-blackeye.jpg"
+description = "BookStack Bugfix v0.18.5 released to fix security issue where content names were visible on 404"
+slug = "beta-security-release-v0-18-5"
+draft = false
++++
+
+### Security Release v0.18.5
+
+**This release fixes the following security issue:**
+
+* Fixed issue where email confirmation was not forced when domain restriction was enabled. ([#573](https://github.com/BookStackApp/BookStack/issues/573))
+
+This issue meant that if you have domain restriction enabled on sign-up, and you did not enable email confirmation, a user could sign up via email (Using an approved email domain) but then login right away without confirming they own the email.
+
+It is suggested that if you had email confirmation disabled but domain restriction enabled you check all user accounts to ensure they are legitimate. This change may also mean that, after updating, some users will need to confirm their email address to access the BookStack instance.
+
+Sincere apologies for this issue.
+
+* [Update instructions](https://www.bookstackapp.com/docs/admin/updates)
+* [GitHub release page](https://github.com/BookStackApp/BookStack/releases/tag/v0.18.5)
+
+### Other Bugfix Releases
+
+Since the last blogpost for v0.18 we've deployed quite a few bugfix releases. Here's the full changelog of v0.18.1 to v0.18.5:
+
+* Fixed issue where images would jump to the bottom when pasted into a page. ([#489](https://github.com/BookStackApp/BookStack/issues/489))
+* Fixed bug preventing pages being saved when including other page content. ([#514](https://github.com/BookStackApp/BookStack/issues/514))
+* 'Spanish Argentina' translations added, Thanks to [@leomartinez](https://github.com/BookStackApp/BookStack/issues/517). ([#517](https://github.com/BookStackApp/BookStack/issues/517))
+* Russian translations added, Thanks to [@turbotankist](https://github.com/BookStackApp/BookStack/issues/506). ([#506](https://github.com/BookStackApp/BookStack/issues/506))
+* Some Dutch translations updated, Thanks to [@sanderdw](https://github.com/BookStackApp/BookStack/issues/510). ([#510](https://github.com/BookStackApp/BookStack/issues/510))
+* When using social authentication, You are now redirected to your original intended location upon login. ([#508](https://github.com/BookStackApp/BookStack/issues/508))
+* Updated code colorscheme to highlight shell commands. ([#535](https://github.com/BookStackApp/BookStack/issues/535))
+* Prevented homepage item 'details' overflowing out of the lists. ([#533](https://github.com/BookStackApp/BookStack/issues/533))
+* Improved search indexing to better split words apart. Fixes words at the start of sentances not being searchable. ([#531](https://github.com/BookStackApp/BookStack/issues/531))
+* Updated Italian translations. Thanks to [@cipi1965](https://github.com/BookStackApp/BookStack/pull/529). ([#529](https://github.com/BookStackApp/BookStack/pull/529))
+* Updated Russian translations. Thanks to [@turbotankist](https://github.com/BookStackApp/BookStack/pull/528). ([#528](https://github.com/BookStackApp/BookStack/pull/528))
+* Update Dutch translations. Thanks to [@sanderdw](https://github.com/BookStackApp/BookStack/pull/523). ([#523](https://github.com/BookStackApp/BookStack/pull/523))
+* Removed trailing spaces from input to achieve cleaner URLs. ([#526](https://github.com/BookStackApp/BookStack/issues/526))
+* Migrated all AngularJS code. Results in much less JavaScript. ([#524](https://github.com/BookStackApp/BookStack/pull/524))
+* Added Office 365/AzureAD as a social auth option. ([#509](https://github.com/BookStackApp/BookStack/issues/509))
+* Added search filter to sort pages by last commented. ([#440](https://github.com/BookStackApp/BookStack/issues/440))
+* Fixed issues where shortcuts would overwrite 'Alt-Gr' based character input. ([#330](https://github.com/BookStackApp/BookStack/issues/330))
+* Improved image fetching for exporting. A hopeful solution to [#392](https://github.com/BookStackApp/BookStack/issues/392).
+* Prevented duplicate hypens in generated slugs. ([#589](https://github.com/BookStackApp/BookStack/issues/589))
+* Fixed url slugs when multi-byte characters are included. Thanks to [@wowkaster](https://github.com/BookStackApp/BookStack/pull/582). ([#582](https://github.com/BookStackApp/BookStack/pull/582))
+* Allow custom session lifetime expiry. ([#570](https://github.com/BookStackApp/BookStack/issues/570))
+* Fixed tag suggestions not functioning when BookStack is on a URI sub-path. Thanks to [@10bass](https://github.com/BookStackApp/BookStack/pull/563). ([#563](https://github.com/BookStackApp/BookStack/pull/563))
+* Updated pt_BR translations. Thanks to [@lbguilherme](https://github.com/BookStackApp/BookStack/pull/558). ([#558](https://github.com/BookStackApp/BookStack/pull/558))
+
+---
+
+<span style="font-size: 0.8em;opacity:0.8;">Header Image Credits: &nbsp;<a style="background-color:black;color:white;text-decoration:none;padding:4px 6px;font-family:-apple-system, BlinkMacSystemFont, &quot;San Francisco&quot;, &quot;Helvetica Neue&quot;, Helvetica, Ubuntu, Roboto, Noto, &quot;Segoe UI&quot;, Arial, sans-serif;font-size:12px;font-weight:bold;line-height:1.2;display:inline-block;border-radius:3px;" href="https://unsplash.com/@jeisblack?utm_medium=referral&amp;utm_campaign=photographer-credit&amp;utm_content=creditBadge" target="_blank" rel="noopener noreferrer" title="Download free do whatever you want high-resolution photos from Jason Blackeye"><span style="display:inline-block;padding:2px 3px;"><svg xmlns="http://www.w3.org/2000/svg" style="height:12px;width:auto;position:relative;vertical-align:middle;top:-1px;fill:white;" viewBox="0 0 32 32"><title></title><path d="M20.8 18.1c0 2.7-2.2 4.8-4.8 4.8s-4.8-2.1-4.8-4.8c0-2.7 2.2-4.8 4.8-4.8 2.7.1 4.8 2.2 4.8 4.8zm11.2-7.4v14.9c0 2.3-1.9 4.3-4.3 4.3h-23.4c-2.4 0-4.3-1.9-4.3-4.3v-15c0-2.3 1.9-4.3 4.3-4.3h3.7l.8-2.3c.4-1.1 1.7-2 2.9-2h8.6c1.2 0 2.5.9 2.9 2l.8 2.4h3.7c2.4 0 4.3 1.9 4.3 4.3zm-8.6 7.5c0-4.1-3.3-7.5-7.5-7.5-4.1 0-7.5 3.4-7.5 7.5s3.3 7.5 7.5 7.5c4.2-.1 7.5-3.4 7.5-7.5z"></path></svg></span><span style="display:inline-block;padding:2px 3px;">Jason Blackeye</span></a></span>
diff --git a/content/docs/admin/_index.md b/content/docs/admin/_index.md
new file mode 100644 (file)
index 0000000..79008fe
--- /dev/null
@@ -0,0 +1,4 @@
+---
+title: "BookStack Blog"
+type: "admin-doc"
+---
\ No newline at end of file
index c042600ec07d4a8e735113278ba1f276678c1303..9b9d2b4d654dcbb60fb78c9115753dfbab9f0641 100644 (file)
@@ -2,7 +2,7 @@
 title = "Backup and Restore"
 description = "How to back up and restore your BookStack data"
 date = "2017-01-01"
-type = "admin-docs"
+type = "admin-doc"
 +++
 
 BookStack does not currently have a built-in way to backup and restore but it
@@ -73,10 +73,12 @@ data. Copy this to a safe place, ideally on a different device.
 
 ## Restore
 
-If you are restoring from scratch follow the
-[installation](/docs/admin/installation)
-instructions first to get a new BookStack instance up and running. Once you are
-sure the new instance is working follow the instructions below.
+If you are restoring from scratch follow the [installation](/docs/admin/installation)
+instructions first to get a new BookStack instance set-up.
+**Do not run the `php artisan migrate` installation step** when installing BookStack.
+You may need to comment this command out if using an installer script. If using
+a docker container, restore the database before running the BookStack container.
+Once you are sure the new instance is set-up follow the instructions below.
 
 #### Database
 
index 846d257c681a43be28ca401c0b853f01dd41c2e0..6697d6b69db2ae7069382b3836d2620c6631fcf9 100644 (file)
@@ -1,26 +1,45 @@
 +++
 title = "Cache & Session Configuration"
-description = "Cache & Session setup with details for redis and memcached"
+description = "Cache & Session setup with details for redis, memcached or database drivers"
 date = "2017-01-01"
-type = "admin-docs"
+type = "admin-doc"
 +++
 
-By default BookStack will use a file system cache that's storage in the `storage/framework` folder. This is also used to store user session data. Below are some alternative systems that can be used for caching & sessions.
+### Cookie Configuration
 
-### Database
+Browser cookies are used to track sessions when using BookStack. The following session cookie options can be set in your .env file:
 
-As an easy alternative to using the filesystem, you can use the database to store the cache and session. The database setup for this is done when installing/updating BookStack so you simply need to set the following in your `.env` file:
+```bash
+# Only send cookies over a HTTPS connection.
+# Ensure you have BookStack served over HTTPS before enabling.
+# Defaults to 'false'
+SESSION_SECURE_COOKIE=true
 
+# Set the name of the cookie used by BookStack to track sessions.
+# Defaults to 'bookstack_session'
+SESSION_COOKIE_NAME=custom_cookie_name
 ```
+
+### Cache & Session Storage
+
+By default BookStack will use a file system cache that's storage in the `storage/framework` folder. This is also used to store user session data. Below are some alternative systems that can be used for caching & sessions.
+
+#### Database
+
+As an easy alternative to using the filesystem, you can use the database to store the cache and session. The database setup for this is done when installing/updating BookStack so you simply need to set the following in your .env file:
+
+```bash
 CACHE_DRIVER=database
 SESSION_DRIVER=database
 ```
 
-### Memcached
+#### Memcached
 
-To use memcached for caching and/or sessions open up your `.env` file and find the `CACHE_DRIVER` & `SESSION_DRIVER` variables. By default these are both set to `file`. Change these variables to `memcached`. You will also need to add a variable to specify the memcached servers you are using. To do this add a variable named `MEMCACHED_SERVERS` to the `.env` file and set the value to be your memcached servers in the following format: `HOST:PORT:WEIGHT,HOST2:PORT:WEIGHT`. You can specify as many servers as you want. Their usage split will be determined by the weight given to them. Here are some examples of what the `.env` file should look like:
+To use memcached for caching and/or sessions open up your .env file and find the `CACHE_DRIVER` & `SESSION_DRIVER` variables. By default these are both set to `file`. Change these variables to `memcached`.
 
-```
+You will also need to add a variable to specify the memcached servers you are using. To do this add a variable named `MEMCACHED_SERVERS` to the .env file and set the value to be your memcached servers in the following format: `HOST:PORT:WEIGHT,HOST2:PORT:WEIGHT`. You can specify as many servers as you want. Their usage split will be determined by the weight given to them. Here are some examples of what the .env file should look like:
+
+```bash
 # Set both the cache and session to use memcached
 CACHE_DRIVER=memcached
 SESSION_DRIVER=memcached
@@ -32,15 +51,17 @@ MEMCACHED_SERVERS=127.0.0.1:11211:100
 MEMCACHED_SERVERS=8.8.8.8:11211:50,8.8.4.4:11211:50
 ```
 
-### Redis
+#### Redis
 
-To use Redis for caching and/or sessions open up your `.env` file and find the `CACHE_DRIVER` & `SESSION_DRIVER` variables. By default these are both set to `file`. Change these variables to `redis`. You will need to add a variable to specify your Redis servers. To do this add a variable named `REDIS_SERVERS` to the `.env` file and set the value to point at your Redis servers in the following format: `HOST:PORT:DATABASE,HOST2:PORT:DATABASE`. The default values for each host are `127.0.0.1:6379:0`. You can list as many servers as you like.  
+To use Redis for caching and/or sessions open up your .env file and find the `CACHE_DRIVER` & `SESSION_DRIVER` variables. By default these are both set to `file`. Change these variables to `redis`.
 
-To specify if you would like to cluster you Redis servers create a `REDIS_CLUSTER` key in the `.env` file and set it to `true`. This option, if set to true, will instruct the built-in Redis client to perform client-side sharding across your Redis nodes, allowing them to pool together for a large amount of RAM. This disadvantage of this it that it does not allow for fail-over.
+You will need to add a variable to specify your Redis servers. To do this add a variable named `REDIS_SERVERS` to the .env file and set the value to point at your Redis servers in the following format: `HOST:PORT:DATABASE,HOST2:PORT:DATABASE`. The default values for each host are `127.0.0.1:6379:0`. You can list as many servers as you like. If your redis servers are password protected you can use the format `HOST:PORT:DATABASE:PASSWORD`.
 
-Here's an example of setting the Redis configuration:
+If more that one server is provided they will automatically be clustered by BookStack to perform client-side sharding across your Redis nodes, allowing them to pool together for a large amount of RAM. This disadvantage of this it that it does not allow for fail-over.
 
-```
+Here's a configuration example of using Redis with BookStack:
+
+```bash
 # Set both the cache and session to use Redis
 CACHE_DRIVER=redis
 SESSION_DRIVER=redis
@@ -50,5 +71,4 @@ REDIS_SERVERS=127.0.0.1:6379:0
 
 # Example of using two non-local Redis servers clustered together
 REDIS_SERVERS=8.8.8.8:6379:0,8.8.4.4:6379:0
-REDIS_CLUSTER=true
 ```
index 43c33f4c74b76f6987de327d37bbd90ee9e1d798..7683a93d1a6ef2cec78220c4d9540c6a6a0782a0 100644 (file)
@@ -2,16 +2,18 @@
 title = "Commands"
 description = "BookStack command-line actions"
 date = "2017-02-26"
-type = "admin-docs"
+type = "admin-doc"
 +++
 
-BookStack has some command line actions that can help with maintenence and common operations. There are also many commands available from the undlying Laravel framework. To list all available commands you can simply run `php artisan` from your BookStack install folder. Custom BookStack commands are all under the 'bookstack' namespace.
+BookStack has some command line actions that can help with maintenance and common operations. There are also many commands available from the underlying Laravel framework. To list all available commands you can simply run `php artisan` from your BookStack install folder. Custom BookStack commands are all under the 'bookstack' namespace.
 
 ### BookStack Commands
 
-Here's a listing of the BookStack specific commands:
+Below is a listing of the BookStack specific commands. For any you can provide a `-h` option to list details and options for the command.
 
-```
+```bash
+# Create a new admin user
+php artisan bookstack:create-admin
 
 # Delete all activity history from the system
 php artisan bookstack:clear-activity
@@ -25,7 +27,24 @@ php artisan bookstack:clear-revisions -a
 # Delete all page views from the system
 php artisan bookstack:clear-views
 
-# Regenerate access permissions - Used mostly in development.
+# Search and remove images that are not used in page content
+php artisan bookstack:cleanup-images
+
+# Generate SQL commands that will upgrade the database to UTF8mb4
+# See https://www.bookstackapp.com/docs/admin/ut8mb4-support/
+php artisan bookstack:db-utf8mb4
+
+# Rebuild the search index
+# Useful if manually inserting pages into the system
+php artisan bookstack:regenerate-search
+
+# Regenerate access permissions - Used mostly in development
 php artisan bookstack:regenerate-permissions
 
+# Delete all users from the system that are not "admin" or system users
+php artisan bookstack:delete-users
+
+# Copy the permission settings of a specified, or all, shelf to their child books
+php artisan bookstack:copy-shelf-permissions --all
+php artisan bookstack:copy-shelf-permissions --slug=my_shelf_slug
 ```
index 1663dd3b2f93b77efb411ff78603a67930b49f6c..81f8251650248521ed3e099636796daf80be7b70 100644 (file)
@@ -2,15 +2,17 @@
 title = "Debugging Errors"
 description = "How to find the cause of issues in BookStack"
 date = "2017-01-01"
-type = "admin-docs"
+type = "admin-doc"
 +++
 
-When using BookStack, Especially when initially setting it up or after updating, you may come across some errors. While we try to reduce these as much as possible and make them helpful sometimes you may come across a bland and non-helpful 'An error has occurred' message. This is to prevent any potentially sensitive information being shown to all users.
+When using BookStack, Especially when initially setting it up or after updating, you may come across some errors. While we try to reduce these as much as possible and make them helpful sometimes you may come across a bland, non-helpful 'An error has occurred' message. This is to prevent any potentially sensitive information being shown to all users.
 
-To enable full error displaying change the edit the `.env` file, in the application root directory and find the line `APP_DEBUG=false`. Change this to `APP_DEBUG=true` and the errors will be displayed in full with details of where it occurred. Remember to revert this change once you have found the issue so that the detailed error information is hidden from everyone.
+_**NOTE: While debugging is enabled it's possible for users to be able to see private credentials used in the BookStack or server configuration. Ensure debugging is only enabled when your instance is not accessible by others. Remember to disable debugging before restoring user access.**_
+
+To enable full error displaying edit the `.env` file, in the application root directory, and find the line `APP_DEBUG=false`. Change this to `APP_DEBUG=true` and the errors will be displayed in full with details of where it occurred. Remember to revert this change once you have found the issue so that the detailed error information is hidden from everyone.
 
 On top of the above, An error log can be found at the path `storage/logs/laravel.log`. If the `laravel.log` file does not exist the `storage/logs` directory may not be writable by the server.
 
 ### Submitting Issues
 
-If you have found the cause of the issue and it is not an issue with your particular setup you can submit it on the [GitHub issues page](https://github.com/BookStackApp/BookStack/issues). Please include as much information as possible when creating an issue with steps with how to replicate it so the bug can be fixed by a developer.
\ No newline at end of file
+If you have found the cause of the issue and it is not an issue with your particular setup you can submit it on the [GitHub issues page](https://github.com/BookStackApp/BookStack/issues). Please include as much information as possible when creating an issue with steps with how to replicate it so the bug can be fixed by a developer.
diff --git a/content/docs/admin/hacking-bookstack.md b/content/docs/admin/hacking-bookstack.md
new file mode 100644 (file)
index 0000000..76c70e6
--- /dev/null
@@ -0,0 +1,79 @@
++++
+title = "Hacking BookStack"
+description = "Performing deeper customisation & extending the platform to suit your needs"
+date = "2020-02-02"
+type = "admin-doc"
++++
+
+Sometimes you may want to perform deeper customisation to BookStack or extend the system to suit your use-case. The core of BookStack is fairly rigid as it's intended to be a configured, ready-to-use system out of the box but there are a few advanced options for performing more advanced modifications without needing to alter the system code-base.
+
+_**Note: Customisation options on this page are not deemed to be stable or officially supported. BookStack core files may change on any release causing changes in behaviour to your hacks.**_
+
+---
+
+
+### BookStack API
+
+_**Note: The API is currently in a limited preview stage to ensure the foundations are correct, It will be expanded upon in future releases.**_
+
+BookStack has a built-in REST API for external interaction and consumption of your BookStack data. API documentation can be found within your BookStack instance at the `/api/docs` URL path. You'll need to have the 'Access system API' role permission to access the API or view the API documentation page.
+
+---
+
+### Custom HTML Head Option
+
+Within the settings area you'll find a 'Custom HTML head content' setting. You can use this to add in any custom JavaScript or CSS content which enables you to override default BookStack functionality and styles.
+
+---
+
+### BookStack Editor Events
+
+Both the TinyMCE based WYSIWYG editor and the CodeMirror based Markdown editor emit events as part of their lifecycle. You can listen for these hook in and alter their configs or to gain a reference to the underlying editor instance. The below code sample shows the events available; Log out the `detail` property of events, as per the below example, to understand what is passed with the events:
+
+```html
+<script>
+       // TinyMCE WYSIWYG editor events
+       window.addEventListener('editor-tinymce::pre-init', event => console.log('TINYMCE-PRE_INIT', event.detail));
+       window.addEventListener('editor-tinymce::setup', event => console.log('TINYMCE-SETUP', event.detail));
+
+       // CodeMirror / Markdown-it Markdown editor events
+       window.addEventListener('editor-markdown-cm::pre-init', event => console.log('MARKDOWN-CODEMIRROR-PRE_INIT', event.detail));
+       window.addEventListener('editor-markdown::setup', event => console.log('MARKDOWN-EDITOR-SETUP', event.detail));
+</script>
+```
+
+---
+
+### Theme System
+
+_**Note: The files that can be override using the theme system are not deemed to be stable. BookStack core files may change on any release causing changes in behaviour to your overrides. Theme overrides are not officially supported in any way.**_
+
+The theme system provides additional customisation options for those that are a bit more adventurous. The theme system enables you to selectively override BookStack UI resources without having to alter the original BookStack code. To get started create a new folder in the `themes` folder of your BookStack install. Edit your `.env` file and add the following:
+
+```bash
+# Change the value below to match the name of your created folder
+APP_THEME=<theme_folder_name>
+```
+
+Files can now be placed in your theme folder to override the following resources:
+
+##### View Files
+
+Content placed in your `themes/<theme_name>/` folder will override the original view files found in the `resources/views` folder. These files are typically [Laravel Blade](https://laravel.com/docs/6.x/blade) files.
+
+##### Icons
+
+SVG files placed in a `themes/<theme_name>/icons` folder will override any icons of the same name within `resources/icons`. You'd typically want to follow the format convention of the existing icons, where no XML deceleration is included and no width & height attributes are set, to ensure optimal compatibility. 
+
+##### Text Content
+
+Folders with PHP translation files placed in a `themes/<theme_name>/lang` folder will override translations defined within the `resources/lang` folder. Custom translations are merged with the original files so you only need to override the select translations you want to override, you don't need to copy the whole original file. Note that you'll need to include the language folder.
+
+As an example, Say I wanted to change 'Search' to 'Find'; Within a `themes/<theme_name>/lang/en/common.php` file I'd set the following:
+
+```php
+<?php
+return [
+    'search' => 'find',
+];
+```
\ No newline at end of file
index 2f5aa23fa611699e7a9ed951658dede6f72ec3c9..b519bbd9b46de1d735a2db7e8d273d1b3f69c81a 100644 (file)
@@ -2,53 +2,71 @@
 title = "Installation"
 description = "How to install BookStack"
 date = "2017-01-01"
-type = "admin-docs"
+type = "admin-doc"
 +++
 
-Below are some different methods of installing BookStack. If you cannot find a guide for your setup search the web for "Laravel install guides" relevant for your system as the process is mostly the same.
+Below you can find details on how to install BookStack on your own hosting. There are a number of installation options available depending on your setup. The install process will require some knowledge of hosting a PHP web application & database.
 
+* [Requirements](#requirements)
+* [Shared Hosting](#shared)
 * [Manual](#manual)
 * [Docker](#docker)
 * [Ubuntu 16.04 Script](#ubuntu-1604)
+* [Ubuntu 18.04 Script](#ubuntu-1804)
 * [Community Guides](#community)
 
-## Manual Installation <a name="manual"></a>
+---
 
-#### Requirements
+<a name="requirements"></a>
 
-BookStack has similar requirements to Laravel:
+## Requirements
 
-* PHP >= 5.6.4, Will need to be usable from the command line.
-* PHP Extensions: `OpenSSL`, `PDO`, `MBstring`, `Tokenizer`, `GD`, `MySQLND`, `Tidy`
-* MySQL >= 5.6, Single DB *(All permissions advised since application manages schema)*
-* Git *(Not strictly required but helps manage updates)*
-* [Composer](https://getcomposer.org/)
+BookStack has the following requirements:
 
-#### Instructions
+* **PHP** >= 7.2
+    * For installation and maintenence, you'll need to be able to run `php` from the command line.
+    * Required Extensions: *OpenSSL, PDO, MBstring, Tokenizer, GD, MySQL, Tidy, SimpleXML & DOM*
+* **MySQL** >= 5.6
+    *  Single Database *(All permissions advised since application manages schema)*
+* **Git Version Control**
+    * (Not strictly required but helps manage updates)
+* **[Composer](https://getcomposer.org/)**
 
-Ensure the above requirements are met before installing.
+---
 
-This project currently uses the `release` branch of the BookStack GitHub repository as a stable channel for providing updates. The installation is currently somewhat complicated and will be made simpler in future releases. Some PHP/Laravel experience will currently benefit.
+<a name="shared"></a>
 
-1. Clone the release branch of the BookStack GitHub repository into a folder.
+## Shared Hosting
+
+BookStack does not currently support shared PHP hosting. There are too many differences between shared hosting providers and too many limitations to support the current install process although we would like to make this easier in the future. You can try searching for 'Laravel Install Guides' for your hosting provider as the process would be similar. Beware that modifying the application source files or applying large work-arounds could lead to security or stability issues.
 
-       ```
-       git clone https://github.com/BookStackApp/BookStack.git --branch release --single-branch
-       ```
+---
+
+<a name="manual"></a>
+
+## Manual Installation
+
+Ensure the above requirements are met before installing.
 
-2. `cd` into the application folder and run `composer install`.
+This project currently uses the `release` branch of the BookStack GitHub repository as a stable channel for providing updates. The installation is currently somewhat complicated and will be made simpler in future releases. Some PHP or Laravel experience will make this easier.
+
+1. Clone the release branch of the BookStack GitHub repository into a folder.
+```bash
+git clone https://github.com/BookStackApp/BookStack.git --branch release --single-branch
+```
+2. `cd` into the application folder and run `composer install --no-dev`.
 3. Copy the `.env.example` file to `.env` and fill with your own database and mail details.
 4. Ensure the `storage`, `bootstrap/cache` & `public/uploads` folders are writable by the web server.
 5. In the application root, Run `php artisan key:generate` to generate a unique application key.
 6. If not using Apache or if `.htaccess` files are disabled you will have to create some URL rewrite rules as shown below.
 7. Set the web root on your server to point to the BookStack `public` folder. This is done with the `root` setting on Nginx or the `DocumentRoot` setting on Apache.
 8. Run `php artisan migrate` to update the database.
-9. Done! You can now login using the default admin details `[email protected]` with a password of `password`. It is recommended to change these details directly after first logging in.
+9. Done! You can now login using the default admin details `[email protected]` with a password of `password`. You should change these details immediately after logging in for the first time.
 
 #### URL Rewrite rules
 
 **Apache**
-```
+```apache
 Options +FollowSymLinks
 RewriteEngine On
 
@@ -58,7 +76,7 @@ RewriteRule ^ index.php [L]
 ```
 
 **Nginx**
-```
+```nginx
 location / {
     try_files $uri $uri/ /index.php?$query_string;
 }
@@ -66,24 +84,35 @@ location / {
 
 ---
 
-## Docker Image <a name="docker"></a>
+<a name="docker"></a>
+
+## Docker Containers
+
+Community docker setups are available for those that would prefer to use a containerised version of BookStack:
+
+#### LinuxServer.io
+
+* [GitHub Repository](https://github.com/linuxserver/docker-bookstack)
+* [Docker Hub page](https://hub.docker.com/r/linuxserver/bookstack)
 
-A community built docker image is available for those that prefer to use a containerised version of BookStack. This image runs on Apache and PHP7. A docker compose file is also available to bring up a whole BookStack environment which includes MySQL 5.7. Here are the links for the docker image:
+#### solidnerd
 
-* [GitHub repository including docker compose file](https://github.com/solidnerd/docker-bookstack)
+* [GitHub Repository](https://github.com/solidnerd/docker-bookstack)
 * [Docker Hub page](https://hub.docker.com/r/solidnerd/bookstack/)
 
 ---
 
-## Ubuntu 16.04 Installation Script <a name="ubuntu-1604"></a>
+<a name="ubuntu-1604"></a>
 
-A script to install BookStack on a fresh instance of Ubuntu 16.04 is available. This script is ONLY FOR A FRESH OS, It will install Nginx, MySQL 5.7, & PHP7 and could OVERWRITE any existing web setup on the machine. It also does not set up mail settings or configure system security so you will have to do those separately. You can use the script as a reference if you're installing on a non-fresh machine.
+## Ubuntu 16.04 Installation Script
+
+A script to install BookStack on a fresh instance of Ubuntu 16.04 is available. This script is ONLY FOR A FRESH OS, It will install Nginx, MySQL 5.7 & PHP7 and could OVERWRITE any existing web setup on the machine. It also does not set up mail settings or configure system security so you will have to do those separately. You can use the script as a reference if you're installing on a non-fresh machine.
 
 [Link to installation script](https://github.com/BookStackApp/devops/blob/master/scripts/installation-ubuntu-16.04.sh)
 
 #### Running the Script
 
-``` bash
+```bash
 # Ensure you have read the above information about what this script does before executing these commands.
 
 # Download the script
@@ -98,8 +127,36 @@ sudo ./installation-ubuntu-16.04.sh
 
 ---
 
-## Community Guides <a name="community"></a>
+<a name="ubuntu-1804"></a>
+
+## Ubuntu 18.04 Installation Script
+
+A script to install BookStack on a fresh instance of Ubuntu 18.04 is available. This script is ONLY FOR A FRESH OS, It will install Apache, MySQL 5.7 & PHP-7.2 and could OVERWRITE any existing web setup on the machine. It also does not set up mail settings or configure system security so you will have to do those separately. You can use the script as a reference if you're installing on a non-fresh machine.
+
+[Link to installation script](https://github.com/BookStackApp/devops/blob/master/scripts/installation-ubuntu-18.04.sh)
+
+#### Running the Script
+
+```bash
+# Ensure you have read the above information about what this script does before executing these commands.
+
+# Download the script
+wget https://raw.githubusercontent.com/BookStackApp/devops/master/scripts/installation-ubuntu-18.04.sh
+
+# Make it executable
+chmod a+x installation-ubuntu-18.04.sh
+
+# Run the script with admin permissions
+sudo ./installation-ubuntu-18.04.sh
+```
+
+---
+
+<a name="community"></a>
+
+## Community Guides
 
 This is a collection of guides created by awesome members of the BookStack community:
 
-* [CentOS 7 Install by Deviant Engineer](https://deviantengineer.com/2017/02/bookstack-centos7/)
+* [CentOS 7 Install by Deviant Engineer](https://deviant.engineer/2017/02/bookstack-centos7/)
+* [Fedora 27 Install by Jared Busch](https://mangolassi.it/topic/16471/install-bookstack-on-fedora-27/)
diff --git a/content/docs/admin/language-config.md b/content/docs/admin/language-config.md
new file mode 100644 (file)
index 0000000..aa8e941
--- /dev/null
@@ -0,0 +1,70 @@
++++
+title = "Language Configuration"
+description = "Configuring the default language option for your BookStack instance"
+date = "2018-08-11"
+type = "admin-doc"
++++
+
+By default the BookStack interface is shown in English. Additional languages are supported
+by the wider BookStack community. English translations may show as a fallback if a chosen
+alternative language does not have fully up-to-date translations.  
+
+### Setting the Default Language
+
+The value of the `APP_LANG` variable needs to be a valid locale code
+The default language will be used as the default for logged-in users and also for
+public users if their language cannot be auto-detected. This can be set
+ in your `.env` file as follows:
+
+```bash
+# Sets application language to French
+APP_LANG=fr
+```
+
+The value of the `APP_LANG` variable must be a valid locale code matching one of the following options:
+
+* Brazilian Portuguese - `pt_BR`
+* Chinese (Simplified) - `zh_CN`
+* Chinese (Traditional) - `zh_TW`
+* Dutch - `nl`
+* English - `en`
+* French - `fr`
+* German (Formal) - `de`
+* German (Informal) - `de_informal`
+* Italian - `it`
+* Japanese - `ja`
+* Korean - `kr`
+* Polish - `pl`
+* Russian - `ru`
+* Slovakian - `sk`
+* Spanish - `es`
+* Spanish, Argentinian - `es_AR`
+* Swedish - `sv`
+* Ukrainian - `uk`
+
+### Public User Locale Autodetection
+
+For users that are not logged-in BookStack will try to detect their language
+based off of information sent from their browser. If you'd prefer to force
+the language seen to be the `APP_LANG` setting you can set the following
+in your `.env` file:
+
+```bash
+APP_AUTO_LANG_PUBLIC=false
+```
+
+### Localised Date Formatting
+
+BookStack does support the localisation of date formats but it does depend on the intended locales being installed
+on the host system. If using ubuntu, you can manage installed locales via the command:
+
+```bash
+sudo dpkg-reconfigure locales
+```
+
+For other operating systems this may be different. After installing new locales you may need to restart any running PHP processes.
+For example, On Ubuntu, running PHP7.2:
+
+```bash
+sudo systemctl restart php7.2-fpm.service 
+```
\ No newline at end of file
index 25d4c663c77e43ab8a64ee06cd2c702338e86646..14b28e2ba3665b55beecf6e97bbfc8697fdb0ebf 100644 (file)
@@ -2,16 +2,18 @@
 title = "LDAP Authentication"
 description = "How to use LDAP as your primary way to register and login to BookStack"
 date = "2017-01-21"
-type = "admin-docs"
+type = "admin-doc"
 +++
 
 BookStack can be configured to allow LDAP based user login. While LDAP login is enabled you cannot log in with the standard user/password login and new user registration is disabled. BookStack will only use the LDAP server for getting user details and for authentication. Data on the LDAP server is not currently editable through BookStack.
 
+### Authentication Setup
+
 When a LDAP user logs into BookStack for the first time their BookStack profile will be created and they will be given the default role set under the 'Default user role after registration' option in the application settings.    
 
 To set up LDAP-based authentication add or modify the following variables in your `.env` file:
 
-```
+```bash
 # General auth
 AUTH_METHOD=ldap
 
@@ -20,7 +22,7 @@ LDAP_SERVER=example.com:389
 # If using LDAP over SSL you should also define the protocol:
 # LDAP_SERVER=ldaps://example.com:636
 
-# The base DN from where users will be searched within.
+# The base DN from where users will be searched within
 LDAP_BASE_DN=ou=People,dc=example,dc=com
 
 # The full DN and password of the user used to search the server
@@ -32,11 +34,29 @@ LDAP_PASS=false
 # The user-provided user-name used to replace any occurrences of '${user}'
 LDAP_USER_FILTER=(&(uid=${user}))
 
-# Set the LDAP version to use when connecting to the server.
+# Set the LDAP version to use when connecting to the server
 LDAP_VERSION=false
 
-# Set the default 'email' attribute. Defaults to 'mail'.
+# Set the property to use as a unique identifier for this user.
+# Stored and used to match LDAP users with existing BookStack users.
+# Prefixing the value with 'BIN;' will assume the LDAP service provides the attribute value as
+# binary data and BookStack will convert the value to a hexidecimal representation.
+# Defaults to 'uid'.
+LDAP_ID_ATTRIBUTE=uid
+
+# Set the default 'email' attribute. Defaults to 'mail'
 LDAP_EMAIL_ATTRIBUTE=mail
+
+# Set the property to use for a user's display name. Defaults to 'cn'
+LDAP_DISPLAY_NAME_ATTRIBUTE=cn
+
+# If you need to allow untrusted LDAPS certificates, add the below and uncomment (remove the #)
+# Only set this option if debugging or you're absolutely sure it's required for your setup.
+#LDAP_TLS_INSECURE=true
+
+# If you need to debug the details coming from your LDAP server, add the below and uncomment (remove the #)
+# Only set this option if debugging since it will block logins and potentially show private details.
+#LDAP_DUMP_USER_DETAILS=true
 ```
 
 You will also need to have the php-ldap extension installed on your system. It's recommended to change your `APP_DEBUG` variable to `true` while setting up LDAP to make any errors visible. Remember to change this back after LDAP is functioning.
@@ -44,3 +64,36 @@ You will also need to have the php-ldap extension installed on your system. It's
 A user in BookStack will be linked to a LDAP user via a 'uid'. If a LDAP user uid changes it can be updated in BookStack by an admin by changing the 'External Authentication ID' field on the user's profile.
 
 You may find that you cannot log in with your initial Admin account after changing the `AUTH_METHOD` to `ldap`. To get around this set the `AUTH_METHOD` to `standard`, login with your admin account then change it back to `ldap`. You get then edit your profile and add your LDAP uid under the 'External Authentication ID' field. You will then be able to login in with that ID.
+
+### Active Directory
+
+BookStack does work with active directory over LDAP. You will likely need to set the below settings for use with AD. Note that the user filter may need to change
+depending on your setup and how you manage users in the system. You will still need to follow the setup instructions above.
+
+```bash
+LDAP_USER_FILTER=(&(sAMAccountName=${user}))
+LDAP_VERSION=3
+LDAP_ID_ATTRIBUTE=BIN;objectGUID
+```
+
+### LDAP Group Sync
+
+BookStack has the ability to sync LDAP user groups with BookStack roles. By default this will match LDAP group names with the BookStack role display names with casing ignored.
+This can be overridden by via the 'External Authentication IDs' field which can be seen when editing a role while LDAP authentication is enabled. This field can be populated with common names (CNs) of accounts *or* groups. If filled, CNs in this field will be used and the role name will be ignored. You can match on multiple CNs by separating them with a comma.
+
+When matching LDAP groups with role names or 'External Authentication IDs' values, BookStack will standardise the names of ldap groups to be lower-cased and spaces will be replaced with hypens. For example, to match a LDAP group named "United Kingdom" an 'External Authentication IDs' value of "united-kingdom" could be used.
+
+This feature requires the LDAP server to be able to provide user groups when queried. This is enabled by default on ActiveDirectory via the 'memberOf' attribute but other LDAP systems may need to be configured to enable such functionality. If using OpenLDAP you'll need to setup the memberof overlay.
+
+Here are the settings required to be added to your `.env` file to enable group syncing:
+
+```bash
+# Enable LDAP group sync, Set to 'true' to enable.
+LDAP_USER_TO_GROUPS=true
+
+# LDAP user attribute containing groups, Defaults to 'memberOf'.
+LDAP_GROUP_ATTRIBUTE="memberOf"
+
+# Remove users from roles that don't match LDAP groups.
+LDAP_REMOVE_FROM_GROUPS=false
+```
index da7203ff3cbfe56b260da089df8bc6a4d1aee2bd..871072b33695a4f4a97869d93be1f436fa22a2db 100644 (file)
@@ -2,7 +2,7 @@
 title = "Multiple BookStack Instances"
 description = "How to host multiple BookStack instances on Apache and Nginx"
 date = "2017-01-01"
-type = "admin-docs"
+type = "admin-doc"
 +++
 
 Currently BookStack does not support multiple instances from one installation but you can set up multiple instances on the same server by creating multiple installations and configuring your web-server appropriately.
@@ -57,26 +57,26 @@ For Nginx you will need to define a server for each BookStack instance you want
 By default, server definitions are stored in the `/etc/nginx/sites-available/` directory. Create a new file here, with a sensible name, for each BookStack instance you want to set up. Use the following configuration as a guide:
 
 
-```
+```nginx
 # /etc/nginx/sites-available/user-docs.conf
 
 server {
     listen 80;
     listen [::]:80;
-    
+
     root /var/www/user-docs/public;
     index index.php;
-    
+
     server_name user-docs.example.com;
-    
+
     location / {
         try_files $uri $uri/ /index.php?$query_string;
     }
-    
+
     location ~ \.php$ {
         try_files $uri /index.php =404;
         fastcgi_split_path_info ^(.+\.php)(/.+)$;
-        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
+        fastcgi_pass unix:/run/php/php7.2-fpm.sock;
         fastcgi_index index.php;
         fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
         include fastcgi_params;
diff --git a/content/docs/admin/other-config.md b/content/docs/admin/other-config.md
new file mode 100644 (file)
index 0000000..bd90128
--- /dev/null
@@ -0,0 +1,60 @@
++++
+title = "Other Configuration"
+description = "Other BookStack configuration such as system revisions and custom avatar fetching"
+date = "2018-01-12"
+type = "admin-doc"
++++
+
+
+* [.env Options](#env-options)
+* [Revision Limit](#revision-limit)
+* [Custom User Avatar Fetching](#custom-user-avatar-fetching)
+
+---
+
+### .env Options
+
+As part of the installation of BookStack you will have a `.env` file containing system options. By default this only contains a few options.
+Within your BookStack install directory you should also have a `.env.example.complete` file which contains every support option available alongside the default value for each.
+You can copy options in this file to your own `.env` file as required. Many of the options in the `.env.example.complete` file are detailed in-depth in this documentation.
+
+The `.env` file essential sets environment variables for BookStack to read. Environment variables will be checked if an option is not in the `.env` file which can be useful
+in the creation and use of docker containers.
+
+---
+
+### Revision Limit
+
+Each time a page is saved a revision is stored to track history. To prevent your database becoming bloated BookStack will automatically remove revisions when the count, per page, exceeds 50. You can set the following option in your `.env` file to increase or remove the limit:
+
+```bash
+# Set the revision limit to 100
+# Defaults to '50'
+REVISION_LIMIT=100
+
+# Alternatively, You can set to 'false' to disable the limit altogether.
+REVISION_LIMIT=false
+```
+
+---
+
+### Custom User Avatar Fetching
+
+When a user is created BookStack will, by default, fetch an avatar image from [Gravatar](https://en.gravatar.com/). This functionality can be disabled or the URL can be customized 
+which allows you to use a different avatar service altogether. Examples of this can be seen below:
+
+```bash
+# In your .env file
+
+# Use libravatar instead of gravatar
+AVATAR_URL=https://seccdn.libravatar.org/avatar/${hash}?s=${size}&d=identicon
+
+# Disable avatar fetching altogether
+AVATAR_URL=false
+```
+
+The following variables can be used in this setting which will be populated by BookStack when used:
+
+* `${email}` - The user's email address, URL encoded.
+* `${hash}` - MD5 hashed copy of the user's email address.
+* `${size}` - BookStack's ideal requested image size in pixels.
\ No newline at end of file
index 18755f4d65e91303a74322f579e0ad403205775b..c21b08ac3d225bf7cc045d2266ba9374c94b6bc3 100644 (file)
@@ -2,7 +2,7 @@
 title = "PDF Rendering"
 description = "Using WKHTMLtoPDF to generate PDF's for better rendering"
 date = "2017-01-22"
-type = "admin-docs"
+type = "admin-doc"
 +++
 
 By default BookStack uses [Dompdf](https://github.com/dompdf/dompdf) to export pages as PDF documents. The benefit of using DomPDF is that it doesn't require any additional installation or setup but the rendering capabilities are somewhat limited.
@@ -13,9 +13,9 @@ As an alternative you can use [wkhtmltopdf](http://wkhtmltopdf.org/) to generate
 
 Pre-compiled binaries for wkhtmltopdf can be found on the downloads page of [their website](http://wkhtmltopdf.org/downloads.html). BookStack will check for a file named `wkhtmltopdf` at the base folder of a BookStack install. If found it will use that to render PDF's. If that does not exist it will check for a `WKHTMLTOPDF` variable in the `.env` file. You can use this variable to set an alternate location to wkhtmltopdf:
 
-```
+```bash
 # In .env file
 WKHTMLTOPDF=/home/user/bins/wkhtmltopdf
 ```
 
-If neither of those exist Dompdf will be used instead.
\ No newline at end of file
+If neither of those exist Dompdf will be used instead.
diff --git a/content/docs/admin/saml2-auth.md b/content/docs/admin/saml2-auth.md
new file mode 100644 (file)
index 0000000..43436ff
--- /dev/null
@@ -0,0 +1,121 @@
++++
+title = "SAML 2.0 Authentication"
+description = "How to use SAML2 as an authentication option in BookStack"
+date = "2020-01-25"
+type = "admin-doc"
++++
+
+BookStack can be configured to utilise a SAML 2.0 based authentication provider as a solution for users to log-in, log-out and self-register within BookStack. This replaces the default email & password authentication mechanism within BookStack. When enabled, BookStack will attempt to match the SAML user to an existing BookStack user based on a stored external id attribute otherwise, if not found, BookStack will effectively auto-register that user to provide a seamless access experience.
+
+### BookStack Configuration
+
+To set up SAML 2.0 based authentication add or modify the following variables in your `.env` file:
+
+```bash
+# Set authentication method to be saml2
+AUTH_METHOD=saml2
+
+# Set the display name to be shown on the login button.
+# (Login with <name>)
+SAML2_NAME=SSO
+
+# Name of the attribute which provides the user's email address
+SAML2_EMAIL_ATTRIBUTE=email
+
+# Name of the attribute to use as an ID for the SAML user.
+SAML2_EXTERNAL_ID_ATTRIBUTE=uid
+
+# Name of the attribute(s) to use for the user's display name
+# Can have mulitple attributes listed, separated with a '|' in which 
+# case those values will be joined with a space.
+# Example: SAML2_DISPLAY_NAME_ATTRIBUTES=firstName|lastName
+# Defaults to the ID value if not found.
+SAML2_DISPLAY_NAME_ATTRIBUTES=username
+
+# Identity Provider entityID URL
+SAML2_IDP_ENTITYID=https://example.com/saml2/idp/metadata.php
+
+# Auto-load metatadata from the IDP
+# Setting this to true negates the need to specify the next three options
+SAML2_AUTOLOAD_METADATA=false
+
+# Identity Provider single-sign-on service URL
+# Not required if using the autoload option above.
+SAML2_IDP_SSO=https://example.com/saml2/idp/SSOService.php
+
+# Identity Provider single-logout-service URL
+# Not required if using the autoload option above.
+# Not required if your identity provider does not support SLS.
+SAML2_IDP_SLO=https://example.com/saml2/idp/SingleLogoutService.php
+
+# Identity Provider x509 public certificate data.
+# Not required if using the autoload option above.
+SAML2_IDP_x509=<cert_data>
+```
+
+A user in BookStack will be linked to a SAML user via the `SAML2_EXTERNAL_ID_ATTRIBUTE`. If the value of this id changes in the identity provider it can be updated in BookStack by an admin by changing the 'External Authentication ID' field on the user's profile.
+
+### Identity Provider Configuration
+
+You'll likely need to provide some details of your BookStack service-provider to your identity provider. Below are the URL paths you'll likely need. Only the relative paths are shown below so you'll need to append them to your BookStack base URL.
+
+* `/saml2/metadata` - Metadata endpoint *(GET)*
+* `/saml2/acs` - Assertion Consumer Service endpoint *(POST)*
+* `/saml2/sls` - Single Logout Service endpoint *(GET)*
+
+BookStack uses the following formats/bindings for communication with the IdP:
+
+* NameIDFormat: `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress`
+* ACS/SLO Binding: `urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST`
+
+Here's a minimal example of configuring a BookStack service provider for a SimpleSAMLphp IdP:
+
+```php
+$metadata['http://bookstack.local/saml2/metadata'] = [
+    'AssertionConsumerService' => 'http://bookstack.local/saml2/acs',
+    'SingleLogoutService' => 'http://bookstack.local/saml2/sls',
+    'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
+];
+```
+
+### Debugging
+
+To help when setting up or configuring BookStack to use your SAML system, there are a few additional `.env` options that can help provide more insight:
+
+```bash
+# Enable the BookStack general debug mode, Provides more error insight.
+# Note, Can leak sensitive details so only use in private, secure environments.
+APP_DEBUG=true
+
+# Option to dump out SAML 2.0 user details as JSON.
+# Only for debugging purposes since it will prevent login.
+SAML2_DUMP_USER_DETAILS=false
+
+# Option to override settings passed to the underlying onelogin library
+# used by BookStack. For development, debugging and testing only.
+# Options provided will be recursively merged into other default & dynamic options.
+# Defaults found within app/Config/saml2.php, under the 'onelogin' key.
+SAML2_ONELOGIN_OVERRIDES=<json_format_data>
+```
+
+### SAML Group Sync
+
+BookStack has the ability to sync SAML user groups with BookStack roles. By default this will match SAML group names with the BookStack role display names with casing ignored.
+This can be overridden by via the 'External Authentication IDs' field which can be seen when editing a role while SAML authentication is enabled. If filled, the names in this field will be used and the role display name will be ignored. You can match on multiple names by separating them with a comma.
+
+When matching SAML groups with role names or 'External Authentication IDs' values, BookStack will standardise the names of SAML groups to be lower-cased and spaces will be replaced with hyphens. For example, to match a SAML group named "United Kingdom" an 'External Authentication IDs' value of "united-kingdom" could be used.
+
+This feature requires the SAML server to be able to provide user groups when queried. You'll need to specify the attribute using the `SAML2_GROUP_ATTRIBUTE` option as shown below. Keep in mind you can use the `SAML2_DUMP_USER_DETAILS` option, as shown in the above [debugging](#debugging) section to dump out the attribute values that BookStack fetches from your IdP.
+
+Here are the settings required to be added to your `.env` file to enable group syncing:
+
+```bash
+# Enable SAML group sync.
+SAML2_USER_TO_GROUPS=true
+
+# Set the attribute from which BookStack will read groups names from.
+SAML2_GROUP_ATTRIBUTE=groups
+
+# Removed user from roles that don't match SAML groups upon login.
+SAML2_REMOVE_FROM_GROUPS=true
+```
index e9d61f3566788d6dd67015213349500eeb375327..00b3a5071b147e3a3fcb85901b4d87c780e8affb 100644 (file)
@@ -2,13 +2,26 @@
 title = "Security"
 description = "BookStack security concerns and considerations"
 date = "2017-01-01"
-type = "admin-docs"
+type = "admin-doc"
 +++
 
 Since BookStack can hold important information for users you should be aware of any potential security concerns.
 Read through the below to ensure you have secured your BookStack instance. Note, The below only
-relates to BookStack itself. The security of the server BookStack is hosted on is not
-instructed below but should be taken into account.
+relates to BookStack itself. The security of the server BookStack is hosted on is not instructed below but should be taken into account.
+
+<ul>
+    <li><a href="#initial-security-setup">Initial Security Setup</a></li>
+    <li><a href="#securing-images">Securing Images</a></li>
+    <li><a href="#attachments">Attachments</a></li>
+    <li><a href="#user-passwords">User Passwords</a></li>
+    <li><a href="#javascript-in-page-content">JavaScript in Page Content</a></li>
+    <li><a href="#web-crawler-control">Web Crawler Control</a></li>
+    <li><a href="#secure-cookies">Secure Cookies</a></li>
+</ul>
+
+---
+
+<a name="initial-security-setup"></a>
 
 ### Initial Security Setup
 
@@ -22,28 +35,44 @@ the database used for BookStack data.
 5. Review the user roles in the settings area.
 6. Read the below to further understand the security for images & attachments.
 
-### Images
+---
 
-Images are stored in a way which is publically accessible. This is done on purpose
-to ensure decent performance while using BookStack as booting the application for every
-image request caused multiple problems during testing. In the settings area of BookStack you can find
-the option 'Enable higher security image uploads?'. Enabling this will add a 16 character
-random string to the name of image files to prevent easy guessing of URLs.
+<a name="securing-images"></a>
 
-Due to the above it's important to ensure you disable 'directory indexes' to prevent random
-users from being able to navigate their way through your images. Here's the configuration
-for NGINX & Apache if your server allows directory indexes:
+### Securing Images
 
+By default, Images are stored in a way which is publicly accessible. This is done on purpose to ensure decent performance while using BookStack. Below are a couple of options to increasing image security:
 
-```
-# NGINX
+#### Image Authentication
+
+You can choose to store images behind authentication so only logged-in users can view images. This solution is currently still in testing you could experience performance issues. This option will only work if you have the  'Allow Public Viewing' setting disabled.
+
+***Back-up your BookStack instance before migrating to this option***
+
+To use this option simply set `STORAGE_TYPE=local_secure` in your `.env` file. Uploaded images will be stored within the `storage/uploads/images` folder.
+
+If you are migrating to this option with existing images you will need to move all content in the folder `public/uploads/images` to `storage/uploads/images`. Do not simply copy and leave content in the `public/uploads/images` as those images will still be publicly accessible. After doing this migration you may have to clean-up and re-upload any 'App Icon' images, found in settings, since these need to remain publicly accessible. 
+
+#### Complex Urls
+
+In the settings area of BookStack you can find the option 'Enable higher security image uploads?'. Enabling this will add a 16 character
+random string to the name of image files to prevent easy guessing of URLs. This increases security without potential performance concerns.
+
+It's important to ensure you disable 'directory indexes' to prevent unknown users from being able to navigate their way through your images. Here's the configuration for NGINX & Apache if your server allows directory indexes:
+
+**NGINX**
+
+```nginx
 # By default indexes are disabled on Nginx but if you have them enabled
 # add this to your BookStack server block
 location /uploads {
        autoindex off;
 }
+```
 
-# Apache
+**Apache**
+
+```apache
 # Add this to your Apache BookStack virtual host if Indexes are enabled.
 # If .htaccess file are enabled then the below should already be active.
 <Location "/uploads">
@@ -51,17 +80,49 @@ location /uploads {
 </Location>
 ```
 
+---
+
+<a name="attachments"></a>
+
 ### Attachments
 
 Attachments, if not using Amazon S3, are stored in the `storage/uploads` directory.
-Unlike images these are stored behind the application authentication layer so access
+By default, unlike images, these are stored behind the application authentication layer so access
 depends on permissions you have set up at a role level and page level.
 
 If you are using Amazon S3 for file storage then access will depend on your S3 permission
 settings. Unlike images, BookStack will not automatically attempt to make uploaded attachments
 publically accessible.  
 
+---
+
+<a name="user-passwords"></a>
+
 ### User Passwords
 
 User passwords, if not using an alternative authentication method, are stored in the database.
 These are hashed using the standard Laravel hashing methods which use the Bcrypt hashing algorithm.
+
+---
+
+<a name="javascript-in-page-content"></a>
+
+### JavaScript in Page Content
+
+By default, JavaScript tags within page content is escaped when rendered. This can be turned off by setting `ALLOW_CONTENT_SCRIPTS=true` in your `.env` file. Note that even if you disable this escaping the WYSIWYG editor may still perform it's own JavaScript escaping.
+
+---
+
+<a name="web-crawler-control"></a>
+
+### Web Crawler Control
+
+The rules found in the `/robots.txt` file are automatically controlled via the "Allow public viewing?" setting. This can be overridden by setting `ALLOW_ROBOTS=false` or `ALLOW_ROBOTS=true` in your `.env` file. If you'd like to customise the rules this can be done via theme overrides.
+
+---
+
+<a name="secure-cookies"></a>
+
+### Secure Cookies
+
+BookStack uses cookies to track sessions, remember logins and for XSRF protection. When using HTTPS you may want to ensure that cookies are only sent back to the browser if the connection is over HTTPS. This can be enabled by setting `SESSION_SECURE_COOKIE=true` in your `.env` file.
\ No newline at end of file
diff --git a/content/docs/admin/social-auth.md b/content/docs/admin/social-auth.md
deleted file mode 100644 (file)
index da5f4bf..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-+++
-title = "Social Authentication"
-description = "Enabling and configuring social authentication for easier logins"
-date = "2017-01-01"
-type = "admin-docs"
-+++
-
-BookStack currently supports login via Google, Facebook, Slack, Twitter & GitHub. Once enabled options for these services will show up in the login, registration and user profile pages. By default these services are disabled. To enable them you will have to create an application on the external services to obtain the require application id's and secrets. Here are instructions to do this for the current supported services:
-
----
-
-### Google
-
-1. Open the [Google Developers Console](https://console.developers.google.com/).
-2. Create a new project (May have to wait a short while for it to be created).
-3. Select 'Enable and manage APIs'.
-4. Enable the 'Google+ API'.
-5. In 'Credentials' choose the 'OAuth consent screen' tab and enter a product name ('BookStack' or your custom set name).
-6. Back in the 'Credentials' tab click 'New credentials' > 'OAuth client ID'.
-7. Choose an application type of 'Web application' and enter the following urls under 'Authorized redirect URIs', changing `https://example.com` to your own domain where BookStack is hosted:
-    - `https://example.com/login/service/google/callback`
-    - `https://example.com/register/service/google/callback`
-8. Click 'Create' and your app_id and secret will be displayed. Replace the false value on both the `GOOGLE_APP_ID` & `GOOGLE_APP_SECRET` variables in the '.env' file in the BookStack root directory with your own app_id and secret.
-9. Set the 'APP_URL' environment variable to be the same domain as you entered in step 7. So, in this example, it will be `https://example.com`.
-10. All done! Users should now be able to link their social accounts in their account profile pages and also register/login using their Google accounts.
-
----
-
-### GitHub
-
-1. While logged in, open up your [GitHub developer applications](https://github.com/settings/developers).
-2. Click 'Register new application'.
-3. Enter an application name ('BookStack' or your custom set name), A link to your app instance under 'Homepage URL' and an 'Authorization callback URL' of the url that your BookStack instance is hosted on then click 'Register application'.
-4. A 'Client ID' and a 'Client Secret' value will be shown. Add these two values to the to the `GITHUB_APP_ID` and `GITHUB_APP_SECRET` variables, replacing the default false value, in the '.env' file found in the BookStack root folder.
-5. Set the 'APP_URL' environment variable to be the same domain as you entered in step 3.
-6. All done! Users should now be able to link their social accounts in their account profile pages and also register/login using their Github account.
-
----
-
-### Twitter
-
-To create a Twitter application for signing in with you may require a phone number linked to your Twitter account.
-
-1. Go to your [Twitter apps page](https://apps.twitter.com/) and click 'Create New App'.
-2. Enter an application name and description. The website and callback URL can just be your BookStack homepage urls. Then submit the form.
-3. Click into your new application and go the the settings tab and ensure 'Allow this application to be used to Sign in with Twitter' is checked.
-4. If you'd like, set an icon and change any other details.
-5. Click the 'Permissions' tab and in the 'Additional Permissions' section check the box 'Request email addresses from users' then save.
-6. Go to the 'Keys and Access Tokens' tab to find your API key and secret. Add or set these to your `.env` file like so:
-       ```
-       # Replace the below (including '{}' braces) with your twitter API_KEY and API_SECRET
-       TWITTER_APP_ID={API_KEY}
-       TWITTER_APP_SECRET={API_SECRET}
-
-       # APP_URL Needs to be set to your BookStack base url
-       APP_URL=http://mybookstackurl.com
-       ```
-7. All done! Users should now be able to link their Twitter account in their account profile pages and also register/login using their Twitter account.
-
----
-
-### Facebook
-
-1. Navigate to the [Facebook developers page](https://developers.facebook.com) then go 'My Apps' -> 'Add a New App'.
-2. Enter an app name ('BookStack login' or something custom) and contact email then continue.
-3. In your new app select 'Add Product' on the left sidebar then choose 'Facebook Login' by clicking the 'Get Started' button. Select the 'Web' option if asked to choose a platform.
-4. Enter the your base BookStack url into the 'Site URL' box and save.
-5. On the left sidebar again go to 'Facebook Login' -> 'Settings'.
-6. Enter your base BookStack URL again into the 'Valid OAuth redirect URIs' input and save.
-7. Navigate back to the app 'Dashboard' in the sidebar to find your app id and secret. Add or set these to your `.env` file like so:
-       ```
-       # Replace the below (including '{}' braces) with your facebook APP_KEY and APP_SECRET
-       FACEBOOK_APP_ID={APP_KEY}
-       FACEBOOK_APP_SECRET={APP_SECRET}
-
-       # APP_URL Needs to be set to your BookStack base url
-       APP_URL=http://mybookstackurl.com
-       ```
-7. All done! Users should now be able to link their Facebook account in their account profile pages and also register/login using their Facebook account.
-
----
-
-### Slack
-
-1. Go to the [Slack apps page](https://api.slack.com/apps) and select 'Create New App'.
-2. Enter an app name ('BookStack login' or something custom), select your team then continue.
-3. You should see your client ID and secret. Copy these details and add them as new variables in your `.env` file like so:
-       ```
-       # Replace the below (including '{}' braces) with your slack CLIENT_ID and CLIENT_SECRET
-       SLACK_APP_ID={CLIENT_ID}
-       SLACK_APP_SECRET={CLIENT_SECRET}
-
-       # APP_URL Needs to be set to your BookStack base url
-       APP_URL=http://mybookstackurl.com
-       ```
-4. In your slack app go to 'OAuth & Permissions' and enter your BookStack base url into the 'Redirect URL(s)' input then save.
-5. All done! Users should now be able to link their Slack account in their account profile pages and also register/login using their Slack account.
\ No newline at end of file
diff --git a/content/docs/admin/subdirectory-setup.md b/content/docs/admin/subdirectory-setup.md
new file mode 100644 (file)
index 0000000..52a785f
--- /dev/null
@@ -0,0 +1,81 @@
++++
+title = "Subdirectory Setup"
+description = "How to setup BookStack in a subdirectory"
+date = "2018-10-04"
+type = "admin-doc"
++++
+
+You may want to host BookStack on a "Subdirectory" of your website, For example `https://example.com/bookstack`. To achieve this you will need to make some alterations to your webserver config. The details for setting this up on Apache can be found below. You'll need to follow the BookStack setup section after configuring any webserver.
+
+If you are using Docker you will likely need to look into setting up reverse proxies instead of following the below.
+
+## Apache Setup
+
+Before following this, ensure you have apache installed along with PHP & ensure mod-php is enabled. This guide assumes a recent Ubuntu-like system is in use. To set-up the required rules, you will need to have mod-rewrite enabled:
+
+```bash
+sudo a2enmod rewrite
+``` 
+
+First, You will need to choose a folder to install BookStack into. This should a separate directory from where your main website is being served from since you don't want to risk exposing any of the private BookStack files.
+By default Apache on Ubuntu serves from the `/var/www/html` directory. In this example, we'll use `/var/www/bookstack` to store our BookStack install. If you use a different path ensure you change that path in the below steps.
+Create this directory and follow the standard [BookStack install steps](/docs/admin/installation) to install BookStack into this folder. Once complete, following our example directory above, you should end up with a `.env` file in the `/var/www/bookstack` folder.
+
+The next step is to alter your Apache configuration to serve any requests to your sub-path from our chosen folder. To do this you'll need to find and edit the Apache virtual-host config for your website. By default, this is often found at `/etc/apache2/sites-available/000-default.conf`. To edit this file you'll likely have to open it with admin permissions (using `sudo`). 
+
+Within the `<VirtualHost>` tags of this file you'll need to add the below additional configuration. Note, the `<VirtualHost>` tags should already exist and the `...` parts represent existing rules. You should only need to copy the middle section:
+
+```apache
+<VirtualHost *:80>
+
+    ...
+
+    # BookStack Configuration
+    Alias "/bookstack" "/var/www/bookstack/public"
+
+    <Directory "/var/www/bookstack/public">
+      Options FollowSymlinks
+      AllowOverride None
+      Require all granted
+
+      RewriteEngine On
+      # Redirect Trailing Slashes If Not A Folder...
+      RewriteCond %{REQUEST_FILENAME} !-d
+      RewriteRule ^(.*)/$ /$1 [L,R=301]
+
+      # Handle Front Controller...
+      RewriteCond %{REQUEST_FILENAME} !-d
+      RewriteCond %{REQUEST_FILENAME} !-f
+      RewriteRule ^ index.php [L]
+    </Directory>
+
+
+    <Directory "/var/www/bookstack">
+      AllowOverride None
+      Require all denied
+    </Directory>
+    # End BookStack Configuration
+
+    ...
+
+</VirtualHost>
+``` 
+
+On line 6 in the above, beginning with `Alias`, You'll need to change `"/bookstack"` path to be the web 'subdirectory' you want to serve BookStack on. For example, If you wanted to serve BookStack on `https://example.com/docs` this would be `"/docs"`. Any instances of `/var/www/bookstack` in the above will need to be changed to the folder you installed BookStack in. The `/public` part of these paths should remain.
+
+Once the configuration has been updated, you'll need to restart apache. On Ubuntu you can do with the following command:
+
+```bash
+sudo systemctl restart apache2.service
+```
+
+Follow the below "BookStack Setup" to add your new URL to your BookStack configuration. Once done you should be able to access your BookStack instance at your desired sub-path.
+
+
+## BookStack Setup
+
+Within your `.env` file ensure you set the `APP_URL` parameter. This should be the base URL for your BookStack instance without a trailing slash. For example:
+
+```bash
+APP_URL=https://example.com/bookstack
+```
\ No newline at end of file
diff --git a/content/docs/admin/third-party-auth.md b/content/docs/admin/third-party-auth.md
new file mode 100644 (file)
index 0000000..e94c75f
--- /dev/null
@@ -0,0 +1,270 @@
++++
+title = "Third Party Authentication"
+description = "Enabling and configuring third-party authentication for easier logins"
+date = "2017-01-01"
+type = "admin-doc"
+aliases = [
+    "/docs/admin/social-auth"
+]
++++
+
+BookStack currently supports login via a range of third party and social applications. Once enabled options for these services will show up in the login, registration and user profile pages. By default these services are disabled. To enable them you will have to create an application on the external services to obtain the require application id's and secrets.
+
+#### Available Services
+
+* [Google](#google)
+* [GitHub](#github)
+* [Twitter](#twitter)
+* [Facebook](#facebook)
+* [Slack](#slack)
+* [AzureAD (Microsoft)](#azuread-microsoft)
+* [Okta](#okta)
+* [GitLab](#gitlab)
+* [Twitch](#twitch)
+* [Discord](#discord)
+
+#### Automatic Registration
+
+You may find that you'd like to auto-register users, from the login screen, when they use a social authentication option. To do this add the following `.env` option, altering the `{SERVICE}` to match the login service you are using:
+
+```bash
+{SERVICE}_AUTO_REGISTER=true
+
+# Examples
+GOOGLE_AUTO_REGISTER=true
+TWITCH_AUTO_REGISTER=true
+```
+
+This will allow registration using these services even if registrations are disabled. It also allows registration if using LDAP as you main authentication option.
+
+#### Automatic Email Confirmation
+
+If you trust a third-party login service you can enable automatic email confirmation. This skips the 'Confirm Email' setting, even if domain restrictions are enabled although the domain of the email address provided by the social service will still be checked. To do this add the following `.env` option, altering the `{SERVICE}` to match the login service you are using and trust:
+
+```bash
+{SERVICE}_AUTO_CONFIRM_EMAIL=true
+
+# Examples
+GOOGLE_AUTO_CONFIRM_EMAIL=true
+TWITCH_AUTO_CONFIRM_EMAIL=true
+```
+
+---
+
+### Google
+
+1. Open the [Google Developers Console](https://console.developers.google.com/).
+2. Create a new project (May have to wait a short while for it to be created).
+3. In 'Credentials' choose the 'OAuth consent screen' tab and enter a product name ('BookStack' or your custom set name).
+4. Back in the 'Credentials' tab click 'New credentials' > 'OAuth client ID'.
+5. Choose an application type of 'Web application' and enter the following urls under 'Authorized redirect URIs', changing `https://example.com` to your own domain where BookStack is hosted:
+    - `https://example.com/login/service/google/callback`
+    - `https://example.com/register/service/google/callback`
+6. Add or set the following items in your `.env` file like so:
+       ```bash
+       # Replace the below (including '{}' braces) with your Google API_KEY and API_SECRET
+       GOOGLE_APP_ID={google_app_id}
+       GOOGLE_APP_SECRET={google_app_secret}
+
+       # APP_URL Needs to be set to your BookStack base url
+       APP_URL=http://mybookstackurl.com
+       ```
+7. All done! Users should now be able to link their social accounts in their account profile pages and also register/login using their Google accounts.
+
+---
+
+### GitHub
+
+1. While logged in, open up your [GitHub developer applications](https://github.com/settings/developers).
+2. Click 'Register new application'.
+3. Enter an application name ('BookStack' or your custom set name), A link to your app instance under 'Homepage URL' and an 'Authorization callback URL' of the url that your BookStack instance is hosted on then click 'Register application'.
+4. A 'Client ID' and a 'Client Secret' value will be shown. Add these two values to the to the `GITHUB_APP_ID` and `GITHUB_APP_SECRET` variables, replacing the default false value, in the '.env' file found in the BookStack root folder.
+5. Set the 'APP_URL' environment variable to be the same domain as you entered in step 3.
+6. All done! Users should now be able to link their social accounts in their account profile pages and also register/login using their Github account.
+
+---
+
+### Twitter
+
+To create a Twitter application for signing in with you may require a phone number linked to your Twitter account.
+
+1. Go to your [Twitter apps page](https://apps.twitter.com/) and click 'Create New App'.
+2. Enter an application name and description. The website and callback URL can just be your BookStack homepage urls. Then submit the form.
+3. Click into your new application and go the the settings tab and ensure 'Allow this application to be used to Sign in with Twitter' is checked.
+4. If you'd like, set an icon and change any other details.
+5. Click the 'Permissions' tab and in the 'Additional Permissions' section check the box 'Request email addresses from users' then save.
+6. Go to the 'Keys and Access Tokens' tab to find your API key and secret. Add or set these to your `.env` file like so:
+       ```bash
+       # Replace the below (including '{}' braces) with your twitter API_KEY and API_SECRET
+       TWITTER_APP_ID={API_KEY}
+       TWITTER_APP_SECRET={API_SECRET}
+
+       # APP_URL Needs to be set to your BookStack base url
+       APP_URL=http://mybookstackurl.com
+       ```
+7. All done! Users should now be able to link their Twitter account in their account profile pages and also register/login using their Twitter account.
+
+---
+
+### Facebook
+
+1. Navigate to the [Facebook developers page](https://developers.facebook.com) then go 'My Apps' -> 'Add a New App'.
+2. Enter an app name ('BookStack login' or something custom) and contact email then continue.
+3. In your new app select 'Add Product' on the left sidebar then choose 'Facebook Login' by clicking the 'Get Started' button. Select the 'Web' option if asked to choose a platform.
+4. Enter the your base BookStack url into the 'Site URL' box and save.
+5. On the left sidebar again go to 'Facebook Login' -> 'Settings'.
+6. Enter the following URLs under 'Valid OAuth Redirect URIs', changing `https://example.com` to your own domain where BookStack is hosted:
+    - `https://example.com/login/service/facebook/callback`
+    - `https://example.com/register/service/facebook/callback`
+7. Navigate back to the app 'Dashboard' in the sidebar to find your app id and secret. Add or set these to your `.env` file like so:
+       ```bash
+       # Replace the below (including '{}' braces) with your facebook APP_KEY and APP_SECRET
+       FACEBOOK_APP_ID={APP_KEY}
+       FACEBOOK_APP_SECRET={APP_SECRET}
+
+       # APP_URL Needs to be set to your BookStack base url
+       APP_URL=http://mybookstackurl.com
+       ```
+7. All done! Users should now be able to link their Facebook account in their account profile pages and also register/login using their Facebook account.
+
+---
+
+### Slack
+
+1. Go to the [Slack apps page](https://api.slack.com/apps) and select 'Create New App'.
+2. Enter an app name ('BookStack login' or something custom), select your team then continue.
+3. You should see your client ID and secret. Copy these details and add them as new variables in your `.env` file like so:
+       ```bash
+       # Replace the below (including '{}' braces) with your slack CLIENT_ID and CLIENT_SECRET
+       SLACK_APP_ID={CLIENT_ID}
+       SLACK_APP_SECRET={CLIENT_SECRET}
+
+       # APP_URL Needs to be set to your BookStack base url
+       APP_URL=http://mybookstackurl.com
+       ```
+4. In your slack app go to 'OAuth & Permissions' and enter your BookStack base URL into the 'Redirect URL(s)' input then save.
+5. All done! Users should now be able to link their Slack account in their account profile pages and also register/login using their Slack account.
+
+---
+
+### AzureAD (Microsoft)
+
+1. Login to your your azure portal and navigate to the 'Azure Activity Directory' area.
+2. Under 'Manage > App registrations' select 'New application registration'.
+3. Enter a name ('BookStack'). Keep the 'Application type' as 'Web app / API'. Set the 'Sign-on URL' to be the following, replacing 'https://example.com/' with your base BookStack url: 
+    - `https://example.com/login/service/azure/callback`
+4. Once created, Click on your new application and note the 'Application ID'. This is the APP_ID value for step 9.
+5. Within your application in azure, Navigate to 'Keys' under 'API access'.
+6. Enter any description you want and set a duration ('Never expires' is okay unless you specifically want it to expire). Then click 'Save'.
+7. Copy the string of characters under 'Value'. This is the APP_SECRET value for step 9 and is only shown once.
+8. Back under 'App registrations' click on 'Endpoints'. This will show a list of URL's that each contain a unique ID. For example, the OAuth2 token endpoint will look something like this: `https://login.microsoftonline.com/<UniqueID>/oauth2/token`. Copy out the unique ID. This is the TENANT value for step 9.
+9. Copy these details and add them as new variables in your `.env` file like so:
+       ```bash
+       # Replace the below (including '{}' braces) with your azure APP_ID and APP_SECRET and TENANT
+       AZURE_APP_ID={APP_ID}
+       AZURE_APP_SECRET={APP_SECRET}
+       AZURE_TENANT={TENANT}
+
+       # APP_URL Needs to be set to your BookStack base url
+       APP_URL=http://mybookstackurl.com
+       ```
+10. All done! Users should now be able to link their AzureAD account in their account profile pages and also register/login using their AzureAD account.
+
+---
+
+### Okta
+
+1. Login to Okta and, once logged in, Note the current URL. This is used for the 'BASE_URL' in step 6.
+2. Navigate to the Admin panel then 'Applications' then select 'Add Application'. Then select 'Create New App' on the left.
+3. For the 'Platform' choose 'Web'. For the 'Sign on method' choose 'OpenID Connect' then click 'Create'.
+4. Give the app a name such as 'BookStack' or 'Our documentation'. Under the 'Login redirect URIs' option add both of the below URLs, Changing `https://example.com` to the base URL of your BookStack instance:
+    - `https://example.com/login/service/okta/callback`
+    - `https://example.com/register/service/okta/callback`
+5. Save and scroll down to the 'Client Credentials' area. Copy the 'Client ID' and 'Client secret' values. These are your 'APP_ID' and 'APP_SECRET' values for step 6.
+6. Copy these details and add them as new variables in your `.env` file like so:
+       ```bash
+       # Replace the below (including '{}' braces) with your okta APP_ID and APP_SECRET and BASE_URL.
+       OKTA_APP_ID={APP_ID}
+       OKTA_APP_SECRET={APP_SECRET}
+       # The base URL is the URL from step 1 but with everything after the domain (okta.com) removed.
+       OKTA_BASE_URL={BASE_URL}
+
+       # APP_URL Needs to be set to your BookStack base url
+       APP_URL=http://mybookstackurl.com
+       ```
+7. All set up! Remember to assign the new application you created in Okta to your Okta users otherwise they will not be able to register/login using the service.
+
+---
+
+### GitLab
+
+GitLab authentication works for both [gitlab.com](https://gitlab.com) and self-hosted GitLab instances.
+
+1. Login to GitLab and go to your user settings.
+2. In the left sidebar select 'Applications'.
+3. Set a name to identify the application, such as 'BookStack Authentication', and in the 'Redirect URI' input add both of the below URLs, Changing `https://example.com` to the base URL of your BookStack instance:
+    - `https://example.com/login/service/gitlab/callback`
+    - `https://example.com/register/service/gitlab/callback`
+4. Do not select any of the 'Scopes' checkboxes.
+5. Press 'Save application'. You will be shown the application ID and secret which you'll need for the next step.  
+6. Copy the below details and add them as new variables in your `.env` file like so:
+    ```bash
+    # Replace the below (including '{}' braces) with your GitLab Application Id and Secret values.
+    GITLAB_APP_ID={APP_ID}
+    GITLAB_APP_SECRET={APP_SECRET}
+
+    # APP_URL Needs to be set to your BookStack base url
+    APP_URL=http://mybookstackurl.com
+
+
+    # ONLY REQURED FOR SELF-HOSTED GITLAB INSTANCES - REMOVE FOR GITLAB.COM
+    # Set the below URI to match the base URI of your GitLab install
+    GITLAB_BASE_URI=http://my-custom-gitlab.example.com
+    ```
+7. All set up! Users will now be able to use GitLab to sign-in and register.
+
+---
+
+### Twitch
+
+To allow twich sign-in you'll first need to create an application from the Twitch developer site. Here's the process:
+
+1. Login into the [Twitch developer website](https://dev.twitch.tv/).
+2. Navigate to your 'Dashboard' then ['Apps'](https://dev.twitch.tv/dashboard/apps) and select 'Register Your Application'.
+3. Set a name to identify the application, such as 'BookStack Authentication', and in the 'OAuth Redirect URI' input add the below URL, Changing `https://example.com` to the base URL of your BookStack instance:
+    - `https://example.com/login/service/twitch/callback`
+4. Under the 'Application Category' option select 'Website Integration' then hit 'Register'.
+5. Click the 'New Secret' button and accept the prompt that appears. You should now see both a 'Client ID' and 'Client Secret' value which you'll use in the next step.
+6. Copy the below details and add them as new variables in your `.env` file like so:
+    ```bash
+    # Replace the below (including '{}' braces) with your Twitch Application Id and Secret values.
+    TWITCH_APP_ID={APP_ID}
+    TWITCH_APP_SECRET={APP_SECRET}
+
+    # APP_URL Needs to be set to your BookStack base url
+    APP_URL=http://mybookstackurl.com
+    ```
+7. All set up! Users will now be able to use Twitch to sign-in and register.
+
+---
+
+### Discord
+
+To allow Discord sign-in you'll first need to create an application on the Discord developer site. Here's the process:
+
+1. Login into the [Discord developer website](https://discordapp.com/developers/applications/me).
+2. Select 'Create an application'.
+3. Set a name to identify the application, such as 'BookStack Authentication', and save.
+4. In the sidebar, Open the OAuth2 settings for your application and add a redirect. Input the below URL, Changing `https://example.com` to be the base URL of your BookStack instance then save:
+    - `https://example.com/login/service/discord/callback`
+5. Back in the 'General Information' section find the 'Client ID' and 'Client Secret' values which you'll use in the next step.
+6. Copy the below details and add them as new variables in your `.env` file like so:
+    ```bash
+    # Replace the below (including '{}' braces) with your Discord Application Id and Secret values.
+    DISCORD_APP_ID={APP_ID}
+    DISCORD_APP_SECRET={APP_SECRET}
+
+    # APP_URL Needs to be set to your BookStack base url
+    APP_URL=http://mybookstackurl.com
+    ```
+7. All set up! Users will now be able to use Discord to sign-in and register.
index 4df48248b3970701022d6380e4e1e4a40e07081f..e0d2f6c4f0e792926c62b56e9bfb79d41dbb5905 100644 (file)
@@ -2,32 +2,97 @@
 title = "Updating BookStack"
 description = "How to update BookStack to the lastest version"
 date = "2017-01-01"
-type = "admin-docs"
+type = "admin-doc"
 +++
 
-BookStack is updated regularly and is still in beta although we do try to keep the platform and upgrade path as stable as possible. The latest release can be found on [GitHub here](https://github.com/BookStackApp/BookStack/releases) and detailed information on releases is posted on the [BookStack blog here](https://www.bookstackapp.com/blog/tag/releases/).
+BookStack is updated regularly and is still in beta although we do try to keep the platform and upgrade path as stable as possible. The latest release can be found on [GitHub here](https://github.com/BookStackApp/BookStack/releases) and detailed information on releases is posted on the [BookStack blog here](/tags/releases/).
 
 **Before updating you should back up the database and any file uploads to prevent potential data loss**. <br>
 Backup and restore documentation can be found [here](/docs/admin/backup-restore).
 
  Updating is currently done via Git version control. To update BookStack you can run the following command in the root directory of the application:
+
+```bash
+git pull origin release && composer install --no-dev && php artisan migrate
 ```
-git pull origin release && composer install && php artisan migrate
-```
+
 This command will update the repository that was created in the installation, install the PHP dependencies using `composer` then run then update the database with any required changes.
 
-In addition, we recommend clearing the cache after an update - 
+In addition, Clearing the cache is also recommended:
 
-```
+```bash
 php artisan cache:clear
 php artisan view:clear
 ```
 
 Check the below list for the version you are updating to for any additional instructions.
 
+---
 
 ## Version Specific Instructions
 
+#### Updating to v0.28 or higher
+
+**Requirements Change** - Minimum PHP version has increased from 7.0.5 to 7.2.
+
+If you installed BookStack on Ubuntu 16.04 using the install script, You should be able to upgrade your PHP version to 7.4 by running the following commands:
+
+```bash
+sudo add-apt-repository -y ppa:ondrej/php
+sudo apt update
+sudo apt install -y php7.4 php7.4-fpm php7.4-curl php7.4-mbstring php7.4-ldap php7.4-tidy php7.4-xml php7.4-zip php7.4-gd php7.4-mysql
+sudo sed -i.bak 's/php7\.0-fpm/php7.4-fpm/' /etc/nginx/sites-available/bookstack
+sudo systemctl restart nginx.service
+```
+
+#### Updating to v0.26 or higher
+
+**Internet Explorer Support** - IE11 Support has now been dropped. We *may* support any critical issues for view-only scenarios otherwise please use a modern browser.
+
+**Translations** - Since many interfaces and lines of text have been updated, It may take a little while for some translations to catch-up. Expect to see more English text than usual if you're using a non-English language option.
+
+**Images** - Due to changes how images are handled, as detailed below, some types of images may become inaccessible. Old logo images will be deleted when changed. Unused Book/Shelf cover images & User profile images will be become inaccessible after the update so you may want to delete them before upgrade.
+
+**Security** - On previous versions of BookStack it was possible for users to insert JavaScript via the Markdown editor using `on*` html attributes. These will now be removed on page render unless you have set `ALLOW_CONTENT_SCRIPTS=true`. If untrusted users has access to your BookStack you may want to scan for `<<space_char>>on` in the HTML column of the pages table to identify any malicious intent.
+
+#### Updating to v0.25.3 or higher
+
+**Security** - On previous versions of BookStack it was possible to upload PHP files via the image upload endpoints. If you have a BookStack instance where untrusted users could upload image files, and you were using the default file storage option, It would have been possible for the user to access anything that the PHP process could. This would likely include, at minimum, any credentials stored in the `.env` file.
+
+#### Updating to v0.25.2 or higher
+
+**Configuration Change** - The .env option `REDIS_CLUSTER` has now been removed. If more than one redis server is provided they will automatically be clustered by BookStack.
+
+#### Updating to v0.25 or higher
+
+**Security** - During the release cycle for Version v0.25 it was found that page content includes could leak their content as preview text to users that don’t have permission to view the included content. It’s recommended to re-save any pages that included other page content that’s restricted to ensure included text is not shown in page preview text.
+
+**Requirements Change** - Minimum required version of PHP has changed from 7.0.0 to 7.0.5.
+
+**Configuration Change** - The .env option `GRAVATAR_URL=false` has been replaced by `AVATAR_URL=false`.
+
+
+#### Updating to v0.24 or higher
+
+Version v0.24 changes the way the homepage option is stored. After updating, You may need to re-configure this setting.
+
+If updating from a much older BookStack version (Pre v0.20) you may need to update the permission and search indexes. You can do this by running the following commands from your BookStack install folder:
+
+```bash
+php artisan bookstack:regenerate-search
+php artisan bookstack:regenerate-permissions
+```
+
+#### Updating to v0.19 or higher
+
+Version v0.19 needs the following requirement change:
+
+* Minimum required version of PHP has changed from 5.6.4 to 7.0.0.
+
+#### Updating to v0.18 or higher
+
+Version v0.18 introduced a commenting system. After updating you should check the permissions for all roles if you'd like to enable comments for your users.
+
 #### Updating to v0.13 or higher
 
 The v0.13 release contained some new features and updates which change the requirements of BookStack.
diff --git a/content/docs/admin/upload-config.md b/content/docs/admin/upload-config.md
new file mode 100644 (file)
index 0000000..68e1aae
--- /dev/null
@@ -0,0 +1,192 @@
++++
+title = "Configuring File Uploads"
+description = "Configuration for files uploads such as images and attachments"
+date = "2018-01-12"
+type = "admin-doc"
++++
+
+BookStack allows users to upload both images for content and files as attachments.
+
+* [Storage Options](#storage-options)
+* [Changing Upload Limits](#changing-upload-limits)
+* [File Upload Timeout](#file-upload-timeout)
+* [File Upload Limit](#file-upload-limit)
+
+**For information relating to security for file uploads please refer to the [Security Page](/docs/admin/security).**
+
+---
+
+### Storage Options
+
+Within BookStack there are a few different options for storing files:
+
+* **local** (Default) - Files are stored on the server running BookStack. Images are publically accessible, served by your websever, but attachments are secured behind BookStack's authentication.
+* **local_secure** - Same as local option but images are served by BookStack, enabling authentication on image requests. Provides higher security but is more system resource intensive and could induce performance issues.
+* **s3** - Store files externally on Amazon S3. Images are made publically accessible on upload.
+
+For all options you can use the 'Enable higher security image uploads' in-app admin setting which appends a random string to each uploaded image name to make URL's hard to guess.
+
+#### Local
+
+This is the default storage mechanism in BookStack. It can be forced by setting the following in your `.env` file:
+
+```bash
+STORAGE_TYPE=local
+```
+
+* Image uploads location: `<bookstack_install_dir>/public/uploads/images`.
+* Attachment uploads location: `<bookstack_install_dir>/storage/uploads/files`.
+
+#### Local (Secure)
+
+The local secure option can be enabled by setting the following in your `.env` file:
+
+```bash
+STORAGE_TYPE=local_secure
+```
+
+After setting this option ensure you test system performance creating a page with many images and reload on that page multiple times to ensure your server can keep with the 
+multitude of image requests.
+
+* Image uploads location: `<bookstack_install_dir>/storage/uploads/images`.
+* Attachment uploads location: `<bookstack_install_dir>/storage/uploads/files`.
+
+If you'd like to switch to this option from the default `local` storage system you'll first need to migrate existing image uploads to the image folder listed above.
+
+#### S3
+
+The Amazon s3 option can be enabled by setting the following in your `.env` file:
+
+```bash
+STORAGE_TYPE=s3
+STORAGE_S3_KEY=your-s3-key
+STORAGE_S3_SECRET=your-s3-secret
+STORAGE_S3_BUCKET=s3-bucket-name
+STORAGE_S3_REGION=s3-bucket-region
+```
+
+For performance reasons uploaded images are made public upon upload to your s3 bucket and fetched directly by the end user when viewing an image on BookStack. Attachments are not made public and are instead fetched by BookStack upon request. Exact security will depend on the configuration and policies of your bucket.
+
+* Image uploads location: `<your_bucket>/uploads/images`.
+* Attachment uploads location: `<your_bucket>/uploads/files`.
+
+By default BookStack will generate a valid Amazon S3 URL for uploaded images. If you'd prefer to use a different URL, that you have pointed at your bucket, you can add the below option to your `.env` file which will be used as a base URL for all image uploads:
+
+```bash
+STORAGE_URL=https://images.example.com
+```
+
+#### Non-Amazon, S3 Compatible Services
+
+Via the s3 connection BookStack does support s3-compatible services such as [Minio](https://www.minio.io/). Read the above S3 details to get an idea of general setup.
+For non-Amazon services the configuration, to be placed in the `.env` file, is a little different:
+
+```bash
+STORAGE_TYPE=s3
+STORAGE_S3_KEY=your-service-key
+STORAGE_S3_SECRET=your-service-secret-key
+STORAGE_S3_BUCKET=your-service-bucket-name
+
+STORAGE_S3_ENDPOINT=https://your-service-base-endpoint.com:8080
+STORAGE_URL=https://your-service-base-endpoint.com:8080/your-service-bucket-name
+```
+
+Take note of how the first part of the `STORAGE_URL` path is the bucket name. This is important to ensure image URLs are set correctly.
+
+BookStack's functionality to set image URL's as publicly accessible will likely not work for third-party services so you'll need to ensure files under the `<your_bucket>/uploads/images` path have policy or permissions to be publicly accessible. If using Minio you can add the following to the bucket policy:
+
+![Minio Bucket Policy](/images/2019/01/minio_s3_policy.png)
+
+#### Separate Image and Attachment Storage
+
+If you'd prefer to store images and attachments via different storage options, you can use the below `.env` options to do so:
+
+```bash
+# Image storage system to use 
+# Defaults to the value of STORAGE_TYPE if unset. 
+# Accepts the same values as STORAGE_TYPE. 
+STORAGE_IMAGE_TYPE=local 
+  
+# Attachment storage system to use 
+# Defaults to the value of STORAGE_TYPE if unset. 
+# Accepts the same values as STORAGE_TYPE although 'local' will be forced to 'local_secure'. 
+STORAGE_ATTACHMENT_TYPE=local_secure 
+ ```
+
+---
+
+### Changing Upload Limits
+
+By default, a lot of server software has strict limits on upload sizes which causes errors when users upload new content. This is not configured as part of BookStack but as part of PHP and your web sever software. If you run into problems with upload size limits follow the below details for PHP and whichever web server you use:
+
+#### PHP
+
+PHP has two main variables which effect upload limits. Find your `php.ini` file and look for the following variables:
+
+* `post_max_size`
+* `upload_max_filesize`
+
+If the values of these variables are low increase them to something sensible that's not too high to cause issues. Unless you need something higher 10MB is a sensible value to enter for these values:
+
+```
+post_max_size = 10M
+upload_max_filesize = 10M
+```
+
+After updating these values ensure you restart your webserver and also PHP if using PHP-FPM or something similar.
+
+#### NGINX
+
+By default NGINX has a limit of 1MB on file uploads. To change this you will need to set the `client_max_body_size` variable. You can do this either in the http block in your `nginx.conf` file or in the server block set up for BookStack. Here's an example of increasing the limit it 10MB in the http block:
+
+```nginx
+http {
+       #...
+        client_max_body_size 100m;
+        client_body_timeout 120s; # Default is 60, May need to be increased for very large uploads
+       #...
+}
+```
+
+As per the example above, If you are expecting upload very large files where upload times will exceed 60 seconds you will also need to add the `client_body_timeout` variable with a large value.
+
+After updating you NGINX configuration don't forget to restart NGINX. You can test the configuration beforehand with `nginx -t`.
+
+#### Apache
+
+Apache does not have any built-in limits which you will need to change but something to note is that if you are using apache and mod_php with `.htaccess` files enabled you may be able to set the above PHP variables in your `.htaccess` file like so:
+
+```apache
+php_value upload_max_filesize 10M
+php_value post_max_size 10M
+```
+
+---
+
+### File Upload Timeout
+
+File uploads in BookStack use a JavaScript library which has a default upload timeout of 60 seconds. This means that if the file that you are uploading does not upload completely to the server within 60 seconds, the system will timeout. 
+
+To modify this timeout, in BookStack settings, Find the 'Custom HTML head content' setting and add the below code. Note that this does not change any server-side upload limits, Your websever may still impose an upload limit.
+
+```html
+<script>
+    // Set the file upload timeout to 120 seconds.
+    // You can change '120' to be the number of seconds you want the timeout to be. 
+    window.uploadTimeout = 120 * 1000;
+</script>
+```
+
+---
+
+### File Upload Limit
+
+File uploads in BookStack use a JavaScript library which has a default upload size limit of 256MB. To modify this timeout, in BookStack settings, Find the 'Custom HTML head content' setting and add the below code. Note that this does not change any server-side upload limits, Your websever may still impose an upload limit.
+
+```html
+<script>
+    // Set the file upload limit to 1.5GB.
+    // The value is defined in MB. 
+    window.uploadLimit = 1500;
+</script>
+```
\ No newline at end of file
diff --git a/content/docs/admin/upload-limits.md b/content/docs/admin/upload-limits.md
deleted file mode 100644 (file)
index d9b540c..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-+++
-title = "Changing Upload Limits"
-description = "How to increase uploads limits for images and attachments"
-date = "2017-01-01"
-type = "admin-docs"
-+++
-
-BookStack allows users to upload both images for content and files as attachments. By default, a lot of server software has strict limits on upload sizes which causes errors when users upload new content. This is not configured as part of BookStack but as part of PHP and your web sever software. If you run into problems with upload size limits follow the below details for PHP and whichever web server you use:
-
----
-
-### PHP
-
-PHP has two main variables which effect upload limits. Find your `php.ini` file and look for the following variables:
-
-* `post_max_size`
-* `upload_max_filesize`
-
-If the values of these variables are low increase them to something sensible that's not too high to cause issues. Unless you need something higher 10MB is a sensible value to enter for these values:
-
-```
-post_max_size = 10M
-upload_max_filesize = 10M
-```
-
-After updating these values ensure you restart your webserver and also PHP if using PHP-FPM or something similar.
-
----
-
-### NGINX
-
-By default NGINX has a limit of 1MB on file uploads. To change this you will need to set the `client_max_body_size` variable. You can do this either in the http block in your `nginx.conf` file or in the server block set up for BookStack. Here's an example of increasing the limit it 10MB in the http block:
-
-```
-http {
-       #...
-        client_max_body_size 100m;
-        client_body_timeout 120s; # Default is 60, May need to be increased for very large uploads
-       #...
-}
-```
-
-As per the example above, If you are expecting upload very large files where upload times will exceed 60 seconds you will also need to add the `client_body_timeout` variable with a large value.
-
-After updating you NGINX configuration don't forget to restart NGINX. You can test the configuration beforehand with `nginx -t`.
-
----
-
-### Apache
-
-Apache does not have any built-in limits which you will need to change but something to note is that if you are using apache and mod_php with `.htaccess` files enabled you may be able to set the above PHP variables in your `.htaccess` file like so:
-
-```
-php_value upload_max_filesize 10M
-php_value post_max_size 10M
-```
\ No newline at end of file
index 85317df53e7931bafdcad3ca839d333925eafd44..158e14514bf2a138c8ae2add84e81cb5271988e9 100644 (file)
@@ -2,7 +2,7 @@
 title = "UTF8mb4/Emoji Support"
 description = "Adding UTF8mb4 support to allow use of emoji in content"
 date = "2017-01-01"
-type = "admin-docs"
+type = "admin-doc"
 slug = "ut8mb4-support"
 +++
 
@@ -15,7 +15,7 @@ to support emoji.
 
 From v0.17.2, BookStack has a helper command to generate the SQL for this change. Ensure you are on BookStack v0.17.2 or above and then run this command from root BookStack folder:
 
-```
+```bash
 php artisan bookstack:db-utf8mb4
 ```
 
index 1f22c5cb60c5ed206aa496b0a1cfcb530fe7373f..f77a387dd15a796e78f939227d8d2bf842e580ca 100644 (file)
@@ -1,17 +1,78 @@
 +++
-title = "Customising BookStack"
+title = "Customising Visuals"
 description = "Changing the colors, logo and styles of BookStack to suit your needs"
-date = "2017-01-01"
-type = "admin-docs"
+date = "2017-08-22"
+type = "admin-doc"
 +++
 
-You may find you want to customise BookStack to use custom branding or you may just not like the default blue theme. Customising the branding of BookStack is super simple and can be done through the settings interface under 'App Settings'. Here you can change the application name, logo and primary color.
+You may find you want to customise BookStack to use custom branding or you may just not like the default blue theme. Customising the branding of BookStack is super simple and can be done through the settings interface under 'App Settings'. Here you can change the application name, logo and the core colours used.
 Changing the app name will simply update the name displayed in the header and browser tab.
 Changing the logo updates the logo shown in the header. This can be removed if you only want to display the chosen name.
 Changing the app color will update the color of the header, links and the majority of buttons within the system.
 
+### Changing Fonts
+
+To change fonts you can make use of the 'Custom HTML head content' setting to add some CSS to alter fonts used.
+Copy the code below and alter the font names to your desired fonts. Then paste this into the 'Custom HTML head content' box
+in the admin settings of BookStack.
+
+```html
+<style>
+body, button, input, select, label, textarea {
+  font-family: "Roboto", sans-serif;
+}
+.Codemirror, pre, #markdown-editor-input, .editor-toolbar, .code-base {
+  font-family: monospace;
+}
+</style>
+```
+
+Here's an example of using the 'Lato' font from [Google Web Fonts](https://fonts.google.com):
+
+```html
+<link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet">
+<style>
+body, button, input, select, label, textarea {
+  font-family: 'Lato', sans-serif;
+}
+.Codemirror, pre, #markdown-editor-input, .editor-toolbar, .code-base {
+  font-family: monospace;
+}
+</style>
+```
+
+Note that this won't change anything in the settings screen for stability purposes.
+
+### Changing Code Block Themes
+
+When inserting code into a page or when using the Markdown editor, the text you enter is highlighted by a default codemirror colour scheme.
+If you'd prefer a different colour scheme for code blocks this can be overridden. BookStack uses CodeMirror to render code blocks. You can [try out different themes here](https://codemirror.net/demo/theme.html#base16-light). Once you've chosen a theme note down the name.
+
+In BookStack settings, Find the 'Custom HTML head content' setting and add the following code:
+
+```html
+<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.29.0/theme/cobalt.min.css"/>
+<script>window.codeTheme='cobalt';</script>
+```
+
+In the above example we are setting the theme to `cobalt`. Change `cobalt` to the name of your desired theme on both of the above lines.
+The first lines adds the required theme styles, Fetched from [cdnjs](https://cdnjs.com/) whom generously host all CodeMirror files.
+The second line then sets the theme name which will be picked up when code blocks are rendered.
+
+### Default Book View
+
+By default the `/books` page displays your books as a list. Users can change this option to list or grid view but if you'd like to set the default for public viewers or new users you can add the following to your `.env` file:
+
+```bash
+# Show grid view by default
+APP_VIEWS_BOOKS=grid
+
+# Show list view by default
+APP_VIEWS_BOOKS=list
+```
+
 ### Further Customisation
 
 If you need to customise BookStack further to the given controls in the settings area you can make use of the 'Custom HTML head content' setting. Using this you can add in any custom JavaScript or CSS content to override default BookStack functionality and styles.
 
-Further customisation options have been requested and are planned in the future once the core features of BookStack have matured.
+[View the Hacking BookStack](/docs/admin/hacking-bookstack/) page for more advanced ways to achieve deeper customisation.
diff --git a/content/docs/user/_index.md b/content/docs/user/_index.md
new file mode 100644 (file)
index 0000000..3c7c302
--- /dev/null
@@ -0,0 +1,4 @@
+---
+title: "BookStack Blog"
+type: "user-doc"
+---
\ No newline at end of file
index 026c69ff23e2526b641c2ab27a6e1c641cf68134..fb556e8bd42efc380c7b98f344ab932f65dde056 100644 (file)
@@ -1,23 +1,34 @@
 +++
 title = "Content Overview"
 description = "Overview of BookStack content objects and data types"
-date = "2017-01-01"
-type = "user-docs"
+date = "2018-09-23"
+type = "user-doc"
 +++
 
-The principles of storing information within BookStack is based of the ideas of a normal stack of books. Just like normal books, BookStack books can contain chapters and pages. You start off by creating a book which acts as the highest level of categorisation. Ideally you'd have separate books for separate topics. Within a book you can directly create pages or you can first create chapters. Chapters provide an additional level of page grouping to keep pages organised but are optional. All the information you write is held within pages. Although books and chapters do not hold information they can be given a short description to assist with searching and visibility.
+The principles of storing information within BookStack is based of the ideas of a normal stack of books. Just like normal books, BookStack books can contain chapters and pages. You start off by creating a book which acts as the highest level of categorisation. Ideally you'd have separate books for separate topics.
+
+Within a book you can directly create pages or you can first create chapters. Chapters provide an additional level of page grouping to keep pages organised but are optional. All the information you write is held within pages. Although books and chapters do not hold information they can be given a short description to assist with searching and visibility.
+
+Once you start to stack-up books you can start to use Bookshelves to organise your Books. Bookshelves can contain mulitple books and a single book could be placed on multiple Bookshelves. 
 
 ### Default Colour Coding
 
-Books, chapters and pages have set colour coding in BookStack to ensure they are easily identifiable. The below examples show the default color scheme. Note that this may be overridden by your administrator.
+Bookshelves, Books, chapters and pages have set colour coding in BookStack to ensure they are easily identifiable. The below examples show the default color scheme. Note that this may be overridden by your administrator.
 
- <span style="color:#009688;line-height:12px;"><svg fill="#009688" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"></path><path d="M18 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM6 4h5v8l-2.5-1.5L6 12V4z"></path></svg> <span style="position:relative;top:-6px;">Books</span></span>
+<span style="color:#009688;line-height:12px;"><svg fill="#009688" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"></path><path d="M18 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM6 4h5v8l-2.5-1.5L6 12V4z"></path></svg> <span style="position:relative;top:-6px;">Books</span></span>
+&nbsp;
 &nbsp;
 <span style="color:#ef7c3c;"><svg fill="#ef7c3c" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0V0z" fill="none"></path><path d="M4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6z"></path><path d="M0 0h24v24H0V0z" fill="none"></path><path d="M20 2H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 10l-2.5-1.5L15 12V4h5v8z"></path></svg> <span style="position:relative;top:-6px;">Chapters</span></span>
 &nbsp;
+&nbsp;
 <span style="color:#0288D1;"><svg fill="#0288D1" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"></path><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"></path></svg> <span style="position:relative;top:-6px;">Pages</span></span>
 &nbsp;
+&nbsp;
 <span style="color:#9A60DA;"><svg fill="#9A60DA" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"></path><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z"></path></svg> <span style="position:relative;top:-6px;">Draft Pages</span></span>
+&nbsp;
+&nbsp;
+<span style="color:#af5a5a;line-height:12px;"><svg class="svg-icon" height="24" width="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#af5a5a"><path fill="none" d="M0 0h24v24H0V0z"></path><path d="M1.088 2.566h17.42v17.42H1.088z" fill="none"></path><path d="M4 20.058h15.892V22H4z"></path><path d="M2.902 1.477h17.42v17.42H2.903z" fill="none"></path><g><path d="M6.658 3.643V18h-2.38V3.643zM11.326 3.643V18H8.947V3.643zM14.722 3.856l5.613 13.214-2.19.93-5.613-13.214z"></path></g></svg> <span style="position:relative;top:-6px;">Bookshelves</span></span>
+
 
 ### Starting Out
 
index 941af060e2c1f37e21338268370e6582a5569473..c90da440e53f601dd14c638d8c39e2192a187d50 100644 (file)
@@ -2,14 +2,13 @@
 title = "Markdown Editor"
 description = "Details on using the markdown editor in BookStack"
 date = "2017-07-28"
-type = "user-docs"
+type = "user-doc"
 +++
 
-If you prefer the write in Markdown the editor in BookStack can be changed at a instance level
-to use a markdown editor instead of the default WYSIWYG editor.
+If you prefer to write in Markdown, the editor in BookStack can be changed at an instance level
+to use a markdown editor instead of the default WYSIWYG editor. The option to use Markdown is currently **not** a user setting but a global instance setting due to formatting differences between the two editors.
 
-The option to use Markdown is currently **not** a user setting but a global instance setting
-due to formatting differences between the two editors.
+> Note that shifting to the markdown editor from the WYSIWYG editor may cause unintended side effects to existing content. This is due to the differences in the way the content is stored in the database.
 
 ### Editor Shortcuts
 
@@ -27,6 +26,10 @@ The following shortcuts are available in the Markdown Editor:
       <td><code>Ctrl+S</code> / <code>Cmd+S</code></td>
       <td>Save Draft</td>
     </tr>
+    <tr>
+      <td><code>Ctrl+Enter</code> / <code>Cmd+Enter</code></td>
+      <td>Save Page &amp; Continue</td>
+    </tr>
     <tr>
       <td>
         <code>Ctrl+1</code> / <code>Cmd+1</code> <br>
index de824f93e6315857f4a9940c2f33805b84026b1e..ee2db2ffdcb7530939617c2bc5b2fa0d752698d2 100644 (file)
@@ -2,7 +2,7 @@
 title = "Organising Content"
 description = "How to organise and sort books, chapters and pages in BookStack"
 date = "2017-01-01"
-type = "user-docs"
+type = "user-doc"
 +++
 
 Once your BookStack instance starts to grow you will find that you may want to re-organise your content. Within BookStack there are two options for moving content around; Either you can move pages and chapters individually or you can sort entire books.
@@ -15,7 +15,7 @@ Books and chapters can be moved directly to a new chapter or book. To move a cha
 
 ![Page Move Menu](/images/docs/page-move-menu.png)
 
-Clicking the 'Move' action will take you to a screen where you can select a new location for your chapter or page. Here you can search for a particular book or chapter using the search bar at the top of the selection screen. Once you select a new parent for your chapter or book press 'Move Page' or 'Move Chapter' and your chapter or page will be moved to the new chapter or book. If you move a chapter all child pages will remain in that chapter and any related activity will now show up under the new parent book.
+Clicking the 'Move' action will take you to a screen where you can select a new location for your chapter or page. Here you can search for a particular book or chapter using the search bar at the top of the selection screen. Once you select a new parent for your chapter or page press 'Move Page' or 'Move Chapter' and your chapter or page will be moved to the new chapter or book. If you move a chapter all child pages will remain in that chapter and any related activity will now show up under the new parent book.
 
 ### Sorting Books
 
@@ -23,4 +23,4 @@ The 'Book Sort' interface allows you to move multiple pages and chapters with ea
 
 ![Book Sort](/images/docs/book-sort.png)
 
-Initially, just the book you came from will show on the left. You can add extra books into the sort interface by selecting them on the right. Here you can simply drag and drop chapters and pages around and also between different books. Once you have organised your content press 'Save' and all included books will be re-organised.
\ No newline at end of file
+Initially, just the book you came from will show on the left. You can add extra books into the sort interface by selecting them on the right. Here you can simply drag and drop chapters and pages around and also between different books. Once you have organised your content press 'Save' and all included books will be re-organised.
index f6aaa8ddd6cf15203961f1bffc97ecf34babfb22..963ffae34d9e30e8e13352b880c98f284c2b28b4 100644 (file)
@@ -2,7 +2,7 @@
 title = "Reusing Page Content"
 description = "How to use include tags to reuse pages and page content within other pages"
 date = "2017-01-22"
-type = "user-docs"
+type = "user-doc"
 slug = "reusing-page-content"
 +++
 
@@ -12,16 +12,16 @@ Note that the include behaviour is non-recursive so including will only work to
 
 ## Include Tags
 
-To include the content of a page within another you can used the following syntax:
+To include the content of a page within another you can use the following syntax:
 
-`{{@page_id}}` or `@{{page_id#content_id}}`
+`{{@page_id}}` or `{{@page_id#content_id}}`
 
 Here are some examples of this in use:
 
-* `{{@5}}` - Include all content from the page with an id of '5'.
-* `{{@10#bkmrk-copyright-year}}` - Include the content within the element of id `bkmrk-copyright-year` in the page with an id of '10'.
+* `{{@5}}` - Includes all the content from the page with an id of '5'.
+* `{{@10#bkmrk-copyright-year}}` - Includes the content within the element of id `bkmrk-copyright-year` in the page with an id of '10'.
 
-You simply enter that in the page editor and then, When the page is viewed, the content will be dynamically be fetched. This means you can update the referenced content and it will show the same changes on any page the content is included within.
+You simply enter that in the page editor and then, when the page is viewed, the content will be dynamically be fetched. This means you can update the referenced content and it will show the same changes on any page the content is included within.
 
 ## Easily Grabbing the Syntax
 
@@ -31,11 +31,11 @@ By default this contains a direct link to that content. If you click the link ic
 
 <video controls src="/images/2017/01/bookstack-includes-popover.mp4"></video>
 
-## Forcing Content ID's
+## Forcing Content IDs
 
-When including a specific block of content the id of the block is used (part after the hash). By default these are generated by BookStack when you save a page. If you are using the WYSIWYG editor the id will stay the same unless the block is removed or re-formatted. In the markdown editor it changes every save and references the content so while it may remain the same there's a good chance an ID can change.
+When including a specific block of content the id of the block is used (part after the hash). By default these are generated by BookStack when you save a page. If you are using the WYSIWYG editor the id will stay the same unless the block is removed or re-formatted. In the markdown editor it changes with every save based on the content so while it may remain the same there's a good chance an ID can change therefore it's recommended to force an ID if you're using the content for includes.
 
-Due to the fact ID's can change it's recommended to force ID's on you content:
+**Note: All ID values must start with "bkmrk" to avoid being overwritten.**
 
 #### WYSIWYG Editor
 
@@ -49,9 +49,8 @@ In the markdown editor you can simply insert HTML with an ID to ensure it does n
 
 ```
 # Old Content
-Copyright BookStack Enterprises 2017
+Copyright BookStack Enterprises 2020
 
 # Revised with ID
-<p id="include-copyright-text">Copyright BookStack Enterprises 2017</p>
-
+<p id="bkmrk-include-copyright-text">Copyright BookStack Enterprises 2020</p>
 ```
index 4d8b5cad89f01b2420fbc03ae2b59277220d2a17..2b06d1e7ca4083f3e05c355a83d8422aed20b850 100644 (file)
@@ -2,15 +2,15 @@
 title = "Searching Content"
 description = "Searching for specific content within BookStack and learning the advanced search syntax"
 date = "2017-04-16"
-type = "user-docs"
+type = "user-doc"
 +++
 
 The ability to search your documentation is vital to day-to-day use.
 There are a few locations within BookStack where you can search for your content.
 Below is a list of search functions within BookStack:
 
-* **Header Search Bar** - The search bar/link in the header of every page allows you to search from anywhere. This search is a global search which will look across all books, chapters and pages in your system. This page contains an interface to help you build a more advanced search. This interface simply generates a more advanced search term using the syntax described below.
-* **Book/Chapter Search Bar** - When viewing a book or chapter a search bar can be found in the top of the right sidebar. These searches will look across all child items.
+* **Header Search Bar** - The search bar/link in the header of every page allows you to search from anywhere. This search is a global search which will look across all books, chapters and pages in your system. After performing a search in this box you'll be led to a search page that includes options and features that can help you build a more advanced search.
+* **Book/Chapter Search Bar** - When viewing a book or chapter a search bar can be found in the top of the left sidebar. These searches will look across all child items.
 * **Move & Link Selection** - When choosing to move a page/chapter or when selecting a page/chapter/book to link to within the editor the most popular items are shown but you also have the ability to search.
 
 ---
@@ -30,13 +30,13 @@ All of the above search locations within BookStack share the ability to use adva
     <td>Normal Searches</td>
     <td>&lt;term_a&gt; &lt;term_b&gt;</td>
     <td>london meeting</td>
-    <td>Normal word search across the name and description or body of your content. When mulitple terms are searched only one term has to match your content but content containing both terms will be higher in the results.</td>
+    <td>Normal word searches across the name and description or body of your content. When mulitple terms are searched only one term has to match your content but content containing both terms will be higher in the results.</td>
   </tr>
   <tr>
     <td>Exact Searches</td>
     <td>"&lt;term&gt;"</td>
     <td>"london meeting"</td>
-    <td>Exact matches will require that the whole string within quotes exists in your content in exactly the same format. Used this if you're looking for an exact phrase containing or if you need to search for a term with spaces in.</td>
+    <td>Exact matches will require that the whole string within quotes exists in your content in exactly the same format. Use this if you're looking for an exact phrase containing or if you need to search for a term with spaces in.</td>
   </tr>
   <tr>
     <td>Tag Searches</td>
@@ -51,7 +51,7 @@ All of the above search locations within BookStack share the ability to use adva
       [location=london] <br>
       [attendees>5]
     </td>
-    <td>Tag searches allow you to find pages with that have specific tags applied. You can search by tag name, by tag value or by both name and value. When searching by tag value an operator must be used to define the match type. You can use <code>=</code>, <code>!=</code>, <code>&lt;</code>, <code>&gt;</code>,<code>&lt;=</code>, <code>&gt;=</code> or <code>like</code> as operators. When using the <code>like</code> operator you can use <code>%</code> symbols to represent wildcards in your search.</td>
+    <td>Tag searches allow you to find pages which have specific tags applied. You can search by tag name, by tag value or by both name and value. When searching by tag value an operator must be used to define the match type. You can use <code>=</code>, <code>!=</code>, <code>&lt;</code>, <code>&gt;</code>,<code>&lt;=</code>, <code>&gt;=</code> or <code>like</code> as operators. When using the <code>like</code> operator you can use <code>%</code> symbols to represent wildcards in your search.</td>
   </tr>
   <tr>
     <td>Filter Searches</td>
@@ -168,7 +168,7 @@ Filters are set advanced search features that can be used in your search term. T
       {type:page|chapter} <br>
       {type:book} <br>
     </td>
-    <td>Restricts the types of content that will be in the search results. <br> Use of this will depend on the type of search. For example, In a chapter search only pages are shown so this has no effect.</td>
+    <td>Restricts the types of content that will be in the search results. <br> Use of this will depend on the type of search. For example, in a chapter search only pages are shown so this has no effect.</td>
   </tr>
 </table>
 
@@ -188,7 +188,7 @@ Below are some examples of using the above syntax and filters with descriptions:
 * `textbook discussion [meeting] {type:page} {created_by:me}`
   * `textbook discussion` - Search content for the words `textbook` or `discussion`
   * `[meeting]` - only show content that has a `meeting` tag applied
-  * `{type:page}` - only show pages, Hide chapters and books
+  * `{type:page}` - only show pages, hide chapters and books
   * `{created_by:me}` - that was created by me.
 
   <br>
index 6f2e0aabcf48bd64d10dcba3a304302ced72f922..bf55cdef7c053e4b71d1a996143ff31f0c506907 100644 (file)
@@ -2,7 +2,7 @@
 title = "Default Page Editor"
 description = "Details on the standard Page editor in BookStack"
 date = "2017-07-28"
-type = "user-docs"
+type = "user-doc"
 +++
 
 The default editor in BookStack is a 'What You See Is What You Get' (WYSIWYG) editor.
@@ -24,6 +24,10 @@ The following shortcuts are available in the WYSIWYG Editor:
       <td><code>Ctrl+S</code> / <code>Cmd+S</code></td>
       <td>Save Draft</td>
     </tr>
+    <tr>
+      <td><code>Ctrl+Enter</code> / <code>Cmd+Enter</code></td>
+      <td>Save Page &amp; Continue</td>
+    </tr>
     <tr>
       <td><code>Ctrl+B</code> / <code>Cmd+B</code></td>
       <td>Bold</td>
index 3c4a822d9aa37c0011322681535356c6f65d14ce..c77159d327d5cc3456622181a75e5563985d3dee 100644 (file)
@@ -1,28 +1,26 @@
-var gulp = require('gulp'),
-    plumber = require('gulp-plumber'),
-    rename = require('gulp-rename');
-var autoprefixer = require('gulp-autoprefixer');
-var minifycss = require('gulp-minify-css');
-var sass = require('gulp-sass');
+const gulp = require('gulp');
+const plumber = require('gulp-plumber');
+const rename = require('gulp-rename');
+const cleanCss = require('gulp-clean-css');
+const sass = require('gulp-sass');
 
-gulp.task('styles', function(){
-  gulp.src(['themes/bookstack/sass/**/*.scss'])
+gulp.task('styles', function() {
+  return gulp.src(['themes/bookstack/sass/**/*.scss'])
     .pipe(plumber({
       errorHandler: function (error) {
         console.log(error.message);
         this.emit('end');
     }}))
     .pipe(sass())
-    .pipe(autoprefixer('last 2 versions'))
     .pipe(gulp.dest('themes/bookstack/static/css/'))
     .pipe(rename({suffix: '.min'}))
-    .pipe(minifycss())
+    .pipe(cleanCss())
     .pipe(gulp.dest('themes/bookstack/static/css/'));
 });
 
 
-gulp.task('default', ['styles']);
+gulp.task('default', gulp.series('styles'));
 
 gulp.task('watch', function() {
-    gulp.watch('themes/bookstack/sass/**/*.scss', ['styles']);
-});
\ No newline at end of file
+  gulp.watch('themes/bookstack/sass/**/*.scss', gulp.series('styles'));
+});
diff --git a/package-lock.json b/package-lock.json
new file mode 100644 (file)
index 0000000..d735fa0
--- /dev/null
@@ -0,0 +1,5067 @@
+{
+  "name": "BookStack-Site",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "abbrev": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+      "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+      "dev": true
+    },
+    "ajv": {
+      "version": "6.10.2",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
+      "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
+      "dev": true,
+      "requires": {
+        "fast-deep-equal": "^2.0.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      }
+    },
+    "amdefine": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
+      "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
+      "dev": true
+    },
+    "ansi-colors": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
+      "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==",
+      "dev": true,
+      "requires": {
+        "ansi-wrap": "^0.1.0"
+      }
+    },
+    "ansi-cyan": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz",
+      "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=",
+      "dev": true,
+      "requires": {
+        "ansi-wrap": "0.1.0"
+      }
+    },
+    "ansi-gray": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz",
+      "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=",
+      "dev": true,
+      "requires": {
+        "ansi-wrap": "0.1.0"
+      }
+    },
+    "ansi-red": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz",
+      "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=",
+      "dev": true,
+      "requires": {
+        "ansi-wrap": "0.1.0"
+      }
+    },
+    "ansi-regex": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+      "dev": true
+    },
+    "ansi-styles": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+      "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+      "dev": true
+    },
+    "ansi-wrap": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz",
+      "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=",
+      "dev": true
+    },
+    "anymatch": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+      "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+      "dev": true,
+      "requires": {
+        "micromatch": "^3.1.4",
+        "normalize-path": "^2.1.1"
+      }
+    },
+    "append-buffer": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz",
+      "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=",
+      "dev": true,
+      "requires": {
+        "buffer-equal": "^1.0.0"
+      }
+    },
+    "aproba": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+      "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
+      "dev": true
+    },
+    "archy": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
+      "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
+      "dev": true
+    },
+    "are-we-there-yet": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+      "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
+      "dev": true,
+      "requires": {
+        "delegates": "^1.0.0",
+        "readable-stream": "^2.0.6"
+      }
+    },
+    "arr-diff": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+      "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+      "dev": true
+    },
+    "arr-filter": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz",
+      "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=",
+      "dev": true,
+      "requires": {
+        "make-iterator": "^1.0.0"
+      }
+    },
+    "arr-flatten": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+      "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+      "dev": true
+    },
+    "arr-map": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz",
+      "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=",
+      "dev": true,
+      "requires": {
+        "make-iterator": "^1.0.0"
+      }
+    },
+    "arr-union": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+      "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
+      "dev": true
+    },
+    "array-each": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
+      "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=",
+      "dev": true
+    },
+    "array-find-index": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
+      "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
+      "dev": true
+    },
+    "array-initial": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz",
+      "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=",
+      "dev": true,
+      "requires": {
+        "array-slice": "^1.0.0",
+        "is-number": "^4.0.0"
+      },
+      "dependencies": {
+        "is-number": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+          "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+          "dev": true
+        }
+      }
+    },
+    "array-last": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz",
+      "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==",
+      "dev": true,
+      "requires": {
+        "is-number": "^4.0.0"
+      },
+      "dependencies": {
+        "is-number": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+          "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+          "dev": true
+        }
+      }
+    },
+    "array-slice": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
+      "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==",
+      "dev": true
+    },
+    "array-sort": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz",
+      "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==",
+      "dev": true,
+      "requires": {
+        "default-compare": "^1.0.0",
+        "get-value": "^2.0.6",
+        "kind-of": "^5.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+          "dev": true
+        }
+      }
+    },
+    "array-unique": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+      "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+      "dev": true
+    },
+    "asn1": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+      "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+      "dev": true,
+      "requires": {
+        "safer-buffer": "~2.1.0"
+      }
+    },
+    "assert-plus": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+      "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+      "dev": true
+    },
+    "assign-symbols": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+      "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
+      "dev": true
+    },
+    "async-done": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.1.tgz",
+      "integrity": "sha512-R1BaUeJ4PMoLNJuk+0tLJgjmEqVsdN118+Z8O+alhnQDQgy0kmD5Mqi0DNEmMx2LM0Ed5yekKu+ZXYvIHceicg==",
+      "dev": true,
+      "requires": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.2",
+        "process-nextick-args": "^1.0.7",
+        "stream-exhaust": "^1.0.1"
+      }
+    },
+    "async-each": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
+      "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
+      "dev": true
+    },
+    "async-foreach": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz",
+      "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=",
+      "dev": true
+    },
+    "async-settle": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz",
+      "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=",
+      "dev": true,
+      "requires": {
+        "async-done": "^1.2.2"
+      }
+    },
+    "asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+      "dev": true
+    },
+    "atob": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+      "dev": true
+    },
+    "aws-sign2": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+      "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+      "dev": true
+    },
+    "aws4": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz",
+      "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==",
+      "dev": true
+    },
+    "bach": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz",
+      "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=",
+      "dev": true,
+      "requires": {
+        "arr-filter": "^1.1.1",
+        "arr-flatten": "^1.0.1",
+        "arr-map": "^2.0.0",
+        "array-each": "^1.0.0",
+        "array-initial": "^1.0.0",
+        "array-last": "^1.1.1",
+        "async-done": "^1.2.2",
+        "async-settle": "^1.0.0",
+        "now-and-later": "^2.0.0"
+      }
+    },
+    "balanced-match": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+      "dev": true
+    },
+    "base": {
+      "version": "0.11.2",
+      "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+      "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+      "dev": true,
+      "requires": {
+        "cache-base": "^1.0.1",
+        "class-utils": "^0.3.5",
+        "component-emitter": "^1.2.1",
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.1",
+        "mixin-deep": "^1.2.0",
+        "pascalcase": "^0.1.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        }
+      }
+    },
+    "bcrypt-pbkdf": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+      "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+      "dev": true,
+      "requires": {
+        "tweetnacl": "^0.14.3"
+      }
+    },
+    "binary-extensions": {
+      "version": "1.13.1",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
+      "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
+      "dev": true
+    },
+    "block-stream": {
+      "version": "0.0.9",
+      "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
+      "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
+      "dev": true,
+      "requires": {
+        "inherits": "~2.0.0"
+      }
+    },
+    "brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "requires": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "braces": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+      "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+      "dev": true,
+      "requires": {
+        "arr-flatten": "^1.1.0",
+        "array-unique": "^0.3.2",
+        "extend-shallow": "^2.0.1",
+        "fill-range": "^4.0.0",
+        "isobject": "^3.0.1",
+        "repeat-element": "^1.1.2",
+        "snapdragon": "^0.8.1",
+        "snapdragon-node": "^2.0.1",
+        "split-string": "^3.0.2",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
+    "buffer-equal": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz",
+      "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=",
+      "dev": true
+    },
+    "buffer-from": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+      "dev": true
+    },
+    "builtin-modules": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
+      "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
+      "dev": true
+    },
+    "cache-base": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+      "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+      "dev": true,
+      "requires": {
+        "collection-visit": "^1.0.0",
+        "component-emitter": "^1.2.1",
+        "get-value": "^2.0.6",
+        "has-value": "^1.0.0",
+        "isobject": "^3.0.1",
+        "set-value": "^2.0.0",
+        "to-object-path": "^0.3.0",
+        "union-value": "^1.0.0",
+        "unset-value": "^1.0.0"
+      }
+    },
+    "camelcase": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
+      "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
+      "dev": true
+    },
+    "camelcase-keys": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
+      "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
+      "dev": true,
+      "requires": {
+        "camelcase": "^2.0.0",
+        "map-obj": "^1.0.0"
+      },
+      "dependencies": {
+        "camelcase": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
+          "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
+          "dev": true
+        }
+      }
+    },
+    "caseless": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+      "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+      "dev": true
+    },
+    "chalk": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+      "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^2.2.1",
+        "escape-string-regexp": "^1.0.2",
+        "has-ansi": "^2.0.0",
+        "strip-ansi": "^3.0.0",
+        "supports-color": "^2.0.0"
+      }
+    },
+    "chokidar": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.5.tgz",
+      "integrity": "sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A==",
+      "dev": true,
+      "requires": {
+        "anymatch": "^2.0.0",
+        "async-each": "^1.0.1",
+        "braces": "^2.3.2",
+        "fsevents": "^1.2.7",
+        "glob-parent": "^3.1.0",
+        "inherits": "^2.0.3",
+        "is-binary-path": "^1.0.0",
+        "is-glob": "^4.0.0",
+        "normalize-path": "^3.0.0",
+        "path-is-absolute": "^1.0.0",
+        "readdirp": "^2.2.1",
+        "upath": "^1.1.1"
+      },
+      "dependencies": {
+        "normalize-path": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+          "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+          "dev": true
+        }
+      }
+    },
+    "class-utils": {
+      "version": "0.3.6",
+      "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+      "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+      "dev": true,
+      "requires": {
+        "arr-union": "^3.1.0",
+        "define-property": "^0.2.5",
+        "isobject": "^3.0.0",
+        "static-extend": "^0.1.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        }
+      }
+    },
+    "cliui": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
+      "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
+      "dev": true,
+      "requires": {
+        "string-width": "^1.0.1",
+        "strip-ansi": "^3.0.1",
+        "wrap-ansi": "^2.0.0"
+      }
+    },
+    "clone-buffer": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz",
+      "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=",
+      "dev": true
+    },
+    "cloneable-readable": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.2.tgz",
+      "integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.1",
+        "process-nextick-args": "^2.0.0",
+        "readable-stream": "^2.3.5"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "process-nextick-args": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+          "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.6",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "code-point-at": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+      "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
+      "dev": true
+    },
+    "collection-map": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz",
+      "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=",
+      "dev": true,
+      "requires": {
+        "arr-map": "^2.0.2",
+        "for-own": "^1.0.0",
+        "make-iterator": "^1.0.0"
+      }
+    },
+    "collection-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+      "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+      "dev": true,
+      "requires": {
+        "map-visit": "^1.0.0",
+        "object-visit": "^1.0.0"
+      }
+    },
+    "color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
+      "requires": {
+        "color-name": "1.1.3"
+      }
+    },
+    "color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+      "dev": true
+    },
+    "color-support": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
+      "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
+      "dev": true
+    },
+    "combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "dev": true,
+      "requires": {
+        "delayed-stream": "~1.0.0"
+      }
+    },
+    "component-emitter": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+      "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+      "dev": true
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+      "dev": true
+    },
+    "concat-stream": {
+      "version": "1.6.2",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+      "dev": true,
+      "requires": {
+        "buffer-from": "^1.0.0",
+        "inherits": "^2.0.3",
+        "readable-stream": "^2.2.2",
+        "typedarray": "^0.0.6"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "process-nextick-args": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+          "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.6",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "console-control-strings": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+      "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
+      "dev": true
+    },
+    "convert-source-map": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz",
+      "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "~5.1.1"
+      }
+    },
+    "copy-descriptor": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+      "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+      "dev": true
+    },
+    "copy-props": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz",
+      "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==",
+      "dev": true,
+      "requires": {
+        "each-props": "^1.3.0",
+        "is-plain-object": "^2.0.1"
+      }
+    },
+    "core-util-is": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+      "dev": true
+    },
+    "cross-spawn": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz",
+      "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=",
+      "dev": true,
+      "requires": {
+        "lru-cache": "^4.0.1",
+        "which": "^1.2.9"
+      }
+    },
+    "currently-unhandled": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
+      "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
+      "dev": true,
+      "requires": {
+        "array-find-index": "^1.0.1"
+      }
+    },
+    "d": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
+      "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
+      "dev": true,
+      "requires": {
+        "es5-ext": "^0.10.9"
+      }
+    },
+    "dashdash": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+      "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+      "dev": true,
+      "requires": {
+        "assert-plus": "^1.0.0"
+      }
+    },
+    "debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "requires": {
+        "ms": "2.0.0"
+      }
+    },
+    "decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+      "dev": true
+    },
+    "decode-uri-component": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+      "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+      "dev": true
+    },
+    "default-compare": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz",
+      "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^5.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+          "dev": true
+        }
+      }
+    },
+    "default-resolution": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz",
+      "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=",
+      "dev": true
+    },
+    "define-properties": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
+      "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+      "dev": true,
+      "requires": {
+        "object-keys": "^1.0.12"
+      }
+    },
+    "define-property": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+      "dev": true,
+      "requires": {
+        "is-descriptor": "^1.0.2",
+        "isobject": "^3.0.1"
+      },
+      "dependencies": {
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        }
+      }
+    },
+    "delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+      "dev": true
+    },
+    "delegates": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+      "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
+      "dev": true
+    },
+    "detect-file": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
+      "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=",
+      "dev": true
+    },
+    "duplexify": {
+      "version": "3.7.1",
+      "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
+      "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
+      "dev": true,
+      "requires": {
+        "end-of-stream": "^1.0.0",
+        "inherits": "^2.0.1",
+        "readable-stream": "^2.0.0",
+        "stream-shift": "^1.0.0"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "process-nextick-args": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+          "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.6",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "each-props": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz",
+      "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==",
+      "dev": true,
+      "requires": {
+        "is-plain-object": "^2.0.1",
+        "object.defaults": "^1.1.0"
+      }
+    },
+    "ecc-jsbn": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+      "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+      "dev": true,
+      "requires": {
+        "jsbn": "~0.1.0",
+        "safer-buffer": "^2.1.0"
+      }
+    },
+    "end-of-stream": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
+      "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
+      "dev": true,
+      "requires": {
+        "once": "^1.4.0"
+      }
+    },
+    "error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "dev": true,
+      "requires": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "es5-ext": {
+      "version": "0.10.50",
+      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.50.tgz",
+      "integrity": "sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw==",
+      "dev": true,
+      "requires": {
+        "es6-iterator": "~2.0.3",
+        "es6-symbol": "~3.1.1",
+        "next-tick": "^1.0.0"
+      }
+    },
+    "es6-iterator": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
+      "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
+      "dev": true,
+      "requires": {
+        "d": "1",
+        "es5-ext": "^0.10.35",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "es6-symbol": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
+      "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
+      "dev": true,
+      "requires": {
+        "d": "1",
+        "es5-ext": "~0.10.14"
+      }
+    },
+    "es6-weak-map": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz",
+      "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",
+      "dev": true,
+      "requires": {
+        "d": "1",
+        "es5-ext": "^0.10.14",
+        "es6-iterator": "^2.0.1",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+      "dev": true
+    },
+    "expand-brackets": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+      "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+      "dev": true,
+      "requires": {
+        "debug": "^2.3.3",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "posix-character-classes": "^0.1.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
+    "expand-tilde": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+      "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
+      "dev": true,
+      "requires": {
+        "homedir-polyfill": "^1.0.1"
+      }
+    },
+    "extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+      "dev": true
+    },
+    "extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+      "dev": true,
+      "requires": {
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      },
+      "dependencies": {
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        }
+      }
+    },
+    "extglob": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+      "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+      "dev": true,
+      "requires": {
+        "array-unique": "^0.3.2",
+        "define-property": "^1.0.0",
+        "expand-brackets": "^2.1.4",
+        "extend-shallow": "^2.0.1",
+        "fragment-cache": "^0.2.1",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        }
+      }
+    },
+    "extsprintf": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+      "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+      "dev": true
+    },
+    "fast-deep-equal": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+      "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
+      "dev": true
+    },
+    "fast-json-stable-stringify": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
+      "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
+      "dev": true
+    },
+    "fill-range": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+      "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^2.0.1",
+        "is-number": "^3.0.0",
+        "repeat-string": "^1.6.1",
+        "to-regex-range": "^2.1.0"
+      },
+      "dependencies": {
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
+    "find-up": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+      "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
+      "dev": true,
+      "requires": {
+        "path-exists": "^2.0.0",
+        "pinkie-promise": "^2.0.0"
+      }
+    },
+    "findup-sync": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz",
+      "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==",
+      "dev": true,
+      "requires": {
+        "detect-file": "^1.0.0",
+        "is-glob": "^4.0.0",
+        "micromatch": "^3.0.4",
+        "resolve-dir": "^1.0.1"
+      }
+    },
+    "fined": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz",
+      "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==",
+      "dev": true,
+      "requires": {
+        "expand-tilde": "^2.0.2",
+        "is-plain-object": "^2.0.3",
+        "object.defaults": "^1.1.0",
+        "object.pick": "^1.2.0",
+        "parse-filepath": "^1.0.1"
+      }
+    },
+    "flagged-respawn": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz",
+      "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==",
+      "dev": true
+    },
+    "flush-write-stream": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
+      "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==",
+      "dev": true,
+      "requires": {
+        "inherits": "^2.0.3",
+        "readable-stream": "^2.3.6"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "process-nextick-args": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+          "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.6",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "for-in": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+      "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+      "dev": true
+    },
+    "for-own": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
+      "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=",
+      "dev": true,
+      "requires": {
+        "for-in": "^1.0.1"
+      }
+    },
+    "forever-agent": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+      "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+      "dev": true
+    },
+    "form-data": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+      "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+      "dev": true,
+      "requires": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.6",
+        "mime-types": "^2.1.12"
+      }
+    },
+    "fragment-cache": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+      "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+      "dev": true,
+      "requires": {
+        "map-cache": "^0.2.2"
+      }
+    },
+    "fs-mkdirp-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz",
+      "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.11",
+        "through2": "^2.0.3"
+      }
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+      "dev": true
+    },
+    "fsevents": {
+      "version": "1.2.9",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz",
+      "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "nan": "^2.12.1",
+        "node-pre-gyp": "^0.12.0"
+      },
+      "dependencies": {
+        "abbrev": {
+          "version": "1.1.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "ansi-regex": {
+          "version": "2.1.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "aproba": {
+          "version": "1.2.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "are-we-there-yet": {
+          "version": "1.1.5",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "delegates": "^1.0.0",
+            "readable-stream": "^2.0.6"
+          }
+        },
+        "balanced-match": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "brace-expansion": {
+          "version": "1.1.11",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "balanced-match": "^1.0.0",
+            "concat-map": "0.0.1"
+          }
+        },
+        "chownr": {
+          "version": "1.1.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "code-point-at": {
+          "version": "1.1.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "concat-map": {
+          "version": "0.0.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "console-control-strings": {
+          "version": "1.1.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "core-util-is": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "debug": {
+          "version": "4.1.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
+        "deep-extend": {
+          "version": "0.6.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "delegates": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "detect-libc": {
+          "version": "1.0.3",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "fs-minipass": {
+          "version": "1.2.5",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "minipass": "^2.2.1"
+          }
+        },
+        "fs.realpath": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "gauge": {
+          "version": "2.7.4",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "aproba": "^1.0.3",
+            "console-control-strings": "^1.0.0",
+            "has-unicode": "^2.0.0",
+            "object-assign": "^4.1.0",
+            "signal-exit": "^3.0.0",
+            "string-width": "^1.0.1",
+            "strip-ansi": "^3.0.1",
+            "wide-align": "^1.1.0"
+          }
+        },
+        "glob": {
+          "version": "7.1.3",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.0.4",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        },
+        "has-unicode": {
+          "version": "2.0.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "iconv-lite": {
+          "version": "0.4.24",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "safer-buffer": ">= 2.1.2 < 3"
+          }
+        },
+        "ignore-walk": {
+          "version": "3.0.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "minimatch": "^3.0.4"
+          }
+        },
+        "inflight": {
+          "version": "1.0.6",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "once": "^1.3.0",
+            "wrappy": "1"
+          }
+        },
+        "inherits": {
+          "version": "2.0.3",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "ini": {
+          "version": "1.3.5",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "number-is-nan": "^1.0.0"
+          }
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "minimatch": {
+          "version": "3.0.4",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "brace-expansion": "^1.1.7"
+          }
+        },
+        "minimist": {
+          "version": "0.0.8",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "minipass": {
+          "version": "2.3.5",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "safe-buffer": "^5.1.2",
+            "yallist": "^3.0.0"
+          }
+        },
+        "minizlib": {
+          "version": "1.2.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "minipass": "^2.2.1"
+          }
+        },
+        "mkdirp": {
+          "version": "0.5.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "minimist": "0.0.8"
+          }
+        },
+        "ms": {
+          "version": "2.1.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "needle": {
+          "version": "2.3.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "debug": "^4.1.0",
+            "iconv-lite": "^0.4.4",
+            "sax": "^1.2.4"
+          }
+        },
+        "node-pre-gyp": {
+          "version": "0.12.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "detect-libc": "^1.0.2",
+            "mkdirp": "^0.5.1",
+            "needle": "^2.2.1",
+            "nopt": "^4.0.1",
+            "npm-packlist": "^1.1.6",
+            "npmlog": "^4.0.2",
+            "rc": "^1.2.7",
+            "rimraf": "^2.6.1",
+            "semver": "^5.3.0",
+            "tar": "^4"
+          }
+        },
+        "nopt": {
+          "version": "4.0.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "abbrev": "1",
+            "osenv": "^0.1.4"
+          }
+        },
+        "npm-bundled": {
+          "version": "1.0.6",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "npm-packlist": {
+          "version": "1.4.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "ignore-walk": "^3.0.1",
+            "npm-bundled": "^1.0.1"
+          }
+        },
+        "npmlog": {
+          "version": "4.1.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "are-we-there-yet": "~1.1.2",
+            "console-control-strings": "~1.1.0",
+            "gauge": "~2.7.3",
+            "set-blocking": "~2.0.0"
+          }
+        },
+        "number-is-nan": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "object-assign": {
+          "version": "4.1.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "once": {
+          "version": "1.4.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "wrappy": "1"
+          }
+        },
+        "os-homedir": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "os-tmpdir": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "osenv": {
+          "version": "0.1.5",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "os-homedir": "^1.0.0",
+            "os-tmpdir": "^1.0.0"
+          }
+        },
+        "path-is-absolute": {
+          "version": "1.0.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "process-nextick-args": {
+          "version": "2.0.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "rc": {
+          "version": "1.2.8",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "deep-extend": "^0.6.0",
+            "ini": "~1.3.0",
+            "minimist": "^1.2.0",
+            "strip-json-comments": "~2.0.1"
+          },
+          "dependencies": {
+            "minimist": {
+              "version": "1.2.0",
+              "bundled": true,
+              "dev": true,
+              "optional": true
+            }
+          }
+        },
+        "readable-stream": {
+          "version": "2.3.6",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "rimraf": {
+          "version": "2.6.3",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "glob": "^7.1.3"
+          }
+        },
+        "safe-buffer": {
+          "version": "5.1.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "safer-buffer": {
+          "version": "2.1.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "sax": {
+          "version": "1.2.4",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "semver": {
+          "version": "5.7.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "set-blocking": {
+          "version": "2.0.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "signal-exit": {
+          "version": "3.0.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "string-width": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "code-point-at": "^1.0.0",
+            "is-fullwidth-code-point": "^1.0.0",
+            "strip-ansi": "^3.0.0"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "3.0.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "ansi-regex": "^2.0.0"
+          }
+        },
+        "strip-json-comments": {
+          "version": "2.0.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "tar": {
+          "version": "4.4.8",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "chownr": "^1.1.1",
+            "fs-minipass": "^1.2.5",
+            "minipass": "^2.3.4",
+            "minizlib": "^1.1.1",
+            "mkdirp": "^0.5.0",
+            "safe-buffer": "^5.1.2",
+            "yallist": "^3.0.2"
+          }
+        },
+        "util-deprecate": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "wide-align": {
+          "version": "1.1.3",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "string-width": "^1.0.2 || 2"
+          }
+        },
+        "wrappy": {
+          "version": "1.0.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "yallist": {
+          "version": "3.0.3",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
+    "fstream": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
+      "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.2",
+        "inherits": "~2.0.0",
+        "mkdirp": ">=0.5 0",
+        "rimraf": "2"
+      }
+    },
+    "function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+      "dev": true
+    },
+    "gauge": {
+      "version": "2.7.4",
+      "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+      "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+      "dev": true,
+      "requires": {
+        "aproba": "^1.0.3",
+        "console-control-strings": "^1.0.0",
+        "has-unicode": "^2.0.0",
+        "object-assign": "^4.1.0",
+        "signal-exit": "^3.0.0",
+        "string-width": "^1.0.1",
+        "strip-ansi": "^3.0.1",
+        "wide-align": "^1.1.0"
+      }
+    },
+    "gaze": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz",
+      "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==",
+      "dev": true,
+      "requires": {
+        "globule": "^1.0.0"
+      }
+    },
+    "get-caller-file": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
+      "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
+      "dev": true
+    },
+    "get-stdin": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
+      "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
+      "dev": true
+    },
+    "get-value": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+      "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+      "dev": true
+    },
+    "getpass": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+      "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+      "dev": true,
+      "requires": {
+        "assert-plus": "^1.0.0"
+      }
+    },
+    "glob": {
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+      "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+      "dev": true,
+      "requires": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      }
+    },
+    "glob-parent": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+      "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+      "dev": true,
+      "requires": {
+        "is-glob": "^3.1.0",
+        "path-dirname": "^1.0.0"
+      },
+      "dependencies": {
+        "is-glob": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+          "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+          "dev": true,
+          "requires": {
+            "is-extglob": "^2.1.0"
+          }
+        }
+      }
+    },
+    "glob-stream": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz",
+      "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=",
+      "dev": true,
+      "requires": {
+        "extend": "^3.0.0",
+        "glob": "^7.1.1",
+        "glob-parent": "^3.1.0",
+        "is-negated-glob": "^1.0.0",
+        "ordered-read-streams": "^1.0.0",
+        "pumpify": "^1.3.5",
+        "readable-stream": "^2.1.5",
+        "remove-trailing-separator": "^1.0.1",
+        "to-absolute-glob": "^2.0.0",
+        "unique-stream": "^2.0.2"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "process-nextick-args": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+          "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.6",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "glob-watcher": {
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz",
+      "integrity": "sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg==",
+      "dev": true,
+      "requires": {
+        "anymatch": "^2.0.0",
+        "async-done": "^1.2.0",
+        "chokidar": "^2.0.0",
+        "is-negated-glob": "^1.0.0",
+        "just-debounce": "^1.0.0",
+        "object.defaults": "^1.1.0"
+      }
+    },
+    "global-modules": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+      "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
+      "dev": true,
+      "requires": {
+        "global-prefix": "^1.0.1",
+        "is-windows": "^1.0.1",
+        "resolve-dir": "^1.0.0"
+      }
+    },
+    "global-prefix": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+      "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=",
+      "dev": true,
+      "requires": {
+        "expand-tilde": "^2.0.2",
+        "homedir-polyfill": "^1.0.1",
+        "ini": "^1.3.4",
+        "is-windows": "^1.0.1",
+        "which": "^1.2.14"
+      }
+    },
+    "globule": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz",
+      "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==",
+      "dev": true,
+      "requires": {
+        "glob": "~7.1.1",
+        "lodash": "~4.17.10",
+        "minimatch": "~3.0.2"
+      }
+    },
+    "glogg": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz",
+      "integrity": "sha1-f+DxmfV6yQbPUS/urY+Q7kooT8U=",
+      "dev": true,
+      "requires": {
+        "sparkles": "^1.0.0"
+      }
+    },
+    "graceful-fs": {
+      "version": "4.1.15",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
+      "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
+      "dev": true
+    },
+    "gulp": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.1.tgz",
+      "integrity": "sha512-yDVtVunxrAdsk7rIV/b7lVSBifPN1Eqe6wTjsESGrFcL+MEVzaaeNTkpUuGTUptloSOU+8oJm/lBJbgPV+tMAw==",
+      "dev": true,
+      "requires": {
+        "glob-watcher": "^5.0.3",
+        "gulp-cli": "^2.2.0",
+        "undertaker": "^1.2.1",
+        "vinyl-fs": "^3.0.0"
+      },
+      "dependencies": {
+        "fancy-log": {
+          "version": "1.3.3",
+          "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz",
+          "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==",
+          "dev": true,
+          "requires": {
+            "ansi-gray": "^0.1.1",
+            "color-support": "^1.1.3",
+            "parse-node-version": "^1.0.0",
+            "time-stamp": "^1.0.0"
+          }
+        },
+        "gulp-cli": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.2.0.tgz",
+          "integrity": "sha512-rGs3bVYHdyJpLqR0TUBnlcZ1O5O++Zs4bA0ajm+zr3WFCfiSLjGwoCBqFs18wzN+ZxahT9DkOK5nDf26iDsWjA==",
+          "dev": true,
+          "requires": {
+            "ansi-colors": "^1.0.1",
+            "archy": "^1.0.0",
+            "array-sort": "^1.0.0",
+            "color-support": "^1.1.3",
+            "concat-stream": "^1.6.0",
+            "copy-props": "^2.0.1",
+            "fancy-log": "^1.3.2",
+            "gulplog": "^1.0.0",
+            "interpret": "^1.1.0",
+            "isobject": "^3.0.1",
+            "liftoff": "^3.1.0",
+            "matchdep": "^2.0.0",
+            "mute-stdout": "^1.0.0",
+            "pretty-hrtime": "^1.0.0",
+            "replace-homedir": "^1.0.0",
+            "semver-greatest-satisfied-range": "^1.1.0",
+            "v8flags": "^3.0.1",
+            "yargs": "^7.1.0"
+          }
+        }
+      }
+    },
+    "gulp-clean-css": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/gulp-clean-css/-/gulp-clean-css-4.2.0.tgz",
+      "integrity": "sha512-r4zQsSOAK2UYUL/ipkAVCTRg/2CLZ2A+oPVORopBximRksJ6qy3EX1KGrIWT4ZrHxz3Hlobb1yyJtqiut7DNjA==",
+      "dev": true,
+      "requires": {
+        "clean-css": "4.2.1",
+        "plugin-error": "1.0.1",
+        "through2": "3.0.1",
+        "vinyl-sourcemaps-apply": "0.2.1"
+      },
+      "dependencies": {
+        "clean-css": {
+          "version": "4.2.1",
+          "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz",
+          "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==",
+          "dev": true,
+          "requires": {
+            "source-map": "~0.6.0"
+          }
+        },
+        "readable-stream": {
+          "version": "3.3.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.3.0.tgz",
+          "integrity": "sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        },
+        "string_decoder": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz",
+          "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        },
+        "through2": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz",
+          "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==",
+          "dev": true,
+          "requires": {
+            "readable-stream": "2 || 3"
+          }
+        }
+      }
+    },
+    "gulp-plumber": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/gulp-plumber/-/gulp-plumber-1.2.1.tgz",
+      "integrity": "sha512-mctAi9msEAG7XzW5ytDVZ9PxWMzzi1pS2rBH7lA095DhMa6KEXjm+St0GOCc567pJKJ/oCvosVAZEpAey0q2eQ==",
+      "dev": true,
+      "requires": {
+        "chalk": "^1.1.3",
+        "fancy-log": "^1.3.2",
+        "plugin-error": "^0.1.2",
+        "through2": "^2.0.3"
+      },
+      "dependencies": {
+        "arr-diff": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz",
+          "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=",
+          "dev": true,
+          "requires": {
+            "arr-flatten": "^1.0.1",
+            "array-slice": "^0.2.3"
+          }
+        },
+        "arr-union": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz",
+          "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=",
+          "dev": true
+        },
+        "array-slice": {
+          "version": "0.2.3",
+          "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz",
+          "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=",
+          "dev": true
+        },
+        "extend-shallow": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz",
+          "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=",
+          "dev": true,
+          "requires": {
+            "kind-of": "^1.1.0"
+          }
+        },
+        "fancy-log": {
+          "version": "1.3.3",
+          "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz",
+          "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==",
+          "dev": true,
+          "requires": {
+            "ansi-gray": "^0.1.1",
+            "color-support": "^1.1.3",
+            "parse-node-version": "^1.0.0",
+            "time-stamp": "^1.0.0"
+          }
+        },
+        "kind-of": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
+          "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=",
+          "dev": true
+        },
+        "plugin-error": {
+          "version": "0.1.2",
+          "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz",
+          "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=",
+          "dev": true,
+          "requires": {
+            "ansi-cyan": "^0.1.1",
+            "ansi-red": "^0.1.1",
+            "arr-diff": "^1.0.1",
+            "arr-union": "^2.0.1",
+            "extend-shallow": "^1.1.2"
+          }
+        }
+      }
+    },
+    "gulp-rename": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.4.0.tgz",
+      "integrity": "sha512-swzbIGb/arEoFK89tPY58vg3Ok1bw+d35PfUNwWqdo7KM4jkmuGA78JiDNqR+JeZFaeeHnRg9N7aihX3YPmsyg==",
+      "dev": true
+    },
+    "gulp-sass": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/gulp-sass/-/gulp-sass-4.0.2.tgz",
+      "integrity": "sha512-q8psj4+aDrblJMMtRxihNBdovfzGrXJp1l4JU0Sz4b/Mhsi2DPrKFYCGDwjIWRENs04ELVHxdOJQ7Vs98OFohg==",
+      "dev": true,
+      "requires": {
+        "chalk": "^2.3.0",
+        "lodash.clonedeep": "^4.3.2",
+        "node-sass": "^4.8.3",
+        "plugin-error": "^1.0.1",
+        "replace-ext": "^1.0.0",
+        "strip-ansi": "^4.0.0",
+        "through2": "^2.0.0",
+        "vinyl-sourcemaps-apply": "^0.2.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+          "dev": true
+        },
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^1.9.0"
+          }
+        },
+        "chalk": {
+          "version": "2.4.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^3.2.1",
+            "escape-string-regexp": "^1.0.5",
+            "supports-color": "^5.3.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^3.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^3.0.0"
+          }
+        }
+      }
+    },
+    "gulplog": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz",
+      "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=",
+      "dev": true,
+      "requires": {
+        "glogg": "^1.0.0"
+      }
+    },
+    "har-schema": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+      "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+      "dev": true
+    },
+    "har-validator": {
+      "version": "5.1.3",
+      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
+      "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+      "dev": true,
+      "requires": {
+        "ajv": "^6.5.5",
+        "har-schema": "^2.0.0"
+      }
+    },
+    "has-ansi": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+      "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+      "dev": true,
+      "requires": {
+        "ansi-regex": "^2.0.0"
+      }
+    },
+    "has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+      "dev": true
+    },
+    "has-symbols": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
+      "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=",
+      "dev": true
+    },
+    "has-unicode": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+      "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
+      "dev": true
+    },
+    "has-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+      "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+      "dev": true,
+      "requires": {
+        "get-value": "^2.0.6",
+        "has-values": "^1.0.0",
+        "isobject": "^3.0.0"
+      }
+    },
+    "has-values": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+      "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+      "dev": true,
+      "requires": {
+        "is-number": "^3.0.0",
+        "kind-of": "^4.0.0"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+          "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "homedir-polyfill": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+      "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+      "dev": true,
+      "requires": {
+        "parse-passwd": "^1.0.0"
+      }
+    },
+    "hosted-git-info": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz",
+      "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==",
+      "dev": true
+    },
+    "http-signature": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+      "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+      "dev": true,
+      "requires": {
+        "assert-plus": "^1.0.0",
+        "jsprim": "^1.2.2",
+        "sshpk": "^1.7.0"
+      }
+    },
+    "in-publish": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz",
+      "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=",
+      "dev": true
+    },
+    "indent-string": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
+      "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
+      "dev": true,
+      "requires": {
+        "repeating": "^2.0.0"
+      }
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "dev": true,
+      "requires": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "inherits": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+      "dev": true
+    },
+    "ini": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+      "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+      "dev": true
+    },
+    "interpret": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz",
+      "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==",
+      "dev": true
+    },
+    "invert-kv": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
+      "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
+      "dev": true
+    },
+    "is-absolute": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
+      "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
+      "dev": true,
+      "requires": {
+        "is-relative": "^1.0.0",
+        "is-windows": "^1.0.1"
+      }
+    },
+    "is-accessor-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+      "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+      "dev": true
+    },
+    "is-binary-path": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+      "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+      "dev": true,
+      "requires": {
+        "binary-extensions": "^1.0.0"
+      }
+    },
+    "is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+      "dev": true
+    },
+    "is-builtin-module": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
+      "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
+      "dev": true,
+      "requires": {
+        "builtin-modules": "^1.0.0"
+      }
+    },
+    "is-data-descriptor": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+      "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "is-descriptor": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+      "dev": true,
+      "requires": {
+        "is-accessor-descriptor": "^0.1.6",
+        "is-data-descriptor": "^0.1.4",
+        "kind-of": "^5.0.0"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+          "dev": true
+        }
+      }
+    },
+    "is-extendable": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+      "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+      "dev": true
+    },
+    "is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+      "dev": true
+    },
+    "is-finite": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
+      "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
+      "dev": true,
+      "requires": {
+        "number-is-nan": "^1.0.0"
+      }
+    },
+    "is-fullwidth-code-point": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+      "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+      "dev": true,
+      "requires": {
+        "number-is-nan": "^1.0.0"
+      }
+    },
+    "is-glob": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+      "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+      "dev": true,
+      "requires": {
+        "is-extglob": "^2.1.1"
+      }
+    },
+    "is-negated-glob": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz",
+      "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=",
+      "dev": true
+    },
+    "is-number": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+      "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "requires": {
+        "isobject": "^3.0.1"
+      }
+    },
+    "is-relative": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
+      "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
+      "dev": true,
+      "requires": {
+        "is-unc-path": "^1.0.0"
+      }
+    },
+    "is-typedarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+      "dev": true
+    },
+    "is-unc-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
+      "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
+      "dev": true,
+      "requires": {
+        "unc-path-regex": "^0.1.2"
+      }
+    },
+    "is-utf8": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+      "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
+      "dev": true
+    },
+    "is-valid-glob": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz",
+      "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=",
+      "dev": true
+    },
+    "is-windows": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+      "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+      "dev": true
+    },
+    "isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+      "dev": true
+    },
+    "isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+      "dev": true
+    },
+    "isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+      "dev": true
+    },
+    "isstream": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+      "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+      "dev": true
+    },
+    "js-base64": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz",
+      "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==",
+      "dev": true
+    },
+    "jsbn": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+      "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+      "dev": true
+    },
+    "json-schema": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+      "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+      "dev": true
+    },
+    "json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "dev": true
+    },
+    "json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
+      "dev": true
+    },
+    "json-stringify-safe": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+      "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+      "dev": true
+    },
+    "jsprim": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+      "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+      "dev": true,
+      "requires": {
+        "assert-plus": "1.0.0",
+        "extsprintf": "1.3.0",
+        "json-schema": "0.2.3",
+        "verror": "1.10.0"
+      }
+    },
+    "just-debounce": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz",
+      "integrity": "sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=",
+      "dev": true
+    },
+    "kind-of": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+      "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+      "dev": true
+    },
+    "last-run": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz",
+      "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=",
+      "dev": true,
+      "requires": {
+        "default-resolution": "^2.0.0",
+        "es6-weak-map": "^2.0.1"
+      }
+    },
+    "lazystream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
+      "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
+      "dev": true,
+      "requires": {
+        "readable-stream": "^2.0.5"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "process-nextick-args": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+          "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.6",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "lcid": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
+      "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
+      "dev": true,
+      "requires": {
+        "invert-kv": "^1.0.0"
+      }
+    },
+    "lead": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz",
+      "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=",
+      "dev": true,
+      "requires": {
+        "flush-write-stream": "^1.0.2"
+      }
+    },
+    "liftoff": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz",
+      "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==",
+      "dev": true,
+      "requires": {
+        "extend": "^3.0.0",
+        "findup-sync": "^3.0.0",
+        "fined": "^1.0.1",
+        "flagged-respawn": "^1.0.0",
+        "is-plain-object": "^2.0.4",
+        "object.map": "^1.0.0",
+        "rechoir": "^0.6.2",
+        "resolve": "^1.1.7"
+      }
+    },
+    "load-json-file": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+      "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.2",
+        "parse-json": "^2.2.0",
+        "pify": "^2.0.0",
+        "pinkie-promise": "^2.0.0",
+        "strip-bom": "^2.0.0"
+      }
+    },
+    "lodash": {
+      "version": "4.17.15",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+      "dev": true
+    },
+    "lodash.clonedeep": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
+      "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
+      "dev": true
+    },
+    "loud-rejection": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
+      "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
+      "dev": true,
+      "requires": {
+        "currently-unhandled": "^0.4.1",
+        "signal-exit": "^3.0.0"
+      }
+    },
+    "lru-cache": {
+      "version": "4.1.5",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+      "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+      "dev": true,
+      "requires": {
+        "pseudomap": "^1.0.2",
+        "yallist": "^2.1.2"
+      }
+    },
+    "make-iterator": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz",
+      "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^6.0.2"
+      }
+    },
+    "map-cache": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+      "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
+      "dev": true
+    },
+    "map-obj": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+      "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
+      "dev": true
+    },
+    "map-visit": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+      "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+      "dev": true,
+      "requires": {
+        "object-visit": "^1.0.0"
+      }
+    },
+    "matchdep": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz",
+      "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=",
+      "dev": true,
+      "requires": {
+        "findup-sync": "^2.0.0",
+        "micromatch": "^3.0.4",
+        "resolve": "^1.4.0",
+        "stack-trace": "0.0.10"
+      },
+      "dependencies": {
+        "findup-sync": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz",
+          "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=",
+          "dev": true,
+          "requires": {
+            "detect-file": "^1.0.0",
+            "is-glob": "^3.1.0",
+            "micromatch": "^3.0.4",
+            "resolve-dir": "^1.0.1"
+          }
+        },
+        "is-glob": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+          "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+          "dev": true,
+          "requires": {
+            "is-extglob": "^2.1.0"
+          }
+        }
+      }
+    },
+    "meow": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
+      "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
+      "dev": true,
+      "requires": {
+        "camelcase-keys": "^2.0.0",
+        "decamelize": "^1.1.2",
+        "loud-rejection": "^1.0.0",
+        "map-obj": "^1.0.1",
+        "minimist": "^1.1.3",
+        "normalize-package-data": "^2.3.4",
+        "object-assign": "^4.0.1",
+        "read-pkg-up": "^1.0.1",
+        "redent": "^1.0.0",
+        "trim-newlines": "^1.0.0"
+      }
+    },
+    "micromatch": {
+      "version": "3.1.10",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+      "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+      "dev": true,
+      "requires": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "braces": "^2.3.1",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "extglob": "^2.0.4",
+        "fragment-cache": "^0.2.1",
+        "kind-of": "^6.0.2",
+        "nanomatch": "^1.2.9",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.2"
+      }
+    },
+    "mime-db": {
+      "version": "1.42.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz",
+      "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==",
+      "dev": true
+    },
+    "mime-types": {
+      "version": "2.1.25",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz",
+      "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==",
+      "dev": true,
+      "requires": {
+        "mime-db": "1.42.0"
+      }
+    },
+    "minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "dev": true,
+      "requires": {
+        "brace-expansion": "^1.1.7"
+      }
+    },
+    "minimist": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+      "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+      "dev": true
+    },
+    "mixin-deep": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+      "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+      "dev": true,
+      "requires": {
+        "for-in": "^1.0.2",
+        "is-extendable": "^1.0.1"
+      },
+      "dependencies": {
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        }
+      }
+    },
+    "mkdirp": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+      "dev": true,
+      "requires": {
+        "minimist": "0.0.8"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "0.0.8",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+          "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+          "dev": true
+        }
+      }
+    },
+    "ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+      "dev": true
+    },
+    "mute-stdout": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz",
+      "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==",
+      "dev": true
+    },
+    "nan": {
+      "version": "2.12.1",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz",
+      "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==",
+      "dev": true,
+      "optional": true
+    },
+    "nanomatch": {
+      "version": "1.2.13",
+      "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+      "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+      "dev": true,
+      "requires": {
+        "arr-diff": "^4.0.0",
+        "array-unique": "^0.3.2",
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "fragment-cache": "^0.2.1",
+        "is-windows": "^1.0.2",
+        "kind-of": "^6.0.2",
+        "object.pick": "^1.3.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      }
+    },
+    "next-tick": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
+      "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
+      "dev": true
+    },
+    "node-gyp": {
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
+      "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==",
+      "dev": true,
+      "requires": {
+        "fstream": "^1.0.0",
+        "glob": "^7.0.3",
+        "graceful-fs": "^4.1.2",
+        "mkdirp": "^0.5.0",
+        "nopt": "2 || 3",
+        "npmlog": "0 || 1 || 2 || 3 || 4",
+        "osenv": "0",
+        "request": "^2.87.0",
+        "rimraf": "2",
+        "semver": "~5.3.0",
+        "tar": "^2.0.0",
+        "which": "1"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "5.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
+          "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
+          "dev": true
+        }
+      }
+    },
+    "node-sass": {
+      "version": "4.13.0",
+      "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.0.tgz",
+      "integrity": "sha512-W1XBrvoJ1dy7VsvTAS5q1V45lREbTlZQqFbiHb3R3OTTCma0XBtuG6xZ6Z4506nR4lmHPTqVRwxT6KgtWC97CA==",
+      "dev": true,
+      "requires": {
+        "async-foreach": "^0.1.3",
+        "chalk": "^1.1.1",
+        "cross-spawn": "^3.0.0",
+        "gaze": "^1.0.0",
+        "get-stdin": "^4.0.1",
+        "glob": "^7.0.3",
+        "in-publish": "^2.0.0",
+        "lodash": "^4.17.15",
+        "meow": "^3.7.0",
+        "mkdirp": "^0.5.1",
+        "nan": "^2.13.2",
+        "node-gyp": "^3.8.0",
+        "npmlog": "^4.0.0",
+        "request": "^2.88.0",
+        "sass-graph": "^2.2.4",
+        "stdout-stream": "^1.4.0",
+        "true-case-path": "^1.0.2"
+      },
+      "dependencies": {
+        "nan": {
+          "version": "2.14.0",
+          "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
+          "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
+          "dev": true
+        }
+      }
+    },
+    "nopt": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
+      "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
+      "dev": true,
+      "requires": {
+        "abbrev": "1"
+      }
+    },
+    "normalize-package-data": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
+      "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
+      "dev": true,
+      "requires": {
+        "hosted-git-info": "^2.1.4",
+        "is-builtin-module": "^1.0.0",
+        "semver": "2 || 3 || 4 || 5",
+        "validate-npm-package-license": "^3.0.1"
+      }
+    },
+    "normalize-path": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+      "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+      "dev": true,
+      "requires": {
+        "remove-trailing-separator": "^1.0.1"
+      }
+    },
+    "now-and-later": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz",
+      "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==",
+      "dev": true,
+      "requires": {
+        "once": "^1.3.2"
+      }
+    },
+    "npmlog": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+      "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+      "dev": true,
+      "requires": {
+        "are-we-there-yet": "~1.1.2",
+        "console-control-strings": "~1.1.0",
+        "gauge": "~2.7.3",
+        "set-blocking": "~2.0.0"
+      }
+    },
+    "number-is-nan": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+      "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+      "dev": true
+    },
+    "oauth-sign": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+      "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+      "dev": true
+    },
+    "object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+      "dev": true
+    },
+    "object-copy": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+      "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+      "dev": true,
+      "requires": {
+        "copy-descriptor": "^0.1.0",
+        "define-property": "^0.2.5",
+        "kind-of": "^3.0.3"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "object-keys": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+      "dev": true
+    },
+    "object-visit": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+      "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+      "dev": true,
+      "requires": {
+        "isobject": "^3.0.0"
+      }
+    },
+    "object.assign": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
+      "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
+      "dev": true,
+      "requires": {
+        "define-properties": "^1.1.2",
+        "function-bind": "^1.1.1",
+        "has-symbols": "^1.0.0",
+        "object-keys": "^1.0.11"
+      }
+    },
+    "object.defaults": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz",
+      "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=",
+      "dev": true,
+      "requires": {
+        "array-each": "^1.0.1",
+        "array-slice": "^1.0.0",
+        "for-own": "^1.0.0",
+        "isobject": "^3.0.0"
+      }
+    },
+    "object.map": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz",
+      "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=",
+      "dev": true,
+      "requires": {
+        "for-own": "^1.0.0",
+        "make-iterator": "^1.0.0"
+      }
+    },
+    "object.pick": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+      "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+      "dev": true,
+      "requires": {
+        "isobject": "^3.0.1"
+      }
+    },
+    "object.reduce": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz",
+      "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=",
+      "dev": true,
+      "requires": {
+        "for-own": "^1.0.0",
+        "make-iterator": "^1.0.0"
+      }
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "dev": true,
+      "requires": {
+        "wrappy": "1"
+      }
+    },
+    "ordered-read-streams": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz",
+      "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=",
+      "dev": true,
+      "requires": {
+        "readable-stream": "^2.0.1"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "process-nextick-args": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+          "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.6",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "os-homedir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+      "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+      "dev": true
+    },
+    "os-locale": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
+      "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
+      "dev": true,
+      "requires": {
+        "lcid": "^1.0.0"
+      }
+    },
+    "os-tmpdir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+      "dev": true
+    },
+    "osenv": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
+      "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
+      "dev": true,
+      "requires": {
+        "os-homedir": "^1.0.0",
+        "os-tmpdir": "^1.0.0"
+      }
+    },
+    "parse-filepath": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz",
+      "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=",
+      "dev": true,
+      "requires": {
+        "is-absolute": "^1.0.0",
+        "map-cache": "^0.2.0",
+        "path-root": "^0.1.1"
+      }
+    },
+    "parse-json": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
+      "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+      "dev": true,
+      "requires": {
+        "error-ex": "^1.2.0"
+      }
+    },
+    "parse-node-version": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.0.tgz",
+      "integrity": "sha512-02GTVHD1u0nWc20n2G7WX/PgdhNFG04j5fi1OkaJzPWLTcf6vh6229Lta1wTmXG/7Dg42tCssgkccVt7qvd8Kg==",
+      "dev": true
+    },
+    "parse-passwd": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+      "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
+      "dev": true
+    },
+    "pascalcase": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+      "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
+      "dev": true
+    },
+    "path-dirname": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+      "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
+      "dev": true
+    },
+    "path-exists": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
+      "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
+      "dev": true,
+      "requires": {
+        "pinkie-promise": "^2.0.0"
+      }
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+      "dev": true
+    },
+    "path-parse": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+      "dev": true
+    },
+    "path-root": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz",
+      "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=",
+      "dev": true,
+      "requires": {
+        "path-root-regex": "^0.1.0"
+      }
+    },
+    "path-root-regex": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz",
+      "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=",
+      "dev": true
+    },
+    "path-type": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+      "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.2",
+        "pify": "^2.0.0",
+        "pinkie-promise": "^2.0.0"
+      }
+    },
+    "performance-now": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+      "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
+      "dev": true
+    },
+    "pify": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+      "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+      "dev": true
+    },
+    "pinkie": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+      "dev": true
+    },
+    "pinkie-promise": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+      "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+      "dev": true,
+      "requires": {
+        "pinkie": "^2.0.0"
+      }
+    },
+    "plugin-error": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz",
+      "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==",
+      "dev": true,
+      "requires": {
+        "ansi-colors": "^1.0.1",
+        "arr-diff": "^4.0.0",
+        "arr-union": "^3.1.0",
+        "extend-shallow": "^3.0.2"
+      }
+    },
+    "posix-character-classes": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+      "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
+      "dev": true
+    },
+    "pretty-hrtime": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
+      "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=",
+      "dev": true
+    },
+    "process-nextick-args": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
+      "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
+      "dev": true
+    },
+    "pseudomap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+      "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
+      "dev": true
+    },
+    "psl": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/psl/-/psl-1.6.0.tgz",
+      "integrity": "sha512-SYKKmVel98NCOYXpkwUqZqh0ahZeeKfmisiLIcEZdsb+WbLv02g/dI5BUmZnIyOe7RzZtLax81nnb2HbvC2tzA==",
+      "dev": true
+    },
+    "pump": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
+      "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
+      "dev": true,
+      "requires": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.1"
+      }
+    },
+    "pumpify": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
+      "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
+      "dev": true,
+      "requires": {
+        "duplexify": "^3.6.0",
+        "inherits": "^2.0.3",
+        "pump": "^2.0.0"
+      }
+    },
+    "punycode": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+      "dev": true
+    },
+    "qs": {
+      "version": "6.5.2",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+      "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+      "dev": true
+    },
+    "read-pkg": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
+      "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
+      "dev": true,
+      "requires": {
+        "load-json-file": "^1.0.0",
+        "normalize-package-data": "^2.3.2",
+        "path-type": "^1.0.0"
+      }
+    },
+    "read-pkg-up": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
+      "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
+      "dev": true,
+      "requires": {
+        "find-up": "^1.0.0",
+        "read-pkg": "^1.0.0"
+      }
+    },
+    "readable-stream": {
+      "version": "2.3.6",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+      "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+      "dev": true,
+      "requires": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      },
+      "dependencies": {
+        "process-nextick-args": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+          "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+          "dev": true
+        }
+      }
+    },
+    "readdirp": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+      "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+      "dev": true,
+      "requires": {
+        "graceful-fs": "^4.1.11",
+        "micromatch": "^3.1.10",
+        "readable-stream": "^2.0.2"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "process-nextick-args": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+          "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.6",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "rechoir": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
+      "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
+      "dev": true,
+      "requires": {
+        "resolve": "^1.1.6"
+      }
+    },
+    "redent": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
+      "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
+      "dev": true,
+      "requires": {
+        "indent-string": "^2.1.0",
+        "strip-indent": "^1.0.1"
+      }
+    },
+    "regex-not": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+      "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^3.0.2",
+        "safe-regex": "^1.1.0"
+      }
+    },
+    "remove-bom-buffer": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz",
+      "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==",
+      "dev": true,
+      "requires": {
+        "is-buffer": "^1.1.5",
+        "is-utf8": "^0.2.1"
+      }
+    },
+    "remove-bom-stream": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz",
+      "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=",
+      "dev": true,
+      "requires": {
+        "remove-bom-buffer": "^3.0.0",
+        "safe-buffer": "^5.1.0",
+        "through2": "^2.0.3"
+      }
+    },
+    "remove-trailing-separator": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+      "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+      "dev": true
+    },
+    "repeat-element": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+      "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
+      "dev": true
+    },
+    "repeat-string": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+      "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+      "dev": true
+    },
+    "repeating": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
+      "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
+      "dev": true,
+      "requires": {
+        "is-finite": "^1.0.0"
+      }
+    },
+    "replace-ext": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
+      "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=",
+      "dev": true
+    },
+    "replace-homedir": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz",
+      "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=",
+      "dev": true,
+      "requires": {
+        "homedir-polyfill": "^1.0.1",
+        "is-absolute": "^1.0.0",
+        "remove-trailing-separator": "^1.1.0"
+      }
+    },
+    "request": {
+      "version": "2.88.0",
+      "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
+      "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
+      "dev": true,
+      "requires": {
+        "aws-sign2": "~0.7.0",
+        "aws4": "^1.8.0",
+        "caseless": "~0.12.0",
+        "combined-stream": "~1.0.6",
+        "extend": "~3.0.2",
+        "forever-agent": "~0.6.1",
+        "form-data": "~2.3.2",
+        "har-validator": "~5.1.0",
+        "http-signature": "~1.2.0",
+        "is-typedarray": "~1.0.0",
+        "isstream": "~0.1.2",
+        "json-stringify-safe": "~5.0.1",
+        "mime-types": "~2.1.19",
+        "oauth-sign": "~0.9.0",
+        "performance-now": "^2.1.0",
+        "qs": "~6.5.2",
+        "safe-buffer": "^5.1.2",
+        "tough-cookie": "~2.4.3",
+        "tunnel-agent": "^0.6.0",
+        "uuid": "^3.3.2"
+      },
+      "dependencies": {
+        "safe-buffer": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
+          "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==",
+          "dev": true
+        }
+      }
+    },
+    "require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+      "dev": true
+    },
+    "require-main-filename": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
+      "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
+      "dev": true
+    },
+    "resolve": {
+      "version": "1.10.1",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.1.tgz",
+      "integrity": "sha512-KuIe4mf++td/eFb6wkaPbMDnP6kObCaEtIDuHOUED6MNUo4K670KZUHuuvYPZDxNF0WVLw49n06M2m2dXphEzA==",
+      "dev": true,
+      "requires": {
+        "path-parse": "^1.0.6"
+      }
+    },
+    "resolve-dir": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+      "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
+      "dev": true,
+      "requires": {
+        "expand-tilde": "^2.0.0",
+        "global-modules": "^1.0.0"
+      }
+    },
+    "resolve-options": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz",
+      "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=",
+      "dev": true,
+      "requires": {
+        "value-or-function": "^3.0.0"
+      }
+    },
+    "resolve-url": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+      "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+      "dev": true
+    },
+    "ret": {
+      "version": "0.1.15",
+      "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+      "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+      "dev": true
+    },
+    "rimraf": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+      "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+      "dev": true,
+      "requires": {
+        "glob": "^7.1.3"
+      }
+    },
+    "safe-buffer": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+      "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
+      "dev": true
+    },
+    "safe-regex": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+      "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+      "dev": true,
+      "requires": {
+        "ret": "~0.1.10"
+      }
+    },
+    "safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true
+    },
+    "sass-graph": {
+      "version": "2.2.4",
+      "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz",
+      "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=",
+      "dev": true,
+      "requires": {
+        "glob": "^7.0.0",
+        "lodash": "^4.0.0",
+        "scss-tokenizer": "^0.2.3",
+        "yargs": "^7.0.0"
+      }
+    },
+    "scss-tokenizer": {
+      "version": "0.2.3",
+      "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz",
+      "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=",
+      "dev": true,
+      "requires": {
+        "js-base64": "^2.1.8",
+        "source-map": "^0.4.2"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.4.4",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
+          "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
+          "dev": true,
+          "requires": {
+            "amdefine": ">=0.0.4"
+          }
+        }
+      }
+    },
+    "semver": {
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
+      "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
+      "dev": true
+    },
+    "semver-greatest-satisfied-range": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz",
+      "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=",
+      "dev": true,
+      "requires": {
+        "sver-compat": "^1.5.0"
+      }
+    },
+    "set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+      "dev": true
+    },
+    "set-value": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+      "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^2.0.1",
+        "is-extendable": "^0.1.1",
+        "is-plain-object": "^2.0.3",
+        "split-string": "^3.0.1"
+      },
+      "dependencies": {
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
+    "signal-exit": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+      "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+      "dev": true
+    },
+    "snapdragon": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+      "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+      "dev": true,
+      "requires": {
+        "base": "^0.11.1",
+        "debug": "^2.2.0",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "map-cache": "^0.2.2",
+        "source-map": "^0.5.6",
+        "source-map-resolve": "^0.5.0",
+        "use": "^3.1.0"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        }
+      }
+    },
+    "snapdragon-node": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+      "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+      "dev": true,
+      "requires": {
+        "define-property": "^1.0.0",
+        "isobject": "^3.0.0",
+        "snapdragon-util": "^3.0.1"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "is-accessor-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+          "dev": true,
+          "requires": {
+            "kind-of": "^6.0.0"
+          }
+        },
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+          "dev": true,
+          "requires": {
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
+          }
+        }
+      }
+    },
+    "snapdragon-util": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+      "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.2.0"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "source-map": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+      "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+      "dev": true
+    },
+    "source-map-resolve": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
+      "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
+      "dev": true,
+      "requires": {
+        "atob": "^2.1.1",
+        "decode-uri-component": "^0.2.0",
+        "resolve-url": "^0.2.1",
+        "source-map-url": "^0.4.0",
+        "urix": "^0.1.0"
+      }
+    },
+    "source-map-url": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
+      "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
+      "dev": true
+    },
+    "sparkles": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz",
+      "integrity": "sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM=",
+      "dev": true
+    },
+    "spdx-correct": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
+      "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+      "dev": true,
+      "requires": {
+        "spdx-expression-parse": "^3.0.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-exceptions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
+      "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
+      "dev": true
+    },
+    "spdx-expression-parse": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+      "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+      "dev": true,
+      "requires": {
+        "spdx-exceptions": "^2.1.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-license-ids": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz",
+      "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==",
+      "dev": true
+    },
+    "split-string": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+      "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+      "dev": true,
+      "requires": {
+        "extend-shallow": "^3.0.0"
+      }
+    },
+    "sshpk": {
+      "version": "1.16.1",
+      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+      "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+      "dev": true,
+      "requires": {
+        "asn1": "~0.2.3",
+        "assert-plus": "^1.0.0",
+        "bcrypt-pbkdf": "^1.0.0",
+        "dashdash": "^1.12.0",
+        "ecc-jsbn": "~0.1.1",
+        "getpass": "^0.1.1",
+        "jsbn": "~0.1.0",
+        "safer-buffer": "^2.0.2",
+        "tweetnacl": "~0.14.0"
+      }
+    },
+    "stack-trace": {
+      "version": "0.0.10",
+      "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
+      "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=",
+      "dev": true
+    },
+    "static-extend": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+      "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+      "dev": true,
+      "requires": {
+        "define-property": "^0.2.5",
+        "object-copy": "^0.1.0"
+      },
+      "dependencies": {
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        }
+      }
+    },
+    "stdout-stream": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz",
+      "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==",
+      "dev": true,
+      "requires": {
+        "readable-stream": "^2.0.1"
+      }
+    },
+    "stream-exhaust": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz",
+      "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==",
+      "dev": true
+    },
+    "stream-shift": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz",
+      "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=",
+      "dev": true
+    },
+    "string-width": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+      "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+      "dev": true,
+      "requires": {
+        "code-point-at": "^1.0.0",
+        "is-fullwidth-code-point": "^1.0.0",
+        "strip-ansi": "^3.0.0"
+      }
+    },
+    "string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "strip-ansi": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+      "dev": true,
+      "requires": {
+        "ansi-regex": "^2.0.0"
+      }
+    },
+    "strip-bom": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+      "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+      "dev": true,
+      "requires": {
+        "is-utf8": "^0.2.0"
+      }
+    },
+    "strip-indent": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
+      "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
+      "dev": true,
+      "requires": {
+        "get-stdin": "^4.0.1"
+      }
+    },
+    "supports-color": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+      "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+      "dev": true
+    },
+    "sver-compat": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz",
+      "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=",
+      "dev": true,
+      "requires": {
+        "es6-iterator": "^2.0.1",
+        "es6-symbol": "^3.1.1"
+      }
+    },
+    "tar": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz",
+      "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==",
+      "dev": true,
+      "requires": {
+        "block-stream": "*",
+        "fstream": "^1.0.12",
+        "inherits": "2"
+      }
+    },
+    "through2": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
+      "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
+      "dev": true,
+      "requires": {
+        "readable-stream": "^2.1.5",
+        "xtend": "~4.0.1"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.3",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
+          "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~1.0.6",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.0.3",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.0.3",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
+          "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        }
+      }
+    },
+    "through2-filter": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz",
+      "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==",
+      "dev": true,
+      "requires": {
+        "through2": "~2.0.0",
+        "xtend": "~4.0.0"
+      }
+    },
+    "time-stamp": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz",
+      "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=",
+      "dev": true
+    },
+    "to-absolute-glob": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz",
+      "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=",
+      "dev": true,
+      "requires": {
+        "is-absolute": "^1.0.0",
+        "is-negated-glob": "^1.0.0"
+      }
+    },
+    "to-object-path": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+      "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+      "dev": true,
+      "requires": {
+        "kind-of": "^3.0.2"
+      },
+      "dependencies": {
+        "kind-of": {
+          "version": "3.2.2",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+          "dev": true,
+          "requires": {
+            "is-buffer": "^1.1.5"
+          }
+        }
+      }
+    },
+    "to-regex": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+      "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+      "dev": true,
+      "requires": {
+        "define-property": "^2.0.2",
+        "extend-shallow": "^3.0.2",
+        "regex-not": "^1.0.2",
+        "safe-regex": "^1.1.0"
+      }
+    },
+    "to-regex-range": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+      "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+      "dev": true,
+      "requires": {
+        "is-number": "^3.0.0",
+        "repeat-string": "^1.6.1"
+      }
+    },
+    "to-through": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz",
+      "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=",
+      "dev": true,
+      "requires": {
+        "through2": "^2.0.3"
+      }
+    },
+    "tough-cookie": {
+      "version": "2.4.3",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
+      "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+      "dev": true,
+      "requires": {
+        "psl": "^1.1.24",
+        "punycode": "^1.4.1"
+      },
+      "dependencies": {
+        "punycode": {
+          "version": "1.4.1",
+          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+          "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+          "dev": true
+        }
+      }
+    },
+    "trim-newlines": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
+      "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
+      "dev": true
+    },
+    "true-case-path": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz",
+      "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==",
+      "dev": true,
+      "requires": {
+        "glob": "^7.1.2"
+      }
+    },
+    "tunnel-agent": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+      "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "tweetnacl": {
+      "version": "0.14.5",
+      "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+      "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+      "dev": true
+    },
+    "typedarray": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+      "dev": true
+    },
+    "unc-path-regex": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
+      "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=",
+      "dev": true
+    },
+    "undertaker": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz",
+      "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==",
+      "dev": true,
+      "requires": {
+        "arr-flatten": "^1.0.1",
+        "arr-map": "^2.0.0",
+        "bach": "^1.0.0",
+        "collection-map": "^1.0.0",
+        "es6-weak-map": "^2.0.1",
+        "last-run": "^1.1.0",
+        "object.defaults": "^1.0.0",
+        "object.reduce": "^1.0.0",
+        "undertaker-registry": "^1.0.0"
+      }
+    },
+    "undertaker-registry": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz",
+      "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=",
+      "dev": true
+    },
+    "union-value": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+      "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+      "dev": true,
+      "requires": {
+        "arr-union": "^3.1.0",
+        "get-value": "^2.0.6",
+        "is-extendable": "^0.1.1",
+        "set-value": "^2.0.1"
+      }
+    },
+    "unique-stream": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz",
+      "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==",
+      "dev": true,
+      "requires": {
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "through2-filter": "^3.0.0"
+      }
+    },
+    "unset-value": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+      "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+      "dev": true,
+      "requires": {
+        "has-value": "^0.3.1",
+        "isobject": "^3.0.0"
+      },
+      "dependencies": {
+        "has-value": {
+          "version": "0.3.1",
+          "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+          "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+          "dev": true,
+          "requires": {
+            "get-value": "^2.0.3",
+            "has-values": "^0.1.4",
+            "isobject": "^2.0.0"
+          },
+          "dependencies": {
+            "isobject": {
+              "version": "2.1.0",
+              "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+              "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+              "dev": true,
+              "requires": {
+                "isarray": "1.0.0"
+              }
+            }
+          }
+        },
+        "has-values": {
+          "version": "0.1.4",
+          "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+          "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
+          "dev": true
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        }
+      }
+    },
+    "upath": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz",
+      "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==",
+      "dev": true
+    },
+    "uri-js": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+      "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+      "dev": true,
+      "requires": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "urix": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+      "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+      "dev": true
+    },
+    "use": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+      "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+      "dev": true
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+      "dev": true
+    },
+    "uuid": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
+      "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==",
+      "dev": true
+    },
+    "v8flags": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.2.tgz",
+      "integrity": "sha512-MtivA7GF24yMPte9Rp/BWGCYQNaUj86zeYxV/x2RRJMKagImbbv3u8iJC57lNhWLPcGLJmHcHmFWkNsplbbLWw==",
+      "dev": true,
+      "requires": {
+        "homedir-polyfill": "^1.0.1"
+      }
+    },
+    "validate-npm-package-license": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+      "dev": true,
+      "requires": {
+        "spdx-correct": "^3.0.0",
+        "spdx-expression-parse": "^3.0.0"
+      }
+    },
+    "value-or-function": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz",
+      "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=",
+      "dev": true
+    },
+    "verror": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+      "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+      "dev": true,
+      "requires": {
+        "assert-plus": "^1.0.0",
+        "core-util-is": "1.0.2",
+        "extsprintf": "^1.2.0"
+      }
+    },
+    "vinyl-fs": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz",
+      "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==",
+      "dev": true,
+      "requires": {
+        "fs-mkdirp-stream": "^1.0.0",
+        "glob-stream": "^6.1.0",
+        "graceful-fs": "^4.0.0",
+        "is-valid-glob": "^1.0.0",
+        "lazystream": "^1.0.0",
+        "lead": "^1.0.0",
+        "object.assign": "^4.0.4",
+        "pumpify": "^1.3.5",
+        "readable-stream": "^2.3.3",
+        "remove-bom-buffer": "^3.0.0",
+        "remove-bom-stream": "^1.2.0",
+        "resolve-options": "^1.1.0",
+        "through2": "^2.0.0",
+        "to-through": "^2.0.0",
+        "value-or-function": "^3.0.0",
+        "vinyl": "^2.0.0",
+        "vinyl-sourcemap": "^1.1.0"
+      },
+      "dependencies": {
+        "clone": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+          "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
+          "dev": true
+        },
+        "clone-stats": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
+          "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=",
+          "dev": true
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+          "dev": true
+        },
+        "process-nextick-args": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+          "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
+          "dev": true
+        },
+        "readable-stream": {
+          "version": "2.3.6",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "replace-ext": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
+          "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=",
+          "dev": true
+        },
+        "string_decoder": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+          "dev": true,
+          "requires": {
+            "safe-buffer": "~5.1.0"
+          }
+        },
+        "vinyl": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz",
+          "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==",
+          "dev": true,
+          "requires": {
+            "clone": "^2.1.1",
+            "clone-buffer": "^1.0.0",
+            "clone-stats": "^1.0.0",
+            "cloneable-readable": "^1.0.0",
+            "remove-trailing-separator": "^1.0.1",
+            "replace-ext": "^1.0.0"
+          }
+        }
+      }
+    },
+    "vinyl-sourcemap": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz",
+      "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=",
+      "dev": true,
+      "requires": {
+        "append-buffer": "^1.0.2",
+        "convert-source-map": "^1.5.0",
+        "graceful-fs": "^4.1.6",
+        "normalize-path": "^2.1.1",
+        "now-and-later": "^2.0.0",
+        "remove-bom-buffer": "^3.0.0",
+        "vinyl": "^2.0.0"
+      },
+      "dependencies": {
+        "clone": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+          "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
+          "dev": true
+        },
+        "clone-stats": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
+          "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=",
+          "dev": true
+        },
+        "replace-ext": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
+          "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=",
+          "dev": true
+        },
+        "vinyl": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz",
+          "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==",
+          "dev": true,
+          "requires": {
+            "clone": "^2.1.1",
+            "clone-buffer": "^1.0.0",
+            "clone-stats": "^1.0.0",
+            "cloneable-readable": "^1.0.0",
+            "remove-trailing-separator": "^1.0.1",
+            "replace-ext": "^1.0.0"
+          }
+        }
+      }
+    },
+    "vinyl-sourcemaps-apply": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz",
+      "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=",
+      "dev": true,
+      "requires": {
+        "source-map": "^0.5.1"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        }
+      }
+    },
+    "which": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "dev": true,
+      "requires": {
+        "isexe": "^2.0.0"
+      }
+    },
+    "which-module": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
+      "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
+      "dev": true
+    },
+    "wide-align": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+      "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+      "dev": true,
+      "requires": {
+        "string-width": "^1.0.2 || 2"
+      }
+    },
+    "wrap-ansi": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+      "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+      "dev": true,
+      "requires": {
+        "string-width": "^1.0.1",
+        "strip-ansi": "^3.0.1"
+      }
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+      "dev": true
+    },
+    "xtend": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+      "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
+      "dev": true
+    },
+    "y18n": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
+      "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
+      "dev": true
+    },
+    "yallist": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+      "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
+      "dev": true
+    },
+    "yargs": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz",
+      "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=",
+      "dev": true,
+      "requires": {
+        "camelcase": "^3.0.0",
+        "cliui": "^3.2.0",
+        "decamelize": "^1.1.1",
+        "get-caller-file": "^1.0.1",
+        "os-locale": "^1.4.0",
+        "read-pkg-up": "^1.0.1",
+        "require-directory": "^2.1.1",
+        "require-main-filename": "^1.0.1",
+        "set-blocking": "^2.0.0",
+        "string-width": "^1.0.2",
+        "which-module": "^1.0.0",
+        "y18n": "^3.2.1",
+        "yargs-parser": "^5.0.0"
+      }
+    },
+    "yargs-parser": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz",
+      "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=",
+      "dev": true,
+      "requires": {
+        "camelcase": "^3.0.0"
+      }
+    }
+  }
+}
index 9a3c17fc3ae98b6c2e8d2d2e031e0ba359302300..6275ac3501786f1c5feddf4bf78f060b89f1d763 100644 (file)
@@ -5,19 +5,18 @@
   "main": "gulpfile.js",
   "scripts": {
     "build": "gulp && hugo",
+    "serve": "hugo serve -DF",
     "dev": "gulp watch",
     "test": "echo \"Error: no test specified\" && exit 1"
   },
   "author": "Dan Brown",
   "license": "MIT",
   "devDependencies": {
-    "gulp": "3.9.0",
-    "gulp-autoprefixer": "3.0.2",
-    "gulp-minify-css": "1.2.1",
-    "gulp-plumber": "1.0.1",
-    "gulp-rename": "1.2.2",
-    "gulp-sass": "2.0.4"
+    "gulp": "4.0.1",
+    "gulp-clean-css": "^4.2.0",
+    "gulp-plumber": "1.2.1",
+    "gulp-rename": "1.4.0",
+    "gulp-sass": "^4.0.2"
   },
-  "dependencies": {
-  }
+  "dependencies": {}
 }
index 1972563a2d69fa0c12be0323b4e2083bfe278090..f472f223002e6f98336b374b94518a8e7e1514fa 100644 (file)
--- a/readme.md
+++ b/readme.md
@@ -2,7 +2,7 @@
 
 This project holds all the data for the https://www.bookstackapp.com/
 
-This site is built using [Hugo](https://gohugo.io). Images are stored using `git-lfs`. 
+This site is built using [Hugo](https://gohugo.io). Images are stored using `git-lfs`.
 
 ### Data Locations
 
@@ -14,4 +14,4 @@ This site is built using [Hugo](https://gohugo.io). Images are stored using `git
 
 The theme is custom made with snippets taken from the [hugo capser theme](https://github.com/vjeantet/hugo-theme-casper).
 
-Scss is used for the styling and is built using gulp. Install NPM dependancies via `npm install` or `yarn` then you can use `npm run-script build` to build the css once or `npm run-script dev` to watch for changes.
\ No newline at end of file
+SCSS is used for the styling and is built using gulp. Install NPM dependencies via `npm install` or `yarn` then you can use `npm run-script build` to build the css once or `npm run-script dev` to watch for changes.
diff --git a/static/images/2017/09/bookstack_mobile_sidebar.mp4 b/static/images/2017/09/bookstack_mobile_sidebar.mp4
new file mode 100644 (file)
index 0000000..0c9b7ab
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7457c60bd502108b09f8371a72c34149ecc1d341f34d916dff7aa4170b040f7b
+size 149287
diff --git a/static/images/2017/09/comments.png b/static/images/2017/09/comments.png
new file mode 100644 (file)
index 0000000..ba226f8
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:07020d08c709b59ccba47e16c030e06aeaa299d83172df520f59c796879c3adb
+size 24266
diff --git a/static/images/2017/09/page_design_new.png b/static/images/2017/09/page_design_new.png
new file mode 100644 (file)
index 0000000..4e8d9ca
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:59c4b053cf38c8b95def24a47e79d8fbc5796ae88c9fe9a6a95c0df6b451311c
+size 97842
diff --git a/static/images/2017/09/page_design_old.png b/static/images/2017/09/page_design_old.png
new file mode 100644 (file)
index 0000000..00c0379
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0b4b49b7d87ca63028bd08f77d1ebf51d09367c956bf104e8a00cb594a9c1c74
+size 91975
diff --git a/static/images/2017/12/analytics-growth-2017.png b/static/images/2017/12/analytics-growth-2017.png
new file mode 100644 (file)
index 0000000..1b50bfa
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e8aa658ecf59a741e77cc0fbe1664095571b399add8fb10cfaee63f7a9f9e1a0
+size 20401
diff --git a/static/images/2017/12/book-grid-view.png b/static/images/2017/12/book-grid-view.png
new file mode 100644 (file)
index 0000000..a470a34
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:839d3ba76c2217dca69cc8259209819350be6ed81371aae4adfdf8c4e4b223ce
+size 869961
diff --git a/static/images/2017/12/progress-indicator.mp4 b/static/images/2017/12/progress-indicator.mp4
new file mode 100644 (file)
index 0000000..2ac18c1
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ea5873194ac40b4c2b187e51b1beb00b3228edea1baa02d7b1ea09282b37fc87
+size 3389822
diff --git a/static/images/2018/02/book-grid-updates.png b/static/images/2018/02/book-grid-updates.png
new file mode 100644 (file)
index 0000000..16dd218
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:70a405589a0ed6a116a716730904396e4cd251aab85950b112b3e5ea777c7469
+size 98039
diff --git a/static/images/2018/02/drawio-support.mp4 b/static/images/2018/02/drawio-support.mp4
new file mode 100644 (file)
index 0000000..8e94f99
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:bb800baf95dd5492d81361b999104cf166f6ec6c5b0d59df9e905db704a7453e
+size 928135
diff --git a/static/images/2018/04/insert-video.mp4 b/static/images/2018/04/insert-video.mp4
new file mode 100644 (file)
index 0000000..598719f
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:310684eda882fe8bbbf5eddaec9de871a7a6488fe011a0d4f5112e20f3d714b3
+size 848665
diff --git a/static/images/2018/05/maintenance.png b/static/images/2018/05/maintenance.png
new file mode 100644 (file)
index 0000000..c2d341d
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6a89974de6cc1b153722c79874d8b0f85d7ce25e9005bd6012238a5e865deb18
+size 43755
diff --git a/static/images/2018/05/sidebar-updates.png b/static/images/2018/05/sidebar-updates.png
new file mode 100644 (file)
index 0000000..418572a
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3da25d060b1dd8a948d061a0cbdf5595e625be9525463c17582ef31978081fbf
+size 80107
diff --git a/static/images/2018/07/bookstack-discord-login.png b/static/images/2018/07/bookstack-discord-login.png
new file mode 100644 (file)
index 0000000..0d30bb7
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:947587c5868381ae48fdd1c61d7c7511988e21bc2e696392eddfda9958846512
+size 5707
diff --git a/static/images/2018/07/bookstack-quick-edit.mp4 b/static/images/2018/07/bookstack-quick-edit.mp4
new file mode 100644 (file)
index 0000000..70100a4
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7eabc8a5e0aed0db3dcfad8c69927928ec207bdd7b94315d3a14014e8726790b
+size 2091878
diff --git a/static/images/2018/09/bookshelves.mp4 b/static/images/2018/09/bookshelves.mp4
new file mode 100644 (file)
index 0000000..7a0d624
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:175b8b74d40ab950eb379c66593c80dfc578547afc53b45c66f9e844ee589cac
+size 521674
diff --git a/static/images/2018/09/bookshelves_copy_permissions.png b/static/images/2018/09/bookshelves_copy_permissions.png
new file mode 100644 (file)
index 0000000..92b520b
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:27294b8c3b26c15aaf2e1755d1f1437a01c94e0e5a916cbe503a28061deafab6
+size 22159
diff --git a/static/images/2018/09/revision_delete.png b/static/images/2018/09/revision_delete.png
new file mode 100644 (file)
index 0000000..0ffeede
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1ba2eccf7dafb07ef906dd8cb23cbdc543ae88c53db5aa64c0567e4e43a8bc68
+size 76363
diff --git a/static/images/2018/09/wysiwyg_rtl_support.png b/static/images/2018/09/wysiwyg_rtl_support.png
new file mode 100644 (file)
index 0000000..41d6d02
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:796f4f4f19698e9faaee18d068e675de9510cd13a42d36343931d9a96104135d
+size 32502
diff --git a/static/images/2019/01/header_signup_link.png b/static/images/2019/01/header_signup_link.png
new file mode 100644 (file)
index 0000000..415ada2
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1ddaa24f976bbff081990b3d89e1724089d914b45fcf5ab5871f743aab55cc2c
+size 4861
diff --git a/static/images/2019/01/header_users_link.png b/static/images/2019/01/header_users_link.png
new file mode 100644 (file)
index 0000000..2f14544
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:99a48f3a229a5b3cbbcd34044eab4ab34b21cbdeb4956e9b6cdf2896a32d6bdd
+size 6406
diff --git a/static/images/2019/01/minio_s3_policy.png b/static/images/2019/01/minio_s3_policy.png
new file mode 100644 (file)
index 0000000..9c6ff19
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d6fe1452c51fdde54b3f788d267f7506159706b319d1e10d8809e1477d75793b
+size 10101
diff --git a/static/images/2019/03/codeblock_lua_powershell.png b/static/images/2019/03/codeblock_lua_powershell.png
new file mode 100644 (file)
index 0000000..378a1f2
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:2cbde80df66efc152beff324aabce7212c16c90788ae73d208fefe3b8b12770b
+size 52306
diff --git a/static/images/2019/05/admin_page_cleanup.png b/static/images/2019/05/admin_page_cleanup.png
new file mode 100644 (file)
index 0000000..db30cbd
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7b3b3dbffe7b37d00af3c5bb1ceee0a332d8a5da3611e5e5880d94c8de1adffc
+size 12016
diff --git a/static/images/2019/05/book_sort_buttons.png b/static/images/2019/05/book_sort_buttons.png
new file mode 100644 (file)
index 0000000..b716742
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8529bc8b929704234c8a2cbef86149efed75ced150170481d1a633415d18c72c
+size 9821
diff --git a/static/images/2019/05/breadcrumb_navigation.png b/static/images/2019/05/breadcrumb_navigation.png
new file mode 100644 (file)
index 0000000..9de247a
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:566f7ce2af24170f406b8f979fb73c7c37ec8cb3ef50f1743a1c2cda516d0b8b
+size 16487
diff --git a/static/images/2019/05/design_update_mobile.png b/static/images/2019/05/design_update_mobile.png
new file mode 100644 (file)
index 0000000..dda43cf
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:07653634fe7b86577f73ab3094932d5ec307161f5751c3712010554193807bbe
+size 111064
diff --git a/static/images/2019/05/design_update_mobile_editing.png b/static/images/2019/05/design_update_mobile_editing.png
new file mode 100644 (file)
index 0000000..029d636
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:46bc99619294150b70f4710435cb600be9b551e32bf19dde10258331f0ce03f7
+size 104344
diff --git a/static/images/2019/05/image_selection_changes.png b/static/images/2019/05/image_selection_changes.png
new file mode 100644 (file)
index 0000000..c33289c
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:31560ccc8d15e4066668f57d62fbdaf130720ada6bc48a5263fa1ab59b0757e2
+size 8588
diff --git a/static/images/2019/05/listing_sort.png b/static/images/2019/05/listing_sort.png
new file mode 100644 (file)
index 0000000..ae7c012
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4c8cc7be6d991c057f40a8a5d3803cc2ddff57cbb3b96f7d33e55bf68482e829
+size 3564
diff --git a/static/images/2019/05/permission_toggle_all.png b/static/images/2019/05/permission_toggle_all.png
new file mode 100644 (file)
index 0000000..7668b1a
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6a2bf8fd91d11f9f08feac0d42a09a0d84e6bc5cb1468db92054382eb4d36fd4
+size 14535
diff --git a/static/images/2019/05/profile_page_changes.png b/static/images/2019/05/profile_page_changes.png
new file mode 100644 (file)
index 0000000..4f0b8e9
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:57adf539fd660a3558585f4ff46af3d8c7d060c69051ce78ff844f5e4f157a2b
+size 64104
diff --git a/static/images/2019/05/search_page_changes.png b/static/images/2019/05/search_page_changes.png
new file mode 100644 (file)
index 0000000..aa56270
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a7b879114d9d12eb8f8f397e00c755d47e438a18b997a14d1759e9412576ab6d
+size 67690
diff --git a/static/images/2019/05/shelf_create_book.png b/static/images/2019/05/shelf_create_book.png
new file mode 100644 (file)
index 0000000..40580a3
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:04e8e04647597c8b5ccdb25b1b2123bfac3a00bd50364ccc624f5f7989a7a76e
+size 17846
diff --git a/static/images/2019/05/shelves_list.png b/static/images/2019/05/shelves_list.png
new file mode 100644 (file)
index 0000000..55cb9af
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c263a13889d5202f3a4e9ddf43c846a02abaca3bbb1090c5d3a9bd5554cc981c
+size 41998
diff --git a/static/images/2019/05/smart_breadcrumbs.png b/static/images/2019/05/smart_breadcrumbs.png
new file mode 100644 (file)
index 0000000..f43fd6f
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f7e9d6ca33da01fa2b40db22922f9885c2d4d4eccbc6efbcac1deb3097b0dba3
+size 7291
diff --git a/static/images/2019/05/toggle_details.png b/static/images/2019/05/toggle_details.png
new file mode 100644 (file)
index 0000000..6c2aaf1
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e85d51c7338480e2cdf04c8784f3d1a1525314132fcefb4fbe2cabf3e40ee377
+size 12083
diff --git a/static/images/2019/08/header_accessibility.mp4 b/static/images/2019/08/header_accessibility.mp4
new file mode 100644 (file)
index 0000000..b96bfd8
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9b84b55f45549f7612538fe677e5c6242698a46c8c5a676dc5d6943b350accbd
+size 408735
diff --git a/static/images/2019/08/invite_flow_email.png b/static/images/2019/08/invite_flow_email.png
new file mode 100644 (file)
index 0000000..3dab6fa
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:dc2ffb0dab23255b2b563b34444fe754eed376512be0619c10ef0ea98395829d
+size 39288
diff --git a/static/images/2019/08/invite_flow_option.png b/static/images/2019/08/invite_flow_option.png
new file mode 100644 (file)
index 0000000..2b99534
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:30d2670a918ae47cde4facdd2e9500dc8ce69ae168826d24b9ee5f2cc81cf45d
+size 15368
diff --git a/static/images/2019/08/page_templates.mp4 b/static/images/2019/08/page_templates.mp4
new file mode 100644 (file)
index 0000000..5248fb2
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e970f3c7f324a5fa46c8491983f8796a2f7fcc8ab10d2b6b97557d942618aa0c
+size 743197
diff --git a/static/images/2019/08/page_templates.png b/static/images/2019/08/page_templates.png
new file mode 100644 (file)
index 0000000..0d26dc9
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:22cf7ff09b7f981654105c1b364096f992117665054da17a951fc79c47d46127
+size 15978
diff --git a/static/images/2020/02/api-docs.png b/static/images/2020/02/api-docs.png
new file mode 100644 (file)
index 0000000..bc34a97
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a24c2ebc9d489402c89f66db9bb3702badc9586480039db356f7742848467da3
+size 27524
diff --git a/static/images/2020/02/api-token-generation.png b/static/images/2020/02/api-token-generation.png
new file mode 100644 (file)
index 0000000..4cd28b4
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d65d57178eb125e7d5836b025788c11cae95ac5e608e25466e3976779b99c832
+size 24954
diff --git a/static/images/2020/02/api-user-tokens.png b/static/images/2020/02/api-user-tokens.png
new file mode 100644 (file)
index 0000000..871fd36
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7d50d8896c07afbdd3bcfba90196d08555f496d2d3a30eeb9f9dfe5d1d6a1c22
+size 10347
diff --git a/static/images/2020/02/bookstack-saml.png b/static/images/2020/02/bookstack-saml.png
new file mode 100644 (file)
index 0000000..d37c075
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:99065329db16ff88aa40f7ef5741e0a38c37a8abb2feaa84f6c34bad0312d906
+size 6620
diff --git a/static/images/2020/02/bookstack-test-email.png b/static/images/2020/02/bookstack-test-email.png
new file mode 100644 (file)
index 0000000..d0f1bc4
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:eb9dc548f94c0fea99efc44b5bf648298121e83bd297409a2157532a684e4a90
+size 8841
diff --git a/static/images/2020/02/crowdin-overview.png b/static/images/2020/02/crowdin-overview.png
new file mode 100644 (file)
index 0000000..76b1ca9
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d00e83f2a66ed9d5c11c061f5bb5fc27723e37612fb4283a7906bb93c3bf0613
+size 21440
diff --git a/static/images/2020/02/test-emails.png b/static/images/2020/02/test-emails.png
new file mode 100644 (file)
index 0000000..2e8eb85
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:168091d79c10371bfe4ddcb0ba392d40e2f8b0a1459a9d6df3a3c1d59b0de4dc
+size 5094
diff --git a/static/images/2020/02/text-overrides.png b/static/images/2020/02/text-overrides.png
new file mode 100644 (file)
index 0000000..a3b0c62
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6b7f4d0e829a764b4097ba1016b510cd2898835595b6069c7d8453feaf86b3b7
+size 2897
diff --git a/static/images/2020/02/theme-colors.png b/static/images/2020/02/theme-colors.png
new file mode 100644 (file)
index 0000000..b78fd16
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ef937462abaeb812975f567c05bd737f7cd05c3b334f22e827bc05b324b0a5f5
+size 14480
diff --git a/static/images/blog-cover-images/book-aaron-burden.jpg b/static/images/blog-cover-images/book-aaron-burden.jpg
new file mode 100644 (file)
index 0000000..961deb2
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5c74a71ace8276d24634f2d6aa311dc24336457ea30d5bdddd454091975a63cd
+size 309865
diff --git a/static/images/blog-cover-images/books-eugenio-mazzone.jpg b/static/images/blog-cover-images/books-eugenio-mazzone.jpg
new file mode 100644 (file)
index 0000000..1c9d416
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:65d8e69cdb29751dbc97953463fc6ecff13081f60561c799014a7081a666a3aa
+size 420832
diff --git a/static/images/blog-cover-images/books-maarten-van-den-heuvel.jpg b/static/images/blog-cover-images/books-maarten-van-den-heuvel.jpg
new file mode 100644 (file)
index 0000000..51cfb00
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d80f2224c50890d77862a46c6892d25a8aee22b66754ffacb8a9c1548905a641
+size 329215
diff --git a/static/images/blog-cover-images/books-radu-marcusu.jpg b/static/images/blog-cover-images/books-radu-marcusu.jpg
new file mode 100644 (file)
index 0000000..27f3c89
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d4de415891f9bdba395994780406eaa6d2dbda6be036e7850e340fcdb7d0b5ad
+size 204905
diff --git a/static/images/blog-cover-images/bookshelf-chuttersnap.jpg b/static/images/blog-cover-images/bookshelf-chuttersnap.jpg
new file mode 100644 (file)
index 0000000..3bea276
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:28d66c2ae5cc153afc791352b8fced7c04b6c17102135a62529d1ccc79c7cca6
+size 307080
diff --git a/static/images/blog-cover-images/bookshelf-giammarco-boscaro.jpg b/static/images/blog-cover-images/bookshelf-giammarco-boscaro.jpg
new file mode 100644 (file)
index 0000000..8a4566a
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:095a99a52564b38c675d5b977c3092e08cc5e58f85b81eac7f34e7006b542a0d
+size 183539
diff --git a/static/images/blog-cover-images/bookshop-john-michael-thomson.jpg b/static/images/blog-cover-images/bookshop-john-michael-thomson.jpg
new file mode 100644 (file)
index 0000000..6b0dcbe
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:2e5a3037f028beeb628bae60c28196501716e3ca2e3f27da6f95fea2bf7344fe
+size 377655
diff --git a/static/images/blog-cover-images/drawing-sergey-zolkin.jpg b/static/images/blog-cover-images/drawing-sergey-zolkin.jpg
new file mode 100644 (file)
index 0000000..6e59837
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b646393491acdba47ea832974c124cb9158335f75651bb97bf10138b7bff625c
+size 135580
diff --git a/static/images/blog-cover-images/flat-books-patrick-tomasso.jpg b/static/images/blog-cover-images/flat-books-patrick-tomasso.jpg
new file mode 100644 (file)
index 0000000..9c9ba4f
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f23d1950cddd5c6d8146cc508dec2fec8802afd3a60362a68ca42a82ef6c69fb
+size 305708
diff --git a/static/images/blog-cover-images/lock-jason-blackeye.jpg b/static/images/blog-cover-images/lock-jason-blackeye.jpg
new file mode 100644 (file)
index 0000000..4b142c2
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e42e387310db899aa165fc5bcd089064fb122518ecfe2b54239fd61b13dd6232
+size 197206
diff --git a/static/images/blog-cover-images/locks-ruben-bagues.jpg b/static/images/blog-cover-images/locks-ruben-bagues.jpg
new file mode 100644 (file)
index 0000000..a67866d
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:deb52305d3b44c7d2c13fa552d838a0ca728b82d896b7ab32b5bb588d0e8f4d2
+size 353358
diff --git a/static/images/blog-cover-images/mountains-eberhard-grossgasteiger.jpg b/static/images/blog-cover-images/mountains-eberhard-grossgasteiger.jpg
new file mode 100644 (file)
index 0000000..1b2a013
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5ba58e3965b17f6eb9f53894c861f9c4ae605ebc65389e0aae5376004113ce98
+size 288024
diff --git a/static/images/blog-cover-images/paint-andrian-valeanu.jpg b/static/images/blog-cover-images/paint-andrian-valeanu.jpg
new file mode 100644 (file)
index 0000000..98e34d5
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:eec6e9947f43e73aab315a99c3c264ad96cc1c35caaf65b9c3b7f341c1fec694
+size 180427
diff --git a/static/images/blog-cover-images/shelves-michael-d-beckwith.jpg b/static/images/blog-cover-images/shelves-michael-d-beckwith.jpg
new file mode 100644 (file)
index 0000000..2c7d339
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ccf7165e3fa194adc2596f09ee60b7030b1ebce618b20d17efa22b5dc209bce3
+size 379865
diff --git a/static/images/blog-cover-images/stars-kristopher-roller.jpg b/static/images/blog-cover-images/stars-kristopher-roller.jpg
new file mode 100644 (file)
index 0000000..aa5f0d9
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c252fa8ce4b97741a65bda003a70c9b26bb55db84e9442ff51ce2b3eb674b985
+size 275735
diff --git a/static/images/blog-cover-images/winter-annie-spratt.jpg b/static/images/blog-cover-images/winter-annie-spratt.jpg
new file mode 100644 (file)
index 0000000..7431f9b
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b2c81eece02e087ea8721b30b0de38c0c12b2aaf7af98f79fae1f37f15c44230
+size 426219
index d2356514db9049dd255c59e154f2d2a640b7b712..2b63f125095c53aab5d57f26c39c9e072ac706a3 100644 (file)
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:185f005807d5f66fe1654ed34fd86d3bd2402f27a5f84b35fe89d153f4fd5a3e
-size 12963
+oid sha256:85ddf4d244c54bb01e133f3d1a705a23f15945c3e7719e3efc56688dad7e020f
+size 7872
index fb4b963795de6117d640b2a550e0e154509a4b47..7f85b146323e890844ee1642df835ea4f4e0238a 100644 (file)
@@ -5,10 +5,10 @@
   <div class="container">
     <div class="row">
       <div class="col-sm-6">
-        {{ if eq .Type "admin-docs" }}
+        {{ if eq .Type "admin-doc" }}
           <h2 class="thin-margin">Admin Documentation</h2>
         {{end}}
-        {{ if eq .Type "user-docs" }}
+        {{ if eq .Type "user-doc" }}
           <h2 class="thin-margin">User Documentation</h2>
         {{end}}
       </div>
 
   <div class="row">
     <div class="col-sm-2 sidebar">
-      {{ if eq .Type "admin-docs" }}
+      <div class="sidebar-inner">
+        {{ if eq .Type "admin-doc" }}
         {{partial "menu_admin_docs"}}
-      {{end}}
-      {{ if eq .Type "user-docs" }}
+        {{end}}
+        {{ if eq .Type "user-doc" }}
         {{partial "menu_user_docs"}}
-      {{end}}
+        {{end}}
+      </div>
     </div>
 
     <div class="col-sm-8 col-sm-offset-1 docs-content">
@@ -40,8 +42,8 @@
       {{.Content}}
 
       <div class="text-center">
-        <a class="edit-link" target="_blank" 
-        href="https://github.com/BookStackApp/website/blob/master/resources/content/{{ .File.Path }}">
+        <a class="edit-link" target="_blank"
+        href="https://github.com/BookStackApp/website/blob/master/content/{{ .File.Path }}">
           <span class="icon small">{{partial "icon/edit.svg"}}</span>
           Edit this Page
         </a>
@@ -52,7 +54,4 @@
 
 </div>
 
-  <script type="text/javascript" src="/libs/highlight/highlight.pack.js"></script>
-  <script>hljs.initHighlightingOnLoad();</script>
-
 {{ partial "footer.html" . }}
index dc3ae5d1355c96c2309cae6331bffc579ff15571..720aedba2386ded34822ca57e35c7b54ce0630f5 100644 (file)
@@ -17,7 +17,7 @@
           {{$author := index .Site.Data.authors (or .Params.author .Site.Params.author)}}
           {{$authorname := or $author.name .Site.Params.author }}
           {{$authorthumbnail := or $author.thumbnail .Site.Params.author }}
-          <img class="post-avatar" width="32" src="{{$authorthumbnail}}" alt="{{$authorname}}"> {{$authorname}} posted on the {{ .Date.Format "2" }}{{ if in (slice 1 21 31) .Date.Day}}st{{ else if in (slice 2 22) .Date.Day}}nd{{ else if in (slice 3 23) .Date.Day}}rd{{ else }}th{{ end }} of {{ .Date.Format "January 2006" }}
+          <img class="post-avatar no-border" width="32" src="{{$authorthumbnail}}" alt="{{$authorname}}"> {{$authorname}} posted on the {{ .Date.Format "2" }}{{ if in (slice 1 21 31) .Date.Day}}st{{ else if in (slice 2 22) .Date.Day}}nd{{ else if in (slice 3 23) .Date.Day}}rd{{ else }}th{{ end }} of {{ .Date.Format "January 2006" }}
       </p>
 
       {{.Content}}
@@ -40,7 +40,7 @@
     <div class="col-md-3 col-md-offset-1 col-sm-4 col-sm-offset-1 blog-sidebar-post-list">
       <h4>Latest Posts</h4>
       <div class="recent-posts">
-        {{ range first 8 ( where .Site.Pages "Section" "blog") }}
+        {{ range first 8 ( where .Site.RegularPages "Section" "blog") }}
           <a class="blogpost-list-small" href="{{.Permalink}}">
             <h5 class="text">{{ .Title }}</h5>
             <time class="post-date" datetime="{{ .Date.Format "2006-01-02T15:04:05Z07:00" | safeHTML }}">
index 9bab93b7f008849ef7ab9220d124168d613a9e73..3c61475e35a189ddd527fc734e8a8f30534eff09 100644 (file)
                          <a href="/docs/admin/installation">Install</a>
                        </p>
                    </div>
-                   <div class="col-md-8 screenshot-container">
-                       <img class="screenshot" src="images/bookstack-hero-screenshot.png" alt="BookStack ScreenShot">
+                   <div class="col-md-8 screenshot-container-parent">
+                       <div class="screenshot-container">
+                               <div class="window-row">
+                                       <div class="window-option red"></div>
+                                       <div class="window-option" style="background-color: orange;"></div>
+                                       <div class="window-option"  style="background-color: green;"></div>
+                               </div>
+                               <img class="screenshot" src="images/bookstack-hero-screenshot.jpg" alt="BookStack ScreenShot">
+                       </div>
                    </div>
                </div>
        </div>
             <div class="col-sm-4" >
                 <h4><span class="icon">{{partial "icon/directions_boat.svg"}}</span>Powerful Features</h4>
                 <p>
-                    On top of the powerful search and linking there is also cross-book sorting, Page revisions, Image management. Some more mega-features are planned such as static-site generation and quick exporting.
+                    On top of the powerful search and linking there is also cross-book sorting, page revisions and image management. A full role and permission system allow you to lock down content and actions as required.
+                </p>
+            </div>
+        </div>
+        <p>
+            <br>
+        </p>
+        <div class="row">
+            <div class="col-sm-4">
+                <h4><span class="icon">{{partial "icon/language.svg"}}</span>Multi-lingual</h4>
+                <p>
+                    BookStack users can set their preferred language. Thanks to great community contributors, Current languages built into BookStack include EN, FR, DE, ES, IT, JA, NL, PL, RU and more.
+                </p>
+            </div>
+            <div class="col-sm-4" >
+                <h4><span class="icon">{{partial "icon/edit.svg"}}</span>Optional Markdown Editor</h4>
+                <p>
+                   If you prefer to write in Markdown then BookStack supports you. A markdown editor is provided and includes a live-preview as you write your documentation.
+                </p>
+            </div>
+            <div class="col-sm-4" >
+                <h4><span class="icon">{{partial "icon/lock.svg"}}</span>Integrated Authentication</h4>
+                <p>
+                       As well as the default email/password login social providers such as GitHub, Google, Slack, AzureAD and more can be used. Okta and LDAP options are available for enterprise environments.
                 </p>
             </div>
         </div>
                                                <label>Demo site url</label> <br><a href="https://demo.bookstackapp.com" target="_blank">https://demo.bookstackapp.com</a> <br>
                                                <label>Admin email</label> <br><input type="text" onclick="this.select();" value="[email protected]" readonly="true"><br>
                                                <label>Admin password</label> <br><input type="text" onclick="this.select();" value="password" readonly="true"> <br><br>
-                                               <a href="https://demo.bookstackapp.com" class="button" target="_blank">Open demo site</a>
+                                               <a href="https://demo.bookstackapp.com/[email protected]&password=password" class="button" target="_blank">Open demo site</a>
                                        </div>
                        </div>
                </div>
                                <div class="row">
                                        <div class="col-sm-4 col-sm-offset-0 col-xs-8 col-xs-offset-2">
                                                <h4>Page View</h4>
+                                               <p>How core content is viewed in BookStack</p>
                                                <figure itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
-                                                   <a href="images/screenshots/page-view.png" data-size="1920x1080">
+                                                   <a href="images/screenshots/page-view.png" data-size="1666x910">
                                                        <img src="images/screenshots/thumb_page-view.png" alt="Page View">
                                                    </a>
                                                </figure>
                                        </div>
                                        <div class="col-sm-4 col-sm-offset-0 col-xs-8 col-xs-offset-2">
                                                <h4>Page Editor</h4>
+                                               <p>The WYSIWYG interface for editing pages</p>
                                                <figure  itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
-                                                   <a href="images/screenshots/page-edit.png" data-size="1920x1080">
+                                                   <a href="images/screenshots/page-edit.png" data-size="1666x910">
                                                        <img src="images/screenshots/thumb_page-edit.png" alt="Page Editing">
                                                    </a>
                                                </figure>
                                        </div>
                                        <div class="col-sm-4 col-sm-offset-0 col-xs-8 col-xs-offset-2">
                                                <h4>Image Manager</h4>
+                                               <p>How images are uploaded and managed</p>
                                                <figure  itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
-                                                   <a href="images/screenshots/image-manager.png" data-size="1920x1080">
+                                                   <a href="images/screenshots/image-manager.png" data-size="1666x910">
                                                        <img src="images/screenshots/thumb_image-manager.png" alt="Image Manager">
                                                    </a>
                                                </figure>
                                        </div>
                                </div>
 
+                               <br>
+
                                <div class="row">
                                        <div class="col-sm-4 col-sm-offset-0 col-xs-8 col-xs-offset-2">
                                                <h4>All Books Overview</h4>
+                                               <p>An overview of the top-level categorisation</p>
                                                <figure  itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
-                                                   <a href="images/screenshots/books-view.png" data-size="1920x1080">
+                                                   <a href="images/screenshots/books-view.png" data-size="1666x910">
                                                        <img src="images/screenshots/thumb_books-view.png" alt="View of all books">
                                                    </a>
                                                </figure>
                                        </div>
                                        <div class="col-sm-4 col-sm-offset-0 col-xs-8 col-xs-offset-2">
                                                <h4>Book Overview</h4>
+                                               <p>A view of the main content container: A book</p>
                                                <figure  itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
-                                                   <a href="images/screenshots/book-overview.png" data-size="1920x1080">
+                                                   <a href="images/screenshots/book-overview.png" data-size="1666x910">
                                                        <img src="images/screenshots/thumb_book-overview.png" alt="Book Overview">
                                                    </a>
                                                </figure>
                                        </div>
                                        <div class="col-sm-4 col-sm-offset-0 col-xs-8 col-xs-offset-2">
                                                <h4>Book Sorting</h4>
+                                               <p>How created content can be sorted within a book</p>
                                                <figure  itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
-                                                   <a href="images/screenshots/book-sorting.png" data-size="1920x1080">
+                                                   <a href="images/screenshots/book-sorting.png" data-size="1666x910">
                                                        <img src="images/screenshots/thumb_book-sorting.png" alt="Book Content Sorting View">
                                                    </a>
                                                </figure>
                                        </div>
                                </div>
 
+                               <br>
+
                                <div class="row">
                                        <div class="col-sm-4 col-sm-offset-0 col-xs-8 col-xs-offset-2">
                                                <h4>Global Search</h4>
+                                               <p>The main interface for searching created content</p>
                                                <figure itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
-                                                   <a href="images/screenshots/search.png" data-size="1920x1080">
+                                                   <a href="images/screenshots/search.png" data-size="1666x910">
                                                        <img src="images/screenshots/thumb_search.png" alt="Searching all content">
                                                    </a>
                                                </figure>
                                        </div>
                                        <div class="col-sm-4 col-sm-offset-0 col-xs-8 col-xs-offset-2">
                                                <h4>App Settings</h4>
+                                               <p>A view the of application system settings</p>
                                                <figure itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
-                                                   <a href="images/screenshots/settings-view.png" data-size="1920x1080">
+                                                   <a href="images/screenshots/settings-view.png" data-size="1666x910">
                                                        <img src="images/screenshots/thumb_settings-view.png" alt="Settings View">
                                                    </a>
                                                </figure>
                                        </div>
                                        <div class="col-sm-4 col-sm-offset-0 col-xs-8 col-xs-offset-2">
-                                               <h4>Profile Update Page</h4>
+                                               <h4>Profile Page</h4>
+                                               <p>A user profile page, showing their activity and content</p>
                                                <figure itemprop="associatedMedia" itemscope itemtype="http://schema.org/ImageObject">
-                                                   <a href="images/screenshots/profile-edit-view.png" data-size="1920x1080">
-                                                       <img src="images/screenshots/thumb_profile-edit-view.png" alt="Profile Editing Screen">
+                                                   <a href="images/screenshots/profile-page.png" data-size="1666x910">
+                                                       <img src="images/screenshots/thumb_profile-page.png" alt="Profile Editing Screen">
                                                    </a>
                                                </figure>
                                        </div>
         <div class="container">
             <h2>Latest From The Blog</h2>
 
-                       {{ range first 4 ( where .Data.Pages "Section" "blog") }}
+                       {{ range first 4 ( where .Site.Pages "Section" "blog") }}
                                <div class="blogpost-card">
                                        <a href="{{.Permalink}}">
                                                {{ if .Params.image }}
index b16d29107b6861b9fdeaa949a4d651184af35716..eaf1290e0fb6c21fcf4f977581817fbb8b04796e 100644 (file)
@@ -3,26 +3,30 @@
     <footer>
         <div class="container">
             <div class="row">
-               <div class="col-lg-5">
+               <div class="col-lg-4">
                        <p class="muted text-small">
                            BookStack - Created By <a href="https://danb.me" title="danb.me" target="_blank" rel="noopener">Dan Brown</a> and developed with the <a href="https://github.com/BookStackApp/BookStack/graphs/contributors" target="_blank" rel="noopener">community</a>.
                         <br>
                         <!-- Thanks to <a href="https://www.browserstack.com/" target="_blank">BrowserStack</a> for providing easy cross-browser testing. <br> -->
-                        Page generated with <a href="https://gohugo.io">hugo</a>, Site source can be found <a href="https://github.com/BookStackApp/website" rel="noopener" target="_blank">here on GitHub</a>
+                        Page generated with <a href="https://gohugo.io">hugo</a>, Site source can be found <a href="https://github.com/BookStackApp/website" rel="noopener" target="_blank">here on GitHub</a>.
                        </p>
                </div>
-               <div class="col-lg-7 col-md-9 menu">
-                    <a href="{{.Site.BaseURL}}docs"><span class="icon">{{partial "icon/book.svg"}}</span> Documentation</a>
-                    <a href="{{.Site.BaseURL}}#features"><span class="icon">{{partial "icon/star.svg"}}</span> Features</a>
-                    <a href="{{.Site.BaseURL}}#demo"><span class="icon">{{partial "icon/touch_app.svg"}}</span> Demo</a>
-                    <a href="https://github.com/BookStackApp/BookStack" target="_blank"><span class="icon">{{partial "icon/github.svg"}}</span> Github</a>
-                    <a href="{{.Site.BaseURL}}blog" target="_blank"><span class="icon">{{partial "icon/rss_feed.svg"}}</span> Blog</a>
+               <div class="col-lg-8 col-md-9 menu">
+                    <a href="{{.Site.BaseURL}}docs"><span class="icon">{{partial "icon/book.svg"}}</span>Documentation</a>
+                    <a href="{{.Site.BaseURL}}#features"><span class="icon">{{partial "icon/star.svg"}}</span>Features</a>
+                    <a href="{{.Site.BaseURL}}#demo"><span class="icon">{{partial "icon/touch_app.svg"}}</span>Demo</a>
+                    <a href="https://github.com/BookStackApp/BookStack" target="_blank"><span class="icon">{{partial "icon/github.svg"}}</span>Github</a>
+                    <a href="https://discord.gg/ztkBqR2" target="_blank"><span class="icon">{{partial "icon/discord.svg"}}</span>Discord</a>
+                    <a href="{{.Site.BaseURL}}blog" target="_blank"><span class="icon">{{partial "icon/rss_feed.svg"}}</span>Blog</a>
                </div>
             </div>
+            <p class="text-small">
+                This website uses Google Analytics for reporting on site metrics and Algolia for providing better search. Third party cookies are not used and IP addresses Google Analytics receives are anonymized to protect your Privacy.
+            </p>
         </div>
     </footer>
 
-
+    <script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.js"></script>
     <script type="text/javascript">
     if (document.querySelector('.doc-search-input') !== null) {
         docsearch({
@@ -33,6 +37,8 @@
             });
     }
     </script>
-    <script async src="{{.Site.BaseURL}}js/script.js"></script>
+    <script src="{{.Site.BaseURL}}libs/codemirror/codemirror.min.js"></script>
+    <script src="{{.Site.BaseURL}}libs/codemirror/modes.js"></script>
+    <script src="{{.Site.BaseURL}}js/script.js"></script>
 </body>
 </html>
index 6bfdb0ce8c0ba7c47d7f24d8ffbdbe6174b58ad5..98817effd23cd75fd4f99f70d722a84406685658 100644 (file)
@@ -7,7 +7,7 @@
 
     {{ partial "twitter_card.html" . }}
 
-       <meta property="og:title" content="{{ if ne .URL "/" }} {{ .Title }} &middot; {{ end }} {{ .Site.Title }}" />
+       <meta property="og:title" content="{{ if ne .RelPermalink "/" }} {{ .Title }} &middot; {{ end }} {{ .Site.Title }}" />
        <meta property="og:site_name" content="{{ .Site.Title }}" />
        <meta property="og:url" content="{{ .Permalink }}" />
 
@@ -23,6 +23,7 @@
 
        <meta property="og:type" content="article" />
     <meta property="og:article:published_time" content="{{ .Date.Format "2006-01-02T15:04:05Z07:00" | safeHTML }}" />
+    <meta property="og:article:modified_time" content="{{ .Lastmod.Format "2006-01-02T15:04:05Z07:00" | safeHTML }}" />
 
     {{ range .Params.tags }}
     <meta property="og:article:tag" content="{{ . }}" />
@@ -32,7 +33,7 @@
     {{ end }}
 
     <title>
-      {{ if ne .URL "/" }} {{ .Title }} &middot; {{ end }} {{ .Site.Title }}
+      {{ if ne .RelPermalink "/" }} {{ .Title }} &middot; {{ end }} {{ .Site.Title }}
     </title>
 
     <meta name="description" content="{{ .Site.Params.description }}" />
     <link rel="icon" type="image/png" href="/images/favicon-96x96.png" sizes="96x96" />
     <link rel="icon" type="image/png" href="/images/favicon-32x32.png" sizes="32x32" />
 
-    <link rel="stylesheet" type="text/css" href="{{.Site.BaseURL}}css/styles.css?v=1.2" />
+    <link rel="stylesheet" type="text/css" href="{{.Site.BaseURL}}css/styles.css?v=1.3" />
 
 
     {{ if .Site.Params.RSSLink}}
         <link href="{{.Site.Params.RSSLink }}" rel="alternate" type="application/rss+xml" title="{{ .Site.Title }}" />
     {{else}}
-      {{ if ne .URL "/" }}
+      {{ if ne .RelPermalink "/" }}
           <link href="{{ .Site.BaseURL }}index.xml" rel="alternate" type="application/rss+xml" title="{{ .Site.Title }}" />
       {{ end }}
       {{if .IsNode}}
-        <link href="{{.RSSLink}}" rel="alternate" type="application/rss+xml" title="{{ if ne .URL "/" }}{{ .Title }} &middot; {{ end }}{{ .Site.Title }}" />
+        <link href="{{ with .OutputFormats.Get "RSS" }}{{ .Permalink }}{{ end }}" rel="alternate" type="application/rss+xml" title="{{ if ne .RelPermalink "/" }}{{ .Title }} &middot; {{ end }}{{ .Site.Title }}" />
       {{end}}
     {{end}}
-    {{.Hugo.Generator}}
+    {{hugo.Generator}}
 
     <link rel="canonical" href="{{ .Permalink }}" />
 
     {{with  .Site.Params.googleAnalyticsUserID }}
     <script>
-      if (window.location.href.toLowerCase().indexOf('https') !== -1) {
-              (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+
+        (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
         (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
         m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
-        })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
-
-        ga('create', '{{.}}', 'auto');
+        })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
+
+        var GA_LOCAL_STORAGE_KEY = 'ga:clientId';
+
+        if (window.localStorage) {
+            ga('create', '{{.}}', {
+                'storage': 'none',
+                'clientId': localStorage.getItem(GA_LOCAL_STORAGE_KEY)
+            });
+            ga(function (tracker) {
+                localStorage.setItem(GA_LOCAL_STORAGE_KEY, tracker.get('clientId'));
+            });
+        }
+        else {
+            ga('create', '{{.}}', {'storage': 'none'});
+        }
+
+        ga('set', 'anonymizeIp', true);
         ga('send', 'pageview');
-      }
+      
     </script>
     {{end}}
 
     <!-- at the end of the HEAD -->
     <link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.css" />
-    <!-- at the end of the BODY -->
-    <script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/2/docsearch.min.js"></script>
 
     {{ if .Site.Params.customHeaderPartial }}
         {{ partial .Site.Params.customHeaderPartial . }}
       <header id="header" class="header">
         <div class="container">
             <div class="row fix-mobile">
-                <div class="col-sm-4 col-xs-8">
+                <div class="col-md-3 col-sm-6 col-xs-8">
                     <div class="logo">
                         <a href="{{.Site.BaseURL}}">
                             {{partial "icon/logo.svg"}}
 
                     </div>
                 </div>
-                <div class="col-sm-8 menu col-xs-4">
+                <div class="col-md-9 col-sm-6 menu col-xs-4">
                     <button tabindex="1" id="menu-button" class="button muted" type="button">{{partial "icon/menu.svg"}}</button>
                     <div class="inner">
-                        <a href="/docs"><span class="icon">{{partial "icon/book.svg"}}</span> Documentation</a>
-                        <a href="/#features"><span class="icon">{{partial "icon/star.svg"}}</span> Features</a>
-                        <a href="/#demo"><span class="icon">{{partial "icon/touch_app.svg"}}</span> Demo</a>
-                        <a href="https://github.com/BookStackApp/BookStack" target="_blank"><span class="icon">{{partial "icon/github.svg"}}</span> Github</a>
-                        <a href="/blog"><span class="icon">{{partial "icon/rss_feed.svg"}}</span> Blog</a>
+                        <a href="/docs"><span class="icon">{{partial "icon/book.svg"}}</span>Documentation</a>
+                        <a href="/#features"><span class="icon">{{partial "icon/star.svg"}}</span>Features</a>
+                        <a href="/#demo"><span class="icon">{{partial "icon/touch_app.svg"}}</span>Demo</a>
+                        <a href="https://github.com/BookStackApp/BookStack" target="_blank"><span class="icon">{{partial "icon/github.svg"}}</span>Github</a>
+                        <a href="https://discord.gg/ztkBqR2" target="_blank"><span class="icon">{{partial "icon/discord.svg"}}</span>Discord</a>
+                        <a href="/blog"><span class="icon">{{partial "icon/rss_feed.svg"}}</span>Blog</a>
                     </div>
                 </div>
             </div>
diff --git a/themes/bookstack/layouts/partials/icon/discord.svg b/themes/bookstack/layouts/partials/icon/discord.svg
new file mode 100644 (file)
index 0000000..cc7d611
--- /dev/null
@@ -0,0 +1 @@
+<svg fill="#ffffff" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 245 240"><path class="st0" d="M104.4 103.9c-5.7 0-10.2 5-10.2 11.1s4.6 11.1 10.2 11.1c5.7 0 10.2-5 10.2-11.1.1-6.1-4.5-11.1-10.2-11.1zM140.9 103.9c-5.7 0-10.2 5-10.2 11.1s4.6 11.1 10.2 11.1c5.7 0 10.2-5 10.2-11.1s-4.5-11.1-10.2-11.1z"/><path class="st0" d="M189.5 20h-134C44.2 20 35 29.2 35 40.6v135.2c0 11.4 9.2 20.6 20.5 20.6h113.4l-5.3-18.5 12.8 11.9 12.1 11.2 21.5 19V40.6c0-11.4-9.2-20.6-20.5-20.6zm-38.6 130.6s-3.6-4.3-6.6-8.1c13.1-3.7 18.1-11.9 18.1-11.9-4.1 2.7-8 4.6-11.5 5.9-5 2.1-9.8 3.5-14.5 4.3-9.6 1.8-18.4 1.3-25.9-.1-5.7-1.1-10.6-2.7-14.7-4.3-2.3-.9-4.8-2-7.3-3.4-.3-.2-.6-.3-.9-.5-.2-.1-.3-.2-.4-.3-1.8-1-2.8-1.7-2.8-1.7s4.8 8 17.5 11.8c-3 3.8-6.7 8.3-6.7 8.3-22.1-.7-30.5-15.2-30.5-15.2 0-32.2 14.4-58.3 14.4-58.3 14.4-10.8 28.1-10.5 28.1-10.5l1 1.2c-18 5.2-26.3 13.1-26.3 13.1s2.2-1.2 5.9-2.9c10.7-4.7 19.2-6 22.7-6.3.6-.1 1.1-.2 1.7-.2 6.1-.8 13-1 20.2-.2 9.5 1.1 19.7 3.9 30.1 9.6 0 0-7.9-7.5-24.9-12.7l1.4-1.6s13.7-.3 28.1 10.5c0 0 14.4 26.1 14.4 58.3 0 0-8.5 14.5-30.6 15.2z"/></svg>
\ No newline at end of file
diff --git a/themes/bookstack/layouts/partials/icon/language.svg b/themes/bookstack/layouts/partials/icon/language.svg
new file mode 100644 (file)
index 0000000..8f2dd77
--- /dev/null
@@ -0,0 +1,4 @@
+<svg fill="#FFFFFF" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
+    <path d="M0 0h24v24H0z" fill="none"/>
+    <path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zm6.93 6h-2.95c-.32-1.25-.78-2.45-1.38-3.56 1.84.63 3.37 1.91 4.33 3.56zM12 4.04c.83 1.2 1.48 2.53 1.91 3.96h-3.82c.43-1.43 1.08-2.76 1.91-3.96zM4.26 14C4.1 13.36 4 12.69 4 12s.1-1.36.26-2h3.38c-.08.66-.14 1.32-.14 2 0 .68.06 1.34.14 2H4.26zm.82 2h2.95c.32 1.25.78 2.45 1.38 3.56-1.84-.63-3.37-1.9-4.33-3.56zm2.95-8H5.08c.96-1.66 2.49-2.93 4.33-3.56C8.81 5.55 8.35 6.75 8.03 8zM12 19.96c-.83-1.2-1.48-2.53-1.91-3.96h3.82c-.43 1.43-1.08 2.76-1.91 3.96zM14.34 14H9.66c-.09-.66-.16-1.32-.16-2 0-.68.07-1.35.16-2h4.68c.09.65.16 1.32.16 2 0 .68-.07 1.34-.16 2zm.25 5.56c.6-1.11 1.06-2.31 1.38-3.56h2.95c-.96 1.65-2.49 2.93-4.33 3.56zM16.36 14c.08-.66.14-1.32.14-2 0-.68-.06-1.34-.14-2h3.38c.16.64.26 1.31.26 2s-.1 1.36-.26 2h-3.38z"/>
+</svg>
\ No newline at end of file
diff --git a/themes/bookstack/layouts/partials/icon/lock.svg b/themes/bookstack/layouts/partials/icon/lock.svg
new file mode 100644 (file)
index 0000000..da01ce6
--- /dev/null
@@ -0,0 +1,4 @@
+<svg fill="#FFFFFF" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
+    <path d="M0 0h24v24H0z" fill="none"/>
+    <path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"/>
+</svg>
\ No newline at end of file
diff --git a/themes/bookstack/layouts/partials/icon/markdown.svg b/themes/bookstack/layouts/partials/icon/markdown.svg
new file mode 100644 (file)
index 0000000..d167160
--- /dev/null
@@ -0,0 +1,4 @@
+<svg fill="#FFFFFF" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
+    <path d="M0 0h24v24H0V0z" fill="none"/>
+    <path d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"/>
+</svg>
\ No newline at end of file
index abbf96f2d24ef50f169c7f52ad073704f1f28d27..7a3eaa605c0147246d0a52784d45c599177cfb02 100644 (file)
@@ -7,24 +7,6 @@
         <p>{{ .Summary }} <a class="read-more" href="{{.RelPermalink}}">&raquo;</a></p>
     </section>
     <footer class="post-meta">
-        {{$author:= .Site.Params.author}}
-        {{if .Params.author }}
-            {{$author:= .Params.author}}
-            {{if isset .Site.Data.authors $author}}
-                {{$author := index .Site.Data.authors .Params.author }}
-            {{end}}
-        {{end}}
-
-        {{ if isset $author "thumbnail" }}
-            <img class="author-thumb" src="{{ .Site.BaseURL }}{{ $author.thumbnail }}" alt="Author image" nopin="nopin" />
-        {{else if .Site.Params.logo }}
-            <img class="author-thumb" src="{{ .Site.BaseURL }}{{.Site.Params.logo}}" alt="Author image" nopin="nopin" />
-        {{end}}
-        {{ if isset $author "name" }}
-            {{$author.name}}
-        {{else if .Site.Params.author}}
-            {{.Site.Params.author}}
-        {{end}}
         {{if .Params.tags }}
             {{ range $index, $tag := .Params.tags }}
                 <a href="{{$baseurl}}tags/{{ $tag | urlize }}/">#{{ $tag }}</a>,
index fafc98dd817a6ccac00e9117640fed769e5637d3..e1d3f9cdd4fb23e349a10e27bf50b2cfdc6063cc 100644 (file)
@@ -1,7 +1,7 @@
 <!-- Begin MailChimp Signup Form -->
 
 <div id="mc_embed_signup">
-    <form action="//bookstackapp.us14.list-manage.com/subscribe/post?u=18917f477406e2be3f062086a&amp;id=7de4fb0c79" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
+    <form action="https://bookstackapp.us14.list-manage.com/subscribe/post?u=18917f477406e2be3f062086a&amp;id=7de4fb0c79" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
         <h4>Subscribe to Updates</h4>
         <p>This is a weekly newsletter, summarising content from the blog.</p>
         <div class="mc-field-group">
@@ -13,5 +13,7 @@
             <div class="response" id="mce-success-response" style="display:none"></div>
         </div>    <!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
         <div style="position: absolute; left: -5000px;" aria-hidden="true"><input type="text" name="b_18917f477406e2be3f062086a_7de4fb0c79" tabindex="-1" value=""></div>
+        <p class="text-small">This service uses MailChimp to manage sending emails so any information provided will go into their systems. Feel free to review their <a href="https://mailchimp.com/legal/privacy" target="_blank">Privacy Policy</a> and <a href="https://mailchimp.com/legal/terms" target="_blank">Terms</a>. You'll be able to opt-out via a link in the email whenever you want. If you don't trust MailChimp or any BookStack maintainers with the data you provide or emit then please don't sign up.</p>
+        <p class="text-small">A security-specific mailing list <a href="http://eepurl.com/glIh8z" target="_blank">can be found here</a>.</p>
     </form>
 </div>
\ No newline at end of file
index d65d906cc9c55cc1af267b7a4ae26d3bf62283a8..0653e22370cb6929517eb581e774b01cd454a0e7 100644 (file)
@@ -1,10 +1,9 @@
 <h4>Setup</h4>
 <ul>
        <li><a href="/docs/admin/installation">Installation</a></li>
-       <li><a href="/docs/admin/visual-customisation">Branding &amp; Customisation</a></li>
        <li><a href="/docs/admin/security">Security</a></li>
-       <li><a href="/docs/admin/upload-limits">Changing Upload Limits</a></li>
        <li><a href="/docs/admin/multi-instance">Multiple Instances</a></li>
+       <li><a href="/docs/admin/subdirectory-setup">Subdirectory Setup</a></li>
 </ul>
 
 <h4>Maintenance</h4>
        <li><a href="/docs/admin/debugging">Debugging</a></li>
 </ul>
 
+<h4>Authentication</h4>
+<ul>
+       <li><a href="/docs/admin/saml2-auth">SAML 2.0</a></li>
+       <li><a href="/docs/admin/ldap-auth">LDAP</a></li>
+       <li><a href="/docs/admin/social-auth">Third Party & Social</a></li>
+</ul>
+
 <h4>Configuration</h4>
 <ul>
+       <li><a href="/docs/admin/visual-customisation">Visual Customisation</a></li>
+       <li><a href="/docs/admin/language-config">Language &amp; Locale</a></li>
+       <li><a href="/docs/admin/upload-config">File Uploads</a></li>
        <li><a href="/docs/admin/cache-session-config">Caching &amp; Sessions</a></li>
-       <li><a href="/docs/admin/social-auth">Social Authentication</a></li>
-       <li><a href="/docs/admin/ldap-auth">LDAP Authentication</a></li>
        <li><a href="/docs/admin/pdf-rendering">PDF Rendering</a></li>
        <li><a href="/docs/admin/ut8mb4-support">UTF8mb4/Emoji Support</a></li>
+       <li><a href="/docs/admin/hacking-bookstack">Hacking BookStack</a></li>
+       <li><a href="/docs/admin/other-config">Other Configuration</a></li>
 </ul>
index d0c07c7255bc65a82f484b75aa025928a72b59ce..17a1d993f67a2759f143576652e7318fa868e522 100644 (file)
@@ -4,7 +4,15 @@
        <div class="container">
                <div class="row">
                        <div class="col-sm-6">
+                               {{if eq .Page.Type "admin-doc"}}
+                               <h2 class="thin-margin">Admin Documentation</h2>
+                               {{else if eq .Page.Type "user-doc"}}
+                               <h2 class="thin-margin">User Documentation</h2>
+                               {{else}}
                                <h2 class="thin-margin">Documentation</h2>
+                               {{end}}
+
+                               
                        </div>
                        <div class="col-sm-6">
                                <div class="float right float-none-sm">
 
 <div class="container">
        <div class="row docs-index">
+
+               {{if ne .Page.Type "user-doc"}}
                <div class="col-sm-6">
                        <div class="shaded padded">
+                               {{if ne .Page.Type "admin-doc"}}
                                <h3>Admin Documentation</h3>
+                               {{end}}
                                {{partial "menu_admin_docs"}}
                        </div>
                </div>
+               {{end}}
+               {{if ne .Page.Type "admin-doc"}}
                <div class="col-sm-6">
                        <div class="shaded padded">
+                               {{if ne .Page.Type "user-doc"}}
                                <h3>User Documentation</h3>
+                               {{end}}
                                {{partial "menu_user_docs"}}    
                        </div>
                </div>
+               {{end}}
        </div>
 </div>
 
+<p><br></p>
+
 {{ partial "footer.html" . }}
\ No newline at end of file
index 76be3a207b9bb87e135f21446bf83540c1bb60ee..ac23d4747225bea2be37068196158ee31a76302b 100644 (file)
@@ -14,9 +14,9 @@
        border: 0;
 }
 
-.post-content img {
+.post-content img:not(.no-border) {
        border-radius: 3px;
-       border: 1px solid $primary;
+       border: 1px solid #DDD;
 }
 
 .post-content video {
diff --git a/themes/bookstack/sass/_codemirror.scss b/themes/bookstack/sass/_codemirror.scss
new file mode 100644 (file)
index 0000000..0ba2770
--- /dev/null
@@ -0,0 +1,405 @@
+/* BASICS */
+
+.CodeMirror {
+  /* Set height, width, borders, and global font properties here */
+  height: 300px;
+  color: black;
+}
+
+/* PADDING */
+
+.CodeMirror-lines {
+  padding: 4px 0; /* Vertical padding around content */
+}
+.CodeMirror pre {
+  padding: 0 4px; /* Horizontal padding of content */
+}
+
+.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+  background-color: white; /* The little square between H and V scrollbars */
+}
+
+/* GUTTER */
+
+.CodeMirror-gutters {
+  border-right: 1px solid #ddd;
+  background-color: #f7f7f7;
+  white-space: nowrap;
+}
+.CodeMirror-linenumbers {}
+.CodeMirror-linenumber {
+  padding: 0 3px 0 5px;
+  min-width: 20px;
+  text-align: right;
+  color: #999;
+  white-space: nowrap;
+}
+
+.CodeMirror-guttermarker { color: black; }
+.CodeMirror-guttermarker-subtle { color: #999; }
+
+/* CURSOR */
+
+.CodeMirror-cursor {
+  border-left: 1px solid black;
+  border-right: none;
+  width: 0;
+}
+/* Shown when moving in bi-directional text */
+.CodeMirror div.CodeMirror-secondarycursor {
+  border-left: 1px solid silver;
+}
+.cm-fat-cursor .CodeMirror-cursor {
+  width: auto;
+  border: 0 !important;
+  background: #7e7;
+}
+.cm-fat-cursor div.CodeMirror-cursors {
+  z-index: 1;
+}
+
+.cm-animate-fat-cursor {
+  width: auto;
+  border: 0;
+  -webkit-animation: blink 1.06s steps(1) infinite;
+  -moz-animation: blink 1.06s steps(1) infinite;
+  animation: blink 1.06s steps(1) infinite;
+  background-color: #7e7;
+}
+@-moz-keyframes blink {
+  0% {}
+  50% { background-color: transparent; }
+  100% {}
+}
+@-webkit-keyframes blink {
+  0% {}
+  50% { background-color: transparent; }
+  100% {}
+}
+@keyframes blink {
+  0% {}
+  50% { background-color: transparent; }
+  100% {}
+}
+
+/* Can style cursor different in overwrite (non-insert) mode */
+.CodeMirror-overwrite .CodeMirror-cursor {}
+
+.cm-tab { display: inline-block; text-decoration: inherit; }
+
+.CodeMirror-rulers {
+  position: absolute;
+  left: 0; right: 0; top: -50px; bottom: -20px;
+  overflow: hidden;
+}
+.CodeMirror-ruler {
+  border-left: 1px solid #ccc;
+  top: 0; bottom: 0;
+  position: absolute;
+}
+
+/* DEFAULT THEME */
+
+.cm-s-default .cm-header {color: blue;}
+.cm-s-default .cm-quote {color: #090;}
+.cm-negative {color: #d44;}
+.cm-positive {color: #292;}
+.cm-header, .cm-strong {font-weight: bold;}
+.cm-em {font-style: italic;}
+.cm-link {text-decoration: underline;}
+.cm-strikethrough {text-decoration: line-through;}
+
+.cm-s-default .cm-keyword {color: #708;}
+.cm-s-default .cm-atom {color: #219;}
+.cm-s-default .cm-number {color: #164;}
+.cm-s-default .cm-def {color: #00f;}
+.cm-s-default .cm-variable,
+.cm-s-default .cm-punctuation,
+.cm-s-default .cm-property,
+.cm-s-default .cm-operator {}
+.cm-s-default .cm-variable-2 {color: #05a;}
+.cm-s-default .cm-variable-3 {color: #085;}
+.cm-s-default .cm-comment {color: #a50;}
+.cm-s-default .cm-string {color: #a11;}
+.cm-s-default .cm-string-2 {color: #f50;}
+.cm-s-default .cm-meta {color: #555;}
+.cm-s-default .cm-qualifier {color: #555;}
+.cm-s-default .cm-builtin {color: #30a;}
+.cm-s-default .cm-bracket {color: #997;}
+.cm-s-default .cm-tag {color: #170;}
+.cm-s-default .cm-attribute {color: #00c;}
+.cm-s-default .cm-hr {color: #999;}
+.cm-s-default .cm-link {color: #00c;}
+
+.cm-s-default .cm-error {color: #f00;}
+.cm-invalidchar {color: #f00;}
+
+.CodeMirror-composing { border-bottom: 2px solid; }
+
+/* Default styles for common addons */
+
+div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
+div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
+.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
+.CodeMirror-activeline-background {background: #e8f2ff;}
+
+/* STOP */
+
+/* The rest of this file contains styles related to the mechanics of
+   the editor. You probably shouldn't touch them. */
+
+.CodeMirror {
+  position: relative;
+  overflow: hidden;
+  background: white;
+}
+
+.CodeMirror-scroll {
+  overflow: scroll !important; /* Things will break if this is overridden */
+  /* 30px is the magic margin used to hide the element's real scrollbars */
+  /* See overflow: hidden in .CodeMirror */
+  margin-bottom: -30px; margin-right: -30px;
+  padding-bottom: 30px;
+  height: 100%;
+  outline: none; /* Prevent dragging from highlighting the element */
+  position: relative;
+}
+.CodeMirror-sizer {
+  position: relative;
+  border-right: 30px solid transparent;
+}
+
+/* The fake, visible scrollbars. Used to force redraw during scrolling
+   before actual scrolling happens, thus preventing shaking and
+   flickering artifacts. */
+.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
+  position: absolute;
+  z-index: 6;
+  display: none;
+}
+.CodeMirror-vscrollbar {
+  right: 0; top: 0;
+  overflow-x: hidden;
+  overflow-y: scroll;
+}
+.CodeMirror-hscrollbar {
+  bottom: 0; left: 0;
+  overflow-y: hidden;
+  overflow-x: scroll;
+}
+.CodeMirror-scrollbar-filler {
+  right: 0; bottom: 0;
+}
+.CodeMirror-gutter-filler {
+  left: 0; bottom: 0;
+}
+
+.CodeMirror-gutters {
+  position: absolute; left: 0; top: 0;
+  min-height: 100%;
+  z-index: 3;
+}
+.CodeMirror-gutter {
+  white-space: normal;
+  height: 100%;
+  display: inline-block;
+  vertical-align: top;
+  margin-bottom: -30px;
+}
+.CodeMirror-gutter-wrapper {
+  position: absolute;
+  z-index: 4;
+  background: none !important;
+  border: none !important;
+}
+.CodeMirror-gutter-background {
+  position: absolute;
+  top: 0; bottom: 0;
+  z-index: 4;
+}
+.CodeMirror-gutter-elt {
+  position: absolute;
+  cursor: default;
+  z-index: 4;
+}
+.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
+.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
+
+.CodeMirror-lines {
+  cursor: text;
+  min-height: 1px; /* prevents collapsing before first draw */
+}
+.CodeMirror pre {
+  /* Reset some styles that the rest of the page might have set */
+  -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
+  border-width: 0;
+  background: transparent;
+  font-size: inherit;
+  margin: 0;
+  white-space: pre;
+  word-wrap: normal;
+  line-height: inherit;
+  color: inherit;
+  z-index: 2;
+  position: relative;
+  overflow: visible;
+  -webkit-tap-highlight-color: transparent;
+  -webkit-font-variant-ligatures: contextual;
+  font-variant-ligatures: contextual;
+  &:after {
+    content: none;
+    display: none;
+  }
+}
+.CodeMirror-wrap pre {
+  word-wrap: break-word;
+  white-space: pre-wrap;
+  word-break: normal;
+}
+
+.CodeMirror-linebackground {
+  position: absolute;
+  left: 0; right: 0; top: 0; bottom: 0;
+  z-index: 0;
+}
+
+.CodeMirror-linewidget {
+  position: relative;
+  z-index: 2;
+  overflow: auto;
+}
+
+.CodeMirror-widget {}
+
+.CodeMirror-rtl pre { direction: rtl; }
+
+.CodeMirror-code {
+  outline: none;
+}
+
+/* Force content-box sizing for the elements where we expect it */
+.CodeMirror-scroll,
+.CodeMirror-sizer,
+.CodeMirror-gutter,
+.CodeMirror-gutters,
+.CodeMirror-linenumber {
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
+}
+
+.CodeMirror-measure {
+  position: absolute;
+  width: 100%;
+  height: 0;
+  overflow: hidden;
+  visibility: hidden;
+}
+
+.CodeMirror-cursor {
+  position: absolute;
+  pointer-events: none;
+}
+.CodeMirror-measure pre { position: static; }
+
+div.CodeMirror-cursors {
+  visibility: hidden;
+  position: relative;
+  z-index: 3;
+}
+div.CodeMirror-dragcursors {
+  visibility: visible;
+}
+
+.CodeMirror-focused div.CodeMirror-cursors {
+  visibility: visible;
+}
+
+.CodeMirror-selected { background: #d9d9d9; }
+.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
+.CodeMirror-crosshair { cursor: crosshair; }
+.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
+.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
+
+.cm-searching {
+  background: #ffa;
+  background: rgba(255, 255, 0, .4);
+}
+
+/* Used to force a border model for a node */
+.cm-force-border { padding-right: .1px; }
+
+@media print {
+  /* Hide the cursor when printing */
+  .CodeMirror div.CodeMirror-cursors {
+    visibility: hidden;
+  }
+}
+
+/* See issue #2901 */
+.cm-tab-wrap-hack:after { content: ''; }
+
+/* Help users use markselection to safely style text background */
+span.CodeMirror-selectedtext { background: none; }
+
+
+/*
+
+    Name:       Base16 Default Light
+    Author:     Chris Kempson (http://chriskempson.com)
+
+    CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
+    Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
+
+*/
+
+.cm-s-base16-light.CodeMirror { background: #f8f8f8; color: #444444; }
+.cm-s-base16-light div.CodeMirror-selected { background: #e0e0e0; }
+.cm-s-base16-light .CodeMirror-line::selection, .cm-s-base16-light .CodeMirror-line > span::selection, .cm-s-base16-light .CodeMirror-line > span > span::selection { background: #e0e0e0; }
+.cm-s-base16-light .CodeMirror-line::-moz-selection, .cm-s-base16-light .CodeMirror-line > span::-moz-selection, .cm-s-base16-light .CodeMirror-line > span > span::-moz-selection { background: #e0e0e0; }
+.cm-s-base16-light .CodeMirror-gutters { background: #f5f5f5; border-right: 0px; }
+.cm-s-base16-light .CodeMirror-guttermarker { color: #ac4142; }
+.cm-s-base16-light .CodeMirror-guttermarker-subtle { color: #b0b0b0; }
+.cm-s-base16-light .CodeMirror-linenumber { color: #b0b0b0; }
+.cm-s-base16-light .CodeMirror-cursor { border-left: 1px solid #505050; }
+
+.cm-s-base16-light span.cm-comment { color: #8f5536; }
+.cm-s-base16-light span.cm-atom { color: #aa759f; }
+.cm-s-base16-light span.cm-number { color: #aa759f; }
+
+.cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute { color: #678c30; }
+.cm-s-base16-light span.cm-keyword { color: #ac4142; }
+.cm-s-base16-light span.cm-string { color: #e09c3c; }
+
+.cm-s-base16-light span.cm-variable { color: #90a959; }
+.cm-s-base16-light span.cm-variable-2 { color: #6a9fb5; }
+.cm-s-base16-light span.cm-def { color: #d28445; }
+.cm-s-base16-light span.cm-bracket { color: #202020; }
+.cm-s-base16-light span.cm-tag { color: #ac4142; }
+.cm-s-base16-light span.cm-link { color: #aa759f; }
+.cm-s-base16-light span.cm-error { background: #ac4142; color: #505050; }
+
+.cm-s-base16-light .CodeMirror-activeline-background { background: #DDDCDC; }
+.cm-s-base16-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }
+
+/**
+ * Custom BookStack overrides
+ */
+.CodeMirror, .CodeMirror pre {
+  font-size: 12px;
+}
+.CodeMirror {
+  font-size: 12px;
+  height: auto;
+  margin-bottom: $-l;
+  border: 1px solid #DDD;;
+}
+.cm-s-base16-light .CodeMirror-gutters { background: #f5f5f5; border-right: 1px solid #DDD; }
+
+.code-fill .CodeMirror {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+}
index 8af9e278608468efbf6b7209b83daadabae793e0..dfe033a34347b9580da537466b29a686e01f8b24 100644 (file)
@@ -18,7 +18,7 @@
   }
   .spaced {
     margin-top: $-xxl;
-    margin-bottom: $-xxl*2;
+    margin-bottom: $-l*2;
     h2, p {
       max-width: 420px;
     }
index e067450e82e1104a1f3a16de3ca3b121e2767e84..5618231b17b666ec8c3c67cb1abcd75a46b75a52 100644 (file)
@@ -10,7 +10,8 @@ body {
   font-size: $fs-m;
   line-height: 1.6;
   color: #616161;
-  -webkit-font-smoothing: antialiased;
+  overflow-x: hidden;
+  max-width: 100%;
 }
 
 table {
index ad818d2b3c0644775a898804fdd65a503d7f2046..b7bc369d0dcafab3130b2719f3c6a9fc304521e1 100644 (file)
@@ -64,7 +64,9 @@ h4 {
   margin-bottom: 0.43137255em;
 }
 
-h1, h2, h3, h4 {
+
+
+h1, h2, h3, h4, h5 {
   font-weight: 400;
   position: relative;
   display: block;
@@ -76,6 +78,14 @@ h1, h2, h3, h4 {
   }
 }
 
+h5 {
+  font-size: 1.1em;
+  line-height: 1.375em;
+  margin-top: 0.78571429em;
+  margin-bottom: 0.43137255em;
+  font-weight: 500;
+}
+
 /*
  * Link styling
  */
@@ -288,6 +298,9 @@ ul {
 ol {
   list-style-type: decimal;
   padding-left: $-m*1.2;
+  li {
+    margin-bottom: 3px;
+  }
 }
 
 /*
index 5ee314d6a66ecc0bb46394c00c9b5759f04b9c5b..047e94068131fb56bed2b729794ff66aec839aef 100644 (file)
@@ -2,6 +2,7 @@
 @import "variables";
 @import "mixins";
 @import "html";
+@import "codemirror";
 @import "text";
 @import "grid";
 @import "blocks";
   }
 }
 
-.screenshot-container {
-  perspective: 1000px;
+.screenshot-container-parent {
+  perspective: 800px;
+  z-index: 5;
   perspective-origin: 50% 50%;
 }
-.screenshot {
+
+@keyframes slow-rotate {
+  from {
+      transform: rotateY(-10deg);
+  }
+  to {
+    transform: rotateY(0deg);
+  }
+}
+
+.screenshot-container {
+  animation: slow-rotate ease-in-out 1s;
   border-radius: 4px;
   display: inline-block;
   overflow: hidden;
-  box-shadow: 0 0 4px 1px rgba(0, 0, 0, 0.2);
-  border: 1px solid #DDD;
+  box-shadow: 0 0 12px 0px rgba(0, 0, 0, 0.2);
+  border: 3px solid #DDD;
   position: absolute;
-  max-width: 100%;
-  transform: rotateY(0);
+  transform: rotateY(0) translateX(0);
+  transform-style: preserve-3d;
   transition: all ease-in-out 280ms;
+  transform-origin: 50% 50%;
+  z-index: 50;
   &:hover {
-    transform: rotateY(-10deg);
+    transform: rotateY(-10deg) translateX(20px);
+    box-shadow: 0 0 20px 0px rgba(0, 0, 0, 0.2);
+  }
+  .window-row {
+    line-height: 1;
+    background-color: #DDD;
+    padding: 2px 4px;
+    .window-option {
+      display: inline-block;
+      background-color: red;
+      width: 8px;
+      margin-right: 2px;
+      height: 8px;
+      border-radius: 50%;
+    }
   }
   @include smaller-than($screen-lg) {
     position: relative;
     margin-bottom: $-l;
   }
 }
+.screenshot {
+  display: block;
+  max-width: 100%;
+  border-radius: 2px;
+}
 
 header .menu, footer .menu {
   text-align: right;
@@ -261,12 +295,24 @@ input[type=text] {
     list-style: none;
     margin-left: 0;
   }
+  li {
+    padding: 2px 0;
+  }
 }
 
 .sidebar {
   border-right: 2px dotted #E5E5E5;
 }
 
+@include larger-than($xl) {
+  .sidebar {
+    position: sticky;
+    top: $-m;
+  }
+}
+
+
+
 h2.thin-margin {
   margin-top: 0;
 }
@@ -283,7 +329,7 @@ h2.thin-margin {
   margin-bottom: $-m;
   width: 280px;
   background-color: #FFF;
-  border: 1px solid #DDD; 
+  border: 1px solid #DDD;
   a {
     display: block;
   }
@@ -324,4 +370,4 @@ input[type="text"].doc-search-input {
   &:focus, &:active {
     outline: none;
   }
-}
\ No newline at end of file
+}
diff --git a/themes/bookstack/static/images/bookstack-hero-screenshot.jpg b/themes/bookstack/static/images/bookstack-hero-screenshot.jpg
new file mode 100644 (file)
index 0000000..1fe6a3f
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:35de68ad0a7b54ca54baaa46fb91f6561b223586cec05a2f80ad8c773b599945
+size 198224
diff --git a/themes/bookstack/static/images/bookstack-hero-screenshot.png b/themes/bookstack/static/images/bookstack-hero-screenshot.png
deleted file mode 100644 (file)
index f44a65c..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:6d050c74b6d6e0f7ae59baf0649dc13498bf7fd5961bd88745b3a848dddd02dd
-size 83898
index add86f5f1bd7d4a5fbe854d9a5b198ada415d059..d1dbdb12813083b322af31ae21f29a1f3b4a2edc 100644 (file)
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:8f56ff358f151f7b024496a12663cc7231d412b423c008b4f7ea83259e20402a
-size 69504
+oid sha256:9db2bab9290ea7fb4db8206ff214e63987c561cfaca83cd97c8a3542d5930cfd
+size 171486
index a78b67ee3841b6b9715d477085808bede3625411..19c6c14eebc035d9393e280c1fb032716e653640 100644 (file)
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:0c0e074704b316f209cf61bfbbef01d538a971d2aec7e3b71bd1d0d717d5c918
-size 40149
+oid sha256:5f81e89490ec6eaa65ae406707204011f2902f3150887e5d63eb72364293ff3a
+size 108661
index f3879fb4d98a99d991bcee6c997f9f9b279710bc..f971d93673089af9a333846f8c2e404f5ee8a17d 100644 (file)
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:c4b07e5f64ee5dd89ea73fd1c4db9860d6857f77629c1a6707a2a11e13bcbd73
-size 53463
+oid sha256:6964dd9ef48d3519dca42d7568c20ba68bbc889a0e7a609141a669b571afc23b
+size 523589
index 389b707d47a22906d6da5cc4ab441f72a2f6297a..a41decee61128480e45855d14c7f225baebf4e6b 100644 (file)
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:98dac9de6bdf8fa8e5709a9e083029201b521fe1a8d4189da14997febf4f8280
-size 385909
+oid sha256:4bebbf99d3652737401e4a7bfeb522312299a1a06be171227819df87ae480e1d
+size 984582
index c62ddea950ff994bef7e14ae37478e5573c6ed9d..c8d7f325fdd47298e30e64662a55401d7a935b2f 100644 (file)
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:ed8747fb41512c1fd6df3984e4ee839c4889106929012142d43d87e8f31bf573
-size 66896
+oid sha256:1193d2ee343ede903cdb69aace951636e839606b3dce36567e35b8a8ac5f514b
+size 360268
index 7774b92de31a2386adb7588638ae93567bba31e3..62593ba09c4c68a4e6d817fbde1d82114c8c990b 100644 (file)
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:359de8ca7ecde0f3cc0eb24e597c20b28b5643190d702affaedb81eeffbd212d
-size 108921
+oid sha256:45003cb5b9499ba66679878719aca0b32ae707641448edced9a6cb0699a35339
+size 408874
diff --git a/themes/bookstack/static/images/screenshots/profile-edit-view.png b/themes/bookstack/static/images/screenshots/profile-edit-view.png
deleted file mode 100644 (file)
index b955cfc..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:757a54b40b23b42fbfaf333190be324b92fa1a5ce3003ca5e88ff3f45d8d61bd
-size 36997
diff --git a/themes/bookstack/static/images/screenshots/profile-page.png b/themes/bookstack/static/images/screenshots/profile-page.png
new file mode 100644 (file)
index 0000000..095ff1e
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d037eed7c830d5c9c2dac53e0983aba15106425a1eba617dc1366d38e12ba304
+size 204354
index d990afdf841ef081f98f6a0b84e633c396136a47..7742c79e48b1b5f06839dc8638c4a0cf16f119c1 100644 (file)
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:dd1a2d711dad1b4a16bdd588023d540c24942c13dc985d81f675217b161c45f0
-size 67420
+oid sha256:fd71017b746182076f3a91d2c12535b1693db7427d1d944f3226bbbe756836f5
+size 126717
index 84a165695531ae6730646e0aa80a55722a64da36..78e016cc44c909834e2a485b695636195f8711b4 100644 (file)
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:0d9905f1e98df0b5ec5a16d8bc32a1e6897b467e57e1c07df37add6ca51e0a8e
-size 50180
+oid sha256:ae6bd35d200d6bbf2b912cc307e8e8bcbb817309dca9c2d87c8eee8d22e28318
+size 76856
index abf74b23bc43f3fa688a621cac0cfd820b3fae8b..198bb43e5221e300966b59c9cb86e500fa0364ac 100644 (file)
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:d8e8bbb5e06bc62b5b1b29b8df137d78a399ac307da239c4b92229a97311f05e
-size 17566
+oid sha256:1867186d11c223d7cdb287a269177909de4040801307584492327fcbcffb7d2b
+size 38745
index 66a5acbd6da4fa4199ec73fb6f12f70e7a5b17e9..a1bb7795b5390b03d4b40c21e2bb63d15c00df10 100644 (file)
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:b67899f6bc79d395e160697c4523007481e979bd4e5c7c6106da2cfe54ae255b
-size 10695
+oid sha256:534d4e9bca76de1081c3fee1dc49219a09d6b4c571b6809e3c105829ab42856d
+size 25446
index a73279350c43b6ffef467245e284c1b32ef65087..5736e7a6715a2ec26d8e0db24ec684d09beedf8d 100644 (file)
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:212d1e9af73783eaf46d5220b8e034e9feb2e85c00aa11be2c8d5c64111a9bd5
-size 13938
+oid sha256:0a88c3a6b309522d2994c952b181035d4473477321bc09317d0f83f5e66af95b
+size 67378
index f252ca2a836cc4dbba39433cbf3bf6cd32e11cec..0d4b31479eea367a82ade3575acea63b7913afc1 100644 (file)
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:69866fac6809393a009b0c002d3abe3b4651dcca9309e02d8eeb6d6ab70eb12d
-size 44255
+oid sha256:afa747110257ae7ba053217bfdf05787785593227108aa8da665792a43e629f2
+size 106469
index 4e9223a41c656fb515834dfc583afa508210afce..78ccde7fc0f789e735901742714c4f303dcaec5f 100644 (file)
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:7ac7e439d1703e3ce86b9f82882c73b7bc0bbcfc81356d0a7213bd8269d860ba
-size 15416
+oid sha256:71c1ceb19bbe8378630597fdf4e500b245a926abeb8580c2ed22491a3c298f19
+size 56958
index 3164da5747800213b6d9648d9fe9bf1f275991ff..080d55b3b128e5c7887308e27ceeb6e0dac12594 100644 (file)
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:431147778aef3c06013b853b3e4ce20b2838e7598781a20becf6c0408d079f8d
-size 18203
+oid sha256:655c97edc9f6f789ec4528abefe64fb4f94fa3c9f18df4cc513bd9c92fd82881
+size 66976
diff --git a/themes/bookstack/static/images/screenshots/thumb_profile-edit-view.png b/themes/bookstack/static/images/screenshots/thumb_profile-edit-view.png
deleted file mode 100644 (file)
index 3a7e922..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:7bf963cfd4e3663de49e7611f57d269b55e8a33ba5942b7ce01c50715a5a44f9
-size 9219
diff --git a/themes/bookstack/static/images/screenshots/thumb_profile-page.png b/themes/bookstack/static/images/screenshots/thumb_profile-page.png
new file mode 100644 (file)
index 0000000..4c1cac0
--- /dev/null
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5c06249815eb42d4f27b45615a45984f7b784f0f18c1b2432effffae632fc396
+size 40051
index 278d25602946b9e8691fd150a5bf1344b44426e3..d07a891ceaced4ca9f778985e391bf751799aaba 100644 (file)
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:cf252036c9d624363a110987aeb5019f0ed4707c72892999a2de6da9120ed201
-size 18207
+oid sha256:19e73b9f7abf39f27e60060bf983bf2ed8ea895abce30ce7edff09d9146463b5
+size 31069
index 217017e4e91fdf62ebdc72f3db4bf49f4aad533f..a46f8154b364dfd6f24167d4e1f91c09d3db4253 100644 (file)
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:6233a4f508accdf8fdc336d1f76fc8c04c69f106e4a01d5d5ca367bd5a604884
-size 12407
+oid sha256:cc370a75012fc1d2217f5321a992807cf87218bc121effe31558903ec2f9941b
+size 18687
index e5c7d2f588b65d039364518c25898ee2dc385c11..19364df02164e40c29b69fde5a80d3a6fe006e82 100644 (file)
@@ -22,7 +22,7 @@ document.body.onclick = function(event) {
 
 
 // Handle video click to play
-let videos = document.querySelectorAll('video');
+var videos = document.querySelectorAll('video');
 for (var i = 0; i < videos.length; i++) {
     videos[i].addEventListener('click', videoClick)
 }
@@ -30,4 +30,37 @@ for (var i = 0; i < videos.length; i++) {
 function videoClick() {
     if (typeof InstallTrigger !== 'undefined') return;
     this.paused ? this.play() : this.pause();
-}
\ No newline at end of file
+}
+
+
+// Codemirror Setup
+
+var modeMap = {
+  'language-html': 'htmlmixed',
+  'language-bash': 'shell',
+  'language-js': 'javascript',
+  'language-shell': 'bash',
+  'language-nginx': 'nginx',
+  'language-apache': 'apache',
+  'language-php': 'php',
+};
+
+var codeBlocks = document.querySelectorAll('pre');
+for (var i = 0; i < codeBlocks.length; i++) {
+  var block = codeBlocks[i];
+  var codeElem = block.querySelector('code');
+  if (codeElem === null) continue;
+
+  var langClass = codeElem.className;
+  var mode = (typeof modeMap[langClass] !== 'undefined') ? modeMap[langClass] : 'htmlmixed';
+  var content = codeElem.textContent.trim();
+  CodeMirror(function(cmElem) {
+    block.parentNode.replaceChild(cmElem, block);
+  }, {
+    theme: 'base16-light',
+    lineNumbers: true,
+    mode: mode,
+    readOnly: true,
+    value: content
+  });
+}
diff --git a/themes/bookstack/static/libs/codemirror/LICENSE b/themes/bookstack/static/libs/codemirror/LICENSE
new file mode 100644 (file)
index 0000000..ff7db4b
--- /dev/null
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (C) 2017 by Marijn Haverbeke <[email protected]> and others
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/themes/bookstack/static/libs/codemirror/codemirror.min.js b/themes/bookstack/static/libs/codemirror/codemirror.min.js
new file mode 100644 (file)
index 0000000..05659fa
--- /dev/null
@@ -0,0 +1 @@
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.CodeMirror=t()}(this,function(){"use strict";function e(e){return new RegExp("(^|\\s)"+e+"(?:$|\\s)\\s*")}function t(e){for(var t=e.childNodes.length;t>0;--t)e.removeChild(e.firstChild);return e}function n(e,n){return t(e).appendChild(n)}function r(e,t,n,r){var i=document.createElement(e);if(n&&(i.className=n),r&&(i.style.cssText=r),"string"==typeof t)i.appendChild(document.createTextNode(t));else if(t)for(var o=0;o<t.length;++o)i.appendChild(t[o]);return i}function i(e,t,n,i){var o=r(e,t,n,i);return o.setAttribute("role","presentation"),o}function o(e,t){if(3==t.nodeType&&(t=t.parentNode),e.contains)return e.contains(t);do{if(11==t.nodeType&&(t=t.host),t==e)return!0}while(t=t.parentNode)}function l(){var e;try{e=document.activeElement}catch(t){e=document.body||null}for(;e&&e.shadowRoot&&e.shadowRoot.activeElement;)e=e.shadowRoot.activeElement;return e}function s(t,n){var r=t.className;e(n).test(r)||(t.className+=(r?" ":"")+n)}function a(t,n){for(var r=t.split(" "),i=0;i<r.length;i++)r[i]&&!e(r[i]).test(n)&&(n+=" "+r[i]);return n}function u(e){var t=Array.prototype.slice.call(arguments,1);return function(){return e.apply(null,t)}}function c(e,t,n){t||(t={});for(var r in e)!e.hasOwnProperty(r)||!1===n&&t.hasOwnProperty(r)||(t[r]=e[r]);return t}function h(e,t,n,r,i){null==t&&-1==(t=e.search(/[^\s\u00a0]/))&&(t=e.length);for(var o=r||0,l=i||0;;){var s=e.indexOf("\t",o);if(s<0||s>=t)return l+(t-o);l+=s-o,l+=n-l%n,o=s+1}}function f(e,t){for(var n=0;n<e.length;++n)if(e[n]==t)return n;return-1}function d(e,t,n){for(var r=0,i=0;;){var o=e.indexOf("\t",r);-1==o&&(o=e.length);var l=o-r;if(o==e.length||i+l>=t)return r+Math.min(l,t-i);if(i+=o-r,i+=n-i%n,r=o+1,i>=t)return r}}function p(e){for(;Rl.length<=e;)Rl.push(g(Rl)+" ");return Rl[e]}function g(e){return e[e.length-1]}function v(e,t){for(var n=[],r=0;r<e.length;r++)n[r]=t(e[r],r);return n}function m(e,t,n){for(var r=0,i=n(t);r<e.length&&n(e[r])<=i;)r++;e.splice(r,0,t)}function y(){}function b(e,t){var n;return Object.create?n=Object.create(e):(y.prototype=e,n=new y),t&&c(t,n),n}function w(e){return/\w/.test(e)||e>"\80"&&(e.toUpperCase()!=e.toLowerCase()||zl.test(e))}function x(e,t){return t?!!(t.source.indexOf("\\w")>-1&&w(e))||t.test(e):w(e)}function C(e){for(var t in e)if(e.hasOwnProperty(t)&&e[t])return!1;return!0}function S(e){return e.charCodeAt(0)>=768&&Bl.test(e)}function L(e,t,n){for(;(n<0?t>0:t<e.length)&&S(e.charAt(t));)t+=n;return t}function k(e,t,n){for(;;){if(Math.abs(t-n)<=1)return e(t)?t:n;var r=Math.floor((t+n)/2);e(r)?n=r:t=r}}function M(e,t,n){var o=this;this.input=n,o.scrollbarFiller=r("div",null,"CodeMirror-scrollbar-filler"),o.scrollbarFiller.setAttribute("cm-not-content","true"),o.gutterFiller=r("div",null,"CodeMirror-gutter-filler"),o.gutterFiller.setAttribute("cm-not-content","true"),o.lineDiv=i("div",null,"CodeMirror-code"),o.selectionDiv=r("div",null,null,"position: relative; z-index: 1"),o.cursorDiv=r("div",null,"CodeMirror-cursors"),o.measure=r("div",null,"CodeMirror-measure"),o.lineMeasure=r("div",null,"CodeMirror-measure"),o.lineSpace=i("div",[o.measure,o.lineMeasure,o.selectionDiv,o.cursorDiv,o.lineDiv],null,"position: relative; outline: none");var l=i("div",[o.lineSpace],"CodeMirror-lines");o.mover=r("div",[l],null,"position: relative"),o.sizer=r("div",[o.mover],"CodeMirror-sizer"),o.sizerWidth=null,o.heightForcer=r("div",null,null,"position: absolute; height: "+Hl+"px; width: 1px;"),o.gutters=r("div",null,"CodeMirror-gutters"),o.lineGutter=null,o.scroller=r("div",[o.sizer,o.heightForcer,o.gutters],"CodeMirror-scroll"),o.scroller.setAttribute("tabIndex","-1"),o.wrapper=r("div",[o.scrollbarFiller,o.gutterFiller,o.scroller],"CodeMirror"),ul&&cl<8&&(o.gutters.style.zIndex=-1,o.scroller.style.paddingRight=0),hl||ol&&wl||(o.scroller.draggable=!0),e&&(e.appendChild?e.appendChild(o.wrapper):e(o.wrapper)),o.viewFrom=o.viewTo=t.first,o.reportedViewFrom=o.reportedViewTo=t.first,o.view=[],o.renderedView=null,o.externalMeasured=null,o.viewOffset=0,o.lastWrapHeight=o.lastWrapWidth=0,o.updateLineNumbers=null,o.nativeBarWidth=o.barHeight=o.barWidth=0,o.scrollbarsClipped=!1,o.lineNumWidth=o.lineNumInnerWidth=o.lineNumChars=null,o.alignWidgets=!1,o.cachedCharWidth=o.cachedTextHeight=o.cachedPaddingH=null,o.maxLine=null,o.maxLineLength=0,o.maxLineChanged=!1,o.wheelDX=o.wheelDY=o.wheelStartX=o.wheelStartY=null,o.shift=!1,o.selForContextMenu=null,o.activeTouch=null,n.init(o)}function T(e,t){if((t-=e.first)<0||t>=e.size)throw new Error("There is no line "+(t+e.first)+" in the document.");for(var n=e;!n.lines;)for(var r=0;;++r){var i=n.children[r],o=i.chunkSize();if(t<o){n=i;break}t-=o}return n.lines[t]}function N(e,t,n){var r=[],i=t.line;return e.iter(t.line,n.line+1,function(e){var o=e.text;i==n.line&&(o=o.slice(0,n.ch)),i==t.line&&(o=o.slice(t.ch)),r.push(o),++i}),r}function O(e,t,n){var r=[];return e.iter(t,n,function(e){r.push(e.text)}),r}function A(e,t){var n=t-e.height;if(n)for(var r=e;r;r=r.parent)r.height+=n}function W(e){if(null==e.parent)return null;for(var t=e.parent,n=f(t.lines,e),r=t.parent;r;t=r,r=r.parent)for(var i=0;r.children[i]!=t;++i)n+=r.children[i].chunkSize();return n+t.first}function D(e,t){var n=e.first;e:do{for(var r=0;r<e.children.length;++r){var i=e.children[r],o=i.height;if(t<o){e=i;continue e}t-=o,n+=i.chunkSize()}return n}while(!e.lines);for(var l=0;l<e.lines.length;++l){var s=e.lines[l].height;if(t<s)break;t-=s}return n+l}function H(e,t){return t>=e.first&&t<e.first+e.size}function F(e,t){return String(e.lineNumberFormatter(t+e.firstLineNumber))}function E(e,t,n){if(void 0===n&&(n=null),!(this instanceof E))return new E(e,t,n);this.line=e,this.ch=t,this.sticky=n}function P(e,t){return e.line-t.line||e.ch-t.ch}function I(e,t){return e.sticky==t.sticky&&0==P(e,t)}function R(e){return E(e.line,e.ch)}function z(e,t){return P(e,t)<0?t:e}function B(e,t){return P(e,t)<0?e:t}function G(e,t){return Math.max(e.first,Math.min(t,e.first+e.size-1))}function U(e,t){if(t.line<e.first)return E(e.first,0);var n=e.first+e.size-1;return t.line>n?E(n,T(e,n).text.length):V(t,T(e,t.line).text.length)}function V(e,t){var n=e.ch;return null==n||n>t?E(e.line,t):n<0?E(e.line,0):e}function K(e,t){for(var n=[],r=0;r<t.length;r++)n[r]=U(e,t[r]);return n}function j(){Gl=!0}function X(){Ul=!0}function Y(e,t,n){this.marker=e,this.from=t,this.to=n}function _(e,t){if(e)for(var n=0;n<e.length;++n){var r=e[n];if(r.marker==t)return r}}function $(e,t){for(var n,r=0;r<e.length;++r)e[r]!=t&&(n||(n=[])).push(e[r]);return n}function q(e,t){e.markedSpans=e.markedSpans?e.markedSpans.concat([t]):[t],t.marker.attachLine(e)}function Z(e,t,n){var r;if(e)for(var i=0;i<e.length;++i){var o=e[i],l=o.marker;if(null==o.from||(l.inclusiveLeft?o.from<=t:o.from<t)||o.from==t&&"bookmark"==l.type&&(!n||!o.marker.insertLeft)){var s=null==o.to||(l.inclusiveRight?o.to>=t:o.to>t);(r||(r=[])).push(new Y(l,o.from,s?null:o.to))}}return r}function Q(e,t,n){var r;if(e)for(var i=0;i<e.length;++i){var o=e[i],l=o.marker;if(null==o.to||(l.inclusiveRight?o.to>=t:o.to>t)||o.from==t&&"bookmark"==l.type&&(!n||o.marker.insertLeft)){var s=null==o.from||(l.inclusiveLeft?o.from<=t:o.from<t);(r||(r=[])).push(new Y(l,s?null:o.from-t,null==o.to?null:o.to-t))}}return r}function J(e,t){if(t.full)return null;var n=H(e,t.from.line)&&T(e,t.from.line).markedSpans,r=H(e,t.to.line)&&T(e,t.to.line).markedSpans;if(!n&&!r)return null;var i=t.from.ch,o=t.to.ch,l=0==P(t.from,t.to),s=Z(n,i,l),a=Q(r,o,l),u=1==t.text.length,c=g(t.text).length+(u?i:0);if(s)for(var h=0;h<s.length;++h){var f=s[h];if(null==f.to){var d=_(a,f.marker);d?u&&(f.to=null==d.to?null:d.to+c):f.to=i}}if(a)for(var p=0;p<a.length;++p){var v=a[p];null!=v.to&&(v.to+=c),null==v.from?_(s,v.marker)||(v.from=c,u&&(s||(s=[])).push(v)):(v.from+=c,u&&(s||(s=[])).push(v))}s&&(s=ee(s)),a&&a!=s&&(a=ee(a));var m=[s];if(!u){var y,b=t.text.length-2;if(b>0&&s)for(var w=0;w<s.length;++w)null==s[w].to&&(y||(y=[])).push(new Y(s[w].marker,null,null));for(var x=0;x<b;++x)m.push(y);m.push(a)}return m}function ee(e){for(var t=0;t<e.length;++t){var n=e[t];null!=n.from&&n.from==n.to&&!1!==n.marker.clearWhenEmpty&&e.splice(t--,1)}return e.length?e:null}function te(e,t,n){var r=null;if(e.iter(t.line,n.line+1,function(e){if(e.markedSpans)for(var t=0;t<e.markedSpans.length;++t){var n=e.markedSpans[t].marker;!n.readOnly||r&&-1!=f(r,n)||(r||(r=[])).push(n)}}),!r)return null;for(var i=[{from:t,to:n}],o=0;o<r.length;++o)for(var l=r[o],s=l.find(0),a=0;a<i.length;++a){var u=i[a];if(!(P(u.to,s.from)<0||P(u.from,s.to)>0)){var c=[a,1],h=P(u.from,s.from),d=P(u.to,s.to);(h<0||!l.inclusiveLeft&&!h)&&c.push({from:u.from,to:s.from}),(d>0||!l.inclusiveRight&&!d)&&c.push({from:s.to,to:u.to}),i.splice.apply(i,c),a+=c.length-3}}return i}function ne(e){var t=e.markedSpans;if(t){for(var n=0;n<t.length;++n)t[n].marker.detachLine(e);e.markedSpans=null}}function re(e,t){if(t){for(var n=0;n<t.length;++n)t[n].marker.attachLine(e);e.markedSpans=t}}function ie(e){return e.inclusiveLeft?-1:0}function oe(e){return e.inclusiveRight?1:0}function le(e,t){var n=e.lines.length-t.lines.length;if(0!=n)return n;var r=e.find(),i=t.find(),o=P(r.from,i.from)||ie(e)-ie(t);if(o)return-o;var l=P(r.to,i.to)||oe(e)-oe(t);return l||t.id-e.id}function se(e,t){var n,r=Ul&&e.markedSpans;if(r)for(var i=void 0,o=0;o<r.length;++o)(i=r[o]).marker.collapsed&&null==(t?i.from:i.to)&&(!n||le(n,i.marker)<0)&&(n=i.marker);return n}function ae(e){return se(e,!0)}function ue(e){return se(e,!1)}function ce(e,t,n,r,i){var o=T(e,t),l=Ul&&o.markedSpans;if(l)for(var s=0;s<l.length;++s){var a=l[s];if(a.marker.collapsed){var u=a.marker.find(0),c=P(u.from,n)||ie(a.marker)-ie(i),h=P(u.to,r)||oe(a.marker)-oe(i);if(!(c>=0&&h<=0||c<=0&&h>=0)&&(c<=0&&(a.marker.inclusiveRight&&i.inclusiveLeft?P(u.to,n)>=0:P(u.to,n)>0)||c>=0&&(a.marker.inclusiveRight&&i.inclusiveLeft?P(u.from,r)<=0:P(u.from,r)<0)))return!0}}}function he(e){for(var t;t=ae(e);)e=t.find(-1,!0).line;return e}function fe(e){for(var t;t=ue(e);)e=t.find(1,!0).line;return e}function de(e){for(var t,n;t=ue(e);)e=t.find(1,!0).line,(n||(n=[])).push(e);return n}function pe(e,t){var n=T(e,t),r=he(n);return n==r?t:W(r)}function ge(e,t){if(t>e.lastLine())return t;var n,r=T(e,t);if(!ve(e,r))return t;for(;n=ue(r);)r=n.find(1,!0).line;return W(r)+1}function ve(e,t){var n=Ul&&t.markedSpans;if(n)for(var r=void 0,i=0;i<n.length;++i)if((r=n[i]).marker.collapsed){if(null==r.from)return!0;if(!r.marker.widgetNode&&0==r.from&&r.marker.inclusiveLeft&&me(e,t,r))return!0}}function me(e,t,n){if(null==n.to){var r=n.marker.find(1,!0);return me(e,r.line,_(r.line.markedSpans,n.marker))}if(n.marker.inclusiveRight&&n.to==t.text.length)return!0;for(var i=void 0,o=0;o<t.markedSpans.length;++o)if((i=t.markedSpans[o]).marker.collapsed&&!i.marker.widgetNode&&i.from==n.to&&(null==i.to||i.to!=n.from)&&(i.marker.inclusiveLeft||n.marker.inclusiveRight)&&me(e,t,i))return!0}function ye(e){for(var t=0,n=(e=he(e)).parent,r=0;r<n.lines.length;++r){var i=n.lines[r];if(i==e)break;t+=i.height}for(var o=n.parent;o;n=o,o=n.parent)for(var l=0;l<o.children.length;++l){var s=o.children[l];if(s==n)break;t+=s.height}return t}function be(e){if(0==e.height)return 0;for(var t,n=e.text.length,r=e;t=ae(r);){var i=t.find(0,!0);r=i.from.line,n+=i.from.ch-i.to.ch}for(r=e;t=ue(r);){var o=t.find(0,!0);n-=r.text.length-o.from.ch,n+=(r=o.to.line).text.length-o.to.ch}return n}function we(e){var t=e.display,n=e.doc;t.maxLine=T(n,n.first),t.maxLineLength=be(t.maxLine),t.maxLineChanged=!0,n.iter(function(e){var n=be(e);n>t.maxLineLength&&(t.maxLineLength=n,t.maxLine=e)})}function xe(e,t,n,r){if(!e)return r(t,n,"ltr");for(var i=!1,o=0;o<e.length;++o){var l=e[o];(l.from<n&&l.to>t||t==n&&l.to==t)&&(r(Math.max(l.from,t),Math.min(l.to,n),1==l.level?"rtl":"ltr"),i=!0)}i||r(t,n,"ltr")}function Ce(e,t,n){var r;Vl=null;for(var i=0;i<e.length;++i){var o=e[i];if(o.from<t&&o.to>t)return i;o.to==t&&(o.from!=o.to&&"before"==n?r=i:Vl=i),o.from==t&&(o.from!=o.to&&"before"!=n?r=i:Vl=i)}return null!=r?r:Vl}function Se(e,t){var n=e.order;return null==n&&(n=e.order=Kl(e.text,t)),n}function Le(e,t,n){var r=L(e.text,t+n,n);return r<0||r>e.text.length?null:r}function ke(e,t,n){var r=Le(e,t.ch,n);return null==r?null:new E(t.line,r,n<0?"after":"before")}function Me(e,t,n,r,i){if(e){var o=Se(n,t.doc.direction);if(o){var l,s=i<0?g(o):o[0],a=i<0==(1==s.level)?"after":"before";if(s.level>0){var u=qt(t,n);l=i<0?n.text.length-1:0;var c=Zt(t,u,l).top;l=k(function(e){return Zt(t,u,e).top==c},i<0==(1==s.level)?s.from:s.to-1,l),"before"==a&&(l=Le(n,l,1))}else l=i<0?s.to:s.from;return new E(r,l,a)}}return new E(r,i<0?n.text.length:0,i<0?"before":"after")}function Te(e,t,n,r){var i=Se(t,e.doc.direction);if(!i)return ke(t,n,r);n.ch>=t.text.length?(n.ch=t.text.length,n.sticky="before"):n.ch<=0&&(n.ch=0,n.sticky="after");var o=Ce(i,n.ch,n.sticky),l=i[o];if("ltr"==e.doc.direction&&l.level%2==0&&(r>0?l.to>n.ch:l.from<n.ch))return ke(t,n,r);var s,a=function(e,n){return Le(t,e instanceof E?e.ch:e,n)},u=function(n){return e.options.lineWrapping?(s=s||qt(e,t),vn(e,t,s,n)):{begin:0,end:t.text.length}},c=u("before"==n.sticky?a(n,-1):n.ch);if("rtl"==e.doc.direction||1==l.level){var h=1==l.level==r<0,f=a(n,h?1:-1);if(null!=f&&(h?f<=l.to&&f<=c.end:f>=l.from&&f>=c.begin)){var d=h?"before":"after";return new E(n.line,f,d)}}var p=function(e,t,r){for(var o=function(e,t){return t?new E(n.line,a(e,1),"before"):new E(n.line,e,"after")};e>=0&&e<i.length;e+=t){var l=i[e],s=t>0==(1!=l.level),u=s?r.begin:a(r.end,-1);if(l.from<=u&&u<l.to)return o(u,s);if(u=s?l.from:a(l.to,-1),r.begin<=u&&u<r.end)return o(u,s)}},g=p(o+r,r,c);if(g)return g;var v=r>0?c.end:a(c.begin,-1);return null==v||r>0&&v==t.text.length||!(g=p(r>0?0:i.length-1,r,u(v)))?null:g}function Ne(e,t){return e._handlers&&e._handlers[t]||jl}function Oe(e,t,n){if(e.removeEventListener)e.removeEventListener(t,n,!1);else if(e.detachEvent)e.detachEvent("on"+t,n);else{var r=e._handlers,i=r&&r[t];if(i){var o=f(i,n);o>-1&&(r[t]=i.slice(0,o).concat(i.slice(o+1)))}}}function Ae(e,t){var n=Ne(e,t);if(n.length)for(var r=Array.prototype.slice.call(arguments,2),i=0;i<n.length;++i)n[i].apply(null,r)}function We(e,t,n){return"string"==typeof t&&(t={type:t,preventDefault:function(){this.defaultPrevented=!0}}),Ae(e,n||t.type,e,t),Ie(t)||t.codemirrorIgnore}function De(e){var t=e._handlers&&e._handlers.cursorActivity;if(t)for(var n=e.curOp.cursorActivityHandlers||(e.curOp.cursorActivityHandlers=[]),r=0;r<t.length;++r)-1==f(n,t[r])&&n.push(t[r])}function He(e,t){return Ne(e,t).length>0}function Fe(e){e.prototype.on=function(e,t){Xl(this,e,t)},e.prototype.off=function(e,t){Oe(this,e,t)}}function Ee(e){e.preventDefault?e.preventDefault():e.returnValue=!1}function Pe(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0}function Ie(e){return null!=e.defaultPrevented?e.defaultPrevented:0==e.returnValue}function Re(e){Ee(e),Pe(e)}function ze(e){return e.target||e.srcElement}function Be(e){var t=e.which;return null==t&&(1&e.button?t=1:2&e.button?t=3:4&e.button&&(t=2)),xl&&e.ctrlKey&&1==t&&(t=3),t}function Ge(e){if(null==Wl){var t=r("span","​");n(e,r("span",[t,document.createTextNode("x")])),0!=e.firstChild.offsetHeight&&(Wl=t.offsetWidth<=1&&t.offsetHeight>2&&!(ul&&cl<8))}var i=Wl?r("span","​"):r("span"," ",null,"display: inline-block; width: 1px; margin-right: -1px");return i.setAttribute("cm-text",""),i}function Ue(e){if(null!=Dl)return Dl;var r=n(e,document.createTextNode("AخA")),i=kl(r,0,1).getBoundingClientRect(),o=kl(r,1,2).getBoundingClientRect();return t(e),!(!i||i.left==i.right)&&(Dl=o.right-i.right<3)}function Ve(e){if(null!=Zl)return Zl;var t=n(e,r("span","x")),i=t.getBoundingClientRect(),o=kl(t,0,1).getBoundingClientRect();return Zl=Math.abs(i.left-o.left)>1}function Ke(e,t){arguments.length>2&&(t.dependencies=Array.prototype.slice.call(arguments,2)),Ql[e]=t}function je(e){if("string"==typeof e&&Jl.hasOwnProperty(e))e=Jl[e];else if(e&&"string"==typeof e.name&&Jl.hasOwnProperty(e.name)){var t=Jl[e.name];"string"==typeof t&&(t={name:t}),(e=b(t,e)).name=t.name}else{if("string"==typeof e&&/^[\w\-]+\/[\w\-]+\+xml$/.test(e))return je("application/xml");if("string"==typeof e&&/^[\w\-]+\/[\w\-]+\+json$/.test(e))return je("application/json")}return"string"==typeof e?{name:e}:e||{name:"null"}}function Xe(e,t){t=je(t);var n=Ql[t.name];if(!n)return Xe(e,"text/plain");var r=n(e,t);if(es.hasOwnProperty(t.name)){var i=es[t.name];for(var o in i)i.hasOwnProperty(o)&&(r.hasOwnProperty(o)&&(r["_"+o]=r[o]),r[o]=i[o])}if(r.name=t.name,t.helperType&&(r.helperType=t.helperType),t.modeProps)for(var l in t.modeProps)r[l]=t.modeProps[l];return r}function Ye(e,t){c(t,es.hasOwnProperty(e)?es[e]:es[e]={})}function _e(e,t){if(!0===t)return t;if(e.copyState)return e.copyState(t);var n={};for(var r in t){var i=t[r];i instanceof Array&&(i=i.concat([])),n[r]=i}return n}function $e(e,t){for(var n;e.innerMode&&(n=e.innerMode(t))&&n.mode!=e;)t=n.state,e=n.mode;return n||{mode:e,state:t}}function qe(e,t,n){return!e.startState||e.startState(t,n)}function Ze(e,t,n,r){var i=[e.state.modeGen],o={};ot(e,t.text,e.doc.mode,n,function(e,t){return i.push(e,t)},o,r);for(var l=n.state,s=0;s<e.state.overlays.length;++s)!function(r){var l=e.state.overlays[r],s=1,a=0;n.state=!0,ot(e,t.text,l.mode,n,function(e,t){for(var n=s;a<e;){var r=i[s];r>e&&i.splice(s,1,e,i[s+1],r),s+=2,a=Math.min(e,r)}if(t)if(l.opaque)i.splice(n,s-n,e,"overlay "+t),s=n+2;else for(;n<s;n+=2){var o=i[n+1];i[n+1]=(o?o+" ":"")+"overlay "+t}},o)}(s);return n.state=l,{styles:i,classes:o.bgClass||o.textClass?o:null}}function Qe(e,t,n){if(!t.styles||t.styles[0]!=e.state.modeGen){var r=Je(e,W(t)),i=t.text.length>e.options.maxHighlightLength&&_e(e.doc.mode,r.state),o=Ze(e,t,r);i&&(r.state=i),t.stateAfter=r.save(!i),t.styles=o.styles,o.classes?t.styleClasses=o.classes:t.styleClasses&&(t.styleClasses=null),n===e.doc.highlightFrontier&&(e.doc.modeFrontier=Math.max(e.doc.modeFrontier,++e.doc.highlightFrontier))}return t.styles}function Je(e,t,n){var r=e.doc,i=e.display;if(!r.mode.startState)return new rs(r,!0,t);var o=lt(e,t,n),l=o>r.first&&T(r,o-1).stateAfter,s=l?rs.fromSaved(r,l,o):new rs(r,qe(r.mode),o);return r.iter(o,t,function(n){et(e,n.text,s);var r=s.line;n.stateAfter=r==t-1||r%5==0||r>=i.viewFrom&&r<i.viewTo?s.save():null,s.nextLine()}),n&&(r.modeFrontier=s.line),s}function et(e,t,n,r){var i=e.doc.mode,o=new ts(t,e.options.tabSize,n);for(o.start=o.pos=r||0,""==t&&tt(i,n.state);!o.eol();)nt(i,o,n.state),o.start=o.pos}function tt(e,t){if(e.blankLine)return e.blankLine(t);if(e.innerMode){var n=$e(e,t);return n.mode.blankLine?n.mode.blankLine(n.state):void 0}}function nt(e,t,n,r){for(var i=0;i<10;i++){r&&(r[0]=$e(e,n).mode);var o=e.token(t,n);if(t.pos>t.start)return o}throw new Error("Mode "+e.name+" failed to advance stream.")}function rt(e,t,n,r){var i,o,l=e.doc,s=l.mode,a=T(l,(t=U(l,t)).line),u=Je(e,t.line,n),c=new ts(a.text,e.options.tabSize,u);for(r&&(o=[]);(r||c.pos<t.ch)&&!c.eol();)c.start=c.pos,i=nt(s,c,u.state),r&&o.push(new is(c,i,_e(l.mode,u.state)));return r?o:new is(c,i,u.state)}function it(e,t){if(e)for(;;){var n=e.match(/(?:^|\s+)line-(background-)?(\S+)/);if(!n)break;e=e.slice(0,n.index)+e.slice(n.index+n[0].length);var r=n[1]?"bgClass":"textClass";null==t[r]?t[r]=n[2]:new RegExp("(?:^|s)"+n[2]+"(?:$|s)").test(t[r])||(t[r]+=" "+n[2])}return e}function ot(e,t,n,r,i,o,l){var s=n.flattenSpans;null==s&&(s=e.options.flattenSpans);var a,u=0,c=null,h=new ts(t,e.options.tabSize,r),f=e.options.addModeClass&&[null];for(""==t&&it(tt(n,r.state),o);!h.eol();){if(h.pos>e.options.maxHighlightLength?(s=!1,l&&et(e,t,r,h.pos),h.pos=t.length,a=null):a=it(nt(n,h,r.state,f),o),f){var d=f[0].name;d&&(a="m-"+(a?d+" "+a:d))}if(!s||c!=a){for(;u<h.start;)i(u=Math.min(h.start,u+5e3),c);c=a}h.start=h.pos}for(;u<h.pos;){var p=Math.min(h.pos,u+5e3);i(p,c),u=p}}function lt(e,t,n){for(var r,i,o=e.doc,l=n?-1:t-(e.doc.mode.innerMode?1e3:100),s=t;s>l;--s){if(s<=o.first)return o.first;var a=T(o,s-1),u=a.stateAfter;if(u&&(!n||s+(u instanceof ns?u.lookAhead:0)<=o.modeFrontier))return s;var c=h(a.text,null,e.options.tabSize);(null==i||r>c)&&(i=s-1,r=c)}return i}function st(e,t){if(e.modeFrontier=Math.min(e.modeFrontier,t),!(e.highlightFrontier<t-10)){for(var n=e.first,r=t-1;r>n;r--){var i=T(e,r).stateAfter;if(i&&(!(i instanceof ns)||r+i.lookAhead<t)){n=r+1;break}}e.highlightFrontier=Math.min(e.highlightFrontier,n)}}function at(e,t,n,r){e.text=t,e.stateAfter&&(e.stateAfter=null),e.styles&&(e.styles=null),null!=e.order&&(e.order=null),ne(e),re(e,n);var i=r?r(e):1;i!=e.height&&A(e,i)}function ut(e){e.parent=null,ne(e)}function ct(e,t){if(!e||/^\s*$/.test(e))return null;var n=t.addModeClass?as:ss;return n[e]||(n[e]=e.replace(/\S+/g,"cm-$&"))}function ht(e,t){var n=i("span",null,null,hl?"padding-right: .1px":null),r={pre:i("pre",[n],"CodeMirror-line"),content:n,col:0,pos:0,cm:e,trailingSpace:!1,splitSpaces:(ul||hl)&&e.getOption("lineWrapping")};t.measure={};for(var o=0;o<=(t.rest?t.rest.length:0);o++){var l=o?t.rest[o-1]:t.line,s=void 0;r.pos=0,r.addToken=dt,Ue(e.display.measure)&&(s=Se(l,e.doc.direction))&&(r.addToken=gt(r.addToken,s)),r.map=[],mt(l,r,Qe(e,l,t!=e.display.externalMeasured&&W(l))),l.styleClasses&&(l.styleClasses.bgClass&&(r.bgClass=a(l.styleClasses.bgClass,r.bgClass||"")),l.styleClasses.textClass&&(r.textClass=a(l.styleClasses.textClass,r.textClass||""))),0==r.map.length&&r.map.push(0,0,r.content.appendChild(Ge(e.display.measure))),0==o?(t.measure.map=r.map,t.measure.cache={}):((t.measure.maps||(t.measure.maps=[])).push(r.map),(t.measure.caches||(t.measure.caches=[])).push({}))}if(hl){var u=r.content.lastChild;(/\bcm-tab\b/.test(u.className)||u.querySelector&&u.querySelector(".cm-tab"))&&(r.content.className="cm-tab-wrap-hack")}return Ae(e,"renderLine",e,t.line,r.pre),r.pre.className&&(r.textClass=a(r.pre.className,r.textClass||"")),r}function ft(e){var t=r("span","•","cm-invalidchar");return t.title="\\u"+e.charCodeAt(0).toString(16),t.setAttribute("aria-label",t.title),t}function dt(e,t,n,i,o,l,s){if(t){var a,u=e.splitSpaces?pt(t,e.trailingSpace):t,c=e.cm.state.specialChars,h=!1;if(c.test(t)){a=document.createDocumentFragment();for(var f=0;;){c.lastIndex=f;var d=c.exec(t),g=d?d.index-f:t.length-f;if(g){var v=document.createTextNode(u.slice(f,f+g));ul&&cl<9?a.appendChild(r("span",[v])):a.appendChild(v),e.map.push(e.pos,e.pos+g,v),e.col+=g,e.pos+=g}if(!d)break;f+=g+1;var m=void 0;if("\t"==d[0]){var y=e.cm.options.tabSize,b=y-e.col%y;(m=a.appendChild(r("span",p(b),"cm-tab"))).setAttribute("role","presentation"),m.setAttribute("cm-text","\t"),e.col+=b}else"\r"==d[0]||"\n"==d[0]?((m=a.appendChild(r("span","\r"==d[0]?"␍":"␤","cm-invalidchar"))).setAttribute("cm-text",d[0]),e.col+=1):((m=e.cm.options.specialCharPlaceholder(d[0])).setAttribute("cm-text",d[0]),ul&&cl<9?a.appendChild(r("span",[m])):a.appendChild(m),e.col+=1);e.map.push(e.pos,e.pos+1,m),e.pos++}}else e.col+=t.length,a=document.createTextNode(u),e.map.push(e.pos,e.pos+t.length,a),ul&&cl<9&&(h=!0),e.pos+=t.length;if(e.trailingSpace=32==u.charCodeAt(t.length-1),n||i||o||h||s){var w=n||"";i&&(w+=i),o&&(w+=o);var x=r("span",[a],w,s);return l&&(x.title=l),e.content.appendChild(x)}e.content.appendChild(a)}}function pt(e,t){if(e.length>1&&!/  /.test(e))return e;for(var n=t,r="",i=0;i<e.length;i++){var o=e.charAt(i);" "!=o||!n||i!=e.length-1&&32!=e.charCodeAt(i+1)||(o=" "),r+=o,n=" "==o}return r}function gt(e,t){return function(n,r,i,o,l,s,a){i=i?i+" cm-force-border":"cm-force-border";for(var u=n.pos,c=u+r.length;;){for(var h=void 0,f=0;f<t.length&&!((h=t[f]).to>u&&h.from<=u);f++);if(h.to>=c)return e(n,r,i,o,l,s,a);e(n,r.slice(0,h.to-u),i,o,null,s,a),o=null,r=r.slice(h.to-u),u=h.to}}}function vt(e,t,n,r){var i=!r&&n.widgetNode;i&&e.map.push(e.pos,e.pos+t,i),!r&&e.cm.display.input.needsContentAttribute&&(i||(i=e.content.appendChild(document.createElement("span"))),i.setAttribute("cm-marker",n.id)),i&&(e.cm.display.input.setUneditable(i),e.content.appendChild(i)),e.pos+=t,e.trailingSpace=!1}function mt(e,t,n){var r=e.markedSpans,i=e.text,o=0;if(r)for(var l,s,a,u,c,h,f,d=i.length,p=0,g=1,v="",m=0;;){if(m==p){a=u=c=h=s="",f=null,m=1/0;for(var y=[],b=void 0,w=0;w<r.length;++w){var x=r[w],C=x.marker;"bookmark"==C.type&&x.from==p&&C.widgetNode?y.push(C):x.from<=p&&(null==x.to||x.to>p||C.collapsed&&x.to==p&&x.from==p)?(null!=x.to&&x.to!=p&&m>x.to&&(m=x.to,u=""),C.className&&(a+=" "+C.className),C.css&&(s=(s?s+";":"")+C.css),C.startStyle&&x.from==p&&(c+=" "+C.startStyle),C.endStyle&&x.to==m&&(b||(b=[])).push(C.endStyle,x.to),C.title&&!h&&(h=C.title),C.collapsed&&(!f||le(f.marker,C)<0)&&(f=x)):x.from>p&&m>x.from&&(m=x.from)}if(b)for(var S=0;S<b.length;S+=2)b[S+1]==m&&(u+=" "+b[S]);if(!f||f.from==p)for(var L=0;L<y.length;++L)vt(t,0,y[L]);if(f&&(f.from||0)==p){if(vt(t,(null==f.to?d+1:f.to)-p,f.marker,null==f.from),null==f.to)return;f.to==p&&(f=!1)}}if(p>=d)break;for(var k=Math.min(d,m);;){if(v){var M=p+v.length;if(!f){var T=M>k?v.slice(0,k-p):v;t.addToken(t,T,l?l+a:a,c,p+T.length==m?u:"",h,s)}if(M>=k){v=v.slice(k-p),p=k;break}p=M,c=""}v=i.slice(o,o=n[g++]),l=ct(n[g++],t.cm.options)}}else for(var N=1;N<n.length;N+=2)t.addToken(t,i.slice(o,o=n[N]),ct(n[N+1],t.cm.options))}function yt(e,t,n){this.line=t,this.rest=de(t),this.size=this.rest?W(g(this.rest))-n+1:1,this.node=this.text=null,this.hidden=ve(e,t)}function bt(e,t,n){for(var r,i=[],o=t;o<n;o=r){var l=new yt(e.doc,T(e.doc,o),o);r=o+l.size,i.push(l)}return i}function wt(e){us?us.ops.push(e):e.ownsGroup=us={ops:[e],delayedCallbacks:[]}}function xt(e){var t=e.delayedCallbacks,n=0;do{for(;n<t.length;n++)t[n].call(null);for(var r=0;r<e.ops.length;r++){var i=e.ops[r];if(i.cursorActivityHandlers)for(;i.cursorActivityCalled<i.cursorActivityHandlers.length;)i.cursorActivityHandlers[i.cursorActivityCalled++].call(null,i.cm)}}while(n<t.length)}function Ct(e,t){var n=e.ownsGroup;if(n)try{xt(n)}finally{us=null,t(n)}}function St(e,t){var n=Ne(e,t);if(n.length){var r,i=Array.prototype.slice.call(arguments,2);us?r=us.delayedCallbacks:cs?r=cs:(r=cs=[],setTimeout(Lt,0));for(var o=0;o<n.length;++o)!function(e){r.push(function(){return n[e].apply(null,i)})}(o)}}function Lt(){var e=cs;cs=null;for(var t=0;t<e.length;++t)e[t]()}function kt(e,t,n,r){for(var i=0;i<t.changes.length;i++){var o=t.changes[i];"text"==o?Ot(e,t):"gutter"==o?Wt(e,t,n,r):"class"==o?At(e,t):"widget"==o&&Dt(e,t,r)}t.changes=null}function Mt(e){return e.node==e.text&&(e.node=r("div",null,null,"position: relative"),e.text.parentNode&&e.text.parentNode.replaceChild(e.node,e.text),e.node.appendChild(e.text),ul&&cl<8&&(e.node.style.zIndex=2)),e.node}function Tt(e,t){var n=t.bgClass?t.bgClass+" "+(t.line.bgClass||""):t.line.bgClass;if(n&&(n+=" CodeMirror-linebackground"),t.background)n?t.background.className=n:(t.background.parentNode.removeChild(t.background),t.background=null);else if(n){var i=Mt(t);t.background=i.insertBefore(r("div",null,n),i.firstChild),e.display.input.setUneditable(t.background)}}function Nt(e,t){var n=e.display.externalMeasured;return n&&n.line==t.line?(e.display.externalMeasured=null,t.measure=n.measure,n.built):ht(e,t)}function Ot(e,t){var n=t.text.className,r=Nt(e,t);t.text==t.node&&(t.node=r.pre),t.text.parentNode.replaceChild(r.pre,t.text),t.text=r.pre,r.bgClass!=t.bgClass||r.textClass!=t.textClass?(t.bgClass=r.bgClass,t.textClass=r.textClass,At(e,t)):n&&(t.text.className=n)}function At(e,t){Tt(e,t),t.line.wrapClass?Mt(t).className=t.line.wrapClass:t.node!=t.text&&(t.node.className="");var n=t.textClass?t.textClass+" "+(t.line.textClass||""):t.line.textClass;t.text.className=n||""}function Wt(e,t,n,i){if(t.gutter&&(t.node.removeChild(t.gutter),t.gutter=null),t.gutterBackground&&(t.node.removeChild(t.gutterBackground),t.gutterBackground=null),t.line.gutterClass){var o=Mt(t);t.gutterBackground=r("div",null,"CodeMirror-gutter-background "+t.line.gutterClass,"left: "+(e.options.fixedGutter?i.fixedPos:-i.gutterTotalWidth)+"px; width: "+i.gutterTotalWidth+"px"),e.display.input.setUneditable(t.gutterBackground),o.insertBefore(t.gutterBackground,t.text)}var l=t.line.gutterMarkers;if(e.options.lineNumbers||l){var s=Mt(t),a=t.gutter=r("div",null,"CodeMirror-gutter-wrapper","left: "+(e.options.fixedGutter?i.fixedPos:-i.gutterTotalWidth)+"px");if(e.display.input.setUneditable(a),s.insertBefore(a,t.text),t.line.gutterClass&&(a.className+=" "+t.line.gutterClass),!e.options.lineNumbers||l&&l["CodeMirror-linenumbers"]||(t.lineNumber=a.appendChild(r("div",F(e.options,n),"CodeMirror-linenumber CodeMirror-gutter-elt","left: "+i.gutterLeft["CodeMirror-linenumbers"]+"px; width: "+e.display.lineNumInnerWidth+"px"))),l)for(var u=0;u<e.options.gutters.length;++u){var c=e.options.gutters[u],h=l.hasOwnProperty(c)&&l[c];h&&a.appendChild(r("div",[h],"CodeMirror-gutter-elt","left: "+i.gutterLeft[c]+"px; width: "+i.gutterWidth[c]+"px"))}}}function Dt(e,t,n){t.alignable&&(t.alignable=null);for(var r=t.node.firstChild,i=void 0;r;r=i)i=r.nextSibling,"CodeMirror-linewidget"==r.className&&t.node.removeChild(r);Ft(e,t,n)}function Ht(e,t,n,r){var i=Nt(e,t);return t.text=t.node=i.pre,i.bgClass&&(t.bgClass=i.bgClass),i.textClass&&(t.textClass=i.textClass),At(e,t),Wt(e,t,n,r),Ft(e,t,r),t.node}function Ft(e,t,n){if(Et(e,t.line,t,n,!0),t.rest)for(var r=0;r<t.rest.length;r++)Et(e,t.rest[r],t,n,!1)}function Et(e,t,n,i,o){if(t.widgets)for(var l=Mt(n),s=0,a=t.widgets;s<a.length;++s){var u=a[s],c=r("div",[u.node],"CodeMirror-linewidget");u.handleMouseEvents||c.setAttribute("cm-ignore-events","true"),Pt(u,c,n,i),e.display.input.setUneditable(c),o&&u.above?l.insertBefore(c,n.gutter||n.text):l.appendChild(c),St(u,"redraw")}}function Pt(e,t,n,r){if(e.noHScroll){(n.alignable||(n.alignable=[])).push(t);var i=r.wrapperWidth;t.style.left=r.fixedPos+"px",e.coverGutter||(i-=r.gutterTotalWidth,t.style.paddingLeft=r.gutterTotalWidth+"px"),t.style.width=i+"px"}e.coverGutter&&(t.style.zIndex=5,t.style.position="relative",e.noHScroll||(t.style.marginLeft=-r.gutterTotalWidth+"px"))}function It(e){if(null!=e.height)return e.height;var t=e.doc.cm;if(!t)return 0;if(!o(document.body,e.node)){var i="position: relative;";e.coverGutter&&(i+="margin-left: -"+t.display.gutters.offsetWidth+"px;"),e.noHScroll&&(i+="width: "+t.display.wrapper.clientWidth+"px;"),n(t.display.measure,r("div",[e.node],null,i))}return e.height=e.node.parentNode.offsetHeight}function Rt(e,t){for(var n=ze(t);n!=e.wrapper;n=n.parentNode)if(!n||1==n.nodeType&&"true"==n.getAttribute("cm-ignore-events")||n.parentNode==e.sizer&&n!=e.mover)return!0}function zt(e){return e.lineSpace.offsetTop}function Bt(e){return e.mover.offsetHeight-e.lineSpace.offsetHeight}function Gt(e){if(e.cachedPaddingH)return e.cachedPaddingH;var t=n(e.measure,r("pre","x")),i=window.getComputedStyle?window.getComputedStyle(t):t.currentStyle,o={left:parseInt(i.paddingLeft),right:parseInt(i.paddingRight)};return isNaN(o.left)||isNaN(o.right)||(e.cachedPaddingH=o),o}function Ut(e){return Hl-e.display.nativeBarWidth}function Vt(e){return e.display.scroller.clientWidth-Ut(e)-e.display.barWidth}function Kt(e){return e.display.scroller.clientHeight-Ut(e)-e.display.barHeight}function jt(e,t,n){var r=e.options.lineWrapping,i=r&&Vt(e);if(!t.measure.heights||r&&t.measure.width!=i){var o=t.measure.heights=[];if(r){t.measure.width=i;for(var l=t.text.firstChild.getClientRects(),s=0;s<l.length-1;s++){var a=l[s],u=l[s+1];Math.abs(a.bottom-u.bottom)>2&&o.push((a.bottom+u.top)/2-n.top)}}o.push(n.bottom-n.top)}}function Xt(e,t,n){if(e.line==t)return{map:e.measure.map,cache:e.measure.cache};for(var r=0;r<e.rest.length;r++)if(e.rest[r]==t)return{map:e.measure.maps[r],cache:e.measure.caches[r]};for(var i=0;i<e.rest.length;i++)if(W(e.rest[i])>n)return{map:e.measure.maps[i],cache:e.measure.caches[i],before:!0}}function Yt(e,t){var r=W(t=he(t)),i=e.display.externalMeasured=new yt(e.doc,t,r);i.lineN=r;var o=i.built=ht(e,i);return i.text=o.pre,n(e.display.lineMeasure,o.pre),i}function _t(e,t,n,r){return Zt(e,qt(e,t),n,r)}function $t(e,t){if(t>=e.display.viewFrom&&t<e.display.viewTo)return e.display.view[kn(e,t)];var n=e.display.externalMeasured;return n&&t>=n.lineN&&t<n.lineN+n.size?n:void 0}function qt(e,t){var n=W(t),r=$t(e,n);r&&!r.text?r=null:r&&r.changes&&(kt(e,r,n,wn(e)),e.curOp.forceUpdate=!0),r||(r=Yt(e,t));var i=Xt(r,t,n);return{line:t,view:r,rect:null,map:i.map,cache:i.cache,before:i.before,hasHeights:!1}}function Zt(e,t,n,r,i){t.before&&(n=-1);var o,l=n+(r||"");return t.cache.hasOwnProperty(l)?o=t.cache[l]:(t.rect||(t.rect=t.view.text.getBoundingClientRect()),t.hasHeights||(jt(e,t.view,t.rect),t.hasHeights=!0),(o=en(e,t,n,r)).bogus||(t.cache[l]=o)),{left:o.left,right:o.right,top:i?o.rtop:o.top,bottom:i?o.rbottom:o.bottom}}function Qt(e,t,n){for(var r,i,o,l,s,a,u=0;u<e.length;u+=3)if(s=e[u],a=e[u+1],t<s?(i=0,o=1,l="left"):t<a?o=(i=t-s)+1:(u==e.length-3||t==a&&e[u+3]>t)&&(i=(o=a-s)-1,t>=a&&(l="right")),null!=i){if(r=e[u+2],s==a&&n==(r.insertLeft?"left":"right")&&(l=n),"left"==n&&0==i)for(;u&&e[u-2]==e[u-3]&&e[u-1].insertLeft;)r=e[2+(u-=3)],l="left";if("right"==n&&i==a-s)for(;u<e.length-3&&e[u+3]==e[u+4]&&!e[u+5].insertLeft;)r=e[(u+=3)+2],l="right";break}return{node:r,start:i,end:o,collapse:l,coverStart:s,coverEnd:a}}function Jt(e,t){var n=hs;if("left"==t)for(var r=0;r<e.length&&(n=e[r]).left==n.right;r++);else for(var i=e.length-1;i>=0&&(n=e[i]).left==n.right;i--);return n}function en(e,t,n,r){var i,o=Qt(t.map,n,r),l=o.node,s=o.start,a=o.end,u=o.collapse;if(3==l.nodeType){for(var c=0;c<4;c++){for(;s&&S(t.line.text.charAt(o.coverStart+s));)--s;for(;o.coverStart+a<o.coverEnd&&S(t.line.text.charAt(o.coverStart+a));)++a;if((i=ul&&cl<9&&0==s&&a==o.coverEnd-o.coverStart?l.parentNode.getBoundingClientRect():Jt(kl(l,s,a).getClientRects(),r)).left||i.right||0==s)break;a=s,s-=1,u="right"}ul&&cl<11&&(i=tn(e.display.measure,i))}else{s>0&&(u=r="right");var h;i=e.options.lineWrapping&&(h=l.getClientRects()).length>1?h["right"==r?h.length-1:0]:l.getBoundingClientRect()}if(ul&&cl<9&&!s&&(!i||!i.left&&!i.right)){var f=l.parentNode.getClientRects()[0];i=f?{left:f.left,right:f.left+bn(e.display),top:f.top,bottom:f.bottom}:hs}for(var d=i.top-t.rect.top,p=i.bottom-t.rect.top,g=(d+p)/2,v=t.view.measure.heights,m=0;m<v.length-1&&!(g<v[m]);m++);var y=m?v[m-1]:0,b=v[m],w={left:("right"==u?i.right:i.left)-t.rect.left,right:("left"==u?i.left:i.right)-t.rect.left,top:y,bottom:b};return i.left||i.right||(w.bogus=!0),e.options.singleCursorHeightPerLine||(w.rtop=d,w.rbottom=p),w}function tn(e,t){if(!window.screen||null==screen.logicalXDPI||screen.logicalXDPI==screen.deviceXDPI||!Ve(e))return t;var n=screen.logicalXDPI/screen.deviceXDPI,r=screen.logicalYDPI/screen.deviceYDPI;return{left:t.left*n,right:t.right*n,top:t.top*r,bottom:t.bottom*r}}function nn(e){if(e.measure&&(e.measure.cache={},e.measure.heights=null,e.rest))for(var t=0;t<e.rest.length;t++)e.measure.caches[t]={}}function rn(e){e.display.externalMeasure=null,t(e.display.lineMeasure);for(var n=0;n<e.display.view.length;n++)nn(e.display.view[n])}function on(e){rn(e),e.display.cachedCharWidth=e.display.cachedTextHeight=e.display.cachedPaddingH=null,e.options.lineWrapping||(e.display.maxLineChanged=!0),e.display.lineNumChars=null}function ln(){return dl&&bl?-(document.body.getBoundingClientRect().left-parseInt(getComputedStyle(document.body).marginLeft)):window.pageXOffset||(document.documentElement||document.body).scrollLeft}function sn(){return dl&&bl?-(document.body.getBoundingClientRect().top-parseInt(getComputedStyle(document.body).marginTop)):window.pageYOffset||(document.documentElement||document.body).scrollTop}function an(e,t,n,r,i){if(!i&&t.widgets)for(var o=0;o<t.widgets.length;++o)if(t.widgets[o].above){var l=It(t.widgets[o]);n.top+=l,n.bottom+=l}if("line"==r)return n;r||(r="local");var s=ye(t);if("local"==r?s+=zt(e.display):s-=e.display.viewOffset,"page"==r||"window"==r){var a=e.display.lineSpace.getBoundingClientRect();s+=a.top+("window"==r?0:sn());var u=a.left+("window"==r?0:ln());n.left+=u,n.right+=u}return n.top+=s,n.bottom+=s,n}function un(e,t,n){if("div"==n)return t;var r=t.left,i=t.top;if("page"==n)r-=ln(),i-=sn();else if("local"==n||!n){var o=e.display.sizer.getBoundingClientRect();r+=o.left,i+=o.top}var l=e.display.lineSpace.getBoundingClientRect();return{left:r-l.left,top:i-l.top}}function cn(e,t,n,r,i){return r||(r=T(e.doc,t.line)),an(e,r,_t(e,r,t.ch,i),n)}function hn(e,t,n,r,i,o){function l(t,l){var s=Zt(e,i,t,l?"right":"left",o);return l?s.left=s.right:s.right=s.left,an(e,r,s,n)}function s(e,t,n){var r=a[t].level%2!=0;return l(n?e-1:e,r!=n)}r=r||T(e.doc,t.line),i||(i=qt(e,r));var a=Se(r,e.doc.direction),u=t.ch,c=t.sticky;if(u>=r.text.length?(u=r.text.length,c="before"):u<=0&&(u=0,c="after"),!a)return l("before"==c?u-1:u,"before"==c);var h=Ce(a,u,c),f=Vl,d=s(u,h,"before"==c);return null!=f&&(d.other=s(u,f,"before"!=c)),d}function fn(e,t){var n=0;t=U(e.doc,t),e.options.lineWrapping||(n=bn(e.display)*t.ch);var r=T(e.doc,t.line),i=ye(r)+zt(e.display);return{left:n,right:n,top:i,bottom:i+r.height}}function dn(e,t,n,r,i){var o=E(e,t,n);return o.xRel=i,r&&(o.outside=!0),o}function pn(e,t,n){var r=e.doc;if((n+=e.display.viewOffset)<0)return dn(r.first,0,null,!0,-1);var i=D(r,n),o=r.first+r.size-1;if(i>o)return dn(r.first+r.size-1,T(r,o).text.length,null,!0,1);t<0&&(t=0);for(var l=T(r,i);;){var s=mn(e,l,i,t,n),a=ue(l),u=a&&a.find(0,!0);if(!a||!(s.ch>u.from.ch||s.ch==u.from.ch&&s.xRel>0))return s;i=W(l=u.to.line)}}function gn(e,t,n,r){var i=function(r){return an(e,t,Zt(e,n,r),"line")},o=t.text.length,l=k(function(e){return i(e-1).bottom<=r},o,0);return o=k(function(e){return i(e).top>r},l,o),{begin:l,end:o}}function vn(e,t,n,r){return gn(e,t,n,an(e,t,Zt(e,n,r),"line").top)}function mn(e,t,n,r,i){i-=ye(t);var o,l=0,s=t.text.length,a=qt(e,t);if(Se(t,e.doc.direction)){if(e.options.lineWrapping){var u;l=(u=gn(e,t,a,i)).begin,s=u.end}o=new E(n,Math.floor(l+(s-l)/2));var c,h,f=hn(e,o,"line",t,a).left,d=f<r?1:-1,p=f-r,g=Math.ceil((s-l)/4);e:do{c=p,h=o;for(var v=0;v<g;++v){var m=o;if(null==(o=Te(e,t,o,d))||o.ch<l||s<=("before"==o.sticky?o.ch-1:o.ch)){o=m;break e}}if(p=hn(e,o,"line",t,a).left-r,g>1){var y=Math.abs(p-c)/g;g=Math.min(g,Math.ceil(Math.abs(p)/y)),d=p<0?1:-1}}while(0!=p&&(g>1||d<0!=p<0&&Math.abs(p)<=Math.abs(c)));if(Math.abs(p)>Math.abs(c)){if(p<0==c<0)throw new Error("Broke out of infinite loop in coordsCharInner");o=h}}else{var b=k(function(n){var o=an(e,t,Zt(e,a,n),"line");return o.top>i?(s=Math.min(n,s),!0):!(o.bottom<=i)&&(o.left>r||!(o.right<r)&&r-o.left<o.right-r)},l,s);o=new E(n,b=L(t.text,b,1),b==s?"before":"after")}var w=hn(e,o,"line",t,a);return(i<w.top||w.bottom<i)&&(o.outside=!0),o.xRel=r<w.left?-1:r>w.right?1:0,o}function yn(e){if(null!=e.cachedTextHeight)return e.cachedTextHeight;if(null==ls){ls=r("pre");for(var i=0;i<49;++i)ls.appendChild(document.createTextNode("x")),ls.appendChild(r("br"));ls.appendChild(document.createTextNode("x"))}n(e.measure,ls);var o=ls.offsetHeight/50;return o>3&&(e.cachedTextHeight=o),t(e.measure),o||1}function bn(e){if(null!=e.cachedCharWidth)return e.cachedCharWidth;var t=r("span","xxxxxxxxxx"),i=r("pre",[t]);n(e.measure,i);var o=t.getBoundingClientRect(),l=(o.right-o.left)/10;return l>2&&(e.cachedCharWidth=l),l||10}function wn(e){for(var t=e.display,n={},r={},i=t.gutters.clientLeft,o=t.gutters.firstChild,l=0;o;o=o.nextSibling,++l)n[e.options.gutters[l]]=o.offsetLeft+o.clientLeft+i,r[e.options.gutters[l]]=o.clientWidth;return{fixedPos:xn(t),gutterTotalWidth:t.gutters.offsetWidth,gutterLeft:n,gutterWidth:r,wrapperWidth:t.wrapper.clientWidth}}function xn(e){return e.scroller.getBoundingClientRect().left-e.sizer.getBoundingClientRect().left}function Cn(e){var t=yn(e.display),n=e.options.lineWrapping,r=n&&Math.max(5,e.display.scroller.clientWidth/bn(e.display)-3);return function(i){if(ve(e.doc,i))return 0;var o=0;if(i.widgets)for(var l=0;l<i.widgets.length;l++)i.widgets[l].height&&(o+=i.widgets[l].height);return n?o+(Math.ceil(i.text.length/r)||1)*t:o+t}}function Sn(e){var t=e.doc,n=Cn(e);t.iter(function(e){var t=n(e);t!=e.height&&A(e,t)})}function Ln(e,t,n,r){var i=e.display;if(!n&&"true"==ze(t).getAttribute("cm-not-content"))return null;var o,l,s=i.lineSpace.getBoundingClientRect();try{o=t.clientX-s.left,l=t.clientY-s.top}catch(t){return null}var a,u=pn(e,o,l);if(r&&1==u.xRel&&(a=T(e.doc,u.line).text).length==u.ch){var c=h(a,a.length,e.options.tabSize)-a.length;u=E(u.line,Math.max(0,Math.round((o-Gt(e.display).left)/bn(e.display))-c))}return u}function kn(e,t){if(t>=e.display.viewTo)return null;if((t-=e.display.viewFrom)<0)return null;for(var n=e.display.view,r=0;r<n.length;r++)if((t-=n[r].size)<0)return r}function Mn(e){e.display.input.showSelection(e.display.input.prepareSelection())}function Tn(e,t){for(var n=e.doc,r={},i=r.cursors=document.createDocumentFragment(),o=r.selection=document.createDocumentFragment(),l=0;l<n.sel.ranges.length;l++)if(!1!==t||l!=n.sel.primIndex){var s=n.sel.ranges[l];if(!(s.from().line>=e.display.viewTo||s.to().line<e.display.viewFrom)){var a=s.empty();(a||e.options.showCursorWhenSelecting)&&Nn(e,s.head,i),a||On(e,s,o)}}return r}function Nn(e,t,n){var i=hn(e,t,"div",null,null,!e.options.singleCursorHeightPerLine),o=n.appendChild(r("div"," ","CodeMirror-cursor"));if(o.style.left=i.left+"px",o.style.top=i.top+"px",o.style.height=Math.max(0,i.bottom-i.top)*e.options.cursorHeight+"px",i.other){var l=n.appendChild(r("div"," ","CodeMirror-cursor CodeMirror-secondarycursor"));l.style.display="",l.style.left=i.other.left+"px",l.style.top=i.other.top+"px",l.style.height=.85*(i.other.bottom-i.other.top)+"px"}}function On(e,t,n){function i(e,t,n,i){t<0&&(t=0),t=Math.round(t),i=Math.round(i),a.appendChild(r("div",null,"CodeMirror-selected","position: absolute; left: "+e+"px;\n                             top: "+t+"px; width: "+(null==n?h-e:n)+"px;\n                             height: "+(i-t)+"px"))}function o(t,n,r){function o(n,r){return cn(e,E(t,n),"div",u,r)}var l,a,u=T(s,t),f=u.text.length;return xe(Se(u,s.direction),n||0,null==r?f:r,function(e,t,s){var u,d,p,g=o(e,"left");if(e==t)u=g,d=p=g.left;else{if(u=o(t-1,"right"),"rtl"==s){var v=g;g=u,u=v}d=g.left,p=u.right}null==n&&0==e&&(d=c),u.top-g.top>3&&(i(d,g.top,null,g.bottom),d=c,g.bottom<u.top&&i(d,g.bottom,null,u.top)),null==r&&t==f&&(p=h),(!l||g.top<l.top||g.top==l.top&&g.left<l.left)&&(l=g),(!a||u.bottom>a.bottom||u.bottom==a.bottom&&u.right>a.right)&&(a=u),d<c+1&&(d=c),i(d,u.top,p-d,u.bottom)}),{start:l,end:a}}var l=e.display,s=e.doc,a=document.createDocumentFragment(),u=Gt(e.display),c=u.left,h=Math.max(l.sizerWidth,Vt(e)-l.sizer.offsetLeft)-u.right,f=t.from(),d=t.to();if(f.line==d.line)o(f.line,f.ch,d.ch);else{var p=T(s,f.line),g=T(s,d.line),v=he(p)==he(g),m=o(f.line,f.ch,v?p.text.length+1:null).end,y=o(d.line,v?0:null,d.ch).start;v&&(m.top<y.top-2?(i(m.right,m.top,null,m.bottom),i(c,y.top,y.left,y.bottom)):i(m.right,m.top,y.left-m.right,m.bottom)),m.bottom<y.top&&i(c,m.bottom,null,y.top)}n.appendChild(a)}function An(e){if(e.state.focused){var t=e.display;clearInterval(t.blinker);var n=!0;t.cursorDiv.style.visibility="",e.options.cursorBlinkRate>0?t.blinker=setInterval(function(){return t.cursorDiv.style.visibility=(n=!n)?"":"hidden"},e.options.cursorBlinkRate):e.options.cursorBlinkRate<0&&(t.cursorDiv.style.visibility="hidden")}}function Wn(e){e.state.focused||(e.display.input.focus(),Hn(e))}function Dn(e){e.state.delayingBlurEvent=!0,setTimeout(function(){e.state.delayingBlurEvent&&(e.state.delayingBlurEvent=!1,Fn(e))},100)}function Hn(e,t){e.state.delayingBlurEvent&&(e.state.delayingBlurEvent=!1),"nocursor"!=e.options.readOnly&&(e.state.focused||(Ae(e,"focus",e,t),e.state.focused=!0,s(e.display.wrapper,"CodeMirror-focused"),e.curOp||e.display.selForContextMenu==e.doc.sel||(e.display.input.reset(),hl&&setTimeout(function(){return e.display.input.reset(!0)},20)),e.display.input.receivedFocus()),An(e))}function Fn(e,t){e.state.delayingBlurEvent||(e.state.focused&&(Ae(e,"blur",e,t),e.state.focused=!1,Nl(e.display.wrapper,"CodeMirror-focused")),clearInterval(e.display.blinker),setTimeout(function(){e.state.focused||(e.display.shift=!1)},150))}function En(e){for(var t=e.display,n=t.lineDiv.offsetTop,r=0;r<t.view.length;r++){var i=t.view[r],o=void 0;if(!i.hidden){if(ul&&cl<8){var l=i.node.offsetTop+i.node.offsetHeight;o=l-n,n=l}else{var s=i.node.getBoundingClientRect();o=s.bottom-s.top}var a=i.line.height-o;if(o<2&&(o=yn(t)),(a>.005||a<-.005)&&(A(i.line,o),Pn(i.line),i.rest))for(var u=0;u<i.rest.length;u++)Pn(i.rest[u])}}}function Pn(e){if(e.widgets)for(var t=0;t<e.widgets.length;++t)e.widgets[t].height=e.widgets[t].node.parentNode.offsetHeight}function In(e,t,n){var r=n&&null!=n.top?Math.max(0,n.top):e.scroller.scrollTop;r=Math.floor(r-zt(e));var i=n&&null!=n.bottom?n.bottom:r+e.wrapper.clientHeight,o=D(t,r),l=D(t,i);if(n&&n.ensure){var s=n.ensure.from.line,a=n.ensure.to.line;s<o?(o=s,l=D(t,ye(T(t,s))+e.wrapper.clientHeight)):Math.min(a,t.lastLine())>=l&&(o=D(t,ye(T(t,a))-e.wrapper.clientHeight),l=a)}return{from:o,to:Math.max(l,o+1)}}function Rn(e){var t=e.display,n=t.view;if(t.alignWidgets||t.gutters.firstChild&&e.options.fixedGutter){for(var r=xn(t)-t.scroller.scrollLeft+e.doc.scrollLeft,i=t.gutters.offsetWidth,o=r+"px",l=0;l<n.length;l++)if(!n[l].hidden){e.options.fixedGutter&&(n[l].gutter&&(n[l].gutter.style.left=o),n[l].gutterBackground&&(n[l].gutterBackground.style.left=o));var s=n[l].alignable;if(s)for(var a=0;a<s.length;a++)s[a].style.left=o}e.options.fixedGutter&&(t.gutters.style.left=r+i+"px")}}function zn(e){if(!e.options.lineNumbers)return!1;var t=e.doc,n=F(e.options,t.first+t.size-1),i=e.display;if(n.length!=i.lineNumChars){var o=i.measure.appendChild(r("div",[r("div",n)],"CodeMirror-linenumber CodeMirror-gutter-elt")),l=o.firstChild.offsetWidth,s=o.offsetWidth-l;return i.lineGutter.style.width="",i.lineNumInnerWidth=Math.max(l,i.lineGutter.offsetWidth-s)+1,i.lineNumWidth=i.lineNumInnerWidth+s,i.lineNumChars=i.lineNumInnerWidth?n.length:-1,i.lineGutter.style.width=i.lineNumWidth+"px",Ar(e),!0}return!1}function Bn(e,t){if(!We(e,"scrollCursorIntoView")){var n=e.display,i=n.sizer.getBoundingClientRect(),o=null;if(t.top+i.top<0?o=!0:t.bottom+i.top>(window.innerHeight||document.documentElement.clientHeight)&&(o=!1),null!=o&&!ml){var l=r("div","​",null,"position: absolute;\n                         top: "+(t.top-n.viewOffset-zt(e.display))+"px;\n                         height: "+(t.bottom-t.top+Ut(e)+n.barHeight)+"px;\n                         left: "+t.left+"px; width: "+Math.max(2,t.right-t.left)+"px;");e.display.lineSpace.appendChild(l),l.scrollIntoView(o),e.display.lineSpace.removeChild(l)}}}function Gn(e,t,n,r){null==r&&(r=0);var i;e.options.lineWrapping||t!=n||(n="before"==(t=t.ch?E(t.line,"before"==t.sticky?t.ch-1:t.ch,"after"):t).sticky?E(t.line,t.ch+1,"before"):t);for(var o=0;o<5;o++){var l=!1,s=hn(e,t),a=n&&n!=t?hn(e,n):s,u=Vn(e,i={left:Math.min(s.left,a.left),top:Math.min(s.top,a.top)-r,right:Math.max(s.left,a.left),bottom:Math.max(s.bottom,a.bottom)+r}),c=e.doc.scrollTop,h=e.doc.scrollLeft;if(null!=u.scrollTop&&(qn(e,u.scrollTop),Math.abs(e.doc.scrollTop-c)>1&&(l=!0)),null!=u.scrollLeft&&(Qn(e,u.scrollLeft),Math.abs(e.doc.scrollLeft-h)>1&&(l=!0)),!l)break}return i}function Un(e,t){var n=Vn(e,t);null!=n.scrollTop&&qn(e,n.scrollTop),null!=n.scrollLeft&&Qn(e,n.scrollLeft)}function Vn(e,t){var n=e.display,r=yn(e.display);t.top<0&&(t.top=0);var i=e.curOp&&null!=e.curOp.scrollTop?e.curOp.scrollTop:n.scroller.scrollTop,o=Kt(e),l={};t.bottom-t.top>o&&(t.bottom=t.top+o);var s=e.doc.height+Bt(n),a=t.top<r,u=t.bottom>s-r;if(t.top<i)l.scrollTop=a?0:t.top;else if(t.bottom>i+o){var c=Math.min(t.top,(u?s:t.bottom)-o);c!=i&&(l.scrollTop=c)}var h=e.curOp&&null!=e.curOp.scrollLeft?e.curOp.scrollLeft:n.scroller.scrollLeft,f=Vt(e)-(e.options.fixedGutter?n.gutters.offsetWidth:0),d=t.right-t.left>f;return d&&(t.right=t.left+f),t.left<10?l.scrollLeft=0:t.left<h?l.scrollLeft=Math.max(0,t.left-(d?0:10)):t.right>f+h-3&&(l.scrollLeft=t.right+(d?0:10)-f),l}function Kn(e,t){null!=t&&(_n(e),e.curOp.scrollTop=(null==e.curOp.scrollTop?e.doc.scrollTop:e.curOp.scrollTop)+t)}function jn(e){_n(e);var t=e.getCursor();e.curOp.scrollToPos={from:t,to:t,margin:e.options.cursorScrollMargin}}function Xn(e,t,n){null==t&&null==n||_n(e),null!=t&&(e.curOp.scrollLeft=t),null!=n&&(e.curOp.scrollTop=n)}function Yn(e,t){_n(e),e.curOp.scrollToPos=t}function _n(e){var t=e.curOp.scrollToPos;t&&(e.curOp.scrollToPos=null,$n(e,fn(e,t.from),fn(e,t.to),t.margin))}function $n(e,t,n,r){var i=Vn(e,{left:Math.min(t.left,n.left),top:Math.min(t.top,n.top)-r,right:Math.max(t.right,n.right),bottom:Math.max(t.bottom,n.bottom)+r});Xn(e,i.scrollLeft,i.scrollTop)}function qn(e,t){Math.abs(e.doc.scrollTop-t)<2||(ol||Nr(e,{top:t}),Zn(e,t,!0),ol&&Nr(e),xr(e,100))}function Zn(e,t,n){t=Math.min(e.display.scroller.scrollHeight-e.display.scroller.clientHeight,t),(e.display.scroller.scrollTop!=t||n)&&(e.doc.scrollTop=t,e.display.scrollbars.setScrollTop(t),e.display.scroller.scrollTop!=t&&(e.display.scroller.scrollTop=t))}function Qn(e,t,n,r){t=Math.min(t,e.display.scroller.scrollWidth-e.display.scroller.clientWidth),(n?t==e.doc.scrollLeft:Math.abs(e.doc.scrollLeft-t)<2)&&!r||(e.doc.scrollLeft=t,Rn(e),e.display.scroller.scrollLeft!=t&&(e.display.scroller.scrollLeft=t),e.display.scrollbars.setScrollLeft(t))}function Jn(e){var t=e.display,n=t.gutters.offsetWidth,r=Math.round(e.doc.height+Bt(e.display));return{clientHeight:t.scroller.clientHeight,viewHeight:t.wrapper.clientHeight,scrollWidth:t.scroller.scrollWidth,clientWidth:t.scroller.clientWidth,viewWidth:t.wrapper.clientWidth,barLeft:e.options.fixedGutter?n:0,docHeight:r,scrollHeight:r+Ut(e)+t.barHeight,nativeBarWidth:t.nativeBarWidth,gutterWidth:n}}function er(e,t){t||(t=Jn(e));var n=e.display.barWidth,r=e.display.barHeight;tr(e,t);for(var i=0;i<4&&n!=e.display.barWidth||r!=e.display.barHeight;i++)n!=e.display.barWidth&&e.options.lineWrapping&&En(e),tr(e,Jn(e)),n=e.display.barWidth,r=e.display.barHeight}function tr(e,t){var n=e.display,r=n.scrollbars.update(t);n.sizer.style.paddingRight=(n.barWidth=r.right)+"px",n.sizer.style.paddingBottom=(n.barHeight=r.bottom)+"px",n.heightForcer.style.borderBottom=r.bottom+"px solid transparent",r.right&&r.bottom?(n.scrollbarFiller.style.display="block",n.scrollbarFiller.style.height=r.bottom+"px",n.scrollbarFiller.style.width=r.right+"px"):n.scrollbarFiller.style.display="",r.bottom&&e.options.coverGutterNextToScrollbar&&e.options.fixedGutter?(n.gutterFiller.style.display="block",n.gutterFiller.style.height=r.bottom+"px",n.gutterFiller.style.width=t.gutterWidth+"px"):n.gutterFiller.style.display=""}function nr(e){e.display.scrollbars&&(e.display.scrollbars.clear(),e.display.scrollbars.addClass&&Nl(e.display.wrapper,e.display.scrollbars.addClass)),e.display.scrollbars=new ps[e.options.scrollbarStyle](function(t){e.display.wrapper.insertBefore(t,e.display.scrollbarFiller),Xl(t,"mousedown",function(){e.state.focused&&setTimeout(function(){return e.display.input.focus()},0)}),t.setAttribute("cm-not-content","true")},function(t,n){"horizontal"==n?Qn(e,t):qn(e,t)},e),e.display.scrollbars.addClass&&s(e.display.wrapper,e.display.scrollbars.addClass)}function rr(e){e.curOp={cm:e,viewChanged:!1,startHeight:e.doc.height,forceUpdate:!1,updateInput:null,typing:!1,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:!1,updateMaxLine:!1,scrollLeft:null,scrollTop:null,scrollToPos:null,focus:!1,id:++gs},wt(e.curOp)}function ir(e){Ct(e.curOp,function(e){for(var t=0;t<e.ops.length;t++)e.ops[t].cm.curOp=null;or(e)})}function or(e){for(var t=e.ops,n=0;n<t.length;n++)lr(t[n]);for(var r=0;r<t.length;r++)sr(t[r]);for(var i=0;i<t.length;i++)ar(t[i]);for(var o=0;o<t.length;o++)ur(t[o]);for(var l=0;l<t.length;l++)cr(t[l])}function lr(e){var t=e.cm,n=t.display;Sr(t),e.updateMaxLine&&we(t),e.mustUpdate=e.viewChanged||e.forceUpdate||null!=e.scrollTop||e.scrollToPos&&(e.scrollToPos.from.line<n.viewFrom||e.scrollToPos.to.line>=n.viewTo)||n.maxLineChanged&&t.options.lineWrapping,e.update=e.mustUpdate&&new vs(t,e.mustUpdate&&{top:e.scrollTop,ensure:e.scrollToPos},e.forceUpdate)}function sr(e){e.updatedDisplay=e.mustUpdate&&Mr(e.cm,e.update)}function ar(e){var t=e.cm,n=t.display;e.updatedDisplay&&En(t),e.barMeasure=Jn(t),n.maxLineChanged&&!t.options.lineWrapping&&(e.adjustWidthTo=_t(t,n.maxLine,n.maxLine.text.length).left+3,t.display.sizerWidth=e.adjustWidthTo,e.barMeasure.scrollWidth=Math.max(n.scroller.clientWidth,n.sizer.offsetLeft+e.adjustWidthTo+Ut(t)+t.display.barWidth),e.maxScrollLeft=Math.max(0,n.sizer.offsetLeft+e.adjustWidthTo-Vt(t))),(e.updatedDisplay||e.selectionChanged)&&(e.preparedSelection=n.input.prepareSelection(e.focus))}function ur(e){var t=e.cm;null!=e.adjustWidthTo&&(t.display.sizer.style.minWidth=e.adjustWidthTo+"px",e.maxScrollLeft<t.doc.scrollLeft&&Qn(t,Math.min(t.display.scroller.scrollLeft,e.maxScrollLeft),!0),t.display.maxLineChanged=!1);var n=e.focus&&e.focus==l()&&(!document.hasFocus||document.hasFocus());e.preparedSelection&&t.display.input.showSelection(e.preparedSelection,n),(e.updatedDisplay||e.startHeight!=t.doc.height)&&er(t,e.barMeasure),e.updatedDisplay&&Wr(t,e.barMeasure),e.selectionChanged&&An(t),t.state.focused&&e.updateInput&&t.display.input.reset(e.typing),n&&Wn(e.cm)}function cr(e){var t=e.cm,n=t.display,r=t.doc;e.updatedDisplay&&Tr(t,e.update),null==n.wheelStartX||null==e.scrollTop&&null==e.scrollLeft&&!e.scrollToPos||(n.wheelStartX=n.wheelStartY=null),null!=e.scrollTop&&Zn(t,e.scrollTop,e.forceScroll),null!=e.scrollLeft&&Qn(t,e.scrollLeft,!0,!0),e.scrollToPos&&Bn(t,Gn(t,U(r,e.scrollToPos.from),U(r,e.scrollToPos.to),e.scrollToPos.margin));var i=e.maybeHiddenMarkers,o=e.maybeUnhiddenMarkers;if(i)for(var l=0;l<i.length;++l)i[l].lines.length||Ae(i[l],"hide");if(o)for(var s=0;s<o.length;++s)o[s].lines.length&&Ae(o[s],"unhide");n.wrapper.offsetHeight&&(r.scrollTop=t.display.scroller.scrollTop),e.changeObjs&&Ae(t,"changes",t,e.changeObjs),e.update&&e.update.finish()}function hr(e,t){if(e.curOp)return t();rr(e);try{return t()}finally{ir(e)}}function fr(e,t){return function(){if(e.curOp)return t.apply(e,arguments);rr(e);try{return t.apply(e,arguments)}finally{ir(e)}}}function dr(e){return function(){if(this.curOp)return e.apply(this,arguments);rr(this);try{return e.apply(this,arguments)}finally{ir(this)}}}function pr(e){return function(){var t=this.cm;if(!t||t.curOp)return e.apply(this,arguments);rr(t);try{return e.apply(this,arguments)}finally{ir(t)}}}function gr(e,t,n,r){null==t&&(t=e.doc.first),null==n&&(n=e.doc.first+e.doc.size),r||(r=0);var i=e.display;if(r&&n<i.viewTo&&(null==i.updateLineNumbers||i.updateLineNumbers>t)&&(i.updateLineNumbers=t),e.curOp.viewChanged=!0,t>=i.viewTo)Ul&&pe(e.doc,t)<i.viewTo&&mr(e);else if(n<=i.viewFrom)Ul&&ge(e.doc,n+r)>i.viewFrom?mr(e):(i.viewFrom+=r,i.viewTo+=r);else if(t<=i.viewFrom&&n>=i.viewTo)mr(e);else if(t<=i.viewFrom){var o=yr(e,n,n+r,1);o?(i.view=i.view.slice(o.index),i.viewFrom=o.lineN,i.viewTo+=r):mr(e)}else if(n>=i.viewTo){var l=yr(e,t,t,-1);l?(i.view=i.view.slice(0,l.index),i.viewTo=l.lineN):mr(e)}else{var s=yr(e,t,t,-1),a=yr(e,n,n+r,1);s&&a?(i.view=i.view.slice(0,s.index).concat(bt(e,s.lineN,a.lineN)).concat(i.view.slice(a.index)),i.viewTo+=r):mr(e)}var u=i.externalMeasured;u&&(n<u.lineN?u.lineN+=r:t<u.lineN+u.size&&(i.externalMeasured=null))}function vr(e,t,n){e.curOp.viewChanged=!0;var r=e.display,i=e.display.externalMeasured;if(i&&t>=i.lineN&&t<i.lineN+i.size&&(r.externalMeasured=null),!(t<r.viewFrom||t>=r.viewTo)){var o=r.view[kn(e,t)];if(null!=o.node){var l=o.changes||(o.changes=[]);-1==f(l,n)&&l.push(n)}}}function mr(e){e.display.viewFrom=e.display.viewTo=e.doc.first,e.display.view=[],e.display.viewOffset=0}function yr(e,t,n,r){var i,o=kn(e,t),l=e.display.view;if(!Ul||n==e.doc.first+e.doc.size)return{index:o,lineN:n};for(var s=e.display.viewFrom,a=0;a<o;a++)s+=l[a].size;if(s!=t){if(r>0){if(o==l.length-1)return null;i=s+l[o].size-t,o++}else i=s-t;t+=i,n+=i}for(;pe(e.doc,n)!=n;){if(o==(r<0?0:l.length-1))return null;n+=r*l[o-(r<0?1:0)].size,o+=r}return{index:o,lineN:n}}function br(e,t,n){var r=e.display;0==r.view.length||t>=r.viewTo||n<=r.viewFrom?(r.view=bt(e,t,n),r.viewFrom=t):(r.viewFrom>t?r.view=bt(e,t,r.viewFrom).concat(r.view):r.viewFrom<t&&(r.view=r.view.slice(kn(e,t))),r.viewFrom=t,r.viewTo<n?r.view=r.view.concat(bt(e,r.viewTo,n)):r.viewTo>n&&(r.view=r.view.slice(0,kn(e,n)))),r.viewTo=n}function wr(e){for(var t=e.display.view,n=0,r=0;r<t.length;r++){var i=t[r];i.hidden||i.node&&!i.changes||++n}return n}function xr(e,t){e.doc.highlightFrontier<e.display.viewTo&&e.state.highlight.set(t,u(Cr,e))}function Cr(e){var t=e.doc;if(!(t.highlightFrontier>=e.display.viewTo)){var n=+new Date+e.options.workTime,r=Je(e,t.highlightFrontier),i=[];t.iter(r.line,Math.min(t.first+t.size,e.display.viewTo+500),function(o){if(r.line>=e.display.viewFrom){var l=o.styles,s=o.text.length>e.options.maxHighlightLength?_e(t.mode,r.state):null,a=Ze(e,o,r,!0);s&&(r.state=s),o.styles=a.styles;var u=o.styleClasses,c=a.classes;c?o.styleClasses=c:u&&(o.styleClasses=null);for(var h=!l||l.length!=o.styles.length||u!=c&&(!u||!c||u.bgClass!=c.bgClass||u.textClass!=c.textClass),f=0;!h&&f<l.length;++f)h=l[f]!=o.styles[f];h&&i.push(r.line),o.stateAfter=r.save(),r.nextLine()}else o.text.length<=e.options.maxHighlightLength&&et(e,o.text,r),o.stateAfter=r.line%5==0?r.save():null,r.nextLine();if(+new Date>n)return xr(e,e.options.workDelay),!0}),t.highlightFrontier=r.line,t.modeFrontier=Math.max(t.modeFrontier,r.line),i.length&&hr(e,function(){for(var t=0;t<i.length;t++)vr(e,i[t],"text")})}}function Sr(e){var t=e.display;!t.scrollbarsClipped&&t.scroller.offsetWidth&&(t.nativeBarWidth=t.scroller.offsetWidth-t.scroller.clientWidth,t.heightForcer.style.height=Ut(e)+"px",t.sizer.style.marginBottom=-t.nativeBarWidth+"px",t.sizer.style.borderRightWidth=Ut(e)+"px",t.scrollbarsClipped=!0)}function Lr(e){if(e.hasFocus())return null;var t=l();if(!t||!o(e.display.lineDiv,t))return null;var n={activeElt:t};if(window.getSelection){var r=window.getSelection();r.anchorNode&&r.extend&&o(e.display.lineDiv,r.anchorNode)&&(n.anchorNode=r.anchorNode,n.anchorOffset=r.anchorOffset,n.focusNode=r.focusNode,n.focusOffset=r.focusOffset)}return n}function kr(e){if(e&&e.activeElt&&e.activeElt!=l()&&(e.activeElt.focus(),e.anchorNode&&o(document.body,e.anchorNode)&&o(document.body,e.focusNode))){var t=window.getSelection(),n=document.createRange();n.setEnd(e.anchorNode,e.anchorOffset),n.collapse(!1),t.removeAllRanges(),t.addRange(n),t.extend(e.focusNode,e.focusOffset)}}function Mr(e,n){var r=e.display,i=e.doc;if(n.editorIsHidden)return mr(e),!1;if(!n.force&&n.visible.from>=r.viewFrom&&n.visible.to<=r.viewTo&&(null==r.updateLineNumbers||r.updateLineNumbers>=r.viewTo)&&r.renderedView==r.view&&0==wr(e))return!1;zn(e)&&(mr(e),n.dims=wn(e));var o=i.first+i.size,l=Math.max(n.visible.from-e.options.viewportMargin,i.first),s=Math.min(o,n.visible.to+e.options.viewportMargin);r.viewFrom<l&&l-r.viewFrom<20&&(l=Math.max(i.first,r.viewFrom)),r.viewTo>s&&r.viewTo-s<20&&(s=Math.min(o,r.viewTo)),Ul&&(l=pe(e.doc,l),s=ge(e.doc,s));var a=l!=r.viewFrom||s!=r.viewTo||r.lastWrapHeight!=n.wrapperHeight||r.lastWrapWidth!=n.wrapperWidth;br(e,l,s),r.viewOffset=ye(T(e.doc,r.viewFrom)),e.display.mover.style.top=r.viewOffset+"px";var u=wr(e);if(!a&&0==u&&!n.force&&r.renderedView==r.view&&(null==r.updateLineNumbers||r.updateLineNumbers>=r.viewTo))return!1;var c=Lr(e);return u>4&&(r.lineDiv.style.display="none"),Or(e,r.updateLineNumbers,n.dims),u>4&&(r.lineDiv.style.display=""),r.renderedView=r.view,kr(c),t(r.cursorDiv),t(r.selectionDiv),r.gutters.style.height=r.sizer.style.minHeight=0,a&&(r.lastWrapHeight=n.wrapperHeight,r.lastWrapWidth=n.wrapperWidth,xr(e,400)),r.updateLineNumbers=null,!0}function Tr(e,t){for(var n=t.viewport,r=!0;(r&&e.options.lineWrapping&&t.oldDisplayWidth!=Vt(e)||(n&&null!=n.top&&(n={top:Math.min(e.doc.height+Bt(e.display)-Kt(e),n.top)}),t.visible=In(e.display,e.doc,n),!(t.visible.from>=e.display.viewFrom&&t.visible.to<=e.display.viewTo)))&&Mr(e,t);r=!1){En(e);var i=Jn(e);Mn(e),er(e,i),Wr(e,i),t.force=!1}t.signal(e,"update",e),e.display.viewFrom==e.display.reportedViewFrom&&e.display.viewTo==e.display.reportedViewTo||(t.signal(e,"viewportChange",e,e.display.viewFrom,e.display.viewTo),e.display.reportedViewFrom=e.display.viewFrom,e.display.reportedViewTo=e.display.viewTo)}function Nr(e,t){var n=new vs(e,t);if(Mr(e,n)){En(e),Tr(e,n);var r=Jn(e);Mn(e),er(e,r),Wr(e,r),n.finish()}}function Or(e,n,r){function i(t){var n=t.nextSibling;return hl&&xl&&e.display.currentWheelTarget==t?t.style.display="none":t.parentNode.removeChild(t),n}for(var o=e.display,l=e.options.lineNumbers,s=o.lineDiv,a=s.firstChild,u=o.view,c=o.viewFrom,h=0;h<u.length;h++){var d=u[h];if(d.hidden);else if(d.node&&d.node.parentNode==s){for(;a!=d.node;)a=i(a);var p=l&&null!=n&&n<=c&&d.lineNumber;d.changes&&(f(d.changes,"gutter")>-1&&(p=!1),kt(e,d,c,r)),p&&(t(d.lineNumber),d.lineNumber.appendChild(document.createTextNode(F(e.options,c)))),a=d.node.nextSibling}else{var g=Ht(e,d,c,r);s.insertBefore(g,a)}c+=d.size}for(;a;)a=i(a)}function Ar(e){var t=e.display.gutters.offsetWidth;e.display.sizer.style.marginLeft=t+"px"}function Wr(e,t){e.display.sizer.style.minHeight=t.docHeight+"px",e.display.heightForcer.style.top=t.docHeight+"px",e.display.gutters.style.height=t.docHeight+e.display.barHeight+Ut(e)+"px"}function Dr(e){var n=e.display.gutters,i=e.options.gutters;t(n);for(var o=0;o<i.length;++o){var l=i[o],s=n.appendChild(r("div",null,"CodeMirror-gutter "+l));"CodeMirror-linenumbers"==l&&(e.display.lineGutter=s,s.style.width=(e.display.lineNumWidth||1)+"px")}n.style.display=o?"":"none",Ar(e)}function Hr(e){var t=f(e.gutters,"CodeMirror-linenumbers");-1==t&&e.lineNumbers?e.gutters=e.gutters.concat(["CodeMirror-linenumbers"]):t>-1&&!e.lineNumbers&&(e.gutters=e.gutters.slice(0),e.gutters.splice(t,1))}function Fr(e){var t=e.wheelDeltaX,n=e.wheelDeltaY;return null==t&&e.detail&&e.axis==e.HORIZONTAL_AXIS&&(t=e.detail),null==n&&e.detail&&e.axis==e.VERTICAL_AXIS?n=e.detail:null==n&&(n=e.wheelDelta),{x:t,y:n}}function Er(e){var t=Fr(e);return t.x*=ys,t.y*=ys,t}function Pr(e,t){var n=Fr(t),r=n.x,i=n.y,o=e.display,l=o.scroller,s=l.scrollWidth>l.clientWidth,a=l.scrollHeight>l.clientHeight;if(r&&s||i&&a){if(i&&xl&&hl)e:for(var u=t.target,c=o.view;u!=l;u=u.parentNode)for(var h=0;h<c.length;h++)if(c[h].node==u){e.display.currentWheelTarget=u;break e}if(r&&!ol&&!pl&&null!=ys)return i&&a&&qn(e,Math.max(0,l.scrollTop+i*ys)),Qn(e,Math.max(0,l.scrollLeft+r*ys)),(!i||i&&a)&&Ee(t),void(o.wheelStartX=null);if(i&&null!=ys){var f=i*ys,d=e.doc.scrollTop,p=d+o.wrapper.clientHeight;f<0?d=Math.max(0,d+f-50):p=Math.min(e.doc.height,p+f+50),Nr(e,{top:d,bottom:p})}ms<20&&(null==o.wheelStartX?(o.wheelStartX=l.scrollLeft,o.wheelStartY=l.scrollTop,o.wheelDX=r,o.wheelDY=i,setTimeout(function(){if(null!=o.wheelStartX){var e=l.scrollLeft-o.wheelStartX,t=l.scrollTop-o.wheelStartY,n=t&&o.wheelDY&&t/o.wheelDY||e&&o.wheelDX&&e/o.wheelDX;o.wheelStartX=o.wheelStartY=null,n&&(ys=(ys*ms+n)/(ms+1),++ms)}},200)):(o.wheelDX+=r,o.wheelDY+=i))}}function Ir(e,t){var n=e[t];e.sort(function(e,t){return P(e.from(),t.from())}),t=f(e,n);for(var r=1;r<e.length;r++){var i=e[r],o=e[r-1];if(P(o.to(),i.from())>=0){var l=B(o.from(),i.from()),s=z(o.to(),i.to()),a=o.empty()?i.from()==i.head:o.from()==o.head;r<=t&&--t,e.splice(--r,2,new ws(a?s:l,a?l:s))}}return new bs(e,t)}function Rr(e,t){return new bs([new ws(e,t||e)],0)}function zr(e){return e.text?E(e.from.line+e.text.length-1,g(e.text).length+(1==e.text.length?e.from.ch:0)):e.to}function Br(e,t){if(P(e,t.from)<0)return e;if(P(e,t.to)<=0)return zr(t);var n=e.line+t.text.length-(t.to.line-t.from.line)-1,r=e.ch;return e.line==t.to.line&&(r+=zr(t).ch-t.to.ch),E(n,r)}function Gr(e,t){for(var n=[],r=0;r<e.sel.ranges.length;r++){var i=e.sel.ranges[r];n.push(new ws(Br(i.anchor,t),Br(i.head,t)))}return Ir(n,e.sel.primIndex)}function Ur(e,t,n){return e.line==t.line?E(n.line,e.ch-t.ch+n.ch):E(n.line+(e.line-t.line),e.ch)}function Vr(e,t,n){for(var r=[],i=E(e.first,0),o=i,l=0;l<t.length;l++){var s=t[l],a=Ur(s.from,i,o),u=Ur(zr(s),i,o);if(i=s.to,o=u,"around"==n){var c=e.sel.ranges[l],h=P(c.head,c.anchor)<0;r[l]=new ws(h?u:a,h?a:u)}else r[l]=new ws(a,a)}return new bs(r,e.sel.primIndex)}function Kr(e){e.doc.mode=Xe(e.options,e.doc.modeOption),jr(e)}function jr(e){e.doc.iter(function(e){e.stateAfter&&(e.stateAfter=null),e.styles&&(e.styles=null)}),e.doc.modeFrontier=e.doc.highlightFrontier=e.doc.first,xr(e,100),e.state.modeGen++,e.curOp&&gr(e)}function Xr(e,t){return 0==t.from.ch&&0==t.to.ch&&""==g(t.text)&&(!e.cm||e.cm.options.wholeLineUpdateBefore)}function Yr(e,t,n,r){function i(e){return n?n[e]:null}function o(e,n,i){at(e,n,i,r),St(e,"change",e,t)}function l(e,t){for(var n=[],o=e;o<t;++o)n.push(new os(u[o],i(o),r));return n}var s=t.from,a=t.to,u=t.text,c=T(e,s.line),h=T(e,a.line),f=g(u),d=i(u.length-1),p=a.line-s.line;if(t.full)e.insert(0,l(0,u.length)),e.remove(u.length,e.size-u.length);else if(Xr(e,t)){var v=l(0,u.length-1);o(h,h.text,d),p&&e.remove(s.line,p),v.length&&e.insert(s.line,v)}else if(c==h)if(1==u.length)o(c,c.text.slice(0,s.ch)+f+c.text.slice(a.ch),d);else{var m=l(1,u.length-1);m.push(new os(f+c.text.slice(a.ch),d,r)),o(c,c.text.slice(0,s.ch)+u[0],i(0)),e.insert(s.line+1,m)}else if(1==u.length)o(c,c.text.slice(0,s.ch)+u[0]+h.text.slice(a.ch),i(0)),e.remove(s.line+1,p);else{o(c,c.text.slice(0,s.ch)+u[0],i(0)),o(h,f+h.text.slice(a.ch),d);var y=l(1,u.length-1);p>1&&e.remove(s.line+1,p-1),e.insert(s.line+1,y)}St(e,"change",e,t)}function _r(e,t,n){function r(e,i,o){if(e.linked)for(var l=0;l<e.linked.length;++l){var s=e.linked[l];if(s.doc!=i){var a=o&&s.sharedHist;n&&!a||(t(s.doc,a),r(s.doc,e,a))}}}r(e,null,!0)}function $r(e,t){if(t.cm)throw new Error("This document is already in use.");e.doc=t,t.cm=e,Sn(e),Kr(e),qr(e),e.options.lineWrapping||we(e),e.options.mode=t.modeOption,gr(e)}function qr(e){("rtl"==e.doc.direction?s:Nl)(e.display.lineDiv,"CodeMirror-rtl")}function Zr(e){hr(e,function(){qr(e),gr(e)})}function Qr(e){this.done=[],this.undone=[],this.undoDepth=1/0,this.lastModTime=this.lastSelTime=0,this.lastOp=this.lastSelOp=null,this.lastOrigin=this.lastSelOrigin=null,this.generation=this.maxGeneration=e||1}function Jr(e,t){var n={from:R(t.from),to:zr(t),text:N(e,t.from,t.to)};return li(e,n,t.from.line,t.to.line+1),_r(e,function(e){return li(e,n,t.from.line,t.to.line+1)},!0),n}function ei(e){for(;e.length&&g(e).ranges;)e.pop()}function ti(e,t){return t?(ei(e.done),g(e.done)):e.done.length&&!g(e.done).ranges?g(e.done):e.done.length>1&&!e.done[e.done.length-2].ranges?(e.done.pop(),g(e.done)):void 0}function ni(e,t,n,r){var i=e.history;i.undone.length=0;var o,l,s=+new Date;if((i.lastOp==r||i.lastOrigin==t.origin&&t.origin&&("+"==t.origin.charAt(0)&&e.cm&&i.lastModTime>s-e.cm.options.historyEventDelay||"*"==t.origin.charAt(0)))&&(o=ti(i,i.lastOp==r)))l=g(o.changes),0==P(t.from,t.to)&&0==P(t.from,l.to)?l.to=zr(t):o.changes.push(Jr(e,t));else{var a=g(i.done);for(a&&a.ranges||oi(e.sel,i.done),o={changes:[Jr(e,t)],generation:i.generation},i.done.push(o);i.done.length>i.undoDepth;)i.done.shift(),i.done[0].ranges||i.done.shift()}i.done.push(n),i.generation=++i.maxGeneration,i.lastModTime=i.lastSelTime=s,i.lastOp=i.lastSelOp=r,i.lastOrigin=i.lastSelOrigin=t.origin,l||Ae(e,"historyAdded")}function ri(e,t,n,r){var i=t.charAt(0);return"*"==i||"+"==i&&n.ranges.length==r.ranges.length&&n.somethingSelected()==r.somethingSelected()&&new Date-e.history.lastSelTime<=(e.cm?e.cm.options.historyEventDelay:500)}function ii(e,t,n,r){var i=e.history,o=r&&r.origin;n==i.lastSelOp||o&&i.lastSelOrigin==o&&(i.lastModTime==i.lastSelTime&&i.lastOrigin==o||ri(e,o,g(i.done),t))?i.done[i.done.length-1]=t:oi(t,i.done),i.lastSelTime=+new Date,i.lastSelOrigin=o,i.lastSelOp=n,r&&!1!==r.clearRedo&&ei(i.undone)}function oi(e,t){var n=g(t);n&&n.ranges&&n.equals(e)||t.push(e)}function li(e,t,n,r){var i=t["spans_"+e.id],o=0;e.iter(Math.max(e.first,n),Math.min(e.first+e.size,r),function(n){n.markedSpans&&((i||(i=t["spans_"+e.id]={}))[o]=n.markedSpans),++o})}function si(e){if(!e)return null;for(var t,n=0;n<e.length;++n)e[n].marker.explicitlyCleared?t||(t=e.slice(0,n)):t&&t.push(e[n]);return t?t.length?t:null:e}function ai(e,t){var n=t["spans_"+e.id];if(!n)return null;for(var r=[],i=0;i<t.text.length;++i)r.push(si(n[i]));return r}function ui(e,t){var n=ai(e,t),r=J(e,t);if(!n)return r;if(!r)return n;for(var i=0;i<n.length;++i){var o=n[i],l=r[i];if(o&&l)e:for(var s=0;s<l.length;++s){for(var a=l[s],u=0;u<o.length;++u)if(o[u].marker==a.marker)continue e;o.push(a)}else l&&(n[i]=l)}return n}function ci(e,t,n){for(var r=[],i=0;i<e.length;++i){var o=e[i];if(o.ranges)r.push(n?bs.prototype.deepCopy.call(o):o);else{var l=o.changes,s=[];r.push({changes:s});for(var a=0;a<l.length;++a){var u=l[a],c=void 0;if(s.push({from:u.from,to:u.to,text:u.text}),t)for(var h in u)(c=h.match(/^spans_(\d+)$/))&&f(t,Number(c[1]))>-1&&(g(s)[h]=u[h],delete u[h])}}}return r}function hi(e,t,n,r){if(r){var i=e.anchor;if(n){var o=P(t,i)<0;o!=P(n,i)<0?(i=t,t=n):o!=P(t,n)<0&&(t=n)}return new ws(i,t)}return new ws(n||t,t)}function fi(e,t,n,r,i){null==i&&(i=e.cm&&(e.cm.display.shift||e.extend)),yi(e,new bs([hi(e.sel.primary(),t,n,i)],0),r)}function di(e,t,n){for(var r=[],i=e.cm&&(e.cm.display.shift||e.extend),o=0;o<e.sel.ranges.length;o++)r[o]=hi(e.sel.ranges[o],t[o],null,i);yi(e,Ir(r,e.sel.primIndex),n)}function pi(e,t,n,r){var i=e.sel.ranges.slice(0);i[t]=n,yi(e,Ir(i,e.sel.primIndex),r)}function gi(e,t,n,r){yi(e,Rr(t,n),r)}function vi(e,t,n){var r={ranges:t.ranges,update:function(t){var n=this;this.ranges=[];for(var r=0;r<t.length;r++)n.ranges[r]=new ws(U(e,t[r].anchor),U(e,t[r].head))},origin:n&&n.origin};return Ae(e,"beforeSelectionChange",e,r),e.cm&&Ae(e.cm,"beforeSelectionChange",e.cm,r),r.ranges!=t.ranges?Ir(r.ranges,r.ranges.length-1):t}function mi(e,t,n){var r=e.history.done,i=g(r);i&&i.ranges?(r[r.length-1]=t,bi(e,t,n)):yi(e,t,n)}function yi(e,t,n){bi(e,t,n),ii(e,e.sel,e.cm?e.cm.curOp.id:NaN,n)}function bi(e,t,n){(He(e,"beforeSelectionChange")||e.cm&&He(e.cm,"beforeSelectionChange"))&&(t=vi(e,t,n)),wi(e,Ci(e,t,n&&n.bias||(P(t.primary().head,e.sel.primary().head)<0?-1:1),!0)),n&&!1===n.scroll||!e.cm||jn(e.cm)}function wi(e,t){t.equals(e.sel)||(e.sel=t,e.cm&&(e.cm.curOp.updateInput=e.cm.curOp.selectionChanged=!0,De(e.cm)),St(e,"cursorActivity",e))}function xi(e){wi(e,Ci(e,e.sel,null,!1))}function Ci(e,t,n,r){for(var i,o=0;o<t.ranges.length;o++){var l=t.ranges[o],s=t.ranges.length==e.sel.ranges.length&&e.sel.ranges[o],a=Li(e,l.anchor,s&&s.anchor,n,r),u=Li(e,l.head,s&&s.head,n,r);(i||a!=l.anchor||u!=l.head)&&(i||(i=t.ranges.slice(0,o)),i[o]=new ws(a,u))}return i?Ir(i,t.primIndex):t}function Si(e,t,n,r,i){var o=T(e,t.line);if(o.markedSpans)for(var l=0;l<o.markedSpans.length;++l){var s=o.markedSpans[l],a=s.marker;if((null==s.from||(a.inclusiveLeft?s.from<=t.ch:s.from<t.ch))&&(null==s.to||(a.inclusiveRight?s.to>=t.ch:s.to>t.ch))){if(i&&(Ae(a,"beforeCursorEnter"),a.explicitlyCleared)){if(o.markedSpans){--l;continue}break}if(!a.atomic)continue;if(n){var u=a.find(r<0?1:-1),c=void 0;if((r<0?a.inclusiveRight:a.inclusiveLeft)&&(u=ki(e,u,-r,u&&u.line==t.line?o:null)),u&&u.line==t.line&&(c=P(u,n))&&(r<0?c<0:c>0))return Si(e,u,t,r,i)}var h=a.find(r<0?-1:1);return(r<0?a.inclusiveLeft:a.inclusiveRight)&&(h=ki(e,h,r,h.line==t.line?o:null)),h?Si(e,h,t,r,i):null}}return t}function Li(e,t,n,r,i){var o=r||1,l=Si(e,t,n,o,i)||!i&&Si(e,t,n,o,!0)||Si(e,t,n,-o,i)||!i&&Si(e,t,n,-o,!0);return l||(e.cantEdit=!0,E(e.first,0))}function ki(e,t,n,r){return n<0&&0==t.ch?t.line>e.first?U(e,E(t.line-1)):null:n>0&&t.ch==(r||T(e,t.line)).text.length?t.line<e.first+e.size-1?E(t.line+1,0):null:new E(t.line,t.ch+n)}function Mi(e){e.setSelection(E(e.firstLine(),0),E(e.lastLine()),El)}function Ti(e,t,n){var r={canceled:!1,from:t.from,to:t.to,text:t.text,origin:t.origin,cancel:function(){return r.canceled=!0}};return n&&(r.update=function(t,n,i,o){t&&(r.from=U(e,t)),n&&(r.to=U(e,n)),i&&(r.text=i),void 0!==o&&(r.origin=o)}),Ae(e,"beforeChange",e,r),e.cm&&Ae(e.cm,"beforeChange",e.cm,r),r.canceled?null:{from:r.from,to:r.to,text:r.text,origin:r.origin}}function Ni(e,t,n){if(e.cm){if(!e.cm.curOp)return fr(e.cm,Ni)(e,t,n);if(e.cm.state.suppressEdits)return}if(!(He(e,"beforeChange")||e.cm&&He(e.cm,"beforeChange"))||(t=Ti(e,t,!0))){var r=Gl&&!n&&te(e,t.from,t.to);if(r)for(var i=r.length-1;i>=0;--i)Oi(e,{from:r[i].from,to:r[i].to,text:i?[""]:t.text,origin:t.origin});else Oi(e,t)}}function Oi(e,t){if(1!=t.text.length||""!=t.text[0]||0!=P(t.from,t.to)){var n=Gr(e,t);ni(e,t,n,e.cm?e.cm.curOp.id:NaN),Di(e,t,n,J(e,t));var r=[];_r(e,function(e,n){n||-1!=f(r,e.history)||(Ii(e.history,t),r.push(e.history)),Di(e,t,null,J(e,t))})}}function Ai(e,t,n){if(!e.cm||!e.cm.state.suppressEdits||n){for(var r,i=e.history,o=e.sel,l="undo"==t?i.done:i.undone,s="undo"==t?i.undone:i.done,a=0;a<l.length&&(r=l[a],n?!r.ranges||r.equals(e.sel):r.ranges);a++);if(a!=l.length){for(i.lastOrigin=i.lastSelOrigin=null;(r=l.pop()).ranges;){if(oi(r,s),n&&!r.equals(e.sel))return void yi(e,r,{clearRedo:!1});o=r}var u=[];oi(o,s),s.push({changes:u,generation:i.generation}),i.generation=r.generation||++i.maxGeneration;for(var c=He(e,"beforeChange")||e.cm&&He(e.cm,"beforeChange"),h=r.changes.length-1;h>=0;--h){var d=function(n){var i=r.changes[n];if(i.origin=t,c&&!Ti(e,i,!1))return l.length=0,{};u.push(Jr(e,i));var o=n?Gr(e,i):g(l);Di(e,i,o,ui(e,i)),!n&&e.cm&&e.cm.scrollIntoView({from:i.from,to:zr(i)});var s=[];_r(e,function(e,t){t||-1!=f(s,e.history)||(Ii(e.history,i),s.push(e.history)),Di(e,i,null,ui(e,i))})}(h);if(d)return d.v}}}}function Wi(e,t){if(0!=t&&(e.first+=t,e.sel=new bs(v(e.sel.ranges,function(e){return new ws(E(e.anchor.line+t,e.anchor.ch),E(e.head.line+t,e.head.ch))}),e.sel.primIndex),e.cm)){gr(e.cm,e.first,e.first-t,t);for(var n=e.cm.display,r=n.viewFrom;r<n.viewTo;r++)vr(e.cm,r,"gutter")}}function Di(e,t,n,r){if(e.cm&&!e.cm.curOp)return fr(e.cm,Di)(e,t,n,r);if(t.to.line<e.first)Wi(e,t.text.length-1-(t.to.line-t.from.line));else if(!(t.from.line>e.lastLine())){if(t.from.line<e.first){var i=t.text.length-1-(e.first-t.from.line);Wi(e,i),t={from:E(e.first,0),to:E(t.to.line+i,t.to.ch),text:[g(t.text)],origin:t.origin}}var o=e.lastLine();t.to.line>o&&(t={from:t.from,to:E(o,T(e,o).text.length),text:[t.text[0]],origin:t.origin}),t.removed=N(e,t.from,t.to),n||(n=Gr(e,t)),e.cm?Hi(e.cm,t,r):Yr(e,t,r),bi(e,n,El)}}function Hi(e,t,n){var r=e.doc,i=e.display,o=t.from,l=t.to,s=!1,a=o.line;e.options.lineWrapping||(a=W(he(T(r,o.line))),r.iter(a,l.line+1,function(e){if(e==i.maxLine)return s=!0,!0})),r.sel.contains(t.from,t.to)>-1&&De(e),Yr(r,t,n,Cn(e)),e.options.lineWrapping||(r.iter(a,o.line+t.text.length,function(e){var t=be(e);t>i.maxLineLength&&(i.maxLine=e,i.maxLineLength=t,i.maxLineChanged=!0,s=!1)}),s&&(e.curOp.updateMaxLine=!0)),st(r,o.line),xr(e,400);var u=t.text.length-(l.line-o.line)-1;t.full?gr(e):o.line!=l.line||1!=t.text.length||Xr(e.doc,t)?gr(e,o.line,l.line+1,u):vr(e,o.line,"text");var c=He(e,"changes"),h=He(e,"change");if(h||c){var f={from:o,to:l,text:t.text,removed:t.removed,origin:t.origin};h&&St(e,"change",e,f),c&&(e.curOp.changeObjs||(e.curOp.changeObjs=[])).push(f)}e.display.selForContextMenu=null}function Fi(e,t,n,r,i){if(r||(r=n),P(r,n)<0){var o=r;r=n,n=o}"string"==typeof t&&(t=e.splitLines(t)),Ni(e,{from:n,to:r,text:t,origin:i})}function Ei(e,t,n,r){n<e.line?e.line+=r:t<e.line&&(e.line=t,e.ch=0)}function Pi(e,t,n,r){for(var i=0;i<e.length;++i){var o=e[i],l=!0;if(o.ranges){o.copied||((o=e[i]=o.deepCopy()).copied=!0);for(var s=0;s<o.ranges.length;s++)Ei(o.ranges[s].anchor,t,n,r),Ei(o.ranges[s].head,t,n,r)}else{for(var a=0;a<o.changes.length;++a){var u=o.changes[a];if(n<u.from.line)u.from=E(u.from.line+r,u.from.ch),u.to=E(u.to.line+r,u.to.ch);else if(t<=u.to.line){l=!1;break}}l||(e.splice(0,i+1),i=0)}}}function Ii(e,t){var n=t.from.line,r=t.to.line,i=t.text.length-(r-n)-1;Pi(e.done,n,r,i),Pi(e.undone,n,r,i)}function Ri(e,t,n,r){var i=t,o=t;return"number"==typeof t?o=T(e,G(e,t)):i=W(t),null==i?null:(r(o,i)&&e.cm&&vr(e.cm,i,n),o)}function zi(e){var t=this;this.lines=e,this.parent=null;for(var n=0,r=0;r<e.length;++r)e[r].parent=t,n+=e[r].height;this.height=n}function Bi(e){var t=this;this.children=e;for(var n=0,r=0,i=0;i<e.length;++i){var o=e[i];n+=o.chunkSize(),r+=o.height,o.parent=t}this.size=n,this.height=r,this.parent=null}function Gi(e,t,n){ye(t)<(e.curOp&&e.curOp.scrollTop||e.doc.scrollTop)&&Kn(e,n)}function Ui(e,t,n,r){var i=new xs(e,n,r),o=e.cm;return o&&i.noHScroll&&(o.display.alignWidgets=!0),Ri(e,t,"widget",function(t){var n=t.widgets||(t.widgets=[]);if(null==i.insertAt?n.push(i):n.splice(Math.min(n.length-1,Math.max(0,i.insertAt)),0,i),i.line=t,o&&!ve(e,t)){var r=ye(t)<e.scrollTop;A(t,t.height+It(i)),r&&Kn(o,i.height),o.curOp.forceUpdate=!0}return!0}),St(o,"lineWidgetAdded",o,i,"number"==typeof t?t:W(t)),i}function Vi(e,t,n,r,o){if(r&&r.shared)return Ki(e,t,n,r,o);if(e.cm&&!e.cm.curOp)return fr(e.cm,Vi)(e,t,n,r,o);var l=new Ss(e,o),s=P(t,n);if(r&&c(r,l,!1),s>0||0==s&&!1!==l.clearWhenEmpty)return l;if(l.replacedWith&&(l.collapsed=!0,l.widgetNode=i("span",[l.replacedWith],"CodeMirror-widget"),r.handleMouseEvents||l.widgetNode.setAttribute("cm-ignore-events","true"),r.insertLeft&&(l.widgetNode.insertLeft=!0)),l.collapsed){if(ce(e,t.line,t,n,l)||t.line!=n.line&&ce(e,n.line,t,n,l))throw new Error("Inserting collapsed marker partially overlapping an existing one");X()}l.addToHistory&&ni(e,{from:t,to:n,origin:"markText"},e.sel,NaN);var a,u=t.line,h=e.cm;if(e.iter(u,n.line+1,function(e){h&&l.collapsed&&!h.options.lineWrapping&&he(e)==h.display.maxLine&&(a=!0),l.collapsed&&u!=t.line&&A(e,0),q(e,new Y(l,u==t.line?t.ch:null,u==n.line?n.ch:null)),++u}),l.collapsed&&e.iter(t.line,n.line+1,function(t){ve(e,t)&&A(t,0)}),l.clearOnEnter&&Xl(l,"beforeCursorEnter",function(){return l.clear()}),l.readOnly&&(j(),(e.history.done.length||e.history.undone.length)&&e.clearHistory()),l.collapsed&&(l.id=++Cs,l.atomic=!0),h){if(a&&(h.curOp.updateMaxLine=!0),l.collapsed)gr(h,t.line,n.line+1);else if(l.className||l.title||l.startStyle||l.endStyle||l.css)for(var f=t.line;f<=n.line;f++)vr(h,f,"text");l.atomic&&xi(h.doc),St(h,"markerAdded",h,l)}return l}function Ki(e,t,n,r,i){(r=c(r)).shared=!1;var o=[Vi(e,t,n,r,i)],l=o[0],s=r.widgetNode;return _r(e,function(e){s&&(r.widgetNode=s.cloneNode(!0)),o.push(Vi(e,U(e,t),U(e,n),r,i));for(var a=0;a<e.linked.length;++a)if(e.linked[a].isParent)return;l=g(o)}),new Ls(o,l)}function ji(e){return e.findMarks(E(e.first,0),e.clipPos(E(e.lastLine())),function(e){return e.parent})}function Xi(e,t){for(var n=0;n<t.length;n++){var r=t[n],i=r.find(),o=e.clipPos(i.from),l=e.clipPos(i.to);if(P(o,l)){var s=Vi(e,o,l,r.primary,r.primary.type);r.markers.push(s),s.parent=r}}}function Yi(e){for(var t=0;t<e.length;t++)!function(t){var n=e[t],r=[n.primary.doc];_r(n.primary.doc,function(e){return r.push(e)});for(var i=0;i<n.markers.length;i++){var o=n.markers[i];-1==f(r,o.doc)&&(o.parent=null,n.markers.splice(i--,1))}}(t)}function _i(e){var t=this;if(Zi(t),!We(t,e)&&!Rt(t.display,e)){Ee(e),ul&&(Ts=+new Date);var n=Ln(t,e,!0),r=e.dataTransfer.files;if(n&&!t.isReadOnly())if(r&&r.length&&window.FileReader&&window.File)for(var i=r.length,o=Array(i),l=0,s=0;s<i;++s)!function(e,r){if(!t.options.allowDropFileTypes||-1!=f(t.options.allowDropFileTypes,e.type)){var s=new FileReader;s.onload=fr(t,function(){var e=s.result;if(/[\x00-\x08\x0e-\x1f]{2}/.test(e)&&(e=""),o[r]=e,++l==i){var a={from:n=U(t.doc,n),to:n,text:t.doc.splitLines(o.join(t.doc.lineSeparator())),origin:"paste"};Ni(t.doc,a),mi(t.doc,Rr(n,zr(a)))}}),s.readAsText(e)}}(r[s],s);else{if(t.state.draggingText&&t.doc.sel.contains(n)>-1)return t.state.draggingText(e),void setTimeout(function(){return t.display.input.focus()},20);try{var a=e.dataTransfer.getData("Text");if(a){var u;if(t.state.draggingText&&!t.state.draggingText.copy&&(u=t.listSelections()),bi(t.doc,Rr(n,n)),u)for(var c=0;c<u.length;++c)Fi(t.doc,"",u[c].anchor,u[c].head,"drag");t.replaceSelection(a,"around","paste"),t.display.input.focus()}}catch(e){}}}}function $i(e,t){if(ul&&(!e.state.draggingText||+new Date-Ts<100))Re(t);else if(!We(e,t)&&!Rt(e.display,t)&&(t.dataTransfer.setData("Text",e.getSelection()),t.dataTransfer.effectAllowed="copyMove",t.dataTransfer.setDragImage&&!gl)){var n=r("img",null,null,"position: fixed; left: 0; top: 0;");n.src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",pl&&(n.width=n.height=1,e.display.wrapper.appendChild(n),n._top=n.offsetTop),t.dataTransfer.setDragImage(n,0,0),pl&&n.parentNode.removeChild(n)}}function qi(e,t){var i=Ln(e,t);if(i){var o=document.createDocumentFragment();Nn(e,i,o),e.display.dragCursor||(e.display.dragCursor=r("div",null,"CodeMirror-cursors CodeMirror-dragcursors"),e.display.lineSpace.insertBefore(e.display.dragCursor,e.display.cursorDiv)),n(e.display.dragCursor,o)}}function Zi(e){e.display.dragCursor&&(e.display.lineSpace.removeChild(e.display.dragCursor),e.display.dragCursor=null)}function Qi(e){if(document.getElementsByClassName)for(var t=document.getElementsByClassName("CodeMirror"),n=0;n<t.length;n++){var r=t[n].CodeMirror;r&&e(r)}}function Ji(){Ns||(eo(),Ns=!0)}function eo(){var e;Xl(window,"resize",function(){null==e&&(e=setTimeout(function(){e=null,Qi(to)},100))}),Xl(window,"blur",function(){return Qi(Fn)})}function to(e){var t=e.display;t.lastWrapHeight==t.wrapper.clientHeight&&t.lastWrapWidth==t.wrapper.clientWidth||(t.cachedCharWidth=t.cachedTextHeight=t.cachedPaddingH=null,t.scrollbarsClipped=!1,e.setSize())}function no(e){var t=e.split(/-(?!$)/);e=t[t.length-1];for(var n,r,i,o,l=0;l<t.length-1;l++){var s=t[l];if(/^(cmd|meta|m)$/i.test(s))o=!0;else if(/^a(lt)?$/i.test(s))n=!0;else if(/^(c|ctrl|control)$/i.test(s))r=!0;else{if(!/^s(hift)?$/i.test(s))throw new Error("Unrecognized modifier name: "+s);i=!0}}return n&&(e="Alt-"+e),r&&(e="Ctrl-"+e),o&&(e="Cmd-"+e),i&&(e="Shift-"+e),e}function ro(e){var t={};for(var n in e)if(e.hasOwnProperty(n)){var r=e[n];if(/^(name|fallthrough|(de|at)tach)$/.test(n))continue;if("..."==r){delete e[n];continue}for(var i=v(n.split(" "),no),o=0;o<i.length;o++){var l=void 0,s=void 0;o==i.length-1?(s=i.join(" "),l=r):(s=i.slice(0,o+1).join(" "),l="...");var a=t[s];if(a){if(a!=l)throw new Error("Inconsistent bindings for "+s)}else t[s]=l}delete e[n]}for(var u in t)e[u]=t[u];return e}function io(e,t,n,r){var i=(t=ao(t)).call?t.call(e,r):t[e];if(!1===i)return"nothing";if("..."===i)return"multi";if(null!=i&&n(i))return"handled";if(t.fallthrough){if("[object Array]"!=Object.prototype.toString.call(t.fallthrough))return io(e,t.fallthrough,n,r);for(var o=0;o<t.fallthrough.length;o++){var l=io(e,t.fallthrough[o],n,r);if(l)return l}}}function oo(e){var t="string"==typeof e?e:Os[e.keyCode];return"Ctrl"==t||"Alt"==t||"Shift"==t||"Mod"==t}function lo(e,t,n){var r=e;return t.altKey&&"Alt"!=r&&(e="Alt-"+e),(Ml?t.metaKey:t.ctrlKey)&&"Ctrl"!=r&&(e="Ctrl-"+e),(Ml?t.ctrlKey:t.metaKey)&&"Cmd"!=r&&(e="Cmd-"+e),!n&&t.shiftKey&&"Shift"!=r&&(e="Shift-"+e),e}function so(e,t){if(pl&&34==e.keyCode&&e.char)return!1;var n=Os[e.keyCode];return null!=n&&!e.altGraphKey&&lo(n,e,t)}function ao(e){return"string"==typeof e?Hs[e]:e}function uo(e,t){for(var n=e.doc.sel.ranges,r=[],i=0;i<n.length;i++){for(var o=t(n[i]);r.length&&P(o.from,g(r).to)<=0;){var l=r.pop();if(P(l.from,o.from)<0){o.from=l.from;break}}r.push(o)}hr(e,function(){for(var t=r.length-1;t>=0;t--)Fi(e.doc,"",r[t].from,r[t].to,"+delete");jn(e)})}function co(e,t){var n=T(e.doc,t),r=he(n);return r!=n&&(t=W(r)),Me(!0,e,r,t,1)}function ho(e,t){var n=T(e.doc,t),r=fe(n);return r!=n&&(t=W(r)),Me(!0,e,n,t,-1)}function fo(e,t){var n=co(e,t.line),r=T(e.doc,n.line),i=Se(r,e.doc.direction);if(!i||0==i[0].level){var o=Math.max(0,r.text.search(/\S/)),l=t.line==n.line&&t.ch<=o&&t.ch;return E(n.line,l?0:o,n.sticky)}return n}function po(e,t,n){if("string"==typeof t&&!(t=Fs[t]))return!1;e.display.input.ensurePolled();var r=e.display.shift,i=!1;try{e.isReadOnly()&&(e.state.suppressEdits=!0),n&&(e.display.shift=!1),i=t(e)!=Fl}finally{e.display.shift=r,e.state.suppressEdits=!1}return i}function go(e,t,n){for(var r=0;r<e.state.keyMaps.length;r++){var i=io(t,e.state.keyMaps[r],n,e);if(i)return i}return e.options.extraKeys&&io(t,e.options.extraKeys,n,e)||io(t,e.options.keyMap,n,e)}function vo(e,t,n,r){var i=e.state.keySeq;if(i){if(oo(t))return"handled";Es.set(50,function(){e.state.keySeq==i&&(e.state.keySeq=null,e.display.input.reset())}),t=i+" "+t}var o=go(e,t,r);return"multi"==o&&(e.state.keySeq=t),"handled"==o&&St(e,"keyHandled",e,t,n),"handled"!=o&&"multi"!=o||(Ee(n),An(e)),i&&!o&&/\'$/.test(t)?(Ee(n),!0):!!o}function mo(e,t){var n=so(t,!0);return!!n&&(t.shiftKey&&!e.state.keySeq?vo(e,"Shift-"+n,t,function(t){return po(e,t,!0)})||vo(e,n,t,function(t){if("string"==typeof t?/^go[A-Z]/.test(t):t.motion)return po(e,t)}):vo(e,n,t,function(t){return po(e,t)}))}function yo(e,t,n){return vo(e,"'"+n+"'",t,function(t){return po(e,t,!0)})}function bo(e){var t=this;if(t.curOp.focus=l(),!We(t,e)){ul&&cl<11&&27==e.keyCode&&(e.returnValue=!1);var n=e.keyCode;t.display.shift=16==n||e.shiftKey;var r=mo(t,e);pl&&(Ps=r?n:null,!r&&88==n&&!ql&&(xl?e.metaKey:e.ctrlKey)&&t.replaceSelection("",null,"cut")),18!=n||/\bCodeMirror-crosshair\b/.test(t.display.lineDiv.className)||wo(t)}}function wo(e){function t(e){18!=e.keyCode&&e.altKey||(Nl(n,"CodeMirror-crosshair"),Oe(document,"keyup",t),Oe(document,"mouseover",t))}var n=e.display.lineDiv;s(n,"CodeMirror-crosshair"),Xl(document,"keyup",t),Xl(document,"mouseover",t)}function xo(e){16==e.keyCode&&(this.doc.sel.shift=!1),We(this,e)}function Co(e){var t=this;if(!(Rt(t.display,e)||We(t,e)||e.ctrlKey&&!e.altKey||xl&&e.metaKey)){var n=e.keyCode,r=e.charCode;if(pl&&n==Ps)return Ps=null,void Ee(e);if(!pl||e.which&&!(e.which<10)||!mo(t,e)){var i=String.fromCharCode(null==r?n:r);"\b"!=i&&(yo(t,e,i)||t.display.input.onKeyPress(e))}}}function So(e,t){var n=+new Date;return zs&&zs.compare(n,e,t)?(Rs=zs=null,"triple"):Rs&&Rs.compare(n,e,t)?(zs=new Is(n,e,t),Rs=null,"double"):(Rs=new Is(n,e,t),zs=null,"single")}function Lo(e){var t=this,n=t.display;if(!(We(t,e)||n.activeTouch&&n.input.supportsTouch()))if(n.input.ensurePolled(),n.shift=e.shiftKey,Rt(n,e))hl||(n.scroller.draggable=!1,setTimeout(function(){return n.scroller.draggable=!0},100));else if(!Do(t,e)){var r=Ln(t,e),i=Be(e),o=r?So(r,i):"single";window.focus(),1==i&&t.state.selectingText&&t.state.selectingText(e),r&&ko(t,i,r,o,e)||(1==i?r?To(t,r,o,e):ze(e)==n.scroller&&Ee(e):2==i?(r&&fi(t.doc,r),setTimeout(function(){return n.input.focus()},20)):3==i&&(Tl?Ho(t,e):Dn(t)))}}function ko(e,t,n,r,i){var o="Click";return"double"==r?o="Double"+o:"triple"==r&&(o="Triple"+o),o=(1==t?"Left":2==t?"Middle":"Right")+o,vo(e,lo(o,i),i,function(t){if("string"==typeof t&&(t=Fs[t]),!t)return!1;var r=!1;try{e.isReadOnly()&&(e.state.suppressEdits=!0),r=t(e,n)!=Fl}finally{e.state.suppressEdits=!1}return r})}function Mo(e,t,n){var r=e.getOption("configureMouse"),i=r?r(e,t,n):{};if(null==i.unit){var o=Cl?n.shiftKey&&n.metaKey:n.altKey;i.unit=o?"rectangle":"single"==t?"char":"double"==t?"word":"line"}return(null==i.extend||e.doc.extend)&&(i.extend=e.doc.extend||n.shiftKey),null==i.addNew&&(i.addNew=xl?n.metaKey:n.ctrlKey),null==i.moveOnDrag&&(i.moveOnDrag=!(xl?n.altKey:n.ctrlKey)),i}function To(e,t,n,r){ul?setTimeout(u(Wn,e),0):e.curOp.focus=l();var i,o=Mo(e,n,r),s=e.doc.sel;e.options.dragDrop&&Yl&&!e.isReadOnly()&&"single"==n&&(i=s.contains(t))>-1&&(P((i=s.ranges[i]).from(),t)<0||t.xRel>0)&&(P(i.to(),t)>0||t.xRel<0)?No(e,r,t,o):Ao(e,r,t,o)}function No(e,t,n,r){var i=e.display,o=!1,l=fr(e,function(t){hl&&(i.scroller.draggable=!1),e.state.draggingText=!1,Oe(document,"mouseup",l),Oe(document,"mousemove",s),Oe(i.scroller,"dragstart",a),Oe(i.scroller,"drop",l),o||(Ee(t),r.addNew||fi(e.doc,n,null,null,r.extend),hl||ul&&9==cl?setTimeout(function(){document.body.focus(),i.input.focus()},20):i.input.focus())}),s=function(e){o=o||Math.abs(t.clientX-e.clientX)+Math.abs(t.clientY-e.clientY)>=10},a=function(){return o=!0};hl&&(i.scroller.draggable=!0),e.state.draggingText=l,l.copy=!r.moveOnDrag,i.scroller.dragDrop&&i.scroller.dragDrop(),Xl(document,"mouseup",l),Xl(document,"mousemove",s),Xl(i.scroller,"dragstart",a),Xl(i.scroller,"drop",l),Dn(e),setTimeout(function(){return i.input.focus()},20)}function Oo(e,t,n){if("char"==n)return new ws(t,t);if("word"==n)return e.findWordAt(t);if("line"==n)return new ws(E(t.line,0),U(e.doc,E(t.line+1,0)));var r=n(e,t);return new ws(r.from,r.to)}function Ao(e,t,n,r){function i(t){if(0!=P(m,t))if(m=t,"rectangle"==r.unit){for(var i=[],o=e.options.tabSize,l=h(T(u,n.line).text,n.ch,o),s=h(T(u,t.line).text,t.ch,o),a=Math.min(l,s),g=Math.max(l,s),v=Math.min(n.line,t.line),y=Math.min(e.lastLine(),Math.max(n.line,t.line));v<=y;v++){var b=T(u,v).text,w=d(b,a,o);a==g?i.push(new ws(E(v,w),E(v,w))):b.length>w&&i.push(new ws(E(v,w),E(v,d(b,g,o))))}i.length||i.push(new ws(n,n)),yi(u,Ir(p.ranges.slice(0,f).concat(i),f),{origin:"*mouse",scroll:!1}),e.scrollIntoView(t)}else{var x,C=c,S=Oo(e,t,r.unit),L=C.anchor;P(S.anchor,L)>0?(x=S.head,L=B(C.from(),S.anchor)):(x=S.anchor,L=z(C.to(),S.head));var k=p.ranges.slice(0);k[f]=new ws(U(u,L),x),yi(u,Ir(k,f),Pl)}}function o(t){var n=++b,s=Ln(e,t,!0,"rectangle"==r.unit);if(s)if(0!=P(s,m)){e.curOp.focus=l(),i(s);var c=In(a,u);(s.line>=c.to||s.line<c.from)&&setTimeout(fr(e,function(){b==n&&o(t)}),150)}else{var h=t.clientY<y.top?-20:t.clientY>y.bottom?20:0;h&&setTimeout(fr(e,function(){b==n&&(a.scroller.scrollTop+=h,o(t))}),50)}}function s(t){e.state.selectingText=!1,b=1/0,Ee(t),a.input.focus(),Oe(document,"mousemove",w),Oe(document,"mouseup",x),u.history.lastSelOrigin=null}var a=e.display,u=e.doc;Ee(t);var c,f,p=u.sel,g=p.ranges;if(r.addNew&&!r.extend?(f=u.sel.contains(n),c=f>-1?g[f]:new ws(n,n)):(c=u.sel.primary(),f=u.sel.primIndex),"rectangle"==r.unit)r.addNew||(c=new ws(n,n)),n=Ln(e,t,!0,!0),f=-1;else{var v=Oo(e,n,r.unit);c=r.extend?hi(c,v.anchor,v.head,r.extend):v}r.addNew?-1==f?(f=g.length,yi(u,Ir(g.concat([c]),f),{scroll:!1,origin:"*mouse"})):g.length>1&&g[f].empty()&&"char"==r.unit&&!r.extend?(yi(u,Ir(g.slice(0,f).concat(g.slice(f+1)),0),{scroll:!1,origin:"*mouse"}),p=u.sel):pi(u,f,c,Pl):(f=0,yi(u,new bs([c],0),Pl),p=u.sel);var m=n,y=a.wrapper.getBoundingClientRect(),b=0,w=fr(e,function(e){Be(e)?o(e):s(e)}),x=fr(e,s);e.state.selectingText=x,Xl(document,"mousemove",w),Xl(document,"mouseup",x)}function Wo(e,t,n,r){var i,o;try{i=t.clientX,o=t.clientY}catch(t){return!1}if(i>=Math.floor(e.display.gutters.getBoundingClientRect().right))return!1;r&&Ee(t);var l=e.display,s=l.lineDiv.getBoundingClientRect();if(o>s.bottom||!He(e,n))return Ie(t);o-=s.top-l.viewOffset;for(var a=0;a<e.options.gutters.length;++a){var u=l.gutters.childNodes[a];if(u&&u.getBoundingClientRect().right>=i)return Ae(e,n,e,D(e.doc,o),e.options.gutters[a],t),Ie(t)}}function Do(e,t){return Wo(e,t,"gutterClick",!0)}function Ho(e,t){Rt(e.display,t)||Fo(e,t)||We(e,t,"contextmenu")||e.display.input.onContextMenu(t)}function Fo(e,t){return!!He(e,"gutterContextMenu")&&Wo(e,t,"gutterContextMenu",!1)}function Eo(e){e.display.wrapper.className=e.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+e.options.theme.replace(/(^|\s)\s*/g," cm-s-"),on(e)}function Po(e){Dr(e),gr(e),Rn(e)}function Io(e,t,n){if(!t!=!(n&&n!=Bs)){var r=e.display.dragFunctions,i=t?Xl:Oe;i(e.display.scroller,"dragstart",r.start),i(e.display.scroller,"dragenter",r.enter),i(e.display.scroller,"dragover",r.over),i(e.display.scroller,"dragleave",r.leave),i(e.display.scroller,"drop",r.drop)}}function Ro(e){e.options.lineWrapping?(s(e.display.wrapper,"CodeMirror-wrap"),e.display.sizer.style.minWidth="",e.display.sizerWidth=null):(Nl(e.display.wrapper,"CodeMirror-wrap"),we(e)),Sn(e),gr(e),on(e),setTimeout(function(){return er(e)},100)}function zo(e,t){var n=this;if(!(this instanceof zo))return new zo(e,t);this.options=t=t?c(t):{},c(Gs,t,!1),Hr(t);var r=t.value;"string"==typeof r&&(r=new Ms(r,t.mode,null,t.lineSeparator,t.direction)),this.doc=r;var i=new zo.inputStyles[t.inputStyle](this),o=this.display=new M(e,r,i);o.wrapper.CodeMirror=this,Dr(this),Eo(this),t.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap"),nr(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,delayingBlurEvent:!1,focused:!1,suppressEdits:!1,pasteIncoming:!1,cutIncoming:!1,selectingText:!1,draggingText:!1,highlight:new Al,keySeq:null,specialChars:null},t.autofocus&&!wl&&o.input.focus(),ul&&cl<11&&setTimeout(function(){return n.display.input.reset(!0)},20),Bo(this),Ji(),rr(this),this.curOp.forceUpdate=!0,$r(this,r),t.autofocus&&!wl||this.hasFocus()?setTimeout(u(Hn,this),20):Fn(this);for(var l in Us)Us.hasOwnProperty(l)&&Us[l](n,t[l],Bs);zn(this),t.finishInit&&t.finishInit(this);for(var s=0;s<Vs.length;++s)Vs[s](n);ir(this),hl&&t.lineWrapping&&"optimizelegibility"==getComputedStyle(o.lineDiv).textRendering&&(o.lineDiv.style.textRendering="auto")}function Bo(e){function t(){i.activeTouch&&(o=setTimeout(function(){return i.activeTouch=null},1e3),(l=i.activeTouch).end=+new Date)}function n(e){if(1!=e.touches.length)return!1;var t=e.touches[0];return t.radiusX<=1&&t.radiusY<=1}function r(e,t){if(null==t.left)return!0;var n=t.left-e.left,r=t.top-e.top;return n*n+r*r>400}var i=e.display;Xl(i.scroller,"mousedown",fr(e,Lo)),ul&&cl<11?Xl(i.scroller,"dblclick",fr(e,function(t){if(!We(e,t)){var n=Ln(e,t);if(n&&!Do(e,t)&&!Rt(e.display,t)){Ee(t);var r=e.findWordAt(n);fi(e.doc,r.anchor,r.head)}}})):Xl(i.scroller,"dblclick",function(t){return We(e,t)||Ee(t)}),Tl||Xl(i.scroller,"contextmenu",function(t){return Ho(e,t)});var o,l={end:0};Xl(i.scroller,"touchstart",function(t){if(!We(e,t)&&!n(t)){i.input.ensurePolled(),clearTimeout(o);var r=+new Date;i.activeTouch={start:r,moved:!1,prev:r-l.end<=300?l:null},1==t.touches.length&&(i.activeTouch.left=t.touches[0].pageX,i.activeTouch.top=t.touches[0].pageY)}}),Xl(i.scroller,"touchmove",function(){i.activeTouch&&(i.activeTouch.moved=!0)}),Xl(i.scroller,"touchend",function(n){var o=i.activeTouch;if(o&&!Rt(i,n)&&null!=o.left&&!o.moved&&new Date-o.start<300){var l,s=e.coordsChar(i.activeTouch,"page");l=!o.prev||r(o,o.prev)?new ws(s,s):!o.prev.prev||r(o,o.prev.prev)?e.findWordAt(s):new ws(E(s.line,0),U(e.doc,E(s.line+1,0))),e.setSelection(l.anchor,l.head),e.focus(),Ee(n)}t()}),Xl(i.scroller,"touchcancel",t),Xl(i.scroller,"scroll",function(){i.scroller.clientHeight&&(qn(e,i.scroller.scrollTop),Qn(e,i.scroller.scrollLeft,!0),Ae(e,"scroll",e))}),Xl(i.scroller,"mousewheel",function(t){return Pr(e,t)}),Xl(i.scroller,"DOMMouseScroll",function(t){return Pr(e,t)}),Xl(i.wrapper,"scroll",function(){return i.wrapper.scrollTop=i.wrapper.scrollLeft=0}),i.dragFunctions={enter:function(t){We(e,t)||Re(t)},over:function(t){We(e,t)||(qi(e,t),Re(t))},start:function(t){return $i(e,t)},drop:fr(e,_i),leave:function(t){We(e,t)||Zi(e)}};var s=i.input.getField();Xl(s,"keyup",function(t){return xo.call(e,t)}),Xl(s,"keydown",fr(e,bo)),Xl(s,"keypress",fr(e,Co)),Xl(s,"focus",function(t){return Hn(e,t)}),Xl(s,"blur",function(t){return Fn(e,t)})}function Go(e,t,n,r){var i,o=e.doc;null==n&&(n="add"),"smart"==n&&(o.mode.indent?i=Je(e,t).state:n="prev");var l=e.options.tabSize,s=T(o,t),a=h(s.text,null,l);s.stateAfter&&(s.stateAfter=null);var u,c=s.text.match(/^\s*/)[0];if(r||/\S/.test(s.text)){if("smart"==n&&((u=o.mode.indent(i,s.text.slice(c.length),s.text))==Fl||u>150)){if(!r)return;n="prev"}}else u=0,n="not";"prev"==n?u=t>o.first?h(T(o,t-1).text,null,l):0:"add"==n?u=a+e.options.indentUnit:"subtract"==n?u=a-e.options.indentUnit:"number"==typeof n&&(u=a+n),u=Math.max(0,u);var f="",d=0;if(e.options.indentWithTabs)for(var g=Math.floor(u/l);g;--g)d+=l,f+="\t";if(d<u&&(f+=p(u-d)),f!=c)return Fi(o,f,E(t,0),E(t,c.length),"+input"),s.stateAfter=null,!0;for(var v=0;v<o.sel.ranges.length;v++){var m=o.sel.ranges[v];if(m.head.line==t&&m.head.ch<c.length){var y=E(t,c.length);pi(o,v,new ws(y,y));break}}}function Uo(e){Ks=e}function Vo(e,t,n,r,i){var o=e.doc;e.display.shift=!1,r||(r=o.sel);var l=e.state.pasteIncoming||"paste"==i,s=_l(t),a=null;if(l&&r.ranges.length>1)if(Ks&&Ks.text.join("\n")==t){if(r.ranges.length%Ks.text.length==0){a=[];for(var u=0;u<Ks.text.length;u++)a.push(o.splitLines(Ks.text[u]))}}else s.length==r.ranges.length&&e.options.pasteLinesPerSelection&&(a=v(s,function(e){return[e]}));for(var c,h=r.ranges.length-1;h>=0;h--){var f=r.ranges[h],d=f.from(),p=f.to();f.empty()&&(n&&n>0?d=E(d.line,d.ch-n):e.state.overwrite&&!l?p=E(p.line,Math.min(T(o,p.line).text.length,p.ch+g(s).length)):Ks&&Ks.lineWise&&Ks.text.join("\n")==t&&(d=p=E(d.line,0))),c=e.curOp.updateInput;var m={from:d,to:p,text:a?a[h%a.length]:s,origin:i||(l?"paste":e.state.cutIncoming?"cut":"+input")};Ni(e.doc,m),St(e,"inputRead",e,m)}t&&!l&&jo(e,t),jn(e),e.curOp.updateInput=c,e.curOp.typing=!0,e.state.pasteIncoming=e.state.cutIncoming=!1}function Ko(e,t){var n=e.clipboardData&&e.clipboardData.getData("Text");if(n)return e.preventDefault(),t.isReadOnly()||t.options.disableInput||hr(t,function(){return Vo(t,n,0,null,"paste")}),!0}function jo(e,t){if(e.options.electricChars&&e.options.smartIndent)for(var n=e.doc.sel,r=n.ranges.length-1;r>=0;r--){var i=n.ranges[r];if(!(i.head.ch>100||r&&n.ranges[r-1].head.line==i.head.line)){var o=e.getModeAt(i.head),l=!1;if(o.electricChars){for(var s=0;s<o.electricChars.length;s++)if(t.indexOf(o.electricChars.charAt(s))>-1){l=Go(e,i.head.line,"smart");break}}else o.electricInput&&o.electricInput.test(T(e.doc,i.head.line).text.slice(0,i.head.ch))&&(l=Go(e,i.head.line,"smart"));l&&St(e,"electricInput",e,i.head.line)}}}function Xo(e){for(var t=[],n=[],r=0;r<e.doc.sel.ranges.length;r++){var i=e.doc.sel.ranges[r].head.line,o={anchor:E(i,0),head:E(i+1,0)};n.push(o),t.push(e.getRange(o.anchor,o.head))}return{text:t,ranges:n}}function Yo(e,t){e.setAttribute("autocorrect","off"),e.setAttribute("autocapitalize","off"),e.setAttribute("spellcheck",!!t)}function _o(){var e=r("textarea",null,null,"position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none"),t=r("div",[e],null,"overflow: hidden; position: relative; width: 3px; height: 0px;");return hl?e.style.width="1000px":e.setAttribute("wrap","off"),yl&&(e.style.border="1px solid black"),Yo(e),t}function $o(e,t,n,r,i){function o(){var r=t.line+n;return!(r<e.first||r>=e.first+e.size)&&(t=new E(r,t.ch,t.sticky),u=T(e,r))}function l(r){var l;if(null==(l=i?Te(e.cm,u,t,n):ke(u,t,n))){if(r||!o())return!1;t=Me(i,e.cm,u,t.line,n)}else t=l;return!0}var s=t,a=n,u=T(e,t.line);if("char"==r)l();else if("column"==r)l(!0);else if("word"==r||"group"==r)for(var c=null,h="group"==r,f=e.cm&&e.cm.getHelper(t,"wordChars"),d=!0;!(n<0)||l(!d);d=!1){var p=u.text.charAt(t.ch)||"\n",g=x(p,f)?"w":h&&"\n"==p?"n":!h||/\s/.test(p)?null:"p";if(!h||d||g||(g="s"),c&&c!=g){n<0&&(n=1,l(),t.sticky="after");break}if(g&&(c=g),n>0&&!l(!d))break}var v=Li(e,t,s,a,!0);return I(s,v)&&(v.hitSide=!0),v}function qo(e,t,n,r){var i,o=e.doc,l=t.left;if("page"==r){var s=Math.min(e.display.wrapper.clientHeight,window.innerHeight||document.documentElement.clientHeight),a=Math.max(s-.5*yn(e.display),3);i=(n>0?t.bottom:t.top)+n*a}else"line"==r&&(i=n>0?t.bottom+3:t.top-3);for(var u;(u=pn(e,l,i)).outside;){if(n<0?i<=0:i>=o.height){u.hitSide=!0;break}i+=5*n}return u}function Zo(e,t){var n=$t(e,t.line);if(!n||n.hidden)return null;var r=T(e.doc,t.line),i=Xt(n,r,t.line),o=Se(r,e.doc.direction),l="left";o&&(l=Ce(o,t.ch)%2?"right":"left");var s=Qt(i.map,t.ch,l);return s.offset="right"==s.collapse?s.end:s.start,s}function Qo(e){for(var t=e;t;t=t.parentNode)if(/CodeMirror-gutter-wrapper/.test(t.className))return!0;return!1}function Jo(e,t){return t&&(e.bad=!0),e}function el(e,t,n,r,i){function o(e){return function(t){return t.id==e}}function l(){c&&(u+=h,c=!1)}function s(e){e&&(l(),u+=e)}function a(t){if(1==t.nodeType){var n=t.getAttribute("cm-text");if(null!=n)return void s(n||t.textContent.replace(/\u200b/g,""));var u,f=t.getAttribute("cm-marker");if(f){var d=e.findMarks(E(r,0),E(i+1,0),o(+f));return void(d.length&&(u=d[0].find(0))&&s(N(e.doc,u.from,u.to).join(h)))}if("false"==t.getAttribute("contenteditable"))return;var p=/^(pre|div|p)$/i.test(t.nodeName);p&&l();for(var g=0;g<t.childNodes.length;g++)a(t.childNodes[g]);p&&(c=!0)}else 3==t.nodeType&&s(t.nodeValue)}for(var u="",c=!1,h=e.doc.lineSeparator();a(t),t!=n;)t=t.nextSibling;return u}function tl(e,t,n){var r;if(t==e.display.lineDiv){if(!(r=e.display.lineDiv.childNodes[n]))return Jo(e.clipPos(E(e.display.viewTo-1)),!0);t=null,n=0}else for(r=t;;r=r.parentNode){if(!r||r==e.display.lineDiv)return null;if(r.parentNode&&r.parentNode==e.display.lineDiv)break}for(var i=0;i<e.display.view.length;i++){var o=e.display.view[i];if(o.node==r)return nl(o,t,n)}}function nl(e,t,n){function r(t,n,r){for(var i=-1;i<(h?h.length:0);i++)for(var o=i<0?c.map:h[i],l=0;l<o.length;l+=3){var s=o[l+2];if(s==t||s==n){var a=W(i<0?e.line:e.rest[i]),u=o[l]+r;return(r<0||s!=t)&&(u=o[l+(r?1:0)]),E(a,u)}}}var i=e.text.firstChild,l=!1;if(!t||!o(i,t))return Jo(E(W(e.line),0),!0);if(t==i&&(l=!0,t=i.childNodes[n],n=0,!t)){var s=e.rest?g(e.rest):e.line;return Jo(E(W(s),s.text.length),l)}var a=3==t.nodeType?t:null,u=t;for(a||1!=t.childNodes.length||3!=t.firstChild.nodeType||(a=t.firstChild,n&&(n=a.nodeValue.length));u.parentNode!=i;)u=u.parentNode;var c=e.measure,h=c.maps,f=r(a,u,n);if(f)return Jo(f,l);for(var d=u.nextSibling,p=a?a.nodeValue.length-n:0;d;d=d.nextSibling){if(f=r(d,d.firstChild,0))return Jo(E(f.line,f.ch-p),l);p+=d.textContent.length}for(var v=u.previousSibling,m=n;v;v=v.previousSibling){if(f=r(v,v.firstChild,-1))return Jo(E(f.line,f.ch+m),l);m+=v.textContent.length}}var rl=navigator.userAgent,il=navigator.platform,ol=/gecko\/\d/i.test(rl),ll=/MSIE \d/.test(rl),sl=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(rl),al=/Edge\/(\d+)/.exec(rl),ul=ll||sl||al,cl=ul&&(ll?document.documentMode||6:+(al||sl)[1]),hl=!al&&/WebKit\//.test(rl),fl=hl&&/Qt\/\d+\.\d+/.test(rl),dl=!al&&/Chrome\//.test(rl),pl=/Opera\//.test(rl),gl=/Apple Computer/.test(navigator.vendor),vl=/Mac OS X 1\d\D([8-9]|\d\d)\D/.test(rl),ml=/PhantomJS/.test(rl),yl=!al&&/AppleWebKit/.test(rl)&&/Mobile\/\w+/.test(rl),bl=/Android/.test(rl),wl=yl||bl||/webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(rl),xl=yl||/Mac/.test(il),Cl=/\bCrOS\b/.test(rl),Sl=/win/i.test(il),Ll=pl&&rl.match(/Version\/(\d*\.\d*)/);Ll&&(Ll=Number(Ll[1])),Ll&&Ll>=15&&(pl=!1,hl=!0);var kl,Ml=xl&&(fl||pl&&(null==Ll||Ll<12.11)),Tl=ol||ul&&cl>=9,Nl=function(t,n){var r=t.className,i=e(n).exec(r);if(i){var o=r.slice(i.index+i[0].length);t.className=r.slice(0,i.index)+(o?i[1]+o:"")}};kl=document.createRange?function(e,t,n,r){var i=document.createRange();return i.setEnd(r||e,n),i.setStart(e,t),i}:function(e,t,n){var r=document.body.createTextRange();try{r.moveToElementText(e.parentNode)}catch(e){return r}return r.collapse(!0),r.moveEnd("character",n),r.moveStart("character",t),r};var Ol=function(e){e.select()};yl?Ol=function(e){e.selectionStart=0,e.selectionEnd=e.value.length}:ul&&(Ol=function(e){try{e.select()}catch(e){}});var Al=function(){this.id=null};Al.prototype.set=function(e,t){clearTimeout(this.id),this.id=setTimeout(t,e)};var Wl,Dl,Hl=30,Fl={toString:function(){return"CodeMirror.Pass"}},El={scroll:!1},Pl={origin:"*mouse"},Il={origin:"+move"},Rl=[""],zl=/[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/,Bl=/[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/,Gl=!1,Ul=!1,Vl=null,Kl=function(){function e(e){return e<=247?n.charAt(e):1424<=e&&e<=1524?"R":1536<=e&&e<=1785?r.charAt(e-1536):1774<=e&&e<=2220?"r":8192<=e&&e<=8203?"w":8204==e?"b":"L"}function t(e,t,n){this.level=e,this.from=t,this.to=n}var n="bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN",r="nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111",i=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,o=/[stwN]/,l=/[LRr]/,s=/[Lb1n]/,a=/[1n]/;return function(n,r){var u="ltr"==r?"L":"R";if(0==n.length||"ltr"==r&&!i.test(n))return!1;for(var c=n.length,h=[],f=0;f<c;++f)h.push(e(n.charCodeAt(f)));for(var d=0,p=u;d<c;++d){var v=h[d];"m"==v?h[d]=p:p=v}for(var m=0,y=u;m<c;++m){var b=h[m];"1"==b&&"r"==y?h[m]="n":l.test(b)&&(y=b,"r"==b&&(h[m]="R"))}for(var w=1,x=h[0];w<c-1;++w){var C=h[w];"+"==C&&"1"==x&&"1"==h[w+1]?h[w]="1":","!=C||x!=h[w+1]||"1"!=x&&"n"!=x||(h[w]=x),x=C}for(var S=0;S<c;++S){var L=h[S];if(","==L)h[S]="N";else if("%"==L){var k=void 0;for(k=S+1;k<c&&"%"==h[k];++k);for(var M=S&&"!"==h[S-1]||k<c&&"1"==h[k]?"1":"N",T=S;T<k;++T)h[T]=M;S=k-1}}for(var N=0,O=u;N<c;++N){var A=h[N];"L"==O&&"1"==A?h[N]="L":l.test(A)&&(O=A)}for(var W=0;W<c;++W)if(o.test(h[W])){var D=void 0;for(D=W+1;D<c&&o.test(h[D]);++D);for(var H="L"==(W?h[W-1]:u),F=H==("L"==(D<c?h[D]:u))?H?"L":"R":u,E=W;E<D;++E)h[E]=F;W=D-1}for(var P,I=[],R=0;R<c;)if(s.test(h[R])){var z=R;for(++R;R<c&&s.test(h[R]);++R);I.push(new t(0,z,R))}else{var B=R,G=I.length;for(++R;R<c&&"L"!=h[R];++R);for(var U=B;U<R;)if(a.test(h[U])){B<U&&I.splice(G,0,new t(1,B,U));var V=U;for(++U;U<R&&a.test(h[U]);++U);I.splice(G,0,new t(2,V,U)),B=U}else++U;B<R&&I.splice(G,0,new t(1,B,R))}return 1==I[0].level&&(P=n.match(/^\s+/))&&(I[0].from=P[0].length,I.unshift(new t(0,0,P[0].length))),1==g(I).level&&(P=n.match(/\s+$/))&&(g(I).to-=P[0].length,I.push(new t(0,c-P[0].length,c))),"rtl"==r?I.reverse():I}}(),jl=[],Xl=function(e,t,n){if(e.addEventListener)e.addEventListener(t,n,!1);else if(e.attachEvent)e.attachEvent("on"+t,n);else{var r=e._handlers||(e._handlers={});r[t]=(r[t]||jl).concat(n)}},Yl=function(){if(ul&&cl<9)return!1;var e=r("div");return"draggable"in e||"dragDrop"in e}(),_l=3!="\n\nb".split(/\n/).length?function(e){for(var t=0,n=[],r=e.length;t<=r;){var i=e.indexOf("\n",t);-1==i&&(i=e.length);var o=e.slice(t,"\r"==e.charAt(i-1)?i-1:i),l=o.indexOf("\r");-1!=l?(n.push(o.slice(0,l)),t+=l+1):(n.push(o),t=i+1)}return n}:function(e){return e.split(/\r\n?|\n/)},$l=window.getSelection?function(e){try{return e.selectionStart!=e.selectionEnd}catch(e){return!1}}:function(e){var t;try{t=e.ownerDocument.selection.createRange()}catch(e){}return!(!t||t.parentElement()!=e)&&0!=t.compareEndPoints("StartToEnd",t)},ql=function(){var e=r("div");return"oncopy"in e||(e.setAttribute("oncopy","return;"),"function"==typeof e.oncopy)}(),Zl=null,Ql={},Jl={},es={},ts=function(e,t,n){this.pos=this.start=0,this.string=e,this.tabSize=t||8,this.lastColumnPos=this.lastColumnValue=0,this.lineStart=0,this.lineOracle=n};ts.prototype.eol=function(){return this.pos>=this.string.length},ts.prototype.sol=function(){return this.pos==this.lineStart},ts.prototype.peek=function(){return this.string.charAt(this.pos)||void 0},ts.prototype.next=function(){if(this.pos<this.string.length)return this.string.charAt(this.pos++)},ts.prototype.eat=function(e){var t=this.string.charAt(this.pos);if("string"==typeof e?t==e:t&&(e.test?e.test(t):e(t)))return++this.pos,t},ts.prototype.eatWhile=function(e){for(var t=this.pos;this.eat(e););return this.pos>t},ts.prototype.eatSpace=function(){for(var e=this,t=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++e.pos;return this.pos>t},ts.prototype.skipToEnd=function(){this.pos=this.string.length},ts.prototype.skipTo=function(e){var t=this.string.indexOf(e,this.pos);if(t>-1)return this.pos=t,!0},ts.prototype.backUp=function(e){this.pos-=e},ts.prototype.column=function(){return this.lastColumnPos<this.start&&(this.lastColumnValue=h(this.string,this.start,this.tabSize,this.lastColumnPos,this.lastColumnValue),this.lastColumnPos=this.start),this.lastColumnValue-(this.lineStart?h(this.string,this.lineStart,this.tabSize):0)},ts.prototype.indentation=function(){return h(this.string,null,this.tabSize)-(this.lineStart?h(this.string,this.lineStart,this.tabSize):0)},ts.prototype.match=function(e,t,n){if("string"!=typeof e){var r=this.string.slice(this.pos).match(e);return r&&r.index>0?null:(r&&!1!==t&&(this.pos+=r[0].length),r)}var i=function(e){return n?e.toLowerCase():e};if(i(this.string.substr(this.pos,e.length))==i(e))return!1!==t&&(this.pos+=e.length),!0},ts.prototype.current=function(){return this.string.slice(this.start,this.pos)},ts.prototype.hideFirstChars=function(e,t){this.lineStart+=e;try{return t()}finally{this.lineStart-=e}},ts.prototype.lookAhead=function(e){var t=this.lineOracle;return t&&t.lookAhead(e)};var ns=function(e,t){this.state=e,this.lookAhead=t},rs=function(e,t,n,r){this.state=t,this.doc=e,this.line=n,this.maxLookAhead=r||0};rs.prototype.lookAhead=function(e){var t=this.doc.getLine(this.line+e);return null!=t&&e>this.maxLookAhead&&(this.maxLookAhead=e),t},rs.prototype.nextLine=function(){this.line++,this.maxLookAhead>0&&this.maxLookAhead--},rs.fromSaved=function(e,t,n){return t instanceof ns?new rs(e,_e(e.mode,t.state),n,t.lookAhead):new rs(e,_e(e.mode,t),n)},rs.prototype.save=function(e){var t=!1!==e?_e(this.doc.mode,this.state):this.state;return this.maxLookAhead>0?new ns(t,this.maxLookAhead):t};var is=function(e,t,n){this.start=e.start,this.end=e.pos,this.string=e.current(),this.type=t||null,this.state=n},os=function(e,t,n){this.text=e,re(this,t),this.height=n?n(this):1};os.prototype.lineNo=function(){return W(this)},Fe(os);var ls,ss={},as={},us=null,cs=null,hs={left:0,right:0,top:0,bottom:0},fs=function(e,t,n){this.cm=n;var i=this.vert=r("div",[r("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),o=this.horiz=r("div",[r("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");e(i),e(o),Xl(i,"scroll",function(){i.clientHeight&&t(i.scrollTop,"vertical")}),Xl(o,"scroll",function(){o.clientWidth&&t(o.scrollLeft,"horizontal")}),this.checkedZeroWidth=!1,ul&&cl<8&&(this.horiz.style.minHeight=this.vert.style.minWidth="18px")};fs.prototype.update=function(e){var t=e.scrollWidth>e.clientWidth+1,n=e.scrollHeight>e.clientHeight+1,r=e.nativeBarWidth;if(n){this.vert.style.display="block",this.vert.style.bottom=t?r+"px":"0";var i=e.viewHeight-(t?r:0);this.vert.firstChild.style.height=Math.max(0,e.scrollHeight-e.clientHeight+i)+"px"}else this.vert.style.display="",this.vert.firstChild.style.height="0";if(t){this.horiz.style.display="block",this.horiz.style.right=n?r+"px":"0",this.horiz.style.left=e.barLeft+"px";var o=e.viewWidth-e.barLeft-(n?r:0);this.horiz.firstChild.style.width=Math.max(0,e.scrollWidth-e.clientWidth+o)+"px"}else this.horiz.style.display="",this.horiz.firstChild.style.width="0";return!this.checkedZeroWidth&&e.clientHeight>0&&(0==r&&this.zeroWidthHack(),this.checkedZeroWidth=!0),{right:n?r:0,bottom:t?r:0}},fs.prototype.setScrollLeft=function(e){this.horiz.scrollLeft!=e&&(this.horiz.scrollLeft=e),this.disableHoriz&&this.enableZeroWidthBar(this.horiz,this.disableHoriz,"horiz")},fs.prototype.setScrollTop=function(e){this.vert.scrollTop!=e&&(this.vert.scrollTop=e),this.disableVert&&this.enableZeroWidthBar(this.vert,this.disableVert,"vert")},fs.prototype.zeroWidthHack=function(){var e=xl&&!vl?"12px":"18px";this.horiz.style.height=this.vert.style.width=e,this.horiz.style.pointerEvents=this.vert.style.pointerEvents="none",this.disableHoriz=new Al,this.disableVert=new Al},fs.prototype.enableZeroWidthBar=function(e,t,n){function r(){var i=e.getBoundingClientRect();("vert"==n?document.elementFromPoint(i.right-1,(i.top+i.bottom)/2):document.elementFromPoint((i.right+i.left)/2,i.bottom-1))!=e?e.style.pointerEvents="none":t.set(1e3,r)}e.style.pointerEvents="auto",t.set(1e3,r)},fs.prototype.clear=function(){var e=this.horiz.parentNode;e.removeChild(this.horiz),e.removeChild(this.vert)};var ds=function(){};ds.prototype.update=function(){return{bottom:0,right:0}},ds.prototype.setScrollLeft=function(){},ds.prototype.setScrollTop=function(){},ds.prototype.clear=function(){};var ps={native:fs,null:ds},gs=0,vs=function(e,t,n){var r=e.display;this.viewport=t,this.visible=In(r,e.doc,t),this.editorIsHidden=!r.wrapper.offsetWidth,this.wrapperHeight=r.wrapper.clientHeight,this.wrapperWidth=r.wrapper.clientWidth,this.oldDisplayWidth=Vt(e),this.force=n,this.dims=wn(e),this.events=[]};vs.prototype.signal=function(e,t){He(e,t)&&this.events.push(arguments)},vs.prototype.finish=function(){for(var e=this,t=0;t<this.events.length;t++)Ae.apply(null,e.events[t])};var ms=0,ys=null;ul?ys=-.53:ol?ys=15:dl?ys=-.7:gl&&(ys=-1/3);var bs=function(e,t){this.ranges=e,this.primIndex=t};bs.prototype.primary=function(){return this.ranges[this.primIndex]},bs.prototype.equals=function(e){var t=this;if(e==this)return!0;if(e.primIndex!=this.primIndex||e.ranges.length!=this.ranges.length)return!1;for(var n=0;n<this.ranges.length;n++){var r=t.ranges[n],i=e.ranges[n];if(!I(r.anchor,i.anchor)||!I(r.head,i.head))return!1}return!0},bs.prototype.deepCopy=function(){for(var e=this,t=[],n=0;n<this.ranges.length;n++)t[n]=new ws(R(e.ranges[n].anchor),R(e.ranges[n].head));return new bs(t,this.primIndex)},bs.prototype.somethingSelected=function(){for(var e=this,t=0;t<this.ranges.length;t++)if(!e.ranges[t].empty())return!0;return!1},bs.prototype.contains=function(e,t){var n=this;t||(t=e);for(var r=0;r<this.ranges.length;r++){var i=n.ranges[r];if(P(t,i.from())>=0&&P(e,i.to())<=0)return r}return-1};var ws=function(e,t){this.anchor=e,this.head=t};ws.prototype.from=function(){return B(this.anchor,this.head)},ws.prototype.to=function(){return z(this.anchor,this.head)},ws.prototype.empty=function(){return this.head.line==this.anchor.line&&this.head.ch==this.anchor.ch},zi.prototype={chunkSize:function(){return this.lines.length},removeInner:function(e,t){for(var n=this,r=e,i=e+t;r<i;++r){var o=n.lines[r];n.height-=o.height,ut(o),St(o,"delete")}this.lines.splice(e,t)},collapse:function(e){e.push.apply(e,this.lines)},insertInner:function(e,t,n){var r=this;this.height+=n,this.lines=this.lines.slice(0,e).concat(t).concat(this.lines.slice(e));for(var i=0;i<t.length;++i)t[i].parent=r},iterN:function(e,t,n){for(var r=this,i=e+t;e<i;++e)if(n(r.lines[e]))return!0}},Bi.prototype={chunkSize:function(){return this.size},removeInner:function(e,t){var n=this;this.size-=t;for(var r=0;r<this.children.length;++r){var i=n.children[r],o=i.chunkSize();if(e<o){var l=Math.min(t,o-e),s=i.height;if(i.removeInner(e,l),n.height-=s-i.height,o==l&&(n.children.splice(r--,1),i.parent=null),0==(t-=l))break;e=0}else e-=o}if(this.size-t<25&&(this.children.length>1||!(this.children[0]instanceof zi))){var a=[];this.collapse(a),this.children=[new zi(a)],this.children[0].parent=this}},collapse:function(e){for(var t=this,n=0;n<this.children.length;++n)t.children[n].collapse(e)},insertInner:function(e,t,n){var r=this;this.size+=t.length,this.height+=n;for(var i=0;i<this.children.length;++i){var o=r.children[i],l=o.chunkSize();if(e<=l){if(o.insertInner(e,t,n),o.lines&&o.lines.length>50){for(var s=o.lines.length%25+25,a=s;a<o.lines.length;){var u=new zi(o.lines.slice(a,a+=25));o.height-=u.height,r.children.splice(++i,0,u),u.parent=r}o.lines=o.lines.slice(0,s),r.maybeSpill()}break}e-=l}},maybeSpill:function(){if(!(this.children.length<=10)){var e=this;do{var t=new Bi(e.children.splice(e.children.length-5,5));if(e.parent){e.size-=t.size,e.height-=t.height;var n=f(e.parent.children,e);e.parent.children.splice(n+1,0,t)}else{var r=new Bi(e.children);r.parent=e,e.children=[r,t],e=r}t.parent=e.parent}while(e.children.length>10);e.parent.maybeSpill()}},iterN:function(e,t,n){for(var r=this,i=0;i<this.children.length;++i){var o=r.children[i],l=o.chunkSize();if(e<l){var s=Math.min(t,l-e);if(o.iterN(e,s,n))return!0;if(0==(t-=s))break;e=0}else e-=l}}};var xs=function(e,t,n){var r=this;if(n)for(var i in n)n.hasOwnProperty(i)&&(r[i]=n[i]);this.doc=e,this.node=t};xs.prototype.clear=function(){var e=this,t=this.doc.cm,n=this.line.widgets,r=this.line,i=W(r);if(null!=i&&n){for(var o=0;o<n.length;++o)n[o]==e&&n.splice(o--,1);n.length||(r.widgets=null);var l=It(this);A(r,Math.max(0,r.height-l)),t&&(hr(t,function(){Gi(t,r,-l),vr(t,i,"widget")}),St(t,"lineWidgetCleared",t,this,i))}},xs.prototype.changed=function(){var e=this,t=this.height,n=this.doc.cm,r=this.line;this.height=null;var i=It(this)-t;i&&(A(r,r.height+i),n&&hr(n,function(){n.curOp.forceUpdate=!0,Gi(n,r,i),St(n,"lineWidgetChanged",n,e,W(r))}))},Fe(xs);var Cs=0,Ss=function(e,t){this.lines=[],this.type=t,this.doc=e,this.id=++Cs};Ss.prototype.clear=function(){var e=this;if(!this.explicitlyCleared){var t=this.doc.cm,n=t&&!t.curOp;if(n&&rr(t),He(this,"clear")){var r=this.find();r&&St(this,"clear",r.from,r.to)}for(var i=null,o=null,l=0;l<this.lines.length;++l){var s=e.lines[l],a=_(s.markedSpans,e);t&&!e.collapsed?vr(t,W(s),"text"):t&&(null!=a.to&&(o=W(s)),null!=a.from&&(i=W(s))),s.markedSpans=$(s.markedSpans,a),null==a.from&&e.collapsed&&!ve(e.doc,s)&&t&&A(s,yn(t.display))}if(t&&this.collapsed&&!t.options.lineWrapping)for(var u=0;u<this.lines.length;++u){var c=he(e.lines[u]),h=be(c);h>t.display.maxLineLength&&(t.display.maxLine=c,t.display.maxLineLength=h,t.display.maxLineChanged=!0)}null!=i&&t&&this.collapsed&&gr(t,i,o+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,t&&xi(t.doc)),t&&St(t,"markerCleared",t,this,i,o),n&&ir(t),this.parent&&this.parent.clear()}},Ss.prototype.find=function(e,t){var n=this;null==e&&"bookmark"==this.type&&(e=1);for(var r,i,o=0;o<this.lines.length;++o){var l=n.lines[o],s=_(l.markedSpans,n);if(null!=s.from&&(r=E(t?l:W(l),s.from),-1==e))return r;if(null!=s.to&&(i=E(t?l:W(l),s.to),1==e))return i}return r&&{from:r,to:i}},Ss.prototype.changed=function(){var e=this,t=this.find(-1,!0),n=this,r=this.doc.cm;t&&r&&hr(r,function(){var i=t.line,o=W(t.line),l=$t(r,o);if(l&&(nn(l),r.curOp.selectionChanged=r.curOp.forceUpdate=!0),r.curOp.updateMaxLine=!0,!ve(n.doc,i)&&null!=n.height){var s=n.height;n.height=null;var a=It(n)-s;a&&A(i,i.height+a)}St(r,"markerChanged",r,e)})},Ss.prototype.attachLine=function(e){if(!this.lines.length&&this.doc.cm){var t=this.doc.cm.curOp;t.maybeHiddenMarkers&&-1!=f(t.maybeHiddenMarkers,this)||(t.maybeUnhiddenMarkers||(t.maybeUnhiddenMarkers=[])).push(this)}this.lines.push(e)},Ss.prototype.detachLine=function(e){if(this.lines.splice(f(this.lines,e),1),!this.lines.length&&this.doc.cm){var t=this.doc.cm.curOp;(t.maybeHiddenMarkers||(t.maybeHiddenMarkers=[])).push(this)}},Fe(Ss);var Ls=function(e,t){var n=this;this.markers=e,this.primary=t;for(var r=0;r<e.length;++r)e[r].parent=n};Ls.prototype.clear=function(){var e=this;if(!this.explicitlyCleared){this.explicitlyCleared=!0;for(var t=0;t<this.markers.length;++t)e.markers[t].clear();St(this,"clear")}},Ls.prototype.find=function(e,t){return this.primary.find(e,t)},Fe(Ls);var ks=0,Ms=function(e,t,n,r,i){if(!(this instanceof Ms))return new Ms(e,t,n,r,i);null==n&&(n=0),Bi.call(this,[new zi([new os("",null)])]),this.first=n,this.scrollTop=this.scrollLeft=0,this.cantEdit=!1,this.cleanGeneration=1,this.modeFrontier=this.highlightFrontier=n;var o=E(n,0);this.sel=Rr(o),this.history=new Qr(null),this.id=++ks,this.modeOption=t,this.lineSep=r,this.direction="rtl"==i?"rtl":"ltr",this.extend=!1,"string"==typeof e&&(e=this.splitLines(e)),Yr(this,{from:o,to:o,text:e}),yi(this,Rr(o),El)};Ms.prototype=b(Bi.prototype,{constructor:Ms,iter:function(e,t,n){n?this.iterN(e-this.first,t-e,n):this.iterN(this.first,this.first+this.size,e)},insert:function(e,t){for(var n=0,r=0;r<t.length;++r)n+=t[r].height;this.insertInner(e-this.first,t,n)},remove:function(e,t){this.removeInner(e-this.first,t)},getValue:function(e){var t=O(this,this.first,this.first+this.size);return!1===e?t:t.join(e||this.lineSeparator())},setValue:pr(function(e){var t=E(this.first,0),n=this.first+this.size-1;Ni(this,{from:t,to:E(n,T(this,n).text.length),text:this.splitLines(e),origin:"setValue",full:!0},!0),this.cm&&Xn(this.cm,0,0),yi(this,Rr(t),El)}),replaceRange:function(e,t,n,r){Fi(this,e,t=U(this,t),n=n?U(this,n):t,r)},getRange:function(e,t,n){var r=N(this,U(this,e),U(this,t));return!1===n?r:r.join(n||this.lineSeparator())},getLine:function(e){var t=this.getLineHandle(e);return t&&t.text},getLineHandle:function(e){if(H(this,e))return T(this,e)},getLineNumber:function(e){return W(e)},getLineHandleVisualStart:function(e){return"number"==typeof e&&(e=T(this,e)),he(e)},lineCount:function(){return this.size},firstLine:function(){return this.first},lastLine:function(){return this.first+this.size-1},clipPos:function(e){return U(this,e)},getCursor:function(e){var t=this.sel.primary();return null==e||"head"==e?t.head:"anchor"==e?t.anchor:"end"==e||"to"==e||!1===e?t.to():t.from()},listSelections:function(){return this.sel.ranges},somethingSelected:function(){return this.sel.somethingSelected()},setCursor:pr(function(e,t,n){gi(this,U(this,"number"==typeof e?E(e,t||0):e),null,n)}),setSelection:pr(function(e,t,n){gi(this,U(this,e),U(this,t||e),n)}),extendSelection:pr(function(e,t,n){fi(this,U(this,e),t&&U(this,t),n)}),extendSelections:pr(function(e,t){di(this,K(this,e),t)}),extendSelectionsBy:pr(function(e,t){di(this,K(this,v(this.sel.ranges,e)),t)}),setSelections:pr(function(e,t,n){var r=this;if(e.length){for(var i=[],o=0;o<e.length;o++)i[o]=new ws(U(r,e[o].anchor),U(r,e[o].head));null==t&&(t=Math.min(e.length-1,this.sel.primIndex)),yi(this,Ir(i,t),n)}}),addSelection:pr(function(e,t,n){var r=this.sel.ranges.slice(0);r.push(new ws(U(this,e),U(this,t||e))),yi(this,Ir(r,r.length-1),n)}),getSelection:function(e){for(var t,n=this,r=this.sel.ranges,i=0;i<r.length;i++){var o=N(n,r[i].from(),r[i].to());t=t?t.concat(o):o}return!1===e?t:t.join(e||this.lineSeparator())},getSelections:function(e){for(var t=this,n=[],r=this.sel.ranges,i=0;i<r.length;i++){var o=N(t,r[i].from(),r[i].to());!1!==e&&(o=o.join(e||t.lineSeparator())),n[i]=o}return n},replaceSelection:function(e,t,n){for(var r=[],i=0;i<this.sel.ranges.length;i++)r[i]=e;this.replaceSelections(r,t,n||"+input")},replaceSelections:pr(function(e,t,n){for(var r=this,i=[],o=this.sel,l=0;l<o.ranges.length;l++){var s=o.ranges[l];i[l]={from:s.from(),to:s.to(),text:r.splitLines(e[l]),origin:n}}for(var a=t&&"end"!=t&&Vr(this,i,t),u=i.length-1;u>=0;u--)Ni(r,i[u]);a?mi(this,a):this.cm&&jn(this.cm)}),undo:pr(function(){Ai(this,"undo")}),redo:pr(function(){Ai(this,"redo")}),undoSelection:pr(function(){Ai(this,"undo",!0)}),redoSelection:pr(function(){Ai(this,"redo",!0)}),setExtending:function(e){this.extend=e},getExtending:function(){return this.extend},historySize:function(){for(var e=this.history,t=0,n=0,r=0;r<e.done.length;r++)e.done[r].ranges||++t;for(var i=0;i<e.undone.length;i++)e.undone[i].ranges||++n;return{undo:t,redo:n}},clearHistory:function(){this.history=new Qr(this.history.maxGeneration)},markClean:function(){this.cleanGeneration=this.changeGeneration(!0)},changeGeneration:function(e){return e&&(this.history.lastOp=this.history.lastSelOp=this.history.lastOrigin=null),this.history.generation},isClean:function(e){return this.history.generation==(e||this.cleanGeneration)},getHistory:function(){return{done:ci(this.history.done),undone:ci(this.history.undone)}},setHistory:function(e){var t=this.history=new Qr(this.history.maxGeneration);t.done=ci(e.done.slice(0),null,!0),t.undone=ci(e.undone.slice(0),null,!0)},setGutterMarker:pr(function(e,t,n){return Ri(this,e,"gutter",function(e){var r=e.gutterMarkers||(e.gutterMarkers={});return r[t]=n,!n&&C(r)&&(e.gutterMarkers=null),!0})}),clearGutter:pr(function(e){var t=this;this.iter(function(n){n.gutterMarkers&&n.gutterMarkers[e]&&Ri(t,n,"gutter",function(){return n.gutterMarkers[e]=null,C(n.gutterMarkers)&&(n.gutterMarkers=null),!0})})}),lineInfo:function(e){var t;if("number"==typeof e){if(!H(this,e))return null;if(t=e,!(e=T(this,e)))return null}else if(null==(t=W(e)))return null;return{line:t,handle:e,text:e.text,gutterMarkers:e.gutterMarkers,textClass:e.textClass,bgClass:e.bgClass,wrapClass:e.wrapClass,widgets:e.widgets}},addLineClass:pr(function(t,n,r){return Ri(this,t,"gutter"==n?"gutter":"class",function(t){var i="text"==n?"textClass":"background"==n?"bgClass":"gutter"==n?"gutterClass":"wrapClass";if(t[i]){if(e(r).test(t[i]))return!1;t[i]+=" "+r}else t[i]=r;return!0})}),removeLineClass:pr(function(t,n,r){return Ri(this,t,"gutter"==n?"gutter":"class",function(t){var i="text"==n?"textClass":"background"==n?"bgClass":"gutter"==n?"gutterClass":"wrapClass",o=t[i];if(!o)return!1;if(null==r)t[i]=null;else{var l=o.match(e(r));if(!l)return!1;var s=l.index+l[0].length;t[i]=o.slice(0,l.index)+(l.index&&s!=o.length?" ":"")+o.slice(s)||null}return!0})}),addLineWidget:pr(function(e,t,n){return Ui(this,e,t,n)}),removeLineWidget:function(e){e.clear()},markText:function(e,t,n){return Vi(this,U(this,e),U(this,t),n,n&&n.type||"range")},setBookmark:function(e,t){var n={replacedWith:t&&(null==t.nodeType?t.widget:t),insertLeft:t&&t.insertLeft,clearWhenEmpty:!1,shared:t&&t.shared,handleMouseEvents:t&&t.handleMouseEvents};return e=U(this,e),Vi(this,e,e,n,"bookmark")},findMarksAt:function(e){var t=[],n=T(this,(e=U(this,e)).line).markedSpans;if(n)for(var r=0;r<n.length;++r){var i=n[r];(null==i.from||i.from<=e.ch)&&(null==i.to||i.to>=e.ch)&&t.push(i.marker.parent||i.marker)}return t},findMarks:function(e,t,n){e=U(this,e),t=U(this,t);var r=[],i=e.line;return this.iter(e.line,t.line+1,function(o){var l=o.markedSpans;if(l)for(var s=0;s<l.length;s++){var a=l[s];null!=a.to&&i==e.line&&e.ch>=a.to||null==a.from&&i!=e.line||null!=a.from&&i==t.line&&a.from>=t.ch||n&&!n(a.marker)||r.push(a.marker.parent||a.marker)}++i}),r},getAllMarks:function(){var e=[];return this.iter(function(t){var n=t.markedSpans;if(n)for(var r=0;r<n.length;++r)null!=n[r].from&&e.push(n[r].marker)}),e},posFromIndex:function(e){var t,n=this.first,r=this.lineSeparator().length;return this.iter(function(i){var o=i.text.length+r;if(o>e)return t=e,!0;e-=o,++n}),U(this,E(n,t))},indexFromPos:function(e){var t=(e=U(this,e)).ch;if(e.line<this.first||e.ch<0)return 0;var n=this.lineSeparator().length;return this.iter(this.first,e.line,function(e){t+=e.text.length+n}),t},copy:function(e){var t=new Ms(O(this,this.first,this.first+this.size),this.modeOption,this.first,this.lineSep,this.direction);return t.scrollTop=this.scrollTop,t.scrollLeft=this.scrollLeft,t.sel=this.sel,t.extend=!1,e&&(t.history.undoDepth=this.history.undoDepth,t.setHistory(this.getHistory())),t},linkedDoc:function(e){e||(e={});var t=this.first,n=this.first+this.size;null!=e.from&&e.from>t&&(t=e.from),null!=e.to&&e.to<n&&(n=e.to);var r=new Ms(O(this,t,n),e.mode||this.modeOption,t,this.lineSep,this.direction);return e.sharedHist&&(r.history=this.history),(this.linked||(this.linked=[])).push({doc:r,sharedHist:e.sharedHist}),r.linked=[{doc:this,isParent:!0,sharedHist:e.sharedHist}],Xi(r,ji(this)),r},unlinkDoc:function(e){var t=this;if(e instanceof zo&&(e=e.doc),this.linked)for(var n=0;n<this.linked.length;++n)if(t.linked[n].doc==e){t.linked.splice(n,1),e.unlinkDoc(t),Yi(ji(t));break}if(e.history==this.history){var r=[e.id];_r(e,function(e){return r.push(e.id)},!0),e.history=new Qr(null),e.history.done=ci(this.history.done,r),e.history.undone=ci(this.history.undone,r)}},iterLinkedDocs:function(e){_r(this,e)},getMode:function(){return this.mode},getEditor:function(){return this.cm},splitLines:function(e){return this.lineSep?e.split(this.lineSep):_l(e)},lineSeparator:function(){return this.lineSep||"\n"},setDirection:pr(function(e){"rtl"!=e&&(e="ltr"),e!=this.direction&&(this.direction=e,this.iter(function(e){return e.order=null}),this.cm&&Zr(this.cm))})}),Ms.prototype.eachLine=Ms.prototype.iter;for(var Ts=0,Ns=!1,Os={3:"Enter",8:"Backspace",9:"Tab",13:"Enter",16:"Shift",17:"Ctrl",18:"Alt",19:"Pause",20:"CapsLock",27:"Esc",32:"Space",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"Left",38:"Up",39:"Right",40:"Down",44:"PrintScrn",45:"Insert",46:"Delete",59:";",61:"=",91:"Mod",92:"Mod",93:"Mod",106:"*",107:"=",109:"-",110:".",111:"/",127:"Delete",173:"-",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'",63232:"Up",63233:"Down",63234:"Left",63235:"Right",63272:"Delete",63273:"Home",63275:"End",63276:"PageUp",63277:"PageDown",63302:"Insert"},As=0;As<10;As++)Os[As+48]=Os[As+96]=String(As);for(var Ws=65;Ws<=90;Ws++)Os[Ws]=String.fromCharCode(Ws);for(var Ds=1;Ds<=12;Ds++)Os[Ds+111]=Os[Ds+63235]="F"+Ds;var Hs={};Hs.basic={Left:"goCharLeft",Right:"goCharRight",Up:"goLineUp",Down:"goLineDown",End:"goLineEnd",Home:"goLineStartSmart",PageUp:"goPageUp",PageDown:"goPageDown",Delete:"delCharAfter",Backspace:"delCharBefore","Shift-Backspace":"delCharBefore",Tab:"defaultTab","Shift-Tab":"indentAuto",Enter:"newlineAndIndent",Insert:"toggleOverwrite",Esc:"singleSelection"},Hs.pcDefault={"Ctrl-A":"selectAll","Ctrl-D":"deleteLine","Ctrl-Z":"undo","Shift-Ctrl-Z":"redo","Ctrl-Y":"redo","Ctrl-Home":"goDocStart","Ctrl-End":"goDocEnd","Ctrl-Up":"goLineUp","Ctrl-Down":"goLineDown","Ctrl-Left":"goGroupLeft","Ctrl-Right":"goGroupRight","Alt-Left":"goLineStart","Alt-Right":"goLineEnd","Ctrl-Backspace":"delGroupBefore","Ctrl-Delete":"delGroupAfter","Ctrl-S":"save","Ctrl-F":"find","Ctrl-G":"findNext","Shift-Ctrl-G":"findPrev","Shift-Ctrl-F":"replace","Shift-Ctrl-R":"replaceAll","Ctrl-[":"indentLess","Ctrl-]":"indentMore","Ctrl-U":"undoSelection","Shift-Ctrl-U":"redoSelection","Alt-U":"redoSelection",fallthrough:"basic"},Hs.emacsy={"Ctrl-F":"goCharRight","Ctrl-B":"goCharLeft","Ctrl-P":"goLineUp","Ctrl-N":"goLineDown","Alt-F":"goWordRight","Alt-B":"goWordLeft","Ctrl-A":"goLineStart","Ctrl-E":"goLineEnd","Ctrl-V":"goPageDown","Shift-Ctrl-V":"goPageUp","Ctrl-D":"delCharAfter","Ctrl-H":"delCharBefore","Alt-D":"delWordAfter","Alt-Backspace":"delWordBefore","Ctrl-K":"killLine","Ctrl-T":"transposeChars","Ctrl-O":"openLine"},Hs.macDefault={"Cmd-A":"selectAll","Cmd-D":"deleteLine","Cmd-Z":"undo","Shift-Cmd-Z":"redo","Cmd-Y":"redo","Cmd-Home":"goDocStart","Cmd-Up":"goDocStart","Cmd-End":"goDocEnd","Cmd-Down":"goDocEnd","Alt-Left":"goGroupLeft","Alt-Right":"goGroupRight","Cmd-Left":"goLineLeft","Cmd-Right":"goLineRight","Alt-Backspace":"delGroupBefore","Ctrl-Alt-Backspace":"delGroupAfter","Alt-Delete":"delGroupAfter","Cmd-S":"save","Cmd-F":"find","Cmd-G":"findNext","Shift-Cmd-G":"findPrev","Cmd-Alt-F":"replace","Shift-Cmd-Alt-F":"replaceAll","Cmd-[":"indentLess","Cmd-]":"indentMore","Cmd-Backspace":"delWrappedLineLeft","Cmd-Delete":"delWrappedLineRight","Cmd-U":"undoSelection","Shift-Cmd-U":"redoSelection","Ctrl-Up":"goDocStart","Ctrl-Down":"goDocEnd",fallthrough:["basic","emacsy"]},Hs.default=xl?Hs.macDefault:Hs.pcDefault;var Fs={selectAll:Mi,singleSelection:function(e){return e.setSelection(e.getCursor("anchor"),e.getCursor("head"),El)},killLine:function(e){return uo(e,function(t){if(t.empty()){var n=T(e.doc,t.head.line).text.length;return t.head.ch==n&&t.head.line<e.lastLine()?{from:t.head,to:E(t.head.line+1,0)}:{from:t.head,to:E(t.head.line,n)}}return{from:t.from(),to:t.to()}})},deleteLine:function(e){return uo(e,function(t){return{from:E(t.from().line,0),to:U(e.doc,E(t.to().line+1,0))}})},delLineLeft:function(e){return uo(e,function(e){return{from:E(e.from().line,0),to:e.from()}})},delWrappedLineLeft:function(e){return uo(e,function(t){var n=e.charCoords(t.head,"div").top+5;return{from:e.coordsChar({left:0,top:n},"div"),to:t.from()}})},delWrappedLineRight:function(e){return uo(e,function(t){var n=e.charCoords(t.head,"div").top+5,r=e.coordsChar({left:e.display.lineDiv.offsetWidth+100,top:n},"div");return{from:t.from(),to:r}})},undo:function(e){return e.undo()},redo:function(e){return e.redo()},undoSelection:function(e){return e.undoSelection()},redoSelection:function(e){return e.redoSelection()},goDocStart:function(e){return e.extendSelection(E(e.firstLine(),0))},goDocEnd:function(e){return e.extendSelection(E(e.lastLine()))},goLineStart:function(e){return e.extendSelectionsBy(function(t){return co(e,t.head.line)},{origin:"+move",bias:1})},goLineStartSmart:function(e){return e.extendSelectionsBy(function(t){return fo(e,t.head)},{origin:"+move",bias:1})},goLineEnd:function(e){return e.extendSelectionsBy(function(t){return ho(e,t.head.line)},{origin:"+move",bias:-1})},goLineRight:function(e){return e.extendSelectionsBy(function(t){var n=e.cursorCoords(t.head,"div").top+5;return e.coordsChar({left:e.display.lineDiv.offsetWidth+100,top:n},"div")},Il)},goLineLeft:function(e){return e.extendSelectionsBy(function(t){var n=e.cursorCoords(t.head,"div").top+5;return e.coordsChar({left:0,top:n},"div")},Il)},goLineLeftSmart:function(e){return e.extendSelectionsBy(function(t){var n=e.cursorCoords(t.head,"div").top+5,r=e.coordsChar({left:0,top:n},"div");return r.ch<e.getLine(r.line).search(/\S/)?fo(e,t.head):r},Il)},goLineUp:function(e){return e.moveV(-1,"line")},goLineDown:function(e){return e.moveV(1,"line")},goPageUp:function(e){return e.moveV(-1,"page")},goPageDown:function(e){return e.moveV(1,"page")},goCharLeft:function(e){return e.moveH(-1,"char")},goCharRight:function(e){return e.moveH(1,"char")},goColumnLeft:function(e){return e.moveH(-1,"column")},goColumnRight:function(e){return e.moveH(1,"column")},goWordLeft:function(e){return e.moveH(-1,"word")},goGroupRight:function(e){return e.moveH(1,"group")},goGroupLeft:function(e){return e.moveH(-1,"group")},goWordRight:function(e){return e.moveH(1,"word")},delCharBefore:function(e){return e.deleteH(-1,"char")},delCharAfter:function(e){return e.deleteH(1,"char")},delWordBefore:function(e){return e.deleteH(-1,"word")},delWordAfter:function(e){return e.deleteH(1,"word")},delGroupBefore:function(e){return e.deleteH(-1,"group")},delGroupAfter:function(e){return e.deleteH(1,"group")},indentAuto:function(e){return e.indentSelection("smart")},indentMore:function(e){return e.indentSelection("add")},indentLess:function(e){return e.indentSelection("subtract")},insertTab:function(e){return e.replaceSelection("\t")},insertSoftTab:function(e){for(var t=[],n=e.listSelections(),r=e.options.tabSize,i=0;i<n.length;i++){var o=n[i].from(),l=h(e.getLine(o.line),o.ch,r);t.push(p(r-l%r))}e.replaceSelections(t)},defaultTab:function(e){e.somethingSelected()?e.indentSelection("add"):e.execCommand("insertTab")},transposeChars:function(e){return hr(e,function(){for(var t=e.listSelections(),n=[],r=0;r<t.length;r++)if(t[r].empty()){var i=t[r].head,o=T(e.doc,i.line).text;if(o)if(i.ch==o.length&&(i=new E(i.line,i.ch-1)),i.ch>0)i=new E(i.line,i.ch+1),e.replaceRange(o.charAt(i.ch-1)+o.charAt(i.ch-2),E(i.line,i.ch-2),i,"+transpose");else if(i.line>e.doc.first){var l=T(e.doc,i.line-1).text;l&&(i=new E(i.line,1),e.replaceRange(o.charAt(0)+e.doc.lineSeparator()+l.charAt(l.length-1),E(i.line-1,l.length-1),i,"+transpose"))}n.push(new ws(i,i))}e.setSelections(n)})},newlineAndIndent:function(e){return hr(e,function(){for(var t=e.listSelections(),n=t.length-1;n>=0;n--)e.replaceRange(e.doc.lineSeparator(),t[n].anchor,t[n].head,"+input");t=e.listSelections();for(var r=0;r<t.length;r++)e.indentLine(t[r].from().line,null,!0);jn(e)})},openLine:function(e){return e.replaceSelection("\n","start")},toggleOverwrite:function(e){return e.toggleOverwrite()}},Es=new Al,Ps=null,Is=function(e,t,n){this.time=e,this.pos=t,this.button=n};Is.prototype.compare=function(e,t,n){return this.time+400>e&&0==P(t,this.pos)&&n==this.button};var Rs,zs,Bs={toString:function(){return"CodeMirror.Init"}},Gs={},Us={};zo.defaults=Gs,zo.optionHandlers=Us;var Vs=[];zo.defineInitHook=function(e){return Vs.push(e)};var Ks=null,js=function(e){this.cm=e,this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null,this.polling=new Al,this.composing=null,this.gracePeriod=!1,this.readDOMTimeout=null};js.prototype.init=function(e){function t(e){if(!We(i,e)){if(i.somethingSelected())Uo({lineWise:!1,text:i.getSelections()}),"cut"==e.type&&i.replaceSelection("",null,"cut");else{if(!i.options.lineWiseCopyCut)return;var t=Xo(i);Uo({lineWise:!0,text:t.text}),"cut"==e.type&&i.operation(function(){i.setSelections(t.ranges,0,El),i.replaceSelection("",null,"cut")})}if(e.clipboardData){e.clipboardData.clearData();var n=Ks.text.join("\n");if(e.clipboardData.setData("Text",n),e.clipboardData.getData("Text")==n)return void e.preventDefault()}var l=_o(),s=l.firstChild;i.display.lineSpace.insertBefore(l,i.display.lineSpace.firstChild),s.value=Ks.text.join("\n");var a=document.activeElement;Ol(s),setTimeout(function(){i.display.lineSpace.removeChild(l),a.focus(),a==o&&r.showPrimarySelection()},50)}}var n=this,r=this,i=r.cm,o=r.div=e.lineDiv;Yo(o,i.options.spellcheck),Xl(o,"paste",function(e){We(i,e)||Ko(e,i)||cl<=11&&setTimeout(fr(i,function(){return n.updateFromDOM()}),20)}),Xl(o,"compositionstart",function(e){n.composing={data:e.data,done:!1}}),Xl(o,"compositionupdate",function(e){n.composing||(n.composing={data:e.data,done:!1})}),Xl(o,"compositionend",function(e){n.composing&&(e.data!=n.composing.data&&n.readFromDOMSoon(),n.composing.done=!0)}),Xl(o,"touchstart",function(){return r.forceCompositionEnd()}),Xl(o,"input",function(){n.composing||n.readFromDOMSoon()}),Xl(o,"copy",t),Xl(o,"cut",t)},js.prototype.prepareSelection=function(){var e=Tn(this.cm,!1);return e.focus=this.cm.state.focused,e},js.prototype.showSelection=function(e,t){e&&this.cm.display.view.length&&((e.focus||t)&&this.showPrimarySelection(),this.showMultipleSelections(e))},js.prototype.showPrimarySelection=function(){var e=window.getSelection(),t=this.cm,n=t.doc.sel.primary(),r=n.from(),i=n.to();if(t.display.viewTo==t.display.viewFrom||r.line>=t.display.viewTo||i.line<t.display.viewFrom)e.removeAllRanges();else{var o=tl(t,e.anchorNode,e.anchorOffset),l=tl(t,e.focusNode,e.focusOffset);if(!o||o.bad||!l||l.bad||0!=P(B(o,l),r)||0!=P(z(o,l),i)){var s=t.display.view,a=r.line>=t.display.viewFrom&&Zo(t,r)||{node:s[0].measure.map[2],offset:0},u=i.line<t.display.viewTo&&Zo(t,i);if(!u){var c=s[s.length-1].measure,h=c.maps?c.maps[c.maps.length-1]:c.map;u={node:h[h.length-1],offset:h[h.length-2]-h[h.length-3]}}if(a&&u){var f,d=e.rangeCount&&e.getRangeAt(0);try{f=kl(a.node,a.offset,u.offset,u.node)}catch(e){}f&&(!ol&&t.state.focused?(e.collapse(a.node,a.offset),f.collapsed||(e.removeAllRanges(),e.addRange(f))):(e.removeAllRanges(),e.addRange(f)),d&&null==e.anchorNode?e.addRange(d):ol&&this.startGracePeriod()),this.rememberSelection()}else e.removeAllRanges()}}},js.prototype.startGracePeriod=function(){var e=this;clearTimeout(this.gracePeriod),this.gracePeriod=setTimeout(function(){e.gracePeriod=!1,e.selectionChanged()&&e.cm.operation(function(){return e.cm.curOp.selectionChanged=!0})},20)},js.prototype.showMultipleSelections=function(e){n(this.cm.display.cursorDiv,e.cursors),n(this.cm.display.selectionDiv,e.selection)},js.prototype.rememberSelection=function(){var e=window.getSelection();this.lastAnchorNode=e.anchorNode,this.lastAnchorOffset=e.anchorOffset,this.lastFocusNode=e.focusNode,this.lastFocusOffset=e.focusOffset},js.prototype.selectionInEditor=function(){var e=window.getSelection();if(!e.rangeCount)return!1;var t=e.getRangeAt(0).commonAncestorContainer;return o(this.div,t)},js.prototype.focus=function(){"nocursor"!=this.cm.options.readOnly&&(this.selectionInEditor()||this.showSelection(this.prepareSelection(),!0),this.div.focus())},js.prototype.blur=function(){this.div.blur()},js.prototype.getField=function(){return this.div},js.prototype.supportsTouch=function(){return!0},js.prototype.receivedFocus=function(){function e(){t.cm.state.focused&&(t.pollSelection(),t.polling.set(t.cm.options.pollInterval,e))}var t=this;this.selectionInEditor()?this.pollSelection():hr(this.cm,function(){return t.cm.curOp.selectionChanged=!0}),this.polling.set(this.cm.options.pollInterval,e)},js.prototype.selectionChanged=function(){var e=window.getSelection();return e.anchorNode!=this.lastAnchorNode||e.anchorOffset!=this.lastAnchorOffset||e.focusNode!=this.lastFocusNode||e.focusOffset!=this.lastFocusOffset},js.prototype.pollSelection=function(){if(null==this.readDOMTimeout&&!this.gracePeriod&&this.selectionChanged()){var e=window.getSelection(),t=this.cm;if(bl&&dl&&this.cm.options.gutters.length&&Qo(e.anchorNode))return this.cm.triggerOnKeyDown({type:"keydown",keyCode:8,preventDefault:Math.abs}),this.blur(),void this.focus();if(!this.composing){this.rememberSelection();var n=tl(t,e.anchorNode,e.anchorOffset),r=tl(t,e.focusNode,e.focusOffset);n&&r&&hr(t,function(){yi(t.doc,Rr(n,r),El),(n.bad||r.bad)&&(t.curOp.selectionChanged=!0)})}}},js.prototype.pollContent=function(){null!=this.readDOMTimeout&&(clearTimeout(this.readDOMTimeout),this.readDOMTimeout=null);var e=this.cm,t=e.display,n=e.doc.sel.primary(),r=n.from(),i=n.to();if(0==r.ch&&r.line>e.firstLine()&&(r=E(r.line-1,T(e.doc,r.line-1).length)),i.ch==T(e.doc,i.line).text.length&&i.line<e.lastLine()&&(i=E(i.line+1,0)),r.line<t.viewFrom||i.line>t.viewTo-1)return!1;var o,l,s;r.line==t.viewFrom||0==(o=kn(e,r.line))?(l=W(t.view[0].line),s=t.view[0].node):(l=W(t.view[o].line),s=t.view[o-1].node.nextSibling);var a,u,c=kn(e,i.line);if(c==t.view.length-1?(a=t.viewTo-1,u=t.lineDiv.lastChild):(a=W(t.view[c+1].line)-1,u=t.view[c+1].node.previousSibling),!s)return!1;for(var h=e.doc.splitLines(el(e,s,u,l,a)),f=N(e.doc,E(l,0),E(a,T(e.doc,a).text.length));h.length>1&&f.length>1;)if(g(h)==g(f))h.pop(),f.pop(),a--;else{if(h[0]!=f[0])break;h.shift(),f.shift(),l++}for(var d=0,p=0,v=h[0],m=f[0],y=Math.min(v.length,m.length);d<y&&v.charCodeAt(d)==m.charCodeAt(d);)++d;for(var b=g(h),w=g(f),x=Math.min(b.length-(1==h.length?d:0),w.length-(1==f.length?d:0));p<x&&b.charCodeAt(b.length-p-1)==w.charCodeAt(w.length-p-1);)++p;if(1==h.length&&1==f.length&&l==r.line)for(;d&&d>r.ch&&b.charCodeAt(b.length-p-1)==w.charCodeAt(w.length-p-1);)d--,p++;h[h.length-1]=b.slice(0,b.length-p).replace(/^\u200b+/,""),h[0]=h[0].slice(d).replace(/\u200b+$/,"");var C=E(l,d),S=E(a,f.length?g(f).length-p:0);return h.length>1||h[0]||P(C,S)?(Fi(e.doc,h,C,S,"+input"),!0):void 0},js.prototype.ensurePolled=function(){this.forceCompositionEnd()},js.prototype.reset=function(){this.forceCompositionEnd()},js.prototype.forceCompositionEnd=function(){this.composing&&(clearTimeout(this.readDOMTimeout),this.composing=null,this.updateFromDOM(),this.div.blur(),this.div.focus())},js.prototype.readFromDOMSoon=function(){var e=this;null==this.readDOMTimeout&&(this.readDOMTimeout=setTimeout(function(){if(e.readDOMTimeout=null,e.composing){if(!e.composing.done)return;e.composing=null}e.updateFromDOM()},80))},js.prototype.updateFromDOM=function(){var e=this;!this.cm.isReadOnly()&&this.pollContent()||hr(this.cm,function(){return gr(e.cm)})},js.prototype.setUneditable=function(e){e.contentEditable="false"},js.prototype.onKeyPress=function(e){0!=e.charCode&&(e.preventDefault(),this.cm.isReadOnly()||fr(this.cm,Vo)(this.cm,String.fromCharCode(null==e.charCode?e.keyCode:e.charCode),0))},js.prototype.readOnlyChanged=function(e){this.div.contentEditable=String("nocursor"!=e)},js.prototype.onContextMenu=function(){},js.prototype.resetPosition=function(){},js.prototype.needsContentAttribute=!0;var Xs=function(e){this.cm=e,this.prevInput="",this.pollingFast=!1,this.polling=new Al,this.hasSelection=!1,this.composing=null};Xs.prototype.init=function(e){function t(e){if(!We(i,e)){if(i.somethingSelected())Uo({lineWise:!1,text:i.getSelections()});else{if(!i.options.lineWiseCopyCut)return;var t=Xo(i);Uo({lineWise:!0,text:t.text}),"cut"==e.type?i.setSelections(t.ranges,null,El):(r.prevInput="",l.value=t.text.join("\n"),Ol(l))}"cut"==e.type&&(i.state.cutIncoming=!0)}}var n=this,r=this,i=this.cm,o=this.wrapper=_o(),l=this.textarea=o.firstChild;e.wrapper.insertBefore(o,e.wrapper.firstChild),yl&&(l.style.width="0px"),Xl(l,"input",function(){ul&&cl>=9&&n.hasSelection&&(n.hasSelection=null),r.poll()}),Xl(l,"paste",function(e){We(i,e)||Ko(e,i)||(i.state.pasteIncoming=!0,r.fastPoll())}),Xl(l,"cut",t),Xl(l,"copy",t),Xl(e.scroller,"paste",function(t){Rt(e,t)||We(i,t)||(i.state.pasteIncoming=!0,r.focus())}),Xl(e.lineSpace,"selectstart",function(t){Rt(e,t)||Ee(t)}),Xl(l,"compositionstart",function(){var e=i.getCursor("from");r.composing&&r.composing.range.clear(),r.composing={start:e,range:i.markText(e,i.getCursor("to"),{className:"CodeMirror-composing"})}}),Xl(l,"compositionend",function(){r.composing&&(r.poll(),r.composing.range.clear(),r.composing=null)})},Xs.prototype.prepareSelection=function(){var e=this.cm,t=e.display,n=e.doc,r=Tn(e);if(e.options.moveInputWithCursor){var i=hn(e,n.sel.primary().head,"div"),o=t.wrapper.getBoundingClientRect(),l=t.lineDiv.getBoundingClientRect();r.teTop=Math.max(0,Math.min(t.wrapper.clientHeight-10,i.top+l.top-o.top)),r.teLeft=Math.max(0,Math.min(t.wrapper.clientWidth-10,i.left+l.left-o.left))}return r},Xs.prototype.showSelection=function(e){var t=this.cm.display;n(t.cursorDiv,e.cursors),n(t.selectionDiv,e.selection),null!=e.teTop&&(this.wrapper.style.top=e.teTop+"px",this.wrapper.style.left=e.teLeft+"px")},Xs.prototype.reset=function(e){if(!this.contextMenuPending&&!this.composing){var t=this.cm;if(t.somethingSelected()){this.prevInput="";var n=t.getSelection();this.textarea.value=n,t.state.focused&&Ol(this.textarea),ul&&cl>=9&&(this.hasSelection=n)}else e||(this.prevInput=this.textarea.value="",ul&&cl>=9&&(this.hasSelection=null))}},Xs.prototype.getField=function(){return this.textarea},Xs.prototype.supportsTouch=function(){return!1},Xs.prototype.focus=function(){if("nocursor"!=this.cm.options.readOnly&&(!wl||l()!=this.textarea))try{this.textarea.focus()}catch(e){}},Xs.prototype.blur=function(){this.textarea.blur()},Xs.prototype.resetPosition=function(){this.wrapper.style.top=this.wrapper.style.left=0},Xs.prototype.receivedFocus=function(){this.slowPoll()},Xs.prototype.slowPoll=function(){var e=this;this.pollingFast||this.polling.set(this.cm.options.pollInterval,function(){e.poll(),e.cm.state.focused&&e.slowPoll()})},Xs.prototype.fastPoll=function(){function e(){n.poll()||t?(n.pollingFast=!1,n.slowPoll()):(t=!0,n.polling.set(60,e))}var t=!1,n=this;n.pollingFast=!0,n.polling.set(20,e)},Xs.prototype.poll=function(){var e=this,t=this.cm,n=this.textarea,r=this.prevInput;if(this.contextMenuPending||!t.state.focused||$l(n)&&!r&&!this.composing||t.isReadOnly()||t.options.disableInput||t.state.keySeq)return!1;var i=n.value;if(i==r&&!t.somethingSelected())return!1;if(ul&&cl>=9&&this.hasSelection===i||xl&&/[\uf700-\uf7ff]/.test(i))return t.display.input.reset(),!1;if(t.doc.sel==t.display.selForContextMenu){var o=i.charCodeAt(0);if(8203!=o||r||(r="​"),8666==o)return this.reset(),this.cm.execCommand("undo")}for(var l=0,s=Math.min(r.length,i.length);l<s&&r.charCodeAt(l)==i.charCodeAt(l);)++l;return hr(t,function(){Vo(t,i.slice(l),r.length-l,null,e.composing?"*compose":null),i.length>1e3||i.indexOf("\n")>-1?n.value=e.prevInput="":e.prevInput=i,e.composing&&(e.composing.range.clear(),e.composing.range=t.markText(e.composing.start,t.getCursor("to"),{className:"CodeMirror-composing"}))}),!0},Xs.prototype.ensurePolled=function(){this.pollingFast&&this.poll()&&(this.pollingFast=!1)},Xs.prototype.onKeyPress=function(){ul&&cl>=9&&(this.hasSelection=null),this.fastPoll()},Xs.prototype.onContextMenu=function(e){function t(){if(null!=l.selectionStart){var e=i.somethingSelected(),t="​"+(e?l.value:"");l.value="⇚",l.value=t,r.prevInput=e?"":"​",l.selectionStart=1,l.selectionEnd=t.length,o.selForContextMenu=i.doc.sel}}function n(){if(r.contextMenuPending=!1,r.wrapper.style.cssText=c,l.style.cssText=u,ul&&cl<9&&o.scrollbars.setScrollTop(o.scroller.scrollTop=a),null!=l.selectionStart){(!ul||ul&&cl<9)&&t();var e=0,n=function(){o.selForContextMenu==i.doc.sel&&0==l.selectionStart&&l.selectionEnd>0&&"​"==r.prevInput?fr(i,Mi)(i):e++<10?o.detectingSelectAll=setTimeout(n,500):(o.selForContextMenu=null,o.input.reset())};o.detectingSelectAll=setTimeout(n,200)}}var r=this,i=r.cm,o=i.display,l=r.textarea,s=Ln(i,e),a=o.scroller.scrollTop;if(s&&!pl){i.options.resetSelectionOnContextMenu&&-1==i.doc.sel.contains(s)&&fr(i,yi)(i.doc,Rr(s),El);var u=l.style.cssText,c=r.wrapper.style.cssText;r.wrapper.style.cssText="position: absolute";var h=r.wrapper.getBoundingClientRect();l.style.cssText="position: absolute; width: 30px; height: 30px;\n      top: "+(e.clientY-h.top-5)+"px; left: "+(e.clientX-h.left-5)+"px;\n      z-index: 1000; background: "+(ul?"rgba(255, 255, 255, .05)":"transparent")+";\n      outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";var f;if(hl&&(f=window.scrollY),o.input.focus(),hl&&window.scrollTo(null,f),o.input.reset(),i.somethingSelected()||(l.value=r.prevInput=" "),r.contextMenuPending=!0,o.selForContextMenu=i.doc.sel,clearTimeout(o.detectingSelectAll),ul&&cl>=9&&t(),Tl){Re(e);var d=function(){Oe(window,"mouseup",d),setTimeout(n,20)};Xl(window,"mouseup",d)}else setTimeout(n,50)}},Xs.prototype.readOnlyChanged=function(e){e||this.reset(),this.textarea.disabled="nocursor"==e},Xs.prototype.setUneditable=function(){},Xs.prototype.needsContentAttribute=!1,function(e){function t(t,r,i,o){e.defaults[t]=r,i&&(n[t]=o?function(e,t,n){n!=Bs&&i(e,t,n)}:i)}var n=e.optionHandlers;e.defineOption=t,e.Init=Bs,t("value","",function(e,t){return e.setValue(t)},!0),t("mode",null,function(e,t){e.doc.modeOption=t,Kr(e)},!0),t("indentUnit",2,Kr,!0),t("indentWithTabs",!1),t("smartIndent",!0),t("tabSize",4,function(e){jr(e),on(e),gr(e)},!0),t("lineSeparator",null,function(e,t){if(e.doc.lineSep=t,t){var n=[],r=e.doc.first;e.doc.iter(function(e){for(var i=0;;){var o=e.text.indexOf(t,i);if(-1==o)break;i=o+t.length,n.push(E(r,o))}r++});for(var i=n.length-1;i>=0;i--)Fi(e.doc,t,n[i],E(n[i].line,n[i].ch+t.length))}}),t("specialChars",/[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g,function(e,t,n){e.state.specialChars=new RegExp(t.source+(t.test("\t")?"":"|\t"),"g"),n!=Bs&&e.refresh()}),t("specialCharPlaceholder",ft,function(e){return e.refresh()},!0),t("electricChars",!0),t("inputStyle",wl?"contenteditable":"textarea",function(){throw new Error("inputStyle can not (yet) be changed in a running editor")},!0),t("spellcheck",!1,function(e,t){return e.getInputField().spellcheck=t},!0),t("rtlMoveVisually",!Sl),t("wholeLineUpdateBefore",!0),t("theme","default",function(e){Eo(e),Po(e)},!0),t("keyMap","default",function(e,t,n){var r=ao(t),i=n!=Bs&&ao(n);i&&i.detach&&i.detach(e,r),r.attach&&r.attach(e,i||null)}),t("extraKeys",null),t("configureMouse",null),t("lineWrapping",!1,Ro,!0),t("gutters",[],function(e){Hr(e.options),Po(e)},!0),t("fixedGutter",!0,function(e,t){e.display.gutters.style.left=t?xn(e.display)+"px":"0",e.refresh()},!0),t("coverGutterNextToScrollbar",!1,function(e){return er(e)},!0),t("scrollbarStyle","native",function(e){nr(e),er(e),e.display.scrollbars.setScrollTop(e.doc.scrollTop),e.display.scrollbars.setScrollLeft(e.doc.scrollLeft)},!0),t("lineNumbers",!1,function(e){Hr(e.options),Po(e)},!0),t("firstLineNumber",1,Po,!0),t("lineNumberFormatter",function(e){return e},Po,!0),t("showCursorWhenSelecting",!1,Mn,!0),t("resetSelectionOnContextMenu",!0),t("lineWiseCopyCut",!0),t("pasteLinesPerSelection",!0),t("readOnly",!1,function(e,t){"nocursor"==t&&(Fn(e),e.display.input.blur()),e.display.input.readOnlyChanged(t)}),t("disableInput",!1,function(e,t){t||e.display.input.reset()},!0),t("dragDrop",!0,Io),t("allowDropFileTypes",null),t("cursorBlinkRate",530),t("cursorScrollMargin",0),t("cursorHeight",1,Mn,!0),t("singleCursorHeightPerLine",!0,Mn,!0),t("workTime",100),t("workDelay",100),t("flattenSpans",!0,jr,!0),t("addModeClass",!1,jr,!0),t("pollInterval",100),t("undoDepth",200,function(e,t){return e.doc.history.undoDepth=t}),t("historyEventDelay",1250),t("viewportMargin",10,function(e){return e.refresh()},!0),t("maxHighlightLength",1e4,jr,!0),t("moveInputWithCursor",!0,function(e,t){t||e.display.input.resetPosition()}),t("tabindex",null,function(e,t){return e.display.input.getField().tabIndex=t||""}),t("autofocus",null),t("direction","ltr",function(e,t){return e.doc.setDirection(t)},!0)}(zo),function(e){var t=e.optionHandlers,n=e.helpers={};e.prototype={constructor:e,focus:function(){window.focus(),this.display.input.focus()},setOption:function(e,n){var r=this.options,i=r[e];r[e]==n&&"mode"!=e||(r[e]=n,t.hasOwnProperty(e)&&fr(this,t[e])(this,n,i),Ae(this,"optionChange",this,e))},getOption:function(e){return this.options[e]},getDoc:function(){return this.doc},addKeyMap:function(e,t){this.state.keyMaps[t?"push":"unshift"](ao(e))},removeKeyMap:function(e){for(var t=this.state.keyMaps,n=0;n<t.length;++n)if(t[n]==e||t[n].name==e)return t.splice(n,1),!0},addOverlay:dr(function(t,n){var r=t.token?t:e.getMode(this.options,t);if(r.startState)throw new Error("Overlays may not be stateful.");m(this.state.overlays,{mode:r,modeSpec:t,opaque:n&&n.opaque,priority:n&&n.priority||0},function(e){return e.priority}),this.state.modeGen++,gr(this)}),removeOverlay:dr(function(e){for(var t=this,n=this.state.overlays,r=0;r<n.length;++r){var i=n[r].modeSpec;if(i==e||"string"==typeof e&&i.name==e)return n.splice(r,1),t.state.modeGen++,void gr(t)}}),indentLine:dr(function(e,t,n){"string"!=typeof t&&"number"!=typeof t&&(t=null==t?this.options.smartIndent?"smart":"prev":t?"add":"subtract"),H(this.doc,e)&&Go(this,e,t,n)}),indentSelection:dr(function(e){for(var t=this,n=this.doc.sel.ranges,r=-1,i=0;i<n.length;i++){var o=n[i];if(o.empty())o.head.line>r&&(Go(t,o.head.line,e,!0),r=o.head.line,i==t.doc.sel.primIndex&&jn(t));else{var l=o.from(),s=o.to(),a=Math.max(r,l.line);r=Math.min(t.lastLine(),s.line-(s.ch?0:1))+1;for(var u=a;u<r;++u)Go(t,u,e);var c=t.doc.sel.ranges;0==l.ch&&n.length==c.length&&c[i].from().ch>0&&pi(t.doc,i,new ws(l,c[i].to()),El)}}}),getTokenAt:function(e,t){return rt(this,e,t)},getLineTokens:function(e,t){return rt(this,E(e),t,!0)},getTokenTypeAt:function(e){e=U(this.doc,e);var t,n=Qe(this,T(this.doc,e.line)),r=0,i=(n.length-1)/2,o=e.ch;if(0==o)t=n[2];else for(;;){var l=r+i>>1;if((l?n[2*l-1]:0)>=o)i=l;else{if(!(n[2*l+1]<o)){t=n[2*l+2];break}r=l+1}}var s=t?t.indexOf("overlay "):-1;return s<0?t:0==s?null:t.slice(0,s-1)},getModeAt:function(t){var n=this.doc.mode;return n.innerMode?e.innerMode(n,this.getTokenAt(t).state).mode:n},getHelper:function(e,t){return this.getHelpers(e,t)[0]},getHelpers:function(e,t){var r=this,i=[];if(!n.hasOwnProperty(t))return i;var o=n[t],l=this.getModeAt(e);if("string"==typeof l[t])o[l[t]]&&i.push(o[l[t]]);else if(l[t])for(var s=0;s<l[t].length;s++){var a=o[l[t][s]];a&&i.push(a)}else l.helperType&&o[l.helperType]?i.push(o[l.helperType]):o[l.name]&&i.push(o[l.name]);for(var u=0;u<o._global.length;u++){var c=o._global[u];c.pred(l,r)&&-1==f(i,c.val)&&i.push(c.val)}return i},getStateAfter:function(e,t){var n=this.doc;return e=G(n,null==e?n.first+n.size-1:e),Je(this,e+1,t).state},cursorCoords:function(e,t){var n,r=this.doc.sel.primary();return n=null==e?r.head:"object"==typeof e?U(this.doc,e):e?r.from():r.to(),hn(this,n,t||"page")},charCoords:function(e,t){return cn(this,U(this.doc,e),t||"page")},coordsChar:function(e,t){return e=un(this,e,t||"page"),pn(this,e.left,e.top)},lineAtHeight:function(e,t){return e=un(this,{top:e,left:0},t||"page").top,D(this.doc,e+this.display.viewOffset)},heightAtLine:function(e,t,n){var r,i=!1;if("number"==typeof e){var o=this.doc.first+this.doc.size-1;e<this.doc.first?e=this.doc.first:e>o&&(e=o,i=!0),r=T(this.doc,e)}else r=e;return an(this,r,{top:0,left:0},t||"page",n||i).top+(i?this.doc.height-ye(r):0)},defaultTextHeight:function(){return yn(this.display)},defaultCharWidth:function(){return bn(this.display)},getViewport:function(){return{from:this.display.viewFrom,to:this.display.viewTo}},addWidget:function(e,t,n,r,i){var o=this.display,l=(e=hn(this,U(this.doc,e))).bottom,s=e.left;if(t.style.position="absolute",t.setAttribute("cm-ignore-events","true"),this.display.input.setUneditable(t),o.sizer.appendChild(t),"over"==r)l=e.top;else if("above"==r||"near"==r){var a=Math.max(o.wrapper.clientHeight,this.doc.height),u=Math.max(o.sizer.clientWidth,o.lineSpace.clientWidth);("above"==r||e.bottom+t.offsetHeight>a)&&e.top>t.offsetHeight?l=e.top-t.offsetHeight:e.bottom+t.offsetHeight<=a&&(l=e.bottom),s+t.offsetWidth>u&&(s=u-t.offsetWidth)}t.style.top=l+"px",t.style.left=t.style.right="","right"==i?(s=o.sizer.clientWidth-t.offsetWidth,t.style.right="0px"):("left"==i?s=0:"middle"==i&&(s=(o.sizer.clientWidth-t.offsetWidth)/2),t.style.left=s+"px"),n&&Un(this,{left:s,top:l,right:s+t.offsetWidth,bottom:l+t.offsetHeight})},triggerOnKeyDown:dr(bo),triggerOnKeyPress:dr(Co),triggerOnKeyUp:xo,triggerOnMouseDown:dr(Lo),execCommand:function(e){if(Fs.hasOwnProperty(e))return Fs[e].call(null,this)},triggerElectric:dr(function(e){jo(this,e)}),findPosH:function(e,t,n,r){var i=this,o=1;t<0&&(o=-1,t=-t);for(var l=U(this.doc,e),s=0;s<t&&!(l=$o(i.doc,l,o,n,r)).hitSide;++s);return l},moveH:dr(function(e,t){var n=this;this.extendSelectionsBy(function(r){return n.display.shift||n.doc.extend||r.empty()?$o(n.doc,r.head,e,t,n.options.rtlMoveVisually):e<0?r.from():r.to()},Il)}),deleteH:dr(function(e,t){var n=this.doc.sel,r=this.doc;n.somethingSelected()?r.replaceSelection("",null,"+delete"):uo(this,function(n){var i=$o(r,n.head,e,t,!1);return e<0?{from:i,to:n.head}:{from:n.head,to:i}})}),findPosV:function(e,t,n,r){var i=this,o=1,l=r;t<0&&(o=-1,t=-t);for(var s=U(this.doc,e),a=0;a<t;++a){var u=hn(i,s,"div");if(null==l?l=u.left:u.left=l,(s=qo(i,u,o,n)).hitSide)break}return s},moveV:dr(function(e,t){var n=this,r=this.doc,i=[],o=!this.display.shift&&!r.extend&&r.sel.somethingSelected();if(r.extendSelectionsBy(function(l){if(o)return e<0?l.from():l.to();var s=hn(n,l.head,"div");null!=l.goalColumn&&(s.left=l.goalColumn),i.push(s.left);var a=qo(n,s,e,t);return"page"==t&&l==r.sel.primary()&&Kn(n,cn(n,a,"div").top-s.top),a},Il),i.length)for(var l=0;l<r.sel.ranges.length;l++)r.sel.ranges[l].goalColumn=i[l]}),findWordAt:function(e){var t=T(this.doc,e.line).text,n=e.ch,r=e.ch;if(t){var i=this.getHelper(e,"wordChars");"before"!=e.sticky&&r!=t.length||!n?++r:--n;for(var o=t.charAt(n),l=x(o,i)?function(e){return x(e,i)}:/\s/.test(o)?function(e){return/\s/.test(e)}:function(e){return!/\s/.test(e)&&!x(e)};n>0&&l(t.charAt(n-1));)--n;for(;r<t.length&&l(t.charAt(r));)++r}return new ws(E(e.line,n),E(e.line,r))},toggleOverwrite:function(e){null!=e&&e==this.state.overwrite||((this.state.overwrite=!this.state.overwrite)?s(this.display.cursorDiv,"CodeMirror-overwrite"):Nl(this.display.cursorDiv,"CodeMirror-overwrite"),Ae(this,"overwriteToggle",this,this.state.overwrite))},hasFocus:function(){return this.display.input.getField()==l()},isReadOnly:function(){return!(!this.options.readOnly&&!this.doc.cantEdit)},scrollTo:dr(function(e,t){Xn(this,e,t)}),getScrollInfo:function(){var e=this.display.scroller;return{left:e.scrollLeft,top:e.scrollTop,height:e.scrollHeight-Ut(this)-this.display.barHeight,width:e.scrollWidth-Ut(this)-this.display.barWidth,clientHeight:Kt(this),clientWidth:Vt(this)}},scrollIntoView:dr(function(e,t){null==e?(e={from:this.doc.sel.primary().head,to:null},null==t&&(t=this.options.cursorScrollMargin)):"number"==typeof e?e={from:E(e,0),to:null}:null==e.from&&(e={from:e,to:null}),e.to||(e.to=e.from),e.margin=t||0,null!=e.from.line?Yn(this,e):$n(this,e.from,e.to,e.margin)}),setSize:dr(function(e,t){var n=this,r=function(e){return"number"==typeof e||/^\d+$/.test(String(e))?e+"px":e};null!=e&&(this.display.wrapper.style.width=r(e)),null!=t&&(this.display.wrapper.style.height=r(t)),this.options.lineWrapping&&rn(this);var i=this.display.viewFrom;this.doc.iter(i,this.display.viewTo,function(e){if(e.widgets)for(var t=0;t<e.widgets.length;t++)if(e.widgets[t].noHScroll){vr(n,i,"widget");break}++i}),this.curOp.forceUpdate=!0,Ae(this,"refresh",this)}),operation:function(e){return hr(this,e)},startOperation:function(){return rr(this)},endOperation:function(){return ir(this)},refresh:dr(function(){var e=this.display.cachedTextHeight;gr(this),this.curOp.forceUpdate=!0,on(this),Xn(this,this.doc.scrollLeft,this.doc.scrollTop),Ar(this),(null==e||Math.abs(e-yn(this.display))>.5)&&Sn(this),Ae(this,"refresh",this)}),swapDoc:dr(function(e){var t=this.doc;return t.cm=null,$r(this,e),on(this),this.display.input.reset(),Xn(this,e.scrollLeft,e.scrollTop),this.curOp.forceScroll=!0,St(this,"swapDoc",this,t),t}),getInputField:function(){return this.display.input.getField()},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}},Fe(e),e.registerHelper=function(t,r,i){n.hasOwnProperty(t)||(n[t]=e[t]={_global:[]}),n[t][r]=i},e.registerGlobalHelper=function(t,r,i,o){e.registerHelper(t,r,o),n[t]._global.push({pred:i,val:o})}}(zo);var Ys="iter insert remove copy getEditor constructor".split(" ");for(var _s in Ms.prototype)Ms.prototype.hasOwnProperty(_s)&&f(Ys,_s)<0&&(zo.prototype[_s]=function(e){return function(){return e.apply(this.doc,arguments)}}(Ms.prototype[_s]));return Fe(Ms),zo.inputStyles={textarea:Xs,contenteditable:js},zo.defineMode=function(e){zo.defaults.mode||"null"==e||(zo.defaults.mode=e),Ke.apply(this,arguments)},zo.defineMIME=function(e,t){Jl[e]=t},zo.defineMode("null",function(){return{token:function(e){return e.skipToEnd()}}}),zo.defineMIME("text/plain","null"),zo.defineExtension=function(e,t){zo.prototype[e]=t},zo.defineDocExtension=function(e,t){Ms.prototype[e]=t},zo.fromTextArea=function(e,t){function n(){e.value=a.getValue()}if(t=t?c(t):{},t.value=e.value,!t.tabindex&&e.tabIndex&&(t.tabindex=e.tabIndex),!t.placeholder&&e.placeholder&&(t.placeholder=e.placeholder),null==t.autofocus){var r=l();t.autofocus=r==e||null!=e.getAttribute("autofocus")&&r==document.body}var i;if(e.form&&(Xl(e.form,"submit",n),!t.leaveSubmitMethodAlone)){var o=e.form;i=o.submit;try{var s=o.submit=function(){n(),o.submit=i,o.submit(),o.submit=s}}catch(e){}}t.finishInit=function(t){t.save=n,t.getTextArea=function(){return e},t.toTextArea=function(){t.toTextArea=isNaN,n(),e.parentNode.removeChild(t.getWrapperElement()),e.style.display="",e.form&&(Oe(e.form,"submit",n),"function"==typeof e.form.submit&&(e.form.submit=i))}},e.style.display="none";var a=zo(function(t){return e.parentNode.insertBefore(t,e.nextSibling)},t);return a},function(e){e.off=Oe,e.on=Xl,e.wheelEventPixels=Er,e.Doc=Ms,e.splitLines=_l,e.countColumn=h,e.findColumn=d,e.isWordChar=w,e.Pass=Fl,e.signal=Ae,e.Line=os,e.changeEnd=zr,e.scrollbarModel=ps,e.Pos=E,e.cmpPos=P,e.modes=Ql,e.mimeModes=Jl,e.resolveMode=je,e.getMode=Xe,e.modeExtensions=es,e.extendMode=Ye,e.copyState=_e,e.startState=qe,e.innerMode=$e,e.commands=Fs,e.keyMap=Hs,e.keyName=so,e.isModifierKey=oo,e.lookupKey=io,e.normalizeKeyMap=ro,e.StringStream=ts,e.SharedTextMarker=Ls,e.TextMarker=Ss,e.LineWidget=xs,e.e_preventDefault=Ee,e.e_stopPropagation=Pe,e.e_stop=Re,e.addClass=s,e.contains=o,e.rmClass=Nl,e.keyNames=Os}(zo),zo.version="5.29.0",zo});
\ No newline at end of file
diff --git a/themes/bookstack/static/libs/codemirror/modes.js b/themes/bookstack/static/libs/codemirror/modes.js
new file mode 100644 (file)
index 0000000..39efca3
--- /dev/null
@@ -0,0 +1,2535 @@
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+"use strict";
+
+CodeMirror.defineMode("css", function(config, parserConfig) {
+  var inline = parserConfig.inline
+  if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
+
+  var indentUnit = config.indentUnit,
+      tokenHooks = parserConfig.tokenHooks,
+      documentTypes = parserConfig.documentTypes || {},
+      mediaTypes = parserConfig.mediaTypes || {},
+      mediaFeatures = parserConfig.mediaFeatures || {},
+      mediaValueKeywords = parserConfig.mediaValueKeywords || {},
+      propertyKeywords = parserConfig.propertyKeywords || {},
+      nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {},
+      fontProperties = parserConfig.fontProperties || {},
+      counterDescriptors = parserConfig.counterDescriptors || {},
+      colorKeywords = parserConfig.colorKeywords || {},
+      valueKeywords = parserConfig.valueKeywords || {},
+      allowNested = parserConfig.allowNested,
+      lineComment = parserConfig.lineComment,
+      supportsAtComponent = parserConfig.supportsAtComponent === true;
+
+  var type, override;
+  function ret(style, tp) { type = tp; return style; }
+
+  // Tokenizers
+
+  function tokenBase(stream, state) {
+    var ch = stream.next();
+    if (tokenHooks[ch]) {
+      var result = tokenHooks[ch](stream, state);
+      if (result !== false) return result;
+    }
+    if (ch == "@") {
+      stream.eatWhile(/[\w\\\-]/);
+      return ret("def", stream.current());
+    } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
+      return ret(null, "compare");
+    } else if (ch == "\"" || ch == "'") {
+      state.tokenize = tokenString(ch);
+      return state.tokenize(stream, state);
+    } else if (ch == "#") {
+      stream.eatWhile(/[\w\\\-]/);
+      return ret("atom", "hash");
+    } else if (ch == "!") {
+      stream.match(/^\s*\w*/);
+      return ret("keyword", "important");
+    } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
+      stream.eatWhile(/[\w.%]/);
+      return ret("number", "unit");
+    } else if (ch === "-") {
+      if (/[\d.]/.test(stream.peek())) {
+        stream.eatWhile(/[\w.%]/);
+        return ret("number", "unit");
+      } else if (stream.match(/^-[\w\\\-]+/)) {
+        stream.eatWhile(/[\w\\\-]/);
+        if (stream.match(/^\s*:/, false))
+          return ret("variable-2", "variable-definition");
+        return ret("variable-2", "variable");
+      } else if (stream.match(/^\w+-/)) {
+        return ret("meta", "meta");
+      }
+    } else if (/[,+>*\/]/.test(ch)) {
+      return ret(null, "select-op");
+    } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
+      return ret("qualifier", "qualifier");
+    } else if (/[:;{}\[\]\(\)]/.test(ch)) {
+      return ret(null, ch);
+    } else if ((ch == "u" && stream.match(/rl(-prefix)?\(/)) ||
+               (ch == "d" && stream.match("omain(")) ||
+               (ch == "r" && stream.match("egexp("))) {
+      stream.backUp(1);
+      state.tokenize = tokenParenthesized;
+      return ret("property", "word");
+    } else if (/[\w\\\-]/.test(ch)) {
+      stream.eatWhile(/[\w\\\-]/);
+      return ret("property", "word");
+    } else {
+      return ret(null, null);
+    }
+  }
+
+  function tokenString(quote) {
+    return function(stream, state) {
+      var escaped = false, ch;
+      while ((ch = stream.next()) != null) {
+        if (ch == quote && !escaped) {
+          if (quote == ")") stream.backUp(1);
+          break;
+        }
+        escaped = !escaped && ch == "\\";
+      }
+      if (ch == quote || !escaped && quote != ")") state.tokenize = null;
+      return ret("string", "string");
+    };
+  }
+
+  function tokenParenthesized(stream, state) {
+    stream.next(); // Must be '('
+    if (!stream.match(/\s*[\"\')]/, false))
+      state.tokenize = tokenString(")");
+    else
+      state.tokenize = null;
+    return ret(null, "(");
+  }
+
+  // Context management
+
+  function Context(type, indent, prev) {
+    this.type = type;
+    this.indent = indent;
+    this.prev = prev;
+  }
+
+  function pushContext(state, stream, type, indent) {
+    state.context = new Context(type, stream.indentation() + (indent === false ? 0 : indentUnit), state.context);
+    return type;
+  }
+
+  function popContext(state) {
+    if (state.context.prev)
+      state.context = state.context.prev;
+    return state.context.type;
+  }
+
+  function pass(type, stream, state) {
+    return states[state.context.type](type, stream, state);
+  }
+  function popAndPass(type, stream, state, n) {
+    for (var i = n || 1; i > 0; i--)
+      state.context = state.context.prev;
+    return pass(type, stream, state);
+  }
+
+  // Parser
+
+  function wordAsValue(stream) {
+    var word = stream.current().toLowerCase();
+    if (valueKeywords.hasOwnProperty(word))
+      override = "atom";
+    else if (colorKeywords.hasOwnProperty(word))
+      override = "keyword";
+    else
+      override = "variable";
+  }
+
+  var states = {};
+
+  states.top = function(type, stream, state) {
+    if (type == "{") {
+      return pushContext(state, stream, "block");
+    } else if (type == "}" && state.context.prev) {
+      return popContext(state);
+    } else if (supportsAtComponent && /@component/.test(type)) {
+      return pushContext(state, stream, "atComponentBlock");
+    } else if (/^@(-moz-)?document$/.test(type)) {
+      return pushContext(state, stream, "documentTypes");
+    } else if (/^@(media|supports|(-moz-)?document|import)$/.test(type)) {
+      return pushContext(state, stream, "atBlock");
+    } else if (/^@(font-face|counter-style)/.test(type)) {
+      state.stateArg = type;
+      return "restricted_atBlock_before";
+    } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) {
+      return "keyframes";
+    } else if (type && type.charAt(0) == "@") {
+      return pushContext(state, stream, "at");
+    } else if (type == "hash") {
+      override = "builtin";
+    } else if (type == "word") {
+      override = "tag";
+    } else if (type == "variable-definition") {
+      return "maybeprop";
+    } else if (type == "interpolation") {
+      return pushContext(state, stream, "interpolation");
+    } else if (type == ":") {
+      return "pseudo";
+    } else if (allowNested && type == "(") {
+      return pushContext(state, stream, "parens");
+    }
+    return state.context.type;
+  };
+
+  states.block = function(type, stream, state) {
+    if (type == "word") {
+      var word = stream.current().toLowerCase();
+      if (propertyKeywords.hasOwnProperty(word)) {
+        override = "property";
+        return "maybeprop";
+      } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) {
+        override = "string-2";
+        return "maybeprop";
+      } else if (allowNested) {
+        override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag";
+        return "block";
+      } else {
+        override += " error";
+        return "maybeprop";
+      }
+    } else if (type == "meta") {
+      return "block";
+    } else if (!allowNested && (type == "hash" || type == "qualifier")) {
+      override = "error";
+      return "block";
+    } else {
+      return states.top(type, stream, state);
+    }
+  };
+
+  states.maybeprop = function(type, stream, state) {
+    if (type == ":") return pushContext(state, stream, "prop");
+    return pass(type, stream, state);
+  };
+
+  states.prop = function(type, stream, state) {
+    if (type == ";") return popContext(state);
+    if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
+    if (type == "}" || type == "{") return popAndPass(type, stream, state);
+    if (type == "(") return pushContext(state, stream, "parens");
+
+    if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) {
+      override += " error";
+    } else if (type == "word") {
+      wordAsValue(stream);
+    } else if (type == "interpolation") {
+      return pushContext(state, stream, "interpolation");
+    }
+    return "prop";
+  };
+
+  states.propBlock = function(type, _stream, state) {
+    if (type == "}") return popContext(state);
+    if (type == "word") { override = "property"; return "maybeprop"; }
+    return state.context.type;
+  };
+
+  states.parens = function(type, stream, state) {
+    if (type == "{" || type == "}") return popAndPass(type, stream, state);
+    if (type == ")") return popContext(state);
+    if (type == "(") return pushContext(state, stream, "parens");
+    if (type == "interpolation") return pushContext(state, stream, "interpolation");
+    if (type == "word") wordAsValue(stream);
+    return "parens";
+  };
+
+  states.pseudo = function(type, stream, state) {
+    if (type == "meta") return "pseudo";
+
+    if (type == "word") {
+      override = "variable-3";
+      return state.context.type;
+    }
+    return pass(type, stream, state);
+  };
+
+  states.documentTypes = function(type, stream, state) {
+    if (type == "word" && documentTypes.hasOwnProperty(stream.current())) {
+      override = "tag";
+      return state.context.type;
+    } else {
+      return states.atBlock(type, stream, state);
+    }
+  };
+
+  states.atBlock = function(type, stream, state) {
+    if (type == "(") return pushContext(state, stream, "atBlock_parens");
+    if (type == "}" || type == ";") return popAndPass(type, stream, state);
+    if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
+
+    if (type == "interpolation") return pushContext(state, stream, "interpolation");
+
+    if (type == "word") {
+      var word = stream.current().toLowerCase();
+      if (word == "only" || word == "not" || word == "and" || word == "or")
+        override = "keyword";
+      else if (mediaTypes.hasOwnProperty(word))
+        override = "attribute";
+      else if (mediaFeatures.hasOwnProperty(word))
+        override = "property";
+      else if (mediaValueKeywords.hasOwnProperty(word))
+        override = "keyword";
+      else if (propertyKeywords.hasOwnProperty(word))
+        override = "property";
+      else if (nonStandardPropertyKeywords.hasOwnProperty(word))
+        override = "string-2";
+      else if (valueKeywords.hasOwnProperty(word))
+        override = "atom";
+      else if (colorKeywords.hasOwnProperty(word))
+        override = "keyword";
+      else
+        override = "error";
+    }
+    return state.context.type;
+  };
+
+  states.atComponentBlock = function(type, stream, state) {
+    if (type == "}")
+      return popAndPass(type, stream, state);
+    if (type == "{")
+      return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top", false);
+    if (type == "word")
+      override = "error";
+    return state.context.type;
+  };
+
+  states.atBlock_parens = function(type, stream, state) {
+    if (type == ")") return popContext(state);
+    if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
+    return states.atBlock(type, stream, state);
+  };
+
+  states.restricted_atBlock_before = function(type, stream, state) {
+    if (type == "{")
+      return pushContext(state, stream, "restricted_atBlock");
+    if (type == "word" && state.stateArg == "@counter-style") {
+      override = "variable";
+      return "restricted_atBlock_before";
+    }
+    return pass(type, stream, state);
+  };
+
+  states.restricted_atBlock = function(type, stream, state) {
+    if (type == "}") {
+      state.stateArg = null;
+      return popContext(state);
+    }
+    if (type == "word") {
+      if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) ||
+          (state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase())))
+        override = "error";
+      else
+        override = "property";
+      return "maybeprop";
+    }
+    return "restricted_atBlock";
+  };
+
+  states.keyframes = function(type, stream, state) {
+    if (type == "word") { override = "variable"; return "keyframes"; }
+    if (type == "{") return pushContext(state, stream, "top");
+    return pass(type, stream, state);
+  };
+
+  states.at = function(type, stream, state) {
+    if (type == ";") return popContext(state);
+    if (type == "{" || type == "}") return popAndPass(type, stream, state);
+    if (type == "word") override = "tag";
+    else if (type == "hash") override = "builtin";
+    return "at";
+  };
+
+  states.interpolation = function(type, stream, state) {
+    if (type == "}") return popContext(state);
+    if (type == "{" || type == ";") return popAndPass(type, stream, state);
+    if (type == "word") override = "variable";
+    else if (type != "variable" && type != "(" && type != ")") override = "error";
+    return "interpolation";
+  };
+
+  return {
+    startState: function(base) {
+      return {tokenize: null,
+              state: inline ? "block" : "top",
+              stateArg: null,
+              context: new Context(inline ? "block" : "top", base || 0, null)};
+    },
+
+    token: function(stream, state) {
+      if (!state.tokenize && stream.eatSpace()) return null;
+      var style = (state.tokenize || tokenBase)(stream, state);
+      if (style && typeof style == "object") {
+        type = style[1];
+        style = style[0];
+      }
+      override = style;
+      if (type != "comment")
+        state.state = states[state.state](type, stream, state);
+      return override;
+    },
+
+    indent: function(state, textAfter) {
+      var cx = state.context, ch = textAfter && textAfter.charAt(0);
+      var indent = cx.indent;
+      if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev;
+      if (cx.prev) {
+        if (ch == "}" && (cx.type == "block" || cx.type == "top" ||
+                          cx.type == "interpolation" || cx.type == "restricted_atBlock")) {
+          // Resume indentation from parent context.
+          cx = cx.prev;
+          indent = cx.indent;
+        } else if (ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") ||
+            ch == "{" && (cx.type == "at" || cx.type == "atBlock")) {
+          // Dedent relative to current context.
+          indent = Math.max(0, cx.indent - indentUnit);
+        }
+      }
+      return indent;
+    },
+
+    electricChars: "}",
+    blockCommentStart: "/*",
+    blockCommentEnd: "*/",
+    lineComment: lineComment,
+    fold: "brace"
+  };
+});
+
+  function keySet(array) {
+    var keys = {};
+    for (var i = 0; i < array.length; ++i) {
+      keys[array[i].toLowerCase()] = true;
+    }
+    return keys;
+  }
+
+  var documentTypes_ = [
+    "domain", "regexp", "url", "url-prefix"
+  ], documentTypes = keySet(documentTypes_);
+
+  var mediaTypes_ = [
+    "all", "aural", "braille", "handheld", "print", "projection", "screen",
+    "tty", "tv", "embossed"
+  ], mediaTypes = keySet(mediaTypes_);
+
+  var mediaFeatures_ = [
+    "width", "min-width", "max-width", "height", "min-height", "max-height",
+    "device-width", "min-device-width", "max-device-width", "device-height",
+    "min-device-height", "max-device-height", "aspect-ratio",
+    "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
+    "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
+    "max-color", "color-index", "min-color-index", "max-color-index",
+    "monochrome", "min-monochrome", "max-monochrome", "resolution",
+    "min-resolution", "max-resolution", "scan", "grid", "orientation",
+    "device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio",
+    "pointer", "any-pointer", "hover", "any-hover"
+  ], mediaFeatures = keySet(mediaFeatures_);
+
+  var mediaValueKeywords_ = [
+    "landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover",
+    "interlace", "progressive"
+  ], mediaValueKeywords = keySet(mediaValueKeywords_);
+
+  var propertyKeywords_ = [
+    "align-content", "align-items", "align-self", "alignment-adjust",
+    "alignment-baseline", "anchor-point", "animation", "animation-delay",
+    "animation-direction", "animation-duration", "animation-fill-mode",
+    "animation-iteration-count", "animation-name", "animation-play-state",
+    "animation-timing-function", "appearance", "azimuth", "backface-visibility",
+    "background", "background-attachment", "background-blend-mode", "background-clip",
+    "background-color", "background-image", "background-origin", "background-position",
+    "background-repeat", "background-size", "baseline-shift", "binding",
+    "bleed", "bookmark-label", "bookmark-level", "bookmark-state",
+    "bookmark-target", "border", "border-bottom", "border-bottom-color",
+    "border-bottom-left-radius", "border-bottom-right-radius",
+    "border-bottom-style", "border-bottom-width", "border-collapse",
+    "border-color", "border-image", "border-image-outset",
+    "border-image-repeat", "border-image-slice", "border-image-source",
+    "border-image-width", "border-left", "border-left-color",
+    "border-left-style", "border-left-width", "border-radius", "border-right",
+    "border-right-color", "border-right-style", "border-right-width",
+    "border-spacing", "border-style", "border-top", "border-top-color",
+    "border-top-left-radius", "border-top-right-radius", "border-top-style",
+    "border-top-width", "border-width", "bottom", "box-decoration-break",
+    "box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
+    "caption-side", "caret-color", "clear", "clip", "color", "color-profile", "column-count",
+    "column-fill", "column-gap", "column-rule", "column-rule-color",
+    "column-rule-style", "column-rule-width", "column-span", "column-width",
+    "columns", "content", "counter-increment", "counter-reset", "crop", "cue",
+    "cue-after", "cue-before", "cursor", "direction", "display",
+    "dominant-baseline", "drop-initial-after-adjust",
+    "drop-initial-after-align", "drop-initial-before-adjust",
+    "drop-initial-before-align", "drop-initial-size", "drop-initial-value",
+    "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
+    "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
+    "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
+    "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
+    "font-stretch", "font-style", "font-synthesis", "font-variant",
+    "font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
+    "font-variant-ligatures", "font-variant-numeric", "font-variant-position",
+    "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
+    "grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap",
+    "grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap",
+    "grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns",
+    "grid-template-rows", "hanging-punctuation", "height", "hyphens",
+    "icon", "image-orientation", "image-rendering", "image-resolution",
+    "inline-box-align", "justify-content", "justify-items", "justify-self", "left", "letter-spacing",
+    "line-break", "line-height", "line-stacking", "line-stacking-ruby",
+    "line-stacking-shift", "line-stacking-strategy", "list-style",
+    "list-style-image", "list-style-position", "list-style-type", "margin",
+    "margin-bottom", "margin-left", "margin-right", "margin-top",
+    "marks", "marquee-direction", "marquee-loop",
+    "marquee-play-count", "marquee-speed", "marquee-style", "max-height",
+    "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
+    "nav-left", "nav-right", "nav-up", "object-fit", "object-position",
+    "opacity", "order", "orphans", "outline",
+    "outline-color", "outline-offset", "outline-style", "outline-width",
+    "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
+    "padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
+    "page", "page-break-after", "page-break-before", "page-break-inside",
+    "page-policy", "pause", "pause-after", "pause-before", "perspective",
+    "perspective-origin", "pitch", "pitch-range", "place-content", "place-items", "place-self", "play-during", "position",
+    "presentation-level", "punctuation-trim", "quotes", "region-break-after",
+    "region-break-before", "region-break-inside", "region-fragment",
+    "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
+    "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang",
+    "ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin",
+    "shape-outside", "size", "speak", "speak-as", "speak-header",
+    "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
+    "tab-size", "table-layout", "target", "target-name", "target-new",
+    "target-position", "text-align", "text-align-last", "text-decoration",
+    "text-decoration-color", "text-decoration-line", "text-decoration-skip",
+    "text-decoration-style", "text-emphasis", "text-emphasis-color",
+    "text-emphasis-position", "text-emphasis-style", "text-height",
+    "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
+    "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
+    "text-wrap", "top", "transform", "transform-origin", "transform-style",
+    "transition", "transition-delay", "transition-duration",
+    "transition-property", "transition-timing-function", "unicode-bidi",
+    "user-select", "vertical-align", "visibility", "voice-balance", "voice-duration",
+    "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
+    "voice-volume", "volume", "white-space", "widows", "width", "will-change", "word-break",
+    "word-spacing", "word-wrap", "z-index",
+    // SVG-specific
+    "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
+    "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
+    "color-interpolation", "color-interpolation-filters",
+    "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
+    "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
+    "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
+    "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
+    "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
+    "glyph-orientation-vertical", "text-anchor", "writing-mode"
+  ], propertyKeywords = keySet(propertyKeywords_);
+
+  var nonStandardPropertyKeywords_ = [
+    "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color",
+    "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color",
+    "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside",
+    "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button",
+    "searchfield-results-decoration", "zoom"
+  ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_);
+
+  var fontProperties_ = [
+    "font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
+    "font-stretch", "font-weight", "font-style"
+  ], fontProperties = keySet(fontProperties_);
+
+  var counterDescriptors_ = [
+    "additive-symbols", "fallback", "negative", "pad", "prefix", "range",
+    "speak-as", "suffix", "symbols", "system"
+  ], counterDescriptors = keySet(counterDescriptors_);
+
+  var colorKeywords_ = [
+    "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
+    "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
+    "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
+    "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
+    "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
+    "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
+    "darkslateblue", "darkslategray", "darkturquoise", "darkviolet",
+    "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick",
+    "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
+    "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew",
+    "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
+    "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
+    "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink",
+    "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray",
+    "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
+    "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
+    "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
+    "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
+    "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
+    "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
+    "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
+    "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown",
+    "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
+    "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
+    "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
+    "whitesmoke", "yellow", "yellowgreen"
+  ], colorKeywords = keySet(colorKeywords_);
+
+  var valueKeywords_ = [
+    "above", "absolute", "activeborder", "additive", "activecaption", "afar",
+    "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate",
+    "always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
+    "arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page",
+    "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
+    "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
+    "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel",
+    "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian",
+    "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
+    "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch",
+    "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
+    "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse",
+    "compact", "condensed", "contain", "content", "contents",
+    "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop",
+    "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal",
+    "decimal-leading-zero", "default", "default-button", "dense", "destination-atop",
+    "destination-in", "destination-out", "destination-over", "devanagari", "difference",
+    "disc", "discard", "disclosure-closed", "disclosure-open", "document",
+    "dot-dash", "dot-dot-dash",
+    "dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
+    "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
+    "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
+    "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
+    "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
+    "ethiopic-halehame-gez", "ethiopic-halehame-om-et",
+    "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
+    "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig",
+    "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed",
+    "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes",
+    "forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove",
+    "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew",
+    "help", "hidden", "hide", "higher", "highlight", "highlighttext",
+    "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "icon", "ignore",
+    "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
+    "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
+    "inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert",
+    "italic", "japanese-formal", "japanese-informal", "justify", "kannada",
+    "katakana", "katakana-iroha", "keep-all", "khmer",
+    "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal",
+    "landscape", "lao", "large", "larger", "left", "level", "lighter", "lighten",
+    "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem",
+    "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
+    "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
+    "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "match", "matrix", "matrix3d",
+    "media-controls-background", "media-current-time-display",
+    "media-fullscreen-button", "media-mute-button", "media-play-button",
+    "media-return-to-realtime-button", "media-rewind-button",
+    "media-seek-back-button", "media-seek-forward-button", "media-slider",
+    "media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
+    "media-volume-slider-container", "media-volume-sliderthumb", "medium",
+    "menu", "menulist", "menulist-button", "menulist-text",
+    "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
+    "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize",
+    "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
+    "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
+    "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote",
+    "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
+    "outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
+    "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter",
+    "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d",
+    "progress", "push-button", "radial-gradient", "radio", "read-only",
+    "read-write", "read-write-plaintext-only", "rectangle", "region",
+    "relative", "repeat", "repeating-linear-gradient",
+    "repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse",
+    "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY",
+    "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running",
+    "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen",
+    "scroll", "scrollbar", "scroll-position", "se-resize", "searchfield",
+    "searchfield-cancel-button", "searchfield-decoration",
+    "searchfield-results-button", "searchfield-results-decoration", "self-start", "self-end",
+    "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
+    "simp-chinese-formal", "simp-chinese-informal", "single",
+    "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal",
+    "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
+    "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali",
+    "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square",
+    "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub",
+    "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table",
+    "table-caption", "table-cell", "table-column", "table-column-group",
+    "table-footer-group", "table-header-group", "table-row", "table-row-group",
+    "tamil",
+    "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
+    "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
+    "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
+    "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
+    "trad-chinese-formal", "trad-chinese-informal", "transform",
+    "translate", "translate3d", "translateX", "translateY", "translateZ",
+    "transparent", "ultra-condensed", "ultra-expanded", "underline", "unset", "up",
+    "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
+    "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
+    "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
+    "visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
+    "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor",
+    "xx-large", "xx-small"
+  ], valueKeywords = keySet(valueKeywords_);
+
+  var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(mediaValueKeywords_)
+    .concat(propertyKeywords_).concat(nonStandardPropertyKeywords_).concat(colorKeywords_)
+    .concat(valueKeywords_);
+  CodeMirror.registerHelper("hintWords", "css", allWords);
+
+  function tokenCComment(stream, state) {
+    var maybeEnd = false, ch;
+    while ((ch = stream.next()) != null) {
+      if (maybeEnd && ch == "/") {
+        state.tokenize = null;
+        break;
+      }
+      maybeEnd = (ch == "*");
+    }
+    return ["comment", "comment"];
+  }
+
+  CodeMirror.defineMIME("text/css", {
+    documentTypes: documentTypes,
+    mediaTypes: mediaTypes,
+    mediaFeatures: mediaFeatures,
+    mediaValueKeywords: mediaValueKeywords,
+    propertyKeywords: propertyKeywords,
+    nonStandardPropertyKeywords: nonStandardPropertyKeywords,
+    fontProperties: fontProperties,
+    counterDescriptors: counterDescriptors,
+    colorKeywords: colorKeywords,
+    valueKeywords: valueKeywords,
+    tokenHooks: {
+      "/": function(stream, state) {
+        if (!stream.eat("*")) return false;
+        state.tokenize = tokenCComment;
+        return tokenCComment(stream, state);
+      }
+    },
+    name: "css"
+  });
+
+  CodeMirror.defineMIME("text/x-scss", {
+    mediaTypes: mediaTypes,
+    mediaFeatures: mediaFeatures,
+    mediaValueKeywords: mediaValueKeywords,
+    propertyKeywords: propertyKeywords,
+    nonStandardPropertyKeywords: nonStandardPropertyKeywords,
+    colorKeywords: colorKeywords,
+    valueKeywords: valueKeywords,
+    fontProperties: fontProperties,
+    allowNested: true,
+    lineComment: "//",
+    tokenHooks: {
+      "/": function(stream, state) {
+        if (stream.eat("/")) {
+          stream.skipToEnd();
+          return ["comment", "comment"];
+        } else if (stream.eat("*")) {
+          state.tokenize = tokenCComment;
+          return tokenCComment(stream, state);
+        } else {
+          return ["operator", "operator"];
+        }
+      },
+      ":": function(stream) {
+        if (stream.match(/\s*\{/, false))
+          return [null, null]
+        return false;
+      },
+      "$": function(stream) {
+        stream.match(/^[\w-]+/);
+        if (stream.match(/^\s*:/, false))
+          return ["variable-2", "variable-definition"];
+        return ["variable-2", "variable"];
+      },
+      "#": function(stream) {
+        if (!stream.eat("{")) return false;
+        return [null, "interpolation"];
+      }
+    },
+    name: "css",
+    helperType: "scss"
+  });
+
+  CodeMirror.defineMIME("text/x-less", {
+    mediaTypes: mediaTypes,
+    mediaFeatures: mediaFeatures,
+    mediaValueKeywords: mediaValueKeywords,
+    propertyKeywords: propertyKeywords,
+    nonStandardPropertyKeywords: nonStandardPropertyKeywords,
+    colorKeywords: colorKeywords,
+    valueKeywords: valueKeywords,
+    fontProperties: fontProperties,
+    allowNested: true,
+    lineComment: "//",
+    tokenHooks: {
+      "/": function(stream, state) {
+        if (stream.eat("/")) {
+          stream.skipToEnd();
+          return ["comment", "comment"];
+        } else if (stream.eat("*")) {
+          state.tokenize = tokenCComment;
+          return tokenCComment(stream, state);
+        } else {
+          return ["operator", "operator"];
+        }
+      },
+      "@": function(stream) {
+        if (stream.eat("{")) return [null, "interpolation"];
+        if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false;
+        stream.eatWhile(/[\w\\\-]/);
+        if (stream.match(/^\s*:/, false))
+          return ["variable-2", "variable-definition"];
+        return ["variable-2", "variable"];
+      },
+      "&": function() {
+        return ["atom", "atom"];
+      }
+    },
+    name: "css",
+    helperType: "less"
+  });
+
+  CodeMirror.defineMIME("text/x-gss", {
+    documentTypes: documentTypes,
+    mediaTypes: mediaTypes,
+    mediaFeatures: mediaFeatures,
+    propertyKeywords: propertyKeywords,
+    nonStandardPropertyKeywords: nonStandardPropertyKeywords,
+    fontProperties: fontProperties,
+    counterDescriptors: counterDescriptors,
+    colorKeywords: colorKeywords,
+    valueKeywords: valueKeywords,
+    supportsAtComponent: true,
+    tokenHooks: {
+      "/": function(stream, state) {
+        if (!stream.eat("*")) return false;
+        state.tokenize = tokenCComment;
+        return tokenCComment(stream, state);
+      }
+    },
+    name: "css",
+    helperType: "gss"
+  });
+
+});
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+  "use strict";
+
+  var defaultTags = {
+    script: [
+      ["lang", /(javascript|babel)/i, "javascript"],
+      ["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i, "javascript"],
+      ["type", /./, "text/plain"],
+      [null, null, "javascript"]
+    ],
+    style:  [
+      ["lang", /^css$/i, "css"],
+      ["type", /^(text\/)?(x-)?(stylesheet|css)$/i, "css"],
+      ["type", /./, "text/plain"],
+      [null, null, "css"]
+    ]
+  };
+
+  function maybeBackup(stream, pat, style) {
+    var cur = stream.current(), close = cur.search(pat);
+    if (close > -1) {
+      stream.backUp(cur.length - close);
+    } else if (cur.match(/<\/?$/)) {
+      stream.backUp(cur.length);
+      if (!stream.match(pat, false)) stream.match(cur);
+    }
+    return style;
+  }
+
+  var attrRegexpCache = {};
+  function getAttrRegexp(attr) {
+    var regexp = attrRegexpCache[attr];
+    if (regexp) return regexp;
+    return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*");
+  }
+
+  function getAttrValue(text, attr) {
+    var match = text.match(getAttrRegexp(attr))
+    return match ? /^\s*(.*?)\s*$/.exec(match[2])[1] : ""
+  }
+
+  function getTagRegexp(tagName, anchored) {
+    return new RegExp((anchored ? "^" : "") + "<\/\s*" + tagName + "\s*>", "i");
+  }
+
+  function addTags(from, to) {
+    for (var tag in from) {
+      var dest = to[tag] || (to[tag] = []);
+      var source = from[tag];
+      for (var i = source.length - 1; i >= 0; i--)
+        dest.unshift(source[i])
+    }
+  }
+
+  function findMatchingMode(tagInfo, tagText) {
+    for (var i = 0; i < tagInfo.length; i++) {
+      var spec = tagInfo[i];
+      if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) return spec[2];
+    }
+  }
+
+  CodeMirror.defineMode("htmlmixed", function (config, parserConfig) {
+    var htmlMode = CodeMirror.getMode(config, {
+      name: "xml",
+      htmlMode: true,
+      multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,
+      multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag
+    });
+
+    var tags = {};
+    var configTags = parserConfig && parserConfig.tags, configScript = parserConfig && parserConfig.scriptTypes;
+    addTags(defaultTags, tags);
+    if (configTags) addTags(configTags, tags);
+    if (configScript) for (var i = configScript.length - 1; i >= 0; i--)
+      tags.script.unshift(["type", configScript[i].matches, configScript[i].mode])
+
+    function html(stream, state) {
+      var style = htmlMode.token(stream, state.htmlState), tag = /\btag\b/.test(style), tagName
+      if (tag && !/[<>\s\/]/.test(stream.current()) &&
+          (tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) &&
+          tags.hasOwnProperty(tagName)) {
+        state.inTag = tagName + " "
+      } else if (state.inTag && tag && />$/.test(stream.current())) {
+        var inTag = /^([\S]+) (.*)/.exec(state.inTag)
+        state.inTag = null
+        var modeSpec = stream.current() == ">" && findMatchingMode(tags[inTag[1]], inTag[2])
+        var mode = CodeMirror.getMode(config, modeSpec)
+        var endTagA = getTagRegexp(inTag[1], true), endTag = getTagRegexp(inTag[1], false);
+        state.token = function (stream, state) {
+          if (stream.match(endTagA, false)) {
+            state.token = html;
+            state.localState = state.localMode = null;
+            return null;
+          }
+          return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState));
+        };
+        state.localMode = mode;
+        state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, ""));
+      } else if (state.inTag) {
+        state.inTag += stream.current()
+        if (stream.eol()) state.inTag += " "
+      }
+      return style;
+    };
+
+    return {
+      startState: function () {
+        var state = CodeMirror.startState(htmlMode);
+        return {token: html, inTag: null, localMode: null, localState: null, htmlState: state};
+      },
+
+      copyState: function (state) {
+        var local;
+        if (state.localState) {
+          local = CodeMirror.copyState(state.localMode, state.localState);
+        }
+        return {token: state.token, inTag: state.inTag,
+                localMode: state.localMode, localState: local,
+                htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
+      },
+
+      token: function (stream, state) {
+        return state.token(stream, state);
+      },
+
+      indent: function (state, textAfter, line) {
+        if (!state.localMode || /^\s*<\//.test(textAfter))
+          return htmlMode.indent(state.htmlState, textAfter);
+        else if (state.localMode.indent)
+          return state.localMode.indent(state.localState, textAfter, line);
+        else
+          return CodeMirror.Pass;
+      },
+
+      innerMode: function (state) {
+        return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
+      }
+    };
+  }, "xml", "javascript", "css");
+
+  CodeMirror.defineMIME("text/html", "htmlmixed");
+});
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+"use strict";
+
+CodeMirror.defineMode("javascript", function(config, parserConfig) {
+  var indentUnit = config.indentUnit;
+  var statementIndent = parserConfig.statementIndent;
+  var jsonldMode = parserConfig.jsonld;
+  var jsonMode = parserConfig.json || jsonldMode;
+  var isTS = parserConfig.typescript;
+  var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
+
+  // Tokenizer
+
+  var keywords = function(){
+    function kw(type) {return {type: type, style: "keyword"};}
+    var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
+    var operator = kw("operator"), atom = {type: "atom", style: "atom"};
+
+    var jsKeywords = {
+      "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
+      "return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C,
+      "var": kw("var"), "const": kw("var"), "let": kw("var"),
+      "function": kw("function"), "catch": kw("catch"),
+      "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
+      "in": operator, "typeof": operator, "instanceof": operator,
+      "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
+      "this": kw("this"), "class": kw("class"), "super": kw("atom"),
+      "yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
+      "await": C
+    };
+
+    // Extend the 'normal' keywords with the TypeScript language extensions
+    if (isTS) {
+      var type = {type: "variable", style: "type"};
+      var tsKeywords = {
+        // object-like things
+        "interface": kw("class"),
+        "implements": C,
+        "namespace": C,
+        "module": kw("module"),
+        "enum": kw("module"),
+
+        // scope modifiers
+        "public": kw("modifier"),
+        "private": kw("modifier"),
+        "protected": kw("modifier"),
+        "abstract": kw("modifier"),
+        "readonly": kw("modifier"),
+
+        // types
+        "string": type, "number": type, "boolean": type, "any": type
+      };
+
+      for (var attr in tsKeywords) {
+        jsKeywords[attr] = tsKeywords[attr];
+      }
+    }
+
+    return jsKeywords;
+  }();
+
+  var isOperatorChar = /[+\-*&%=<>!?|~^@]/;
+  var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
+
+  function readRegexp(stream) {
+    var escaped = false, next, inSet = false;
+    while ((next = stream.next()) != null) {
+      if (!escaped) {
+        if (next == "/" && !inSet) return;
+        if (next == "[") inSet = true;
+        else if (inSet && next == "]") inSet = false;
+      }
+      escaped = !escaped && next == "\\";
+    }
+  }
+
+  // Used as scratch variables to communicate multiple values without
+  // consing up tons of objects.
+  var type, content;
+  function ret(tp, style, cont) {
+    type = tp; content = cont;
+    return style;
+  }
+  function tokenBase(stream, state) {
+    var ch = stream.next();
+    if (ch == '"' || ch == "'") {
+      state.tokenize = tokenString(ch);
+      return state.tokenize(stream, state);
+    } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
+      return ret("number", "number");
+    } else if (ch == "." && stream.match("..")) {
+      return ret("spread", "meta");
+    } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
+      return ret(ch);
+    } else if (ch == "=" && stream.eat(">")) {
+      return ret("=>", "operator");
+    } else if (ch == "0" && stream.eat(/x/i)) {
+      stream.eatWhile(/[\da-f]/i);
+      return ret("number", "number");
+    } else if (ch == "0" && stream.eat(/o/i)) {
+      stream.eatWhile(/[0-7]/i);
+      return ret("number", "number");
+    } else if (ch == "0" && stream.eat(/b/i)) {
+      stream.eatWhile(/[01]/i);
+      return ret("number", "number");
+    } else if (/\d/.test(ch)) {
+      stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
+      return ret("number", "number");
+    } else if (ch == "/") {
+      if (stream.eat("*")) {
+        state.tokenize = tokenComment;
+        return tokenComment(stream, state);
+      } else if (stream.eat("/")) {
+        stream.skipToEnd();
+        return ret("comment", "comment");
+      } else if (expressionAllowed(stream, state, 1)) {
+        readRegexp(stream);
+        stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
+        return ret("regexp", "string-2");
+      } else {
+        stream.eatWhile(isOperatorChar);
+        return ret("operator", "operator", stream.current());
+      }
+    } else if (ch == "`") {
+      state.tokenize = tokenQuasi;
+      return tokenQuasi(stream, state);
+    } else if (ch == "#") {
+      stream.skipToEnd();
+      return ret("error", "error");
+    } else if (isOperatorChar.test(ch)) {
+      if (ch != ">" || !state.lexical || state.lexical.type != ">")
+        stream.eatWhile(isOperatorChar);
+      return ret("operator", "operator", stream.current());
+    } else if (wordRE.test(ch)) {
+      stream.eatWhile(wordRE);
+      var word = stream.current()
+      if (state.lastType != ".") {
+        if (keywords.propertyIsEnumerable(word)) {
+          var kw = keywords[word]
+          return ret(kw.type, kw.style, word)
+        }
+        if (word == "async" && stream.match(/^\s*[\(\w]/, false))
+          return ret("async", "keyword", word)
+      }
+      return ret("variable", "variable", word)
+    }
+  }
+
+  function tokenString(quote) {
+    return function(stream, state) {
+      var escaped = false, next;
+      if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
+        state.tokenize = tokenBase;
+        return ret("jsonld-keyword", "meta");
+      }
+      while ((next = stream.next()) != null) {
+        if (next == quote && !escaped) break;
+        escaped = !escaped && next == "\\";
+      }
+      if (!escaped) state.tokenize = tokenBase;
+      return ret("string", "string");
+    };
+  }
+
+  function tokenComment(stream, state) {
+    var maybeEnd = false, ch;
+    while (ch = stream.next()) {
+      if (ch == "/" && maybeEnd) {
+        state.tokenize = tokenBase;
+        break;
+      }
+      maybeEnd = (ch == "*");
+    }
+    return ret("comment", "comment");
+  }
+
+  function tokenQuasi(stream, state) {
+    var escaped = false, next;
+    while ((next = stream.next()) != null) {
+      if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
+        state.tokenize = tokenBase;
+        break;
+      }
+      escaped = !escaped && next == "\\";
+    }
+    return ret("quasi", "string-2", stream.current());
+  }
+
+  var brackets = "([{}])";
+  // This is a crude lookahead trick to try and notice that we're
+  // parsing the argument patterns for a fat-arrow function before we
+  // actually hit the arrow token. It only works if the arrow is on
+  // the same line as the arguments and there's no strange noise
+  // (comments) in between. Fallback is to only notice when we hit the
+  // arrow, and not declare the arguments as locals for the arrow
+  // body.
+  function findFatArrow(stream, state) {
+    if (state.fatArrowAt) state.fatArrowAt = null;
+    var arrow = stream.string.indexOf("=>", stream.start);
+    if (arrow < 0) return;
+
+    if (isTS) { // Try to skip TypeScript return type declarations after the arguments
+      var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow))
+      if (m) arrow = m.index
+    }
+
+    var depth = 0, sawSomething = false;
+    for (var pos = arrow - 1; pos >= 0; --pos) {
+      var ch = stream.string.charAt(pos);
+      var bracket = brackets.indexOf(ch);
+      if (bracket >= 0 && bracket < 3) {
+        if (!depth) { ++pos; break; }
+        if (--depth == 0) { if (ch == "(") sawSomething = true; break; }
+      } else if (bracket >= 3 && bracket < 6) {
+        ++depth;
+      } else if (wordRE.test(ch)) {
+        sawSomething = true;
+      } else if (/["'\/]/.test(ch)) {
+        return;
+      } else if (sawSomething && !depth) {
+        ++pos;
+        break;
+      }
+    }
+    if (sawSomething && !depth) state.fatArrowAt = pos;
+  }
+
+  // Parser
+
+  var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
+
+  function JSLexical(indented, column, type, align, prev, info) {
+    this.indented = indented;
+    this.column = column;
+    this.type = type;
+    this.prev = prev;
+    this.info = info;
+    if (align != null) this.align = align;
+  }
+
+  function inScope(state, varname) {
+    for (var v = state.localVars; v; v = v.next)
+      if (v.name == varname) return true;
+    for (var cx = state.context; cx; cx = cx.prev) {
+      for (var v = cx.vars; v; v = v.next)
+        if (v.name == varname) return true;
+    }
+  }
+
+  function parseJS(state, style, type, content, stream) {
+    var cc = state.cc;
+    // Communicate our context to the combinators.
+    // (Less wasteful than consing up a hundred closures on every call.)
+    cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
+
+    if (!state.lexical.hasOwnProperty("align"))
+      state.lexical.align = true;
+
+    while(true) {
+      var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
+      if (combinator(type, content)) {
+        while(cc.length && cc[cc.length - 1].lex)
+          cc.pop()();
+        if (cx.marked) return cx.marked;
+        if (type == "variable" && inScope(state, content)) return "variable-2";
+        return style;
+      }
+    }
+  }
+
+  // Combinator utils
+
+  var cx = {state: null, column: null, marked: null, cc: null};
+  function pass() {
+    for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
+  }
+  function cont() {
+    pass.apply(null, arguments);
+    return true;
+  }
+  function register(varname) {
+    function inList(list) {
+      for (var v = list; v; v = v.next)
+        if (v.name == varname) return true;
+      return false;
+    }
+    var state = cx.state;
+    cx.marked = "def";
+    if (state.context) {
+      if (inList(state.localVars)) return;
+      state.localVars = {name: varname, next: state.localVars};
+    } else {
+      if (inList(state.globalVars)) return;
+      if (parserConfig.globalVars)
+        state.globalVars = {name: varname, next: state.globalVars};
+    }
+  }
+
+  // Combinators
+
+  var defaultVars = {name: "this", next: {name: "arguments"}};
+  function pushcontext() {
+    cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
+    cx.state.localVars = defaultVars;
+  }
+  function popcontext() {
+    cx.state.localVars = cx.state.context.vars;
+    cx.state.context = cx.state.context.prev;
+  }
+  function pushlex(type, info) {
+    var result = function() {
+      var state = cx.state, indent = state.indented;
+      if (state.lexical.type == "stat") indent = state.lexical.indented;
+      else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
+        indent = outer.indented;
+      state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
+    };
+    result.lex = true;
+    return result;
+  }
+  function poplex() {
+    var state = cx.state;
+    if (state.lexical.prev) {
+      if (state.lexical.type == ")")
+        state.indented = state.lexical.indented;
+      state.lexical = state.lexical.prev;
+    }
+  }
+  poplex.lex = true;
+
+  function expect(wanted) {
+    function exp(type) {
+      if (type == wanted) return cont();
+      else if (wanted == ";") return pass();
+      else return cont(exp);
+    };
+    return exp;
+  }
+
+  function statement(type, value) {
+    if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
+    if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex);
+    if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
+    if (type == "{") return cont(pushlex("}"), block, poplex);
+    if (type == ";") return cont();
+    if (type == "if") {
+      if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
+        cx.state.cc.pop()();
+      return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse);
+    }
+    if (type == "function") return cont(functiondef);
+    if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
+    if (type == "variable") {
+      if (isTS && value == "type") {
+        cx.marked = "keyword"
+        return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
+      } if (isTS && value == "declare") {
+        cx.marked = "keyword"
+        return cont(statement)
+      } else {
+        return cont(pushlex("stat"), maybelabel);
+      }
+    }
+    if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"),
+                                      block, poplex, poplex);
+    if (type == "case") return cont(expression, expect(":"));
+    if (type == "default") return cont(expect(":"));
+    if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
+                                     statement, poplex, popcontext);
+    if (type == "class") return cont(pushlex("form"), className, poplex);
+    if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
+    if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
+    if (type == "module") return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
+    if (type == "async") return cont(statement)
+    if (value == "@") return cont(expression, statement)
+    return pass(pushlex("stat"), expression, expect(";"), poplex);
+  }
+  function expression(type) {
+    return expressionInner(type, false);
+  }
+  function expressionNoComma(type) {
+    return expressionInner(type, true);
+  }
+  function parenExpr(type) {
+    if (type != "(") return pass()
+    return cont(pushlex(")"), expression, expect(")"), poplex)
+  }
+  function expressionInner(type, noComma) {
+    if (cx.state.fatArrowAt == cx.stream.start) {
+      var body = noComma ? arrowBodyNoComma : arrowBody;
+      if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
+      else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
+    }
+
+    var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
+    if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
+    if (type == "function") return cont(functiondef, maybeop);
+    if (type == "class") return cont(pushlex("form"), classExpression, poplex);
+    if (type == "keyword c" || type == "async") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
+    if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
+    if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
+    if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
+    if (type == "{") return contCommasep(objprop, "}", null, maybeop);
+    if (type == "quasi") return pass(quasi, maybeop);
+    if (type == "new") return cont(maybeTarget(noComma));
+    return cont();
+  }
+  function maybeexpression(type) {
+    if (type.match(/[;\}\)\],]/)) return pass();
+    return pass(expression);
+  }
+  function maybeexpressionNoComma(type) {
+    if (type.match(/[;\}\)\],]/)) return pass();
+    return pass(expressionNoComma);
+  }
+
+  function maybeoperatorComma(type, value) {
+    if (type == ",") return cont(expression);
+    return maybeoperatorNoComma(type, value, false);
+  }
+  function maybeoperatorNoComma(type, value, noComma) {
+    var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
+    var expr = noComma == false ? expression : expressionNoComma;
+    if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
+    if (type == "operator") {
+      if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me);
+      if (value == "?") return cont(expression, expect(":"), expr);
+      return cont(expr);
+    }
+    if (type == "quasi") { return pass(quasi, me); }
+    if (type == ";") return;
+    if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
+    if (type == ".") return cont(property, me);
+    if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
+    if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) }
+  }
+  function quasi(type, value) {
+    if (type != "quasi") return pass();
+    if (value.slice(value.length - 2) != "${") return cont(quasi);
+    return cont(expression, continueQuasi);
+  }
+  function continueQuasi(type) {
+    if (type == "}") {
+      cx.marked = "string-2";
+      cx.state.tokenize = tokenQuasi;
+      return cont(quasi);
+    }
+  }
+  function arrowBody(type) {
+    findFatArrow(cx.stream, cx.state);
+    return pass(type == "{" ? statement : expression);
+  }
+  function arrowBodyNoComma(type) {
+    findFatArrow(cx.stream, cx.state);
+    return pass(type == "{" ? statement : expressionNoComma);
+  }
+  function maybeTarget(noComma) {
+    return function(type) {
+      if (type == ".") return cont(noComma ? targetNoComma : target);
+      else if (type == "variable" && isTS) return cont(maybeTypeArgs, noComma ? maybeoperatorNoComma : maybeoperatorComma)
+      else return pass(noComma ? expressionNoComma : expression);
+    };
+  }
+  function target(_, value) {
+    if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); }
+  }
+  function targetNoComma(_, value) {
+    if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); }
+  }
+  function maybelabel(type) {
+    if (type == ":") return cont(poplex, statement);
+    return pass(maybeoperatorComma, expect(";"), poplex);
+  }
+  function property(type) {
+    if (type == "variable") {cx.marked = "property"; return cont();}
+  }
+  function objprop(type, value) {
+    if (type == "async") {
+      cx.marked = "property";
+      return cont(objprop);
+    } else if (type == "variable" || cx.style == "keyword") {
+      cx.marked = "property";
+      if (value == "get" || value == "set") return cont(getterSetter);
+      return cont(afterprop);
+    } else if (type == "number" || type == "string") {
+      cx.marked = jsonldMode ? "property" : (cx.style + " property");
+      return cont(afterprop);
+    } else if (type == "jsonld-keyword") {
+      return cont(afterprop);
+    } else if (type == "modifier") {
+      return cont(objprop)
+    } else if (type == "[") {
+      return cont(expression, expect("]"), afterprop);
+    } else if (type == "spread") {
+      return cont(expression, afterprop);
+    } else if (type == ":") {
+      return pass(afterprop)
+    }
+  }
+  function getterSetter(type) {
+    if (type != "variable") return pass(afterprop);
+    cx.marked = "property";
+    return cont(functiondef);
+  }
+  function afterprop(type) {
+    if (type == ":") return cont(expressionNoComma);
+    if (type == "(") return pass(functiondef);
+  }
+  function commasep(what, end, sep) {
+    function proceed(type, value) {
+      if (sep ? sep.indexOf(type) > -1 : type == ",") {
+        var lex = cx.state.lexical;
+        if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
+        return cont(function(type, value) {
+          if (type == end || value == end) return pass()
+          return pass(what)
+        }, proceed);
+      }
+      if (type == end || value == end) return cont();
+      return cont(expect(end));
+    }
+    return function(type, value) {
+      if (type == end || value == end) return cont();
+      return pass(what, proceed);
+    };
+  }
+  function contCommasep(what, end, info) {
+    for (var i = 3; i < arguments.length; i++)
+      cx.cc.push(arguments[i]);
+    return cont(pushlex(end, info), commasep(what, end), poplex);
+  }
+  function block(type) {
+    if (type == "}") return cont();
+    return pass(statement, block);
+  }
+  function maybetype(type, value) {
+    if (isTS) {
+      if (type == ":") return cont(typeexpr);
+      if (value == "?") return cont(maybetype);
+    }
+  }
+  function typeexpr(type, value) {
+    if (type == "variable") {
+      if (value == "keyof") {
+        cx.marked = "keyword"
+        return cont(typeexpr)
+      } else {
+        cx.marked = "type"
+        return cont(afterType)
+      }
+    }
+    if (type == "string" || type == "number" || type == "atom") return cont(afterType);
+    if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType)
+    if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType)
+    if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType)
+  }
+  function maybeReturnType(type) {
+    if (type == "=>") return cont(typeexpr)
+  }
+  function typeprop(type, value) {
+    if (type == "variable" || cx.style == "keyword") {
+      cx.marked = "property"
+      return cont(typeprop)
+    } else if (value == "?") {
+      return cont(typeprop)
+    } else if (type == ":") {
+      return cont(typeexpr)
+    } else if (type == "[") {
+      return cont(expression, maybetype, expect("]"), typeprop)
+    }
+  }
+  function typearg(type) {
+    if (type == "variable") return cont(typearg)
+    else if (type == ":") return cont(typeexpr)
+  }
+  function afterType(type, value) {
+    if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
+    if (value == "|" || type == ".") return cont(typeexpr)
+    if (type == "[") return cont(expect("]"), afterType)
+    if (value == "extends") return cont(typeexpr)
+  }
+  function maybeTypeArgs(_, value) {
+    if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
+  }
+  function vardef() {
+    return pass(pattern, maybetype, maybeAssign, vardefCont);
+  }
+  function pattern(type, value) {
+    if (type == "modifier") return cont(pattern)
+    if (type == "variable") { register(value); return cont(); }
+    if (type == "spread") return cont(pattern);
+    if (type == "[") return contCommasep(pattern, "]");
+    if (type == "{") return contCommasep(proppattern, "}");
+  }
+  function proppattern(type, value) {
+    if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
+      register(value);
+      return cont(maybeAssign);
+    }
+    if (type == "variable") cx.marked = "property";
+    if (type == "spread") return cont(pattern);
+    if (type == "}") return pass();
+    return cont(expect(":"), pattern, maybeAssign);
+  }
+  function maybeAssign(_type, value) {
+    if (value == "=") return cont(expressionNoComma);
+  }
+  function vardefCont(type) {
+    if (type == ",") return cont(vardef);
+  }
+  function maybeelse(type, value) {
+    if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
+  }
+  function forspec(type) {
+    if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
+  }
+  function forspec1(type) {
+    if (type == "var") return cont(vardef, expect(";"), forspec2);
+    if (type == ";") return cont(forspec2);
+    if (type == "variable") return cont(formaybeinof);
+    return pass(expression, expect(";"), forspec2);
+  }
+  function formaybeinof(_type, value) {
+    if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
+    return cont(maybeoperatorComma, forspec2);
+  }
+  function forspec2(type, value) {
+    if (type == ";") return cont(forspec3);
+    if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
+    return pass(expression, expect(";"), forspec3);
+  }
+  function forspec3(type) {
+    if (type != ")") cont(expression);
+  }
+  function functiondef(type, value) {
+    if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
+    if (type == "variable") {register(value); return cont(functiondef);}
+    if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext);
+    if (isTS && value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, functiondef)
+  }
+  function funarg(type) {
+    if (type == "spread" || type == "modifier") return cont(funarg);
+    return pass(pattern, maybetype, maybeAssign);
+  }
+  function classExpression(type, value) {
+    // Class expressions may have an optional name.
+    if (type == "variable") return className(type, value);
+    return classNameAfter(type, value);
+  }
+  function className(type, value) {
+    if (type == "variable") {register(value); return cont(classNameAfter);}
+  }
+  function classNameAfter(type, value) {
+    if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, classNameAfter)
+    if (value == "extends" || value == "implements" || (isTS && type == ","))
+      return cont(isTS ? typeexpr : expression, classNameAfter);
+    if (type == "{") return cont(pushlex("}"), classBody, poplex);
+  }
+  function classBody(type, value) {
+    if (type == "modifier" || type == "async" ||
+        (type == "variable" &&
+         (value == "static" || value == "get" || value == "set") &&
+         cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) {
+      cx.marked = "keyword";
+      return cont(classBody);
+    }
+    if (type == "variable") {
+      cx.marked = "property";
+      return cont(isTS ? classfield : functiondef, classBody);
+    }
+    if (type == "[")
+      return cont(expression, expect("]"), isTS ? classfield : functiondef, classBody)
+    if (value == "*") {
+      cx.marked = "keyword";
+      return cont(classBody);
+    }
+    if (type == ";") return cont(classBody);
+    if (type == "}") return cont();
+    if (value == "@") return cont(expression, classBody)
+  }
+  function classfield(type, value) {
+    if (value == "?") return cont(classfield)
+    if (type == ":") return cont(typeexpr, maybeAssign)
+    if (value == "=") return cont(expressionNoComma)
+    return pass(functiondef)
+  }
+  function afterExport(type, value) {
+    if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
+    if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
+    if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";"));
+    return pass(statement);
+  }
+  function exportField(type, value) {
+    if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); }
+    if (type == "variable") return pass(expressionNoComma, exportField);
+  }
+  function afterImport(type) {
+    if (type == "string") return cont();
+    return pass(importSpec, maybeMoreImports, maybeFrom);
+  }
+  function importSpec(type, value) {
+    if (type == "{") return contCommasep(importSpec, "}");
+    if (type == "variable") register(value);
+    if (value == "*") cx.marked = "keyword";
+    return cont(maybeAs);
+  }
+  function maybeMoreImports(type) {
+    if (type == ",") return cont(importSpec, maybeMoreImports)
+  }
+  function maybeAs(_type, value) {
+    if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
+  }
+  function maybeFrom(_type, value) {
+    if (value == "from") { cx.marked = "keyword"; return cont(expression); }
+  }
+  function arrayLiteral(type) {
+    if (type == "]") return cont();
+    return pass(commasep(expressionNoComma, "]"));
+  }
+
+  function isContinuedStatement(state, textAfter) {
+    return state.lastType == "operator" || state.lastType == "," ||
+      isOperatorChar.test(textAfter.charAt(0)) ||
+      /[,.]/.test(textAfter.charAt(0));
+  }
+
+  function expressionAllowed(stream, state, backUp) {
+    return state.tokenize == tokenBase &&
+      /^(?:operator|sof|keyword c|case|new|export|default|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
+      (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
+  }
+
+  // Interface
+
+  return {
+    startState: function(basecolumn) {
+      var state = {
+        tokenize: tokenBase,
+        lastType: "sof",
+        cc: [],
+        lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
+        localVars: parserConfig.localVars,
+        context: parserConfig.localVars && {vars: parserConfig.localVars},
+        indented: basecolumn || 0
+      };
+      if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
+        state.globalVars = parserConfig.globalVars;
+      return state;
+    },
+
+    token: function(stream, state) {
+      if (stream.sol()) {
+        if (!state.lexical.hasOwnProperty("align"))
+          state.lexical.align = false;
+        state.indented = stream.indentation();
+        findFatArrow(stream, state);
+      }
+      if (state.tokenize != tokenComment && stream.eatSpace()) return null;
+      var style = state.tokenize(stream, state);
+      if (type == "comment") return style;
+      state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
+      return parseJS(state, style, type, content, stream);
+    },
+
+    indent: function(state, textAfter) {
+      if (state.tokenize == tokenComment) return CodeMirror.Pass;
+      if (state.tokenize != tokenBase) return 0;
+      var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top
+      // Kludge to prevent 'maybelse' from blocking lexical scope pops
+      if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
+        var c = state.cc[i];
+        if (c == poplex) lexical = lexical.prev;
+        else if (c != maybeelse) break;
+      }
+      while ((lexical.type == "stat" || lexical.type == "form") &&
+             (firstChar == "}" || ((top = state.cc[state.cc.length - 1]) &&
+                                   (top == maybeoperatorComma || top == maybeoperatorNoComma) &&
+                                   !/^[,\.=+\-*:?[\(]/.test(textAfter))))
+        lexical = lexical.prev;
+      if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
+        lexical = lexical.prev;
+      var type = lexical.type, closing = firstChar == type;
+
+      if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
+      else if (type == "form" && firstChar == "{") return lexical.indented;
+      else if (type == "form") return lexical.indented + indentUnit;
+      else if (type == "stat")
+        return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
+      else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
+        return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
+      else if (lexical.align) return lexical.column + (closing ? 0 : 1);
+      else return lexical.indented + (closing ? 0 : indentUnit);
+    },
+
+    electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
+    blockCommentStart: jsonMode ? null : "/*",
+    blockCommentEnd: jsonMode ? null : "*/",
+    lineComment: jsonMode ? null : "//",
+    fold: "brace",
+    closeBrackets: "()[]{}''\"\"``",
+
+    helperType: jsonMode ? "json" : "javascript",
+    jsonldMode: jsonldMode,
+    jsonMode: jsonMode,
+
+    expressionAllowed: expressionAllowed,
+
+    skipExpression: function(state) {
+      var top = state.cc[state.cc.length - 1]
+      if (top == expression || top == expressionNoComma) state.cc.pop()
+    }
+  };
+});
+
+CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
+
+CodeMirror.defineMIME("text/javascript", "javascript");
+CodeMirror.defineMIME("text/ecmascript", "javascript");
+CodeMirror.defineMIME("application/javascript", "javascript");
+CodeMirror.defineMIME("application/x-javascript", "javascript");
+CodeMirror.defineMIME("application/ecmascript", "javascript");
+CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
+CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
+CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
+CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
+CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
+
+});
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+"use strict";
+
+CodeMirror.defineMode("nginx", function(config) {
+
+  function words(str) {
+    var obj = {}, words = str.split(" ");
+    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
+    return obj;
+  }
+
+  var keywords = words(
+    /* ngxDirectiveControl */ "break return rewrite set" +
+    /* ngxDirective */ " accept_mutex accept_mutex_delay access_log add_after_body add_before_body add_header addition_types aio alias allow ancient_browser ancient_browser_value auth_basic auth_basic_user_file auth_http auth_http_header auth_http_timeout autoindex autoindex_exact_size autoindex_localtime charset charset_types client_body_buffer_size client_body_in_file_only client_body_in_single_buffer client_body_temp_path client_body_timeout client_header_buffer_size client_header_timeout client_max_body_size connection_pool_size create_full_put_path daemon dav_access dav_methods debug_connection debug_points default_type degradation degrade deny devpoll_changes devpoll_events directio directio_alignment empty_gif env epoll_events error_log eventport_events expires fastcgi_bind fastcgi_buffer_size fastcgi_buffers fastcgi_busy_buffers_size fastcgi_cache fastcgi_cache_key fastcgi_cache_methods fastcgi_cache_min_uses fastcgi_cache_path fastcgi_cache_use_stale fastcgi_cache_valid fastcgi_catch_stderr fastcgi_connect_timeout fastcgi_hide_header fastcgi_ignore_client_abort fastcgi_ignore_headers fastcgi_index fastcgi_intercept_errors fastcgi_max_temp_file_size fastcgi_next_upstream fastcgi_param fastcgi_pass_header fastcgi_pass_request_body fastcgi_pass_request_headers fastcgi_read_timeout fastcgi_send_lowat fastcgi_send_timeout fastcgi_split_path_info fastcgi_store fastcgi_store_access fastcgi_temp_file_write_size fastcgi_temp_path fastcgi_upstream_fail_timeout fastcgi_upstream_max_fails flv geoip_city geoip_country google_perftools_profiles gzip gzip_buffers gzip_comp_level gzip_disable gzip_hash gzip_http_version gzip_min_length gzip_no_buffer gzip_proxied gzip_static gzip_types gzip_vary gzip_window if_modified_since ignore_invalid_headers image_filter image_filter_buffer image_filter_jpeg_quality image_filter_transparency imap_auth imap_capabilities imap_client_buffer index ip_hash keepalive_requests keepalive_timeout kqueue_changes kqueue_events large_client_header_buffers limit_conn limit_conn_log_level limit_rate limit_rate_after limit_req limit_req_log_level limit_req_zone limit_zone lingering_time lingering_timeout lock_file log_format log_not_found log_subrequest map_hash_bucket_size map_hash_max_size master_process memcached_bind memcached_buffer_size memcached_connect_timeout memcached_next_upstream memcached_read_timeout memcached_send_timeout memcached_upstream_fail_timeout memcached_upstream_max_fails merge_slashes min_delete_depth modern_browser modern_browser_value msie_padding msie_refresh multi_accept open_file_cache open_file_cache_errors open_file_cache_events open_file_cache_min_uses open_file_cache_valid open_log_file_cache output_buffers override_charset perl perl_modules perl_require perl_set pid pop3_auth pop3_capabilities port_in_redirect postpone_gzipping postpone_output protocol proxy proxy_bind proxy_buffer proxy_buffer_size proxy_buffering proxy_buffers proxy_busy_buffers_size proxy_cache proxy_cache_key proxy_cache_methods proxy_cache_min_uses proxy_cache_path proxy_cache_use_stale proxy_cache_valid proxy_connect_timeout proxy_headers_hash_bucket_size proxy_headers_hash_max_size proxy_hide_header proxy_ignore_client_abort proxy_ignore_headers proxy_intercept_errors proxy_max_temp_file_size proxy_method proxy_next_upstream proxy_pass_error_message proxy_pass_header proxy_pass_request_body proxy_pass_request_headers proxy_read_timeout proxy_redirect proxy_send_lowat proxy_send_timeout proxy_set_body proxy_set_header proxy_ssl_session_reuse proxy_store proxy_store_access proxy_temp_file_write_size proxy_temp_path proxy_timeout proxy_upstream_fail_timeout proxy_upstream_max_fails random_index read_ahead real_ip_header recursive_error_pages request_pool_size reset_timedout_connection resolver resolver_timeout rewrite_log rtsig_overflow_events rtsig_overflow_test rtsig_overflow_threshold rtsig_signo satisfy secure_link_secret send_lowat send_timeout sendfile sendfile_max_chunk server_name_in_redirect server_names_hash_bucket_size server_names_hash_max_size server_tokens set_real_ip_from smtp_auth smtp_capabilities smtp_client_buffer smtp_greeting_delay so_keepalive source_charset ssi ssi_ignore_recycled_buffers ssi_min_file_chunk ssi_silent_errors ssi_types ssi_value_length ssl ssl_certificate ssl_certificate_key ssl_ciphers ssl_client_certificate ssl_crl ssl_dhparam ssl_engine ssl_prefer_server_ciphers ssl_protocols ssl_session_cache ssl_session_timeout ssl_verify_client ssl_verify_depth starttls stub_status sub_filter sub_filter_once sub_filter_types tcp_nodelay tcp_nopush thread_stack_size timeout timer_resolution types_hash_bucket_size types_hash_max_size underscores_in_headers uninitialized_variable_warn use user userid userid_domain userid_expires userid_mark userid_name userid_p3p userid_path userid_service valid_referers variables_hash_bucket_size variables_hash_max_size worker_connections worker_cpu_affinity worker_priority worker_processes worker_rlimit_core worker_rlimit_nofile worker_rlimit_sigpending worker_threads working_directory xclient xml_entities xslt_stylesheet xslt_typesdrew@li229-23"
+    );
+
+  var keywords_block = words(
+    /* ngxDirectiveBlock */ "http mail events server types location upstream charset_map limit_except if geo map"
+    );
+
+  var keywords_important = words(
+    /* ngxDirectiveImportant */ "include root server server_name listen internal proxy_pass memcached_pass fastcgi_pass try_files"
+    );
+
+  var indentUnit = config.indentUnit, type;
+  function ret(style, tp) {type = tp; return style;}
+
+  function tokenBase(stream, state) {
+
+
+    stream.eatWhile(/[\w\$_]/);
+
+    var cur = stream.current();
+
+
+    if (keywords.propertyIsEnumerable(cur)) {
+      return "keyword";
+    }
+    else if (keywords_block.propertyIsEnumerable(cur)) {
+      return "variable-2";
+    }
+    else if (keywords_important.propertyIsEnumerable(cur)) {
+      return "string-2";
+    }
+    /**/
+
+    var ch = stream.next();
+    if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("meta", stream.current());}
+    else if (ch == "/" && stream.eat("*")) {
+      state.tokenize = tokenCComment;
+      return tokenCComment(stream, state);
+    }
+    else if (ch == "<" && stream.eat("!")) {
+      state.tokenize = tokenSGMLComment;
+      return tokenSGMLComment(stream, state);
+    }
+    else if (ch == "=") ret(null, "compare");
+    else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
+    else if (ch == "\"" || ch == "'") {
+      state.tokenize = tokenString(ch);
+      return state.tokenize(stream, state);
+    }
+    else if (ch == "#") {
+      stream.skipToEnd();
+      return ret("comment", "comment");
+    }
+    else if (ch == "!") {
+      stream.match(/^\s*\w*/);
+      return ret("keyword", "important");
+    }
+    else if (/\d/.test(ch)) {
+      stream.eatWhile(/[\w.%]/);
+      return ret("number", "unit");
+    }
+    else if (/[,.+>*\/]/.test(ch)) {
+      return ret(null, "select-op");
+    }
+    else if (/[;{}:\[\]]/.test(ch)) {
+      return ret(null, ch);
+    }
+    else {
+      stream.eatWhile(/[\w\\\-]/);
+      return ret("variable", "variable");
+    }
+  }
+
+  function tokenCComment(stream, state) {
+    var maybeEnd = false, ch;
+    while ((ch = stream.next()) != null) {
+      if (maybeEnd && ch == "/") {
+        state.tokenize = tokenBase;
+        break;
+      }
+      maybeEnd = (ch == "*");
+    }
+    return ret("comment", "comment");
+  }
+
+  function tokenSGMLComment(stream, state) {
+    var dashes = 0, ch;
+    while ((ch = stream.next()) != null) {
+      if (dashes >= 2 && ch == ">") {
+        state.tokenize = tokenBase;
+        break;
+      }
+      dashes = (ch == "-") ? dashes + 1 : 0;
+    }
+    return ret("comment", "comment");
+  }
+
+  function tokenString(quote) {
+    return function(stream, state) {
+      var escaped = false, ch;
+      while ((ch = stream.next()) != null) {
+        if (ch == quote && !escaped)
+          break;
+        escaped = !escaped && ch == "\\";
+      }
+      if (!escaped) state.tokenize = tokenBase;
+      return ret("string", "string");
+    };
+  }
+
+  return {
+    startState: function(base) {
+      return {tokenize: tokenBase,
+              baseIndent: base || 0,
+              stack: []};
+    },
+
+    token: function(stream, state) {
+      if (stream.eatSpace()) return null;
+      type = null;
+      var style = state.tokenize(stream, state);
+
+      var context = state.stack[state.stack.length-1];
+      if (type == "hash" && context == "rule") style = "atom";
+      else if (style == "variable") {
+        if (context == "rule") style = "number";
+        else if (!context || context == "@media{") style = "tag";
+      }
+
+      if (context == "rule" && /^[\{\};]$/.test(type))
+        state.stack.pop();
+      if (type == "{") {
+        if (context == "@media") state.stack[state.stack.length-1] = "@media{";
+        else state.stack.push("{");
+      }
+      else if (type == "}") state.stack.pop();
+      else if (type == "@media") state.stack.push("@media");
+      else if (context == "{" && type != "comment") state.stack.push("rule");
+      return style;
+    },
+
+    indent: function(state, textAfter) {
+      var n = state.stack.length;
+      if (/^\}/.test(textAfter))
+        n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1;
+      return state.baseIndent + n * indentUnit;
+    },
+
+    electricChars: "}"
+  };
+});
+
+CodeMirror.defineMIME("text/x-nginx-conf", "nginx");
+
+});
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+"use strict";
+
+CodeMirror.defineMode('shell', function() {
+
+  var words = {};
+  function define(style, string) {
+    var split = string.split(' ');
+    for(var i = 0; i < split.length; i++) {
+      words[split[i]] = style;
+    }
+  };
+
+  // Atoms
+  define('atom', 'true false');
+
+  // Keywords
+  define('keyword', 'if then do else elif while until for in esac fi fin ' +
+    'fil done exit set unset export function');
+
+  // Commands
+  define('builtin', 'ab awk bash beep cat cc cd chown chmod chroot clear cp ' +
+    'curl cut diff echo find gawk gcc get git grep hg kill killall ln ls make ' +
+    'mkdir openssl mv nc node npm ping ps restart rm rmdir sed service sh ' +
+    'shopt shred source sort sleep ssh start stop su sudo svn tee telnet top ' +
+    'touch vi vim wall wc wget who write yes zsh');
+
+  function tokenBase(stream, state) {
+    if (stream.eatSpace()) return null;
+
+    var sol = stream.sol();
+    var ch = stream.next();
+
+    if (ch === '\\') {
+      stream.next();
+      return null;
+    }
+    if (ch === '\'' || ch === '"' || ch === '`') {
+      state.tokens.unshift(tokenString(ch, ch === "`" ? "quote" : "string"));
+      return tokenize(stream, state);
+    }
+    if (ch === '#') {
+      if (sol && stream.eat('!')) {
+        stream.skipToEnd();
+        return 'meta'; // 'comment'?
+      }
+      stream.skipToEnd();
+      return 'comment';
+    }
+    if (ch === '$') {
+      state.tokens.unshift(tokenDollar);
+      return tokenize(stream, state);
+    }
+    if (ch === '+' || ch === '=') {
+      return 'operator';
+    }
+    if (ch === '-') {
+      stream.eat('-');
+      stream.eatWhile(/\w/);
+      return 'attribute';
+    }
+    if (/\d/.test(ch)) {
+      stream.eatWhile(/\d/);
+      if(stream.eol() || !/\w/.test(stream.peek())) {
+        return 'number';
+      }
+    }
+    stream.eatWhile(/[\w-]/);
+    var cur = stream.current();
+    if (stream.peek() === '=' && /\w+/.test(cur)) return 'def';
+    return words.hasOwnProperty(cur) ? words[cur] : null;
+  }
+
+  function tokenString(quote, style) {
+    var close = quote == "(" ? ")" : quote == "{" ? "}" : quote
+    return function(stream, state) {
+      var next, end = false, escaped = false;
+      while ((next = stream.next()) != null) {
+        if (next === close && !escaped) {
+          end = true;
+          break;
+        }
+        if (next === '$' && !escaped && quote !== "'") {
+          escaped = true;
+          stream.backUp(1);
+          state.tokens.unshift(tokenDollar);
+          break;
+        }
+        if (!escaped && next === quote && quote !== close) {
+          state.tokens.unshift(tokenString(quote, style))
+          return tokenize(stream, state)
+        }
+        escaped = !escaped && next === '\\';
+      }
+      if (end) state.tokens.shift();
+      return style;
+    };
+  };
+
+  var tokenDollar = function(stream, state) {
+    if (state.tokens.length > 1) stream.eat('$');
+    var ch = stream.next()
+    if (/['"({]/.test(ch)) {
+      state.tokens[0] = tokenString(ch, ch == "(" ? "quote" : ch == "{" ? "def" : "string");
+      return tokenize(stream, state);
+    }
+    if (!/\d/.test(ch)) stream.eatWhile(/\w/);
+    state.tokens.shift();
+    return 'def';
+  };
+
+  function tokenize(stream, state) {
+    return (state.tokens[0] || tokenBase) (stream, state);
+  };
+
+  return {
+    startState: function() {return {tokens:[]};},
+    token: function(stream, state) {
+      return tokenize(stream, state);
+    },
+    closeBrackets: "()[]{}''\"\"``",
+    lineComment: '#',
+    fold: "brace"
+  };
+});
+
+CodeMirror.defineMIME('text/x-sh', 'shell');
+// Apache uses a slightly different Media Type for Shell scripts
+// http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
+CodeMirror.defineMIME('application/x-sh', 'shell');
+
+});
+// CodeMirror, copyright (c) by Marijn Haverbeke and others
+// Distributed under an MIT license: http://codemirror.net/LICENSE
+
+(function(mod) {
+  if (typeof exports == "object" && typeof module == "object") // CommonJS
+    mod(require("../../lib/codemirror"));
+  else if (typeof define == "function" && define.amd) // AMD
+    define(["../../lib/codemirror"], mod);
+  else // Plain browser env
+    mod(CodeMirror);
+})(function(CodeMirror) {
+"use strict";
+
+var htmlConfig = {
+  autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
+                    'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
+                    'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
+                    'track': true, 'wbr': true, 'menuitem': true},
+  implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
+                     'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
+                     'th': true, 'tr': true},
+  contextGrabbers: {
+    'dd': {'dd': true, 'dt': true},
+    'dt': {'dd': true, 'dt': true},
+    'li': {'li': true},
+    'option': {'option': true, 'optgroup': true},
+    'optgroup': {'optgroup': true},
+    'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
+          'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
+          'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
+          'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
+          'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
+    'rp': {'rp': true, 'rt': true},
+    'rt': {'rp': true, 'rt': true},
+    'tbody': {'tbody': true, 'tfoot': true},
+    'td': {'td': true, 'th': true},
+    'tfoot': {'tbody': true},
+    'th': {'td': true, 'th': true},
+    'thead': {'tbody': true, 'tfoot': true},
+    'tr': {'tr': true}
+  },
+  doNotIndent: {"pre": true},
+  allowUnquoted: true,
+  allowMissing: true,
+  caseFold: true
+}
+
+var xmlConfig = {
+  autoSelfClosers: {},
+  implicitlyClosed: {},
+  contextGrabbers: {},
+  doNotIndent: {},
+  allowUnquoted: false,
+  allowMissing: false,
+  caseFold: false
+}
+
+CodeMirror.defineMode("xml", function(editorConf, config_) {
+  var indentUnit = editorConf.indentUnit
+  var config = {}
+  var defaults = config_.htmlMode ? htmlConfig : xmlConfig
+  for (var prop in defaults) config[prop] = defaults[prop]
+  for (var prop in config_) config[prop] = config_[prop]
+
+  // Return variables for tokenizers
+  var type, setStyle;
+
+  function inText(stream, state) {
+    function chain(parser) {
+      state.tokenize = parser;
+      return parser(stream, state);
+    }
+
+    var ch = stream.next();
+    if (ch == "<") {
+      if (stream.eat("!")) {
+        if (stream.eat("[")) {
+          if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
+          else return null;
+        } else if (stream.match("--")) {
+          return chain(inBlock("comment", "-->"));
+        } else if (stream.match("DOCTYPE", true, true)) {
+          stream.eatWhile(/[\w\._\-]/);
+          return chain(doctype(1));
+        } else {
+          return null;
+        }
+      } else if (stream.eat("?")) {
+        stream.eatWhile(/[\w\._\-]/);
+        state.tokenize = inBlock("meta", "?>");
+        return "meta";
+      } else {
+        type = stream.eat("/") ? "closeTag" : "openTag";
+        state.tokenize = inTag;
+        return "tag bracket";
+      }
+    } else if (ch == "&") {
+      var ok;
+      if (stream.eat("#")) {
+        if (stream.eat("x")) {
+          ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
+        } else {
+          ok = stream.eatWhile(/[\d]/) && stream.eat(";");
+        }
+      } else {
+        ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
+      }
+      return ok ? "atom" : "error";
+    } else {
+      stream.eatWhile(/[^&<]/);
+      return null;
+    }
+  }
+  inText.isInText = true;
+
+  function inTag(stream, state) {
+    var ch = stream.next();
+    if (ch == ">" || (ch == "/" && stream.eat(">"))) {
+      state.tokenize = inText;
+      type = ch == ">" ? "endTag" : "selfcloseTag";
+      return "tag bracket";
+    } else if (ch == "=") {
+      type = "equals";
+      return null;
+    } else if (ch == "<") {
+      state.tokenize = inText;
+      state.state = baseState;
+      state.tagName = state.tagStart = null;
+      var next = state.tokenize(stream, state);
+      return next ? next + " tag error" : "tag error";
+    } else if (/[\'\"]/.test(ch)) {
+      state.tokenize = inAttribute(ch);
+      state.stringStartCol = stream.column();
+      return state.tokenize(stream, state);
+    } else {
+      stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
+      return "word";
+    }
+  }
+
+  function inAttribute(quote) {
+    var closure = function(stream, state) {
+      while (!stream.eol()) {
+        if (stream.next() == quote) {
+          state.tokenize = inTag;
+          break;
+        }
+      }
+      return "string";
+    };
+    closure.isInAttribute = true;
+    return closure;
+  }
+
+  function inBlock(style, terminator) {
+    return function(stream, state) {
+      while (!stream.eol()) {
+        if (stream.match(terminator)) {
+          state.tokenize = inText;
+          break;
+        }
+        stream.next();
+      }
+      return style;
+    };
+  }
+  function doctype(depth) {
+    return function(stream, state) {
+      var ch;
+      while ((ch = stream.next()) != null) {
+        if (ch == "<") {
+          state.tokenize = doctype(depth + 1);
+          return state.tokenize(stream, state);
+        } else if (ch == ">") {
+          if (depth == 1) {
+            state.tokenize = inText;
+            break;
+          } else {
+            state.tokenize = doctype(depth - 1);
+            return state.tokenize(stream, state);
+          }
+        }
+      }
+      return "meta";
+    };
+  }
+
+  function Context(state, tagName, startOfLine) {
+    this.prev = state.context;
+    this.tagName = tagName;
+    this.indent = state.indented;
+    this.startOfLine = startOfLine;
+    if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
+      this.noIndent = true;
+  }
+  function popContext(state) {
+    if (state.context) state.context = state.context.prev;
+  }
+  function maybePopContext(state, nextTagName) {
+    var parentTagName;
+    while (true) {
+      if (!state.context) {
+        return;
+      }
+      parentTagName = state.context.tagName;
+      if (!config.contextGrabbers.hasOwnProperty(parentTagName) ||
+          !config.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
+        return;
+      }
+      popContext(state);
+    }
+  }
+
+  function baseState(type, stream, state) {
+    if (type == "openTag") {
+      state.tagStart = stream.column();
+      return tagNameState;
+    } else if (type == "closeTag") {
+      return closeTagNameState;
+    } else {
+      return baseState;
+    }
+  }
+  function tagNameState(type, stream, state) {
+    if (type == "word") {
+      state.tagName = stream.current();
+      setStyle = "tag";
+      return attrState;
+    } else {
+      setStyle = "error";
+      return tagNameState;
+    }
+  }
+  function closeTagNameState(type, stream, state) {
+    if (type == "word") {
+      var tagName = stream.current();
+      if (state.context && state.context.tagName != tagName &&
+          config.implicitlyClosed.hasOwnProperty(state.context.tagName))
+        popContext(state);
+      if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) {
+        setStyle = "tag";
+        return closeState;
+      } else {
+        setStyle = "tag error";
+        return closeStateErr;
+      }
+    } else {
+      setStyle = "error";
+      return closeStateErr;
+    }
+  }
+
+  function closeState(type, _stream, state) {
+    if (type != "endTag") {
+      setStyle = "error";
+      return closeState;
+    }
+    popContext(state);
+    return baseState;
+  }
+  function closeStateErr(type, stream, state) {
+    setStyle = "error";
+    return closeState(type, stream, state);
+  }
+
+  function attrState(type, _stream, state) {
+    if (type == "word") {
+      setStyle = "attribute";
+      return attrEqState;
+    } else if (type == "endTag" || type == "selfcloseTag") {
+      var tagName = state.tagName, tagStart = state.tagStart;
+      state.tagName = state.tagStart = null;
+      if (type == "selfcloseTag" ||
+          config.autoSelfClosers.hasOwnProperty(tagName)) {
+        maybePopContext(state, tagName);
+      } else {
+        maybePopContext(state, tagName);
+        state.context = new Context(state, tagName, tagStart == state.indented);
+      }
+      return baseState;
+    }
+    setStyle = "error";
+    return attrState;
+  }
+  function attrEqState(type, stream, state) {
+    if (type == "equals") return attrValueState;
+    if (!config.allowMissing) setStyle = "error";
+    return attrState(type, stream, state);
+  }
+  function attrValueState(type, stream, state) {
+    if (type == "string") return attrContinuedState;
+    if (type == "word" && config.allowUnquoted) {setStyle = "string"; return attrState;}
+    setStyle = "error";
+    return attrState(type, stream, state);
+  }
+  function attrContinuedState(type, stream, state) {
+    if (type == "string") return attrContinuedState;
+    return attrState(type, stream, state);
+  }
+
+  return {
+    startState: function(baseIndent) {
+      var state = {tokenize: inText,
+                   state: baseState,
+                   indented: baseIndent || 0,
+                   tagName: null, tagStart: null,
+                   context: null}
+      if (baseIndent != null) state.baseIndent = baseIndent
+      return state
+    },
+
+    token: function(stream, state) {
+      if (!state.tagName && stream.sol())
+        state.indented = stream.indentation();
+
+      if (stream.eatSpace()) return null;
+      type = null;
+      var style = state.tokenize(stream, state);
+      if ((style || type) && style != "comment") {
+        setStyle = null;
+        state.state = state.state(type || style, stream, state);
+        if (setStyle)
+          style = setStyle == "error" ? style + " error" : setStyle;
+      }
+      return style;
+    },
+
+    indent: function(state, textAfter, fullLine) {
+      var context = state.context;
+      // Indent multi-line strings (e.g. css).
+      if (state.tokenize.isInAttribute) {
+        if (state.tagStart == state.indented)
+          return state.stringStartCol + 1;
+        else
+          return state.indented + indentUnit;
+      }
+      if (context && context.noIndent) return CodeMirror.Pass;
+      if (state.tokenize != inTag && state.tokenize != inText)
+        return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
+      // Indent the starts of attribute names.
+      if (state.tagName) {
+        if (config.multilineTagIndentPastTag !== false)
+          return state.tagStart + state.tagName.length + 2;
+        else
+          return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1);
+      }
+      if (config.alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
+      var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter);
+      if (tagAfter && tagAfter[1]) { // Closing tag spotted
+        while (context) {
+          if (context.tagName == tagAfter[2]) {
+            context = context.prev;
+            break;
+          } else if (config.implicitlyClosed.hasOwnProperty(context.tagName)) {
+            context = context.prev;
+          } else {
+            break;
+          }
+        }
+      } else if (tagAfter) { // Opening tag spotted
+        while (context) {
+          var grabbers = config.contextGrabbers[context.tagName];
+          if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))
+            context = context.prev;
+          else
+            break;
+        }
+      }
+      while (context && context.prev && !context.startOfLine)
+        context = context.prev;
+      if (context) return context.indent + indentUnit;
+      else return state.baseIndent || 0;
+    },
+
+    electricInput: /<\/[\s\w:]+>$/,
+    blockCommentStart: "<!--",
+    blockCommentEnd: "-->",
+
+    configuration: config.htmlMode ? "html" : "xml",
+    helperType: config.htmlMode ? "html" : "xml",
+
+    skipAttribute: function(state) {
+      if (state.state == attrValueState)
+        state.state = attrState
+    }
+  };
+});
+
+CodeMirror.defineMIME("text/xml", "xml");
+CodeMirror.defineMIME("application/xml", "xml");
+if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
+  CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
+
+});
diff --git a/themes/bookstack/static/libs/highlight/LICENSE b/themes/bookstack/static/libs/highlight/LICENSE
deleted file mode 100644 (file)
index 422deb7..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-Copyright (c) 2006, Ivan Sagalaev
-All rights reserved.
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in the
-      documentation and/or other materials provided with the distribution.
-    * Neither the name of highlight.js nor the names of its contributors 
-      may be used to endorse or promote products derived from this software 
-      without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/themes/bookstack/static/libs/highlight/README.md b/themes/bookstack/static/libs/highlight/README.md
deleted file mode 100644 (file)
index 9f76e6b..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-# Highlight.js
-
-[![Build Status](https://travis-ci.org/isagalaev/highlight.js.svg?branch=master)](https://travis-ci.org/isagalaev/highlight.js)
-
-Highlight.js is a syntax highlighter written in JavaScript. It works in
-the browser as well as on the server. It works with pretty much any
-markup, doesn’t depend on any framework and has automatic language
-detection.
-
-## Getting Started
-
-The bare minimum for using highlight.js on a web page is linking to the
-library along with one of the styles and calling
-[`initHighlightingOnLoad`][1]:
-
-```html
-<link rel="stylesheet" href="/path/to/styles/default.css">
-<script src="/path/to/highlight.pack.js"></script>
-<script>hljs.initHighlightingOnLoad();</script>
-```
-
-This will find and highlight code inside of `<pre><code>` tags; it tries
-to detect the language automatically. If automatic detection doesn’t
-work for you, you can specify the language in the `class` attribute:
-
-```html
-<pre><code class="html">...</code></pre>
-```
-
-The list of supported language classes is available in the [class
-reference][2].  Classes can also be prefixed with either `language-` or
-`lang-`.
-
-To disable highlighting altogether use the `nohighlight` class:
-
-```html
-<pre><code class="nohighlight">...</code></pre>
-```
-
-## Custom Initialization
-
-When you need a bit more control over the initialization of
-highlight.js, you can use the [`highlightBlock`][3] and [`configure`][4]
-functions. This allows you to control *what* to highlight and *when*.
-
-Here’s an equivalent way to calling [`initHighlightingOnLoad`][1] using
-jQuery:
-
-```javascript
-$(document).ready(function() {
-  $('pre code').each(function(i, block) {
-    hljs.highlightBlock(block);
-  });
-});
-```
-
-You can use any tags instead of `<pre><code>` to mark up your code. If
-you don't use a container that preserve line breaks you will need to
-configure highlight.js to use the `<br>` tag:
-
-```javascript
-hljs.configure({useBR: true});
-
-$('div.code').each(function(i, block) {
-  hljs.highlightBlock(block);
-});
-```
-
-For other options refer to the documentation for [`configure`][4].
-
-
-## Web Workers
-
-You can run highlighting inside a web worker to avoid freezing the browser
-window while dealing with very big chunks of code.
-
-In your main script:
-
-```javascript
-addEventListener('load', function() {
-  var code = document.querySelector('#code');
-  var worker = new Worker('worker.js');
-  worker.onmessage = function(event) { code.innerHTML = event.data; }
-  worker.postMessage(code.textContent);
-})
-```
-
-In worker.js:
-
-```javascript
-onmessage = function(event) {
-  importScripts('<path>/highlight.pack.js');
-  var result = self.hljs.highlightAuto(event.data);
-  postMessage(result.value);
-}
-```
-
-
-## Getting the Library
-
-You can get highlight.js as a hosted, or custom-build, browser script or
-as a server module. Right out of the box the browser script supports
-both AMD and CommonJS, so if you wish you can use RequireJS or
-Browserify without having to build from source. The server module also
-works perfectly fine with Browserify, but there is the option to use a
-build specific to browsers rather than something meant for a server.
-Head over to the [download page][5] for all the options.
-
-**Don't link to GitHub directly.** The library is not supposed to work straight
-from the source, it requires building. If none of the pre-packaged options
-work for you refer to the [building documentation][6].
-
-**The CDN-hosted package doesn't have all the languages.** Otherwise it'd be
-too big. If you don't see the language you need in the ["Common" section][5],
-it can be added manually:
-
-```html
-<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.4.0/languages/go.min.js"></script>
-```
-
-**On Almond.** You need to use the optimizer to give the module a name. For
-example:
-
-```
-r.js -o name=hljs paths.hljs=/path/to/highlight out=highlight.js
-```
-
-
-## License
-
-Highlight.js is released under the BSD License. See [LICENSE][7] file
-for details.
-
-## Links
-
-The official site for the library is at <https://highlightjs.org/>.
-
-Further in-depth documentation for the API and other topics is at
-<http://highlightjs.readthedocs.io/>.
-
-Authors and contributors are listed in the [AUTHORS.en.txt][8] file.
-
-[1]: http://highlightjs.readthedocs.io/en/latest/api.html#inithighlightingonload
-[2]: http://highlightjs.readthedocs.io/en/latest/css-classes-reference.html
-[3]: http://highlightjs.readthedocs.io/en/latest/api.html#highlightblock-block
-[4]: http://highlightjs.readthedocs.io/en/latest/api.html#configure-options
-[5]: https://highlightjs.org/download/
-[6]: http://highlightjs.readthedocs.io/en/latest/building-testing.html
-[7]: https://github.com/isagalaev/highlight.js/blob/master/LICENSE
-[8]: https://github.com/isagalaev/highlight.js/blob/master/AUTHORS.en.txt
diff --git a/themes/bookstack/static/libs/highlight/highlight.pack.js b/themes/bookstack/static/libs/highlight/highlight.pack.js
deleted file mode 100644 (file)
index 755cfc1..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/*! highlight.js v9.6.0 | BSD3 License | git.io/hljslicense */
-!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/[&<>]/gm,function(e){return I[e]})}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=B.exec(o))return R(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||R(i))return i}function o(e,n){var t,r={};for(t in e)r[t]=e[t];if(n)for(t in n)r[t]=n[t];return r}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset<r[0].offset?e:r:"start"===r[0].event?e:r:e.length?e:r}function o(e){function r(e){return" "+e.nodeName+'="'+n(e.value)+'"'}l+="<"+t(e)+w.map.call(e.attributes,r).join("")+">"}function u(e){l+="</"+t(e)+">"}function c(e){("start"===e.event?o:u)(e.node)}for(var s=0,l="",f=[];e.length||r.length;){var g=i();if(l+=n(a.substr(s,g[0].offset-s)),s=g[0].offset,g===e){f.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===s);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),c(g.splice(0,1)[0])}return l+n(a.substr(s))}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var u={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");u[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):E(a.k).forEach(function(e){c(e,a.k[e])}),a.k=u}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]);var s=[];a.c.forEach(function(e){e.v?e.v.forEach(function(n){s.push(o(e,n))}):s.push("self"===e?a:e)}),a.c=s,a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var l=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=l.length?t(l.join("|"),!0):{exec:function(){return null}}}}r(e)}function l(e,t,a,i){function o(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function c(e,n){return!a&&r(n.iR,e)}function g(e,n){var t=N.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function h(e,n,t,r){var a=r?"":y.classPrefix,i='<span class="'+a,o=t?"":C;return i+=e+'">',i+n+o}function p(){var e,t,r,a;if(!E.k)return n(B);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(B);r;)a+=n(B.substr(t,r.index-t)),e=g(E,r),e?(M+=e[1],a+=h(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(B);return a+n(B.substr(t))}function d(){var e="string"==typeof E.sL;if(e&&!x[E.sL])return n(B);var t=e?l(E.sL,B,!0,L[E.sL]):f(B,E.sL.length?E.sL:void 0);return E.r>0&&(M+=t.r),e&&(L[E.sL]=t.top),h(t.language,t.value,!1,!0)}function b(){k+=null!=E.sL?d():p(),B=""}function v(e){k+=e.cN?h(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function m(e,n){if(B+=e,null==n)return b(),0;var t=o(n,E);if(t)return t.skip?B+=n:(t.eB&&(B+=n),b(),t.rB||t.eB||(B=n)),v(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?B+=n:(a.rE||a.eE||(B+=n),b(),a.eE&&(B=n));do E.cN&&(k+=C),E.skip||(M+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&v(r.starts,""),a.rE?0:n.length}if(c(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"<unnamed>")+'"');return B+=n,n.length||1}var N=R(e);if(!N)throw new Error('Unknown language: "'+e+'"');s(N);var w,E=i||N,L={},k="";for(w=E;w!==N;w=w.parent)w.cN&&(k=h(w.cN,"",!0)+k);var B="",M=0;try{for(var I,j,O=0;;){if(E.t.lastIndex=O,I=E.t.exec(t),!I)break;j=m(t.substr(O,I.index-O),I[0]),O=I.index+j}for(m(t.substr(O)),w=E;w.parent;w=w.parent)w.cN&&(k+=C);return{r:M,value:k,language:e,top:E}}catch(T){if(T.message&&-1!==T.message.indexOf("Illegal"))return{r:0,value:n(t)};throw T}}function f(e,t){t=t||y.languages||E(x);var r={r:0,value:n(e)},a=r;return t.filter(R).forEach(function(n){var t=l(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function g(e){return y.tabReplace||y.useBR?e.replace(M,function(e,n){return y.useBR&&"\n"===e?"<br>":y.tabReplace?n.replace(/\t/g,y.tabReplace):void 0}):e}function h(e,n,t){var r=n?L[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function p(e){var n,t,r,o,s,p=i(e);a(p)||(y.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(/<br[ \/]*>/g,"\n")):n=e,s=n.textContent,r=p?l(p,s,!0):f(s),t=u(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=c(t,u(o),s)),r.value=g(r.value),e.innerHTML=r.value,e.className=h(e.className,p,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function d(e){y=o(y,e)}function b(){if(!b.called){b.called=!0;var e=document.querySelectorAll("pre code");w.forEach.call(e,p)}}function v(){addEventListener("DOMContentLoaded",b,!1),addEventListener("load",b,!1)}function m(n,t){var r=x[n]=t(e);r.aliases&&r.aliases.forEach(function(e){L[e]=n})}function N(){return E(x)}function R(e){return e=(e||"").toLowerCase(),x[e]||x[L[e]]}var w=[],E=Object.keys,x={},L={},k=/^(no-?highlight|plain|text)$/i,B=/\blang(?:uage)?-([\w-]+)\b/i,M=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,C="</span>",y={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},I={"&":"&amp;","<":"&lt;",">":"&gt;"};return e.highlight=l,e.highlightAuto=f,e.fixMarkup=g,e.highlightBlock=p,e.configure=d,e.initHighlighting=b,e.initHighlightingOnLoad=v,e.registerLanguage=m,e.listLanguages=N,e.getLanguage=R,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|like)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("json",function(e){var i={literal:"true false null"},n=[e.QSM,e.CNM],r={e:",",eW:!0,eE:!0,c:n,k:i},t={b:"{",e:"}",c:[{cN:"attr",b:/"/,e:/"/,c:[e.BE],i:"\\n"},e.inherit(r,{b:/:/})],i:"\\S"},c={b:"\\[",e:"\\]",c:[e.inherit(r)],i:"\\S"};return n.splice(n.length,0,t,c),{c:n,k:i,i:"\\S"}});hljs.registerLanguage("scss",function(e){var t="[a-zA-Z-][a-zA-Z0-9_-]*",i={cN:"variable",b:"(\\$"+t+")\\b"},r={cN:"number",b:"#[0-9A-Fa-f]+"};({cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:!0,i:"[^\\s]",starts:{eW:!0,eE:!0,c:[r,e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"meta",b:"!important"}]}});return{cI:!0,i:"[=/|']",c:[e.CLCM,e.CBCM,{cN:"selector-id",b:"\\#[A-Za-z0-9_-]+",r:0},{cN:"selector-class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"selector-attr",b:"\\[",e:"\\]",i:"$"},{cN:"selector-tag",b:"\\b(a|abbr|acronym|address|area|article|aside|audio|b|base|big|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|frame|frameset|(h[1-6])|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|map|mark|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|samp|script|section|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|ul|var|video)\\b",r:0},{b:":(visited|valid|root|right|required|read-write|read-only|out-range|optional|only-of-type|only-child|nth-of-type|nth-last-of-type|nth-last-child|nth-child|not|link|left|last-of-type|last-child|lang|invalid|indeterminate|in-range|hover|focus|first-of-type|first-line|first-letter|first-child|first|enabled|empty|disabled|default|checked|before|after|active)"},{b:"::(after|before|choices|first-letter|first-line|repeat-index|repeat-item|selection|value)"},i,{cN:"attribute",b:"\\b(z-index|word-wrap|word-spacing|word-break|width|widows|white-space|visibility|vertical-align|unicode-bidi|transition-timing-function|transition-property|transition-duration|transition-delay|transition|transform-style|transform-origin|transform|top|text-underline-position|text-transform|text-shadow|text-rendering|text-overflow|text-indent|text-decoration-style|text-decoration-line|text-decoration-color|text-decoration|text-align-last|text-align|tab-size|table-layout|right|resize|quotes|position|pointer-events|perspective-origin|perspective|page-break-inside|page-break-before|page-break-after|padding-top|padding-right|padding-left|padding-bottom|padding|overflow-y|overflow-x|overflow-wrap|overflow|outline-width|outline-style|outline-offset|outline-color|outline|orphans|order|opacity|object-position|object-fit|normal|none|nav-up|nav-right|nav-left|nav-index|nav-down|min-width|min-height|max-width|max-height|mask|marks|margin-top|margin-right|margin-left|margin-bottom|margin|list-style-type|list-style-position|list-style-image|list-style|line-height|letter-spacing|left|justify-content|initial|inherit|ime-mode|image-orientation|image-resolution|image-rendering|icon|hyphens|height|font-weight|font-variant-ligatures|font-variant|font-style|font-stretch|font-size-adjust|font-size|font-language-override|font-kerning|font-feature-settings|font-family|font|float|flex-wrap|flex-shrink|flex-grow|flex-flow|flex-direction|flex-basis|flex|filter|empty-cells|display|direction|cursor|counter-reset|counter-increment|content|column-width|column-span|column-rule-width|column-rule-style|column-rule-color|column-rule|column-gap|column-fill|column-count|columns|color|clip-path|clip|clear|caption-side|break-inside|break-before|break-after|box-sizing|box-shadow|box-decoration-break|bottom|border-width|border-top-width|border-top-style|border-top-right-radius|border-top-left-radius|border-top-color|border-top|border-style|border-spacing|border-right-width|border-right-style|border-right-color|border-right|border-radius|border-left-width|border-left-style|border-left-color|border-left|border-image-width|border-image-source|border-image-slice|border-image-repeat|border-image-outset|border-image|border-color|border-collapse|border-bottom-width|border-bottom-style|border-bottom-right-radius|border-bottom-left-radius|border-bottom-color|border-bottom|border|background-size|background-repeat|background-position|background-origin|background-image|background-color|background-clip|background-attachment|background-blend-mode|background|backface-visibility|auto|animation-timing-function|animation-play-state|animation-name|animation-iteration-count|animation-fill-mode|animation-duration|animation-direction|animation-delay|animation|align-self|align-items|align-content)\\b",i:"[^\\s]"},{b:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b"},{b:":",e:";",c:[i,r,e.CSSNM,e.QSM,e.ASM,{cN:"meta",b:"!important"}]},{b:"@",e:"[{;]",k:"mixin include extend for if else each while charset import debug media page content font-face namespace warn",c:[i,e.QSM,e.ASM,r,e.CSSNM,{b:"\\s[A-Za-z0-9_.-]+",r:0}]}]}});hljs.registerLanguage("sql",function(e){var t=e.C("--","$");return{cI:!0,i:/[<>{}*#]/,c:[{bK:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke comment",e:/;/,eW:!0,l:/[\w\.]+/,k:{keyword:"abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias allocate allow alter always analyze ancillary and any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second section securefile security seed segment select self sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek",literal:"true false null",built_in:"array bigint binary bit blob boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text varchar varying void"},c:[{cN:"string",b:"'",e:"'",c:[e.BE,{b:"''"}]},{cN:"string",b:'"',e:'"',c:[e.BE,{b:'""'}]},{cN:"string",b:"`",e:"`",c:[e.BE]},e.CNM,e.CBCM,t]},e.CBCM,t]}});hljs.registerLanguage("javascript",function(e){return{aliases:["js","jsx"],k:{keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},c:[{cN:"meta",r:10,b:/^\s*['"]use (strict|asm)['"]/},{cN:"meta",b:/^#!/,e:/$/},e.ASM,e.QSM,{cN:"string",b:"`",e:"`",c:[e.BE,{cN:"subst",b:"\\$\\{",e:"\\}"}]},e.CLCM,e.CBCM,{cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{b:/</,e:/(\/\w+|\w+\/)>/,sL:"xml",c:[{b:/<\w+\s*\/>/,skip:!0},{b:/<\w+/,e:/(\/\w+|\w+\/)>/,skip:!0,c:["self"]}]}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:[e.CLCM,e.CBCM]}],i:/\[|%/},{b:/\$[(.]/},e.METHOD_GUARD,{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]},{bK:"constructor",e:/\{/,eE:!0}],i:/#(?!!)/}});hljs.registerLanguage("nginx",function(e){var r={cN:"variable",v:[{b:/\$\d+/},{b:/\$\{/,e:/}/},{b:"[\\$\\@]"+e.UIR}]},b={eW:!0,l:"[a-z/_]+",k:{literal:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},r:0,i:"=>",c:[e.HCM,{cN:"string",c:[e.BE,r],v:[{b:/"/,e:/"/},{b:/'/,e:/'/}]},{b:"([a-z]+):/",e:"\\s",eW:!0,eE:!0,c:[r]},{cN:"regexp",c:[e.BE,r],v:[{b:"\\s\\^",e:"\\s|{|;",rE:!0},{b:"~\\*?\\s+",e:"\\s|{|;",rE:!0},{b:"\\*(\\.[a-z\\-]+)+"},{b:"([a-z\\-]+\\.)+\\*"}]},{cN:"number",b:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{cN:"number",b:"\\b\\d+[kKmMgGdshdwy]*\\b",r:0},r]};return{aliases:["nginxconf"],c:[e.HCM,{b:e.UIR+"\\s+{",rB:!0,e:"{",c:[{cN:"section",b:e.UIR}],r:0},{b:e.UIR+"\\s",e:";|{",rB:!0,c:[{cN:"attribute",b:e.UIR,starts:b}],r:0}],i:"[^\\s\\}]"}});hljs.registerLanguage("php",function(e){var c={b:"\\$+[a-zA-Z_\7f-ÿ][a-zA-Z0-9_\7f-ÿ]*"},i={cN:"meta",b:/<\?(php)?|\?>/},t={cN:"string",c:[e.BE,i],v:[{b:'b"',e:'"'},{b:"b'",e:"'"},e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null})]},a={v:[e.BNM,e.CNM]};return{aliases:["php3","php4","php5","php6"],cI:!0,k:"and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try switch continue endfor endif declare unset true false trait goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally",c:[e.HCM,e.C("//","$",{c:[i]}),e.C("/\\*","\\*/",{c:[{cN:"doctag",b:"@[A-Za-z]+"}]}),e.C("__halt_compiler.+?;",!1,{eW:!0,k:"__halt_compiler",l:e.UIR}),{cN:"string",b:/<<<['"]?\w+['"]?$/,e:/^\w+;?$/,c:[e.BE,{cN:"subst",v:[{b:/\$\w+/},{b:/\{\$/,e:/\}/}]}]},i,{cN:"keyword",b:/\$this\b/},c,{b:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{cN:"function",bK:"function",e:/[;{]/,eE:!0,i:"\\$|\\[|%",c:[e.UTM,{cN:"params",b:"\\(",e:"\\)",c:["self",c,e.CBCM,t,a]}]},{cN:"class",bK:"class interface",e:"{",eE:!0,i:/[:\(\$"]/,c:[{bK:"extends implements"},e.UTM]},{bK:"namespace",e:";",i:/[\.']/,c:[e.UTM]},{bK:"use",e:";",c:[e.UTM]},{b:"=>"},t,a]}});hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},s={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/-?[a-z\._]+/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"meta",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,s,a,t]}});hljs.registerLanguage("apache",function(e){var r={cN:"number",b:"[\\$%]\\d+"};return{aliases:["apacheconf"],cI:!0,c:[e.HCM,{cN:"section",b:"</?",e:">"},{cN:"attribute",b:/\w+/,r:0,k:{nomarkup:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername"},starts:{e:/$/,r:0,k:{literal:"on off all"},c:[{cN:"meta",b:"\\s\\[",e:"\\]$"},{cN:"variable",b:"[\\$%]\\{",e:"\\}",c:["self",r]},r,e.QSM]}}],i:/\S/}});hljs.registerLanguage("xml",function(s){var e="[A-Za-z0-9\\._:-]+",t={eW:!0,i:/</,r:0,c:[{cN:"attr",b:e,r:0},{b:/=\s*/,r:0,c:[{cN:"string",endsParent:!0,v:[{b:/"/,e:/"/},{b:/'/,e:/'/},{b:/[^\s"'=<>`]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist"],cI:!0,c:[{cN:"meta",b:"<!DOCTYPE",e:">",r:10,c:[{b:"\\[",e:"\\]"}]},s.C("<!--","-->",{r:10}),{b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{b:/<\?(php)?/,e:/\?>/,sL:"php",c:[{b:"/\\*",e:"\\*/",skip:!0}]},{cN:"tag",b:"<style(?=\\s|>|$)",e:">",k:{name:"style"},c:[t],starts:{e:"</style>",rE:!0,sL:["css","xml"]}},{cN:"tag",b:"<script(?=\\s|>|$)",e:">",k:{name:"script"},c:[t],starts:{e:"</script>",rE:!0,sL:["actionscript","javascript","handlebars","xml"]}},{cN:"meta",v:[{b:/<\?xml/,e:/\?>/,r:10},{b:/<\?\w+/,e:/\?>/}]},{cN:"tag",b:"</?",e:"/?>",c:[{cN:"name",b:/[^\/><\s]+/,r:0},t]}]}});hljs.registerLanguage("diff",function(e){return{aliases:["patch"],c:[{cN:"meta",r:10,v:[{b:/^@@ +\-\d+,\d+ +\+\d+,\d+ +@@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"comment",v:[{b:/Index: /,e:/$/},{b:/={3,}/,e:/$/},{b:/^\-{3}/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+{3}/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"addition",b:"^\\!",e:"$"}]}});hljs.registerLanguage("markdown",function(e){return{aliases:["md","mkdown","mkd"],c:[{cN:"section",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"quote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"^```w*s*$",e:"^```s*$"},{b:"`.+?`"},{b:"^( {4}|    )",e:"$",r:0}]},{b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].*?[\\)\\]]",rB:!0,c:[{cN:"string",b:"\\[",e:"\\]",eB:!0,rE:!0,r:0},{cN:"link",b:"\\]\\(",e:"\\)",eB:!0,eE:!0},{cN:"symbol",b:"\\]\\[",e:"\\]",eB:!0,eE:!0}],r:10},{b:/^\[[^\n]+\]:/,rB:!0,c:[{cN:"symbol",b:/\[/,e:/\]/,eB:!0,eE:!0},{cN:"link",b:/:\s*/,e:/$/,eB:!0}]}]}});hljs.registerLanguage("css",function(e){var c="[a-zA-Z-][a-zA-Z0-9_-]*",t={b:/[A-Z\_\.\-]+\s*:/,rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:/\S/,e:":",eE:!0,starts:{eW:!0,eE:!0,c:[{b:/[\w-]+\(/,rB:!0,c:[{cN:"built_in",b:/[\w-]+/},{b:/\(/,e:/\)/,c:[e.ASM,e.QSM]}]},e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"number",b:"#[0-9A-Fa-f]+"},{cN:"meta",b:"!important"}]}}]};return{cI:!0,i:/[=\/|'\$]/,c:[e.CBCM,{cN:"selector-id",b:/#[A-Za-z0-9_-]+/},{cN:"selector-class",b:/\.[A-Za-z0-9_-]+/},{cN:"selector-attr",b:/\[/,e:/\]/,i:"$"},{cN:"selector-pseudo",b:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{b:"@",e:"[{;]",i:/:/,c:[{cN:"keyword",b:/\w+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[e.ASM,e.QSM,e.CSSNM]}]},{cN:"selector-tag",b:c,r:0},{b:"{",e:"}",i:/\S/,c:[e.CBCM,t]}]}});hljs.registerLanguage("cpp",function(t){var e={cN:"keyword",b:"\\b[a-z\\d_]*_t\\b"},r={cN:"string",v:[{b:'(u8?|U)?L?"',e:'"',i:"\\n",c:[t.BE]},{b:'(u8?|U)?R"',e:'"',c:[t.BE]},{b:"'\\\\?.",e:"'",i:"."}]},s={cN:"number",v:[{b:"\\b(0b[01'_]+)"},{b:"\\b([\\d'_]+(\\.[\\d'_]*)?|\\.[\\d'_]+)(u|U|l|L|ul|UL|f|F|b|B)"},{b:"(-?)(\\b0[xX][a-fA-F0-9'_]+|(\\b[\\d'_]+(\\.[\\d'_]*)?|\\.[\\d'_]+)([eE][-+]?[\\d'_]+)?)"}],r:0},i={cN:"meta",b:/#\s*[a-z]+\b/,e:/$/,k:{"meta-keyword":"if else elif endif define undef warning error line pragma ifdef ifndef include"},c:[{b:/\\\n/,r:0},t.inherit(r,{cN:"meta-string"}),{cN:"meta-string",b:"<",e:">",i:"\\n"},t.CLCM,t.CBCM]},a=t.IR+"\\s*\\(",c={keyword:"int float while private char catch import module export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const struct for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using class asm case typeid short reinterpret_cast|10 default double register explicit signed typename try this switch continue inline delete alignof constexpr decltype noexcept static_assert thread_local restrict _Bool complex _Complex _Imaginary atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong new throw return",built_in:"std string cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap array shared_ptr abort abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr",literal:"true false nullptr NULL"},n=[e,t.CLCM,t.CBCM,s,r];return{aliases:["c","cc","h","c++","h++","hpp"],k:c,i:"</",c:n.concat([i,{b:"\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<",e:">",k:c,c:["self",e]},{b:t.IR+"::",k:c},{v:[{b:/=/,e:/;/},{b:/\(/,e:/\)/},{bK:"new throw return else",e:/;/}],k:c,c:n.concat([{b:/\(/,e:/\)/,k:c,c:n.concat(["self"]),r:0}]),r:0},{cN:"function",b:"("+t.IR+"[\\*&\\s]+)+"+a,rB:!0,e:/[{;=]/,eE:!0,k:c,i:/[^\w\s\*&]/,c:[{b:a,rB:!0,c:[t.TM],r:0},{cN:"params",b:/\(/,e:/\)/,k:c,r:0,c:[t.CLCM,t.CBCM,r,s,e]},t.CLCM,t.CBCM,i]}]),exports:{preprocessor:i,strings:r,k:c}}});
\ No newline at end of file
diff --git a/themes/bookstack/static/libs/highlight/styles/atom-one-light.css b/themes/bookstack/static/libs/highlight/styles/atom-one-light.css
deleted file mode 100644 (file)
index 0ac3bb6..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
-
-Atom One Light by Daniel Gamage
-Original One Light Syntax theme from https://github.com/atom/one-light-syntax
-
-base:    #fafafa
-mono-1:  #383a42
-mono-2:  #686b77
-mono-3:  #a0a1a7
-hue-1:   #0184bb
-hue-2:   #4078f2
-hue-3:   #a626a4
-hue-4:   #50a14f
-hue-5:   #e45649
-hue-5-2: #c91243
-hue-6:   #986801
-hue-6-2: #c18401
-
-*/
-
-.hljs {
-  display: block;
-  overflow-x: auto;
-  padding: 0.5em;
-  color: #383a42;
-  background: #fafafa;
-}
-
-.hljs-comment,
-.hljs-quote {
-  color: #a0a1a7;
-  font-style: italic;
-}
-
-.hljs-doctag,
-.hljs-keyword,
-.hljs-formula {
-  color: #a626a4;
-}
-
-.hljs-section,
-.hljs-name,
-.hljs-selector-tag,
-.hljs-deletion,
-.hljs-subst {
-  color: #e45649;
-}
-
-.hljs-literal {
-  color: #0184bb;
-}
-
-.hljs-string,
-.hljs-regexp,
-.hljs-addition,
-.hljs-attribute,
-.hljs-meta-string {
-  color: #50a14f;
-}
-
-.hljs-built_in,
-.hljs-class .hljs-title {
-  color: #c18401;
-}
-
-.hljs-variable,
-.hljs-template-variable,
-.hljs-type,
-.hljs-selector-class,
-.hljs-selector-attr,
-.hljs-selector-pseudo,
-.hljs-number {
-  color: #986801;
-}
-
-.hljs-symbol,
-.hljs-bullet,
-.hljs-link,
-.hljs-meta,
-.hljs-selector-id,
-.hljs-title {
-  color: #4078f2;
-}
-
-.hljs-emphasis {
-  font-style: italic;
-}
-
-.hljs-strong {
-  font-weight: bold;
-}
-
-.hljs-link {
-  text-decoration: underline;
-}
diff --git a/yarn.lock b/yarn.lock
deleted file mode 100644 (file)
index 8557980..0000000
--- a/yarn.lock
+++ /dev/null
@@ -1,2006 +0,0 @@
-# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
-# yarn lockfile v1
-abbrev@1:
-  version "1.0.9"
-  resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135"
-
-amdefine@>=0.0.4:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
-
-ansi-regex@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.0.0.tgz#c5061b6e0ef8a81775e50f5d66151bf6bf371107"
-
-ansi-styles@^2.2.1:
-  version "2.2.1"
-  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
-
-aproba@^1.0.3:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0"
-
-archy@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40"
-
-are-we-there-yet@~1.1.2:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3"
-  dependencies:
-    delegates "^1.0.0"
-    readable-stream "^2.0.0 || ^1.1.13"
-
-arr-diff@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
-  dependencies:
-    arr-flatten "^1.0.1"
-
-arr-flatten@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b"
-
-array-differ@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031"
-
-array-find-index@^1.0.1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
-
-array-uniq@^1.0.2:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
-
-array-unique@^0.2.1:
-  version "0.2.1"
-  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
-
-asn1@~0.2.3:
-  version "0.2.3"
-  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
-
-assert-plus@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
-
-assert-plus@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
-
-async-foreach@^0.1.3:
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542"
-
-asynckit@^0.4.0:
-  version "0.4.0"
-  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
-
-autoprefixer@^6.0.0:
-  version "6.6.1"
-  resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.6.1.tgz#11a4077abb4b313253ec2f6e1adb91ad84253519"
-  dependencies:
-    browserslist "~1.5.1"
-    caniuse-db "^1.0.30000604"
-    normalize-range "^0.1.2"
-    num2fraction "^1.2.2"
-    postcss "^5.2.8"
-    postcss-value-parser "^3.2.3"
-
-aws-sign2@~0.6.0:
-  version "0.6.0"
-  resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
-
-aws4@^1.2.1:
-  version "1.5.0"
-  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755"
-
-balanced-match@^0.4.1:
-  version "0.4.2"
-  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
-
-bcrypt-pbkdf@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz#3ca76b85241c7170bf7d9703e7b9aa74630040d4"
-  dependencies:
-    tweetnacl "^0.14.3"
-
-beeper@^1.0.0:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809"
-
-block-stream@*:
-  version "0.0.9"
-  resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
-  dependencies:
-    inherits "~2.0.0"
-
-  version "2.10.1"
-  resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
-  dependencies:
-    hoek "2.x.x"
-
-brace-expansion@^1.0.0:
-  version "1.1.6"
-  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
-  dependencies:
-    balanced-match "^0.4.1"
-    concat-map "0.0.1"
-
-braces@^1.8.2:
-  version "1.8.5"
-  resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
-  dependencies:
-    expand-range "^1.8.1"
-    preserve "^0.2.0"
-    repeat-element "^1.1.2"
-
-browserslist@~1.5.1:
-  version "1.5.2"
-  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.5.2.tgz#1c82fde0ee8693e6d15c49b7bff209dc06298c56"
-  dependencies:
-    caniuse-db "^1.0.30000604"
-
-buffer-shims@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51"
-
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/bufferstreams/-/bufferstreams-1.0.1.tgz#cfb1ad9568d3ba3cfe935ba9abdd952de88aab2a"
-  dependencies:
-    readable-stream "^1.0.33"
-
-builtin-modules@^1.0.0:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
-
-camelcase-keys@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
-  dependencies:
-    camelcase "^2.0.0"
-    map-obj "^1.0.0"
-
-camelcase@^2.0.0:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
-
-camelcase@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
-
-caniuse-db@^1.0.30000604:
-  version "1.0.30000609"
-  resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000609.tgz#8c141ef09e8c66b7cb6c2b288fa931cc331e38c6"
-
-caseless@~0.11.0:
-  version "0.11.0"
-  resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
-
-chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
-  dependencies:
-    ansi-styles "^2.2.1"
-    escape-string-regexp "^1.0.2"
-    has-ansi "^2.0.0"
-    strip-ansi "^3.0.0"
-    supports-color "^2.0.0"
-
-clean-css@^3.3.3:
-  version "3.4.23"
-  resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.23.tgz#604fbbca24c12feb59b02f00b84f1fb7ded6d001"
-  dependencies:
-    commander "2.8.x"
-    source-map "0.4.x"
-
-cliui@^3.2.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
-  dependencies:
-    string-width "^1.0.1"
-    strip-ansi "^3.0.1"
-    wrap-ansi "^2.0.0"
-
-clone-stats@^0.0.1:
-  version "0.0.1"
-  resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1"
-
-clone@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f"
-
-clone@^1.0.0, clone@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149"
-
-code-point-at@^1.0.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
-
-combined-stream@^1.0.5, combined-stream@~1.0.5:
-  version "1.0.5"
-  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
-  dependencies:
-    delayed-stream "~1.0.0"
-
-commander@^2.9.0:
-  version "2.9.0"
-  resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"
-  dependencies:
-    graceful-readlink ">= 1.0.0"
-
-  version "2.8.1"
-  resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4"
-  dependencies:
-    graceful-readlink ">= 1.0.0"
-
-  version "0.0.1"
-  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
-
-console-control-strings@^1.0.0, console-control-strings@~1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
-
-core-util-is@~1.0.0:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
-
-cross-spawn@^3.0.0:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982"
-  dependencies:
-    lru-cache "^4.0.1"
-    which "^1.2.9"
-
-  version "2.0.5"
-  resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
-  dependencies:
-    boom "2.x.x"
-
-currently-unhandled@^0.4.1:
-  version "0.4.1"
-  resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
-  dependencies:
-    array-find-index "^1.0.1"
-
-dashdash@^1.12.0:
-  version "1.14.1"
-  resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
-  dependencies:
-    assert-plus "^1.0.0"
-
-dateformat@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.0.0.tgz#2743e3abb5c3fc2462e527dca445e04e9f4dee17"
-
-decamelize@^1.1.1, decamelize@^1.1.2:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
-
-defaults@^1.0.0:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
-  dependencies:
-    clone "^1.0.2"
-
-delayed-stream@~1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
-
-delegates@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
-
-deprecated@^0.0.1:
-  version "0.0.1"
-  resolved "https://registry.yarnpkg.com/deprecated/-/deprecated-0.0.1.tgz#f9c9af5464afa1e7a971458a8bdef2aa94d5bb19"
-
-detect-file@^0.1.0:
-  version "0.1.0"
-  resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63"
-  dependencies:
-    fs-exists-sync "^0.1.0"
-
-  version "0.0.2"
-  resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db"
-  dependencies:
-    readable-stream "~1.1.9"
-
-ecc-jsbn@~0.1.1:
-  version "0.1.1"
-  resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
-  dependencies:
-    jsbn "~0.1.0"
-
-end-of-stream@~0.1.5:
-  version "0.1.5"
-  resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-0.1.5.tgz#8e177206c3c80837d85632e8b9359dfe8b2f6eaf"
-  dependencies:
-    once "~1.3.0"
-
-error-ex@^1.2.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.0.tgz#e67b43f3e82c96ea3a584ffee0b9fc3325d802d9"
-  dependencies:
-    is-arrayish "^0.2.1"
-
-escape-string-regexp@^1.0.2:
-  version "1.0.5"
-  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
-
-expand-brackets@^0.1.4:
-  version "0.1.5"
-  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
-  dependencies:
-    is-posix-bracket "^0.1.0"
-
-expand-range@^1.8.1:
-  version "1.8.2"
-  resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
-  dependencies:
-    fill-range "^2.1.0"
-
-expand-tilde@^1.2.1, expand-tilde@^1.2.2:
-  version "1.2.2"
-  resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449"
-  dependencies:
-    os-homedir "^1.0.1"
-
-extend@^3.0.0, extend@~3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
-
-extglob@^0.3.1:
-  version "0.3.2"
-  resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
-  dependencies:
-    is-extglob "^1.0.0"
-
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
-
-fancy-log@^1.1.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.0.tgz#45be17d02bb9917d60ccffd4995c999e6c8c9948"
-  dependencies:
-    chalk "^1.1.1"
-    time-stamp "^1.0.0"
-
-filename-regex@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
-
-fill-range@^2.1.0:
-  version "2.2.3"
-  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
-  dependencies:
-    is-number "^2.1.0"
-    isobject "^2.0.0"
-    randomatic "^1.1.3"
-    repeat-element "^1.1.2"
-    repeat-string "^1.5.2"
-
-find-index@^0.1.1:
-  version "0.1.1"
-  resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4"
-
-find-up@^1.0.0:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
-  dependencies:
-    path-exists "^2.0.0"
-    pinkie-promise "^2.0.0"
-
-findup-sync@^0.4.2:
-  version "0.4.3"
-  resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12"
-  dependencies:
-    detect-file "^0.1.0"
-    is-glob "^2.0.1"
-    micromatch "^2.3.7"
-    resolve-dir "^0.1.0"
-
-fined@^1.0.1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/fined/-/fined-1.0.2.tgz#5b28424b760d7598960b7ef8480dff8ad3660e97"
-  dependencies:
-    expand-tilde "^1.2.1"
-    lodash.assignwith "^4.0.7"
-    lodash.isempty "^4.2.1"
-    lodash.isplainobject "^4.0.4"
-    lodash.isstring "^4.0.1"
-    lodash.pick "^4.2.1"
-    parse-filepath "^1.0.1"
-
-first-chunk-stream@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e"
-
-flagged-respawn@^0.3.2:
-  version "0.3.2"
-  resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-0.3.2.tgz#ff191eddcd7088a675b2610fffc976be9b8074b5"
-
-for-in@^0.1.5:
-  version "0.1.6"
-  resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8"
-
-for-own@^0.1.4:
-  version "0.1.4"
-  resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072"
-  dependencies:
-    for-in "^0.1.5"
-
-forever-agent@~0.6.1:
-  version "0.6.1"
-  resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
-
-form-data@~2.1.1:
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4"
-  dependencies:
-    asynckit "^0.4.0"
-    combined-stream "^1.0.5"
-    mime-types "^2.1.12"
-
-fs-exists-sync@^0.1.0:
-  version "0.1.0"
-  resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add"
-
-fs.realpath@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
-
-fstream@^1.0.0, fstream@^1.0.2:
-  version "1.0.10"
-  resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822"
-  dependencies:
-    graceful-fs "^4.1.2"
-    inherits "~2.0.0"
-    mkdirp ">=0.5 0"
-    rimraf "2"
-
-gauge@~2.7.1:
-  version "2.7.2"
-  resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.2.tgz#15cecc31b02d05345a5d6b0e171cdb3ad2307774"
-  dependencies:
-    aproba "^1.0.3"
-    console-control-strings "^1.0.0"
-    has-unicode "^2.0.0"
-    object-assign "^4.1.0"
-    signal-exit "^3.0.0"
-    string-width "^1.0.1"
-    strip-ansi "^3.0.1"
-    supports-color "^0.2.0"
-    wide-align "^1.1.0"
-
-gaze@^0.5.1:
-  version "0.5.2"
-  resolved "https://registry.yarnpkg.com/gaze/-/gaze-0.5.2.tgz#40b709537d24d1d45767db5a908689dfe69ac44f"
-  dependencies:
-    globule "~0.1.0"
-
-gaze@^1.0.0:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.2.tgz#847224677adb8870d679257ed3388fdb61e40105"
-  dependencies:
-    globule "^1.0.0"
-
-generate-function@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74"
-
-generate-object-property@^1.1.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0"
-  dependencies:
-    is-property "^1.0.0"
-
-get-caller-file@^1.0.1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
-
-get-stdin@^4.0.1:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
-
-getpass@^0.1.1:
-  version "0.1.6"
-  resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6"
-  dependencies:
-    assert-plus "^1.0.0"
-
-glob-base@^0.3.0:
-  version "0.3.0"
-  resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
-  dependencies:
-    glob-parent "^2.0.0"
-    is-glob "^2.0.0"
-
-glob-parent@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
-  dependencies:
-    is-glob "^2.0.0"
-
-glob-stream@^3.1.5:
-  version "3.1.18"
-  resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-3.1.18.tgz#9170a5f12b790306fdfe598f313f8f7954fd143b"
-  dependencies:
-    glob "^4.3.1"
-    glob2base "^0.0.12"
-    minimatch "^2.0.1"
-    ordered-read-streams "^0.1.0"
-    through2 "^0.6.1"
-    unique-stream "^1.0.0"
-
-glob-watcher@^0.0.6:
-  version "0.0.6"
-  resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-0.0.6.tgz#b95b4a8df74b39c83298b0c05c978b4d9a3b710b"
-  dependencies:
-    gaze "^0.5.1"
-
-glob@^4.3.1:
-  version "4.5.3"
-  resolved "https://registry.yarnpkg.com/glob/-/glob-4.5.3.tgz#c6cb73d3226c1efef04de3c56d012f03377ee15f"
-  dependencies:
-    inflight "^1.0.4"
-    inherits "2"
-    minimatch "^2.0.1"
-    once "^1.3.0"
-
-glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@~7.1.1:
-  version "7.1.1"
-  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
-  dependencies:
-    fs.realpath "^1.0.0"
-    inflight "^1.0.4"
-    inherits "2"
-    minimatch "^3.0.2"
-    once "^1.3.0"
-    path-is-absolute "^1.0.0"
-
-glob@~3.1.21:
-  version "3.1.21"
-  resolved "https://registry.yarnpkg.com/glob/-/glob-3.1.21.tgz#d29e0a055dea5138f4d07ed40e8982e83c2066cd"
-  dependencies:
-    graceful-fs "~1.2.0"
-    inherits "1"
-    minimatch "~0.2.11"
-
-glob2base@^0.0.12:
-  version "0.0.12"
-  resolved "https://registry.yarnpkg.com/glob2base/-/glob2base-0.0.12.tgz#9d419b3e28f12e83a362164a277055922c9c0d56"
-  dependencies:
-    find-index "^0.1.1"
-
-global-modules@^0.2.3:
-  version "0.2.3"
-  resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d"
-  dependencies:
-    global-prefix "^0.1.4"
-    is-windows "^0.2.0"
-
-global-prefix@^0.1.4:
-  version "0.1.5"
-  resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f"
-  dependencies:
-    homedir-polyfill "^1.0.0"
-    ini "^1.3.4"
-    is-windows "^0.2.0"
-    which "^1.2.12"
-
-globule@^1.0.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/globule/-/globule-1.1.0.tgz#c49352e4dc183d85893ee825385eb994bb6df45f"
-  dependencies:
-    glob "~7.1.1"
-    lodash "~4.16.4"
-    minimatch "~3.0.2"
-
-globule@~0.1.0:
-  version "0.1.0"
-  resolved "https://registry.yarnpkg.com/globule/-/globule-0.1.0.tgz#d9c8edde1da79d125a151b79533b978676346ae5"
-  dependencies:
-    glob "~3.1.21"
-    lodash "~1.0.1"
-    minimatch "~0.2.11"
-
-glogg@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.0.tgz#7fe0f199f57ac906cf512feead8f90ee4a284fc5"
-  dependencies:
-    sparkles "^1.0.0"
-
-graceful-fs@^3.0.0:
-  version "3.0.11"
-  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818"
-  dependencies:
-    natives "^1.1.0"
-
-graceful-fs@^4.1.2:
-  version "4.1.11"
-  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
-
-graceful-fs@~1.2.0:
-  version "1.2.3"
-  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364"
-
-"graceful-readlink@>= 1.0.0":
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
-
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/gulp-autoprefixer/-/gulp-autoprefixer-3.0.2.tgz#b6454046757aeedf21076048f608264e3ff6f4c1"
-  dependencies:
-    autoprefixer "^6.0.0"
-    gulp-util "^3.0.0"
-    postcss "^5.0.4"
-    through2 "^2.0.0"
-    vinyl-sourcemaps-apply "^0.1.3"
-
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/gulp-minify-css/-/gulp-minify-css-1.2.1.tgz#1d34d6bc685c7c2d8cf73d533a64bc432bbcef32"
-  dependencies:
-    clean-css "^3.3.3"
-    gulp-util "^3.0.5"
-    object-assign "^4.0.1"
-    readable-stream "^2.0.0"
-    vinyl-bufferstream "^1.0.1"
-    vinyl-sourcemaps-apply "^0.1.4"
-
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/gulp-plumber/-/gulp-plumber-1.0.1.tgz#56d8e74a0a05a8b75d2ecc11800d0191df542af2"
-  dependencies:
-    gulp-util "~3"
-    through2 "~0.6"
-
-  version "1.2.2"
-  resolved "https://registry.yarnpkg.com/gulp-rename/-/gulp-rename-1.2.2.tgz#3ad4428763f05e2764dec1c67d868db275687817"
-
-  version "2.0.4"
-  resolved "https://registry.yarnpkg.com/gulp-sass/-/gulp-sass-2.0.4.tgz#9703de980b9ebf2a418271e0c5e3e4ed9adf76ba"
-  dependencies:
-    gulp-util "^3.0"
-    node-sass "^3.0.0"
-    object-assign "^2.0.0"
-    through2 "^0.6.3"
-    vinyl-sourcemaps-apply "~0.1.1"
-
-gulp-util@^3.0, gulp-util@^3.0.0, gulp-util@^3.0.5, gulp-util@~3:
-  version "3.0.8"
-  resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f"
-  dependencies:
-    array-differ "^1.0.0"
-    array-uniq "^1.0.2"
-    beeper "^1.0.0"
-    chalk "^1.0.0"
-    dateformat "^2.0.0"
-    fancy-log "^1.1.0"
-    gulplog "^1.0.0"
-    has-gulplog "^0.1.0"
-    lodash._reescape "^3.0.0"
-    lodash._reevaluate "^3.0.0"
-    lodash._reinterpolate "^3.0.0"
-    lodash.template "^3.0.0"
-    minimist "^1.1.0"
-    multipipe "^0.1.2"
-    object-assign "^3.0.0"
-    replace-ext "0.0.1"
-    through2 "^2.0.0"
-    vinyl "^0.5.0"
-
-  version "3.9.0"
-  resolved "https://registry.yarnpkg.com/gulp/-/gulp-3.9.0.tgz#cf1fba4cb558bb8c6ae6c9613f583ae2620d214a"
-  dependencies:
-    archy "^1.0.0"
-    chalk "^1.0.0"
-    deprecated "^0.0.1"
-    gulp-util "^3.0.0"
-    interpret "^0.6.2"
-    liftoff "^2.1.0"
-    minimist "^1.1.0"
-    orchestrator "^0.3.0"
-    pretty-hrtime "^1.0.0"
-    semver "^4.1.0"
-    tildify "^1.0.0"
-    v8flags "^2.0.2"
-    vinyl-fs "^0.3.0"
-
-gulplog@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5"
-  dependencies:
-    glogg "^1.0.0"
-
-har-validator@~2.0.6:
-  version "2.0.6"
-  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d"
-  dependencies:
-    chalk "^1.1.1"
-    commander "^2.9.0"
-    is-my-json-valid "^2.12.4"
-    pinkie-promise "^2.0.0"
-
-has-ansi@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
-  dependencies:
-    ansi-regex "^2.0.0"
-
-has-flag@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
-
-has-gulplog@^0.1.0:
-  version "0.1.0"
-  resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce"
-  dependencies:
-    sparkles "^1.0.0"
-
-has-unicode@^2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
-
-hawk@~3.1.3:
-  version "3.1.3"
-  resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
-  dependencies:
-    boom "2.x.x"
-    cryptiles "2.x.x"
-    hoek "2.x.x"
-    sntp "1.x.x"
-
-  version "2.16.3"
-  resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
-
-homedir-polyfill@^1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc"
-  dependencies:
-    parse-passwd "^1.0.0"
-
-hosted-git-info@^2.1.4:
-  version "2.1.5"
-  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b"
-
-http-signature@~1.1.0:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
-  dependencies:
-    assert-plus "^0.2.0"
-    jsprim "^1.2.2"
-    sshpk "^1.7.0"
-
-in-publish@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51"
-
-indent-string@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
-  dependencies:
-    repeating "^2.0.0"
-
-inflight@^1.0.4:
-  version "1.0.6"
-  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
-  dependencies:
-    once "^1.3.0"
-    wrappy "1"
-
-inherits@~2.0.0, inherits@~2.0.1, inherits@2:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
-
-inherits@1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b"
-
-ini@^1.3.4:
-  version "1.3.4"
-  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
-
-interpret@^0.6.2:
-  version "0.6.6"
-  resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b"
-
-invert-kv@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
-
-is-absolute@^0.2.3:
-  version "0.2.6"
-  resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-0.2.6.tgz#20de69f3db942ef2d87b9c2da36f172235b1b5eb"
-  dependencies:
-    is-relative "^0.2.1"
-    is-windows "^0.2.0"
-
-is-arrayish@^0.2.1:
-  version "0.2.1"
-  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
-
-is-buffer@^1.0.2:
-  version "1.1.4"
-  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b"
-
-is-builtin-module@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe"
-  dependencies:
-    builtin-modules "^1.0.0"
-
-is-dotfile@^1.0.0:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d"
-
-is-equal-shallow@^0.1.3:
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
-  dependencies:
-    is-primitive "^2.0.0"
-
-is-extendable@^0.1.1:
-  version "0.1.1"
-  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
-
-is-extglob@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
-
-is-finite@^1.0.0:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
-  dependencies:
-    number-is-nan "^1.0.0"
-
-is-fullwidth-code-point@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
-  dependencies:
-    number-is-nan "^1.0.0"
-
-is-glob@^2.0.0, is-glob@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
-  dependencies:
-    is-extglob "^1.0.0"
-
-is-my-json-valid@^2.12.4:
-  version "2.15.0"
-  resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b"
-  dependencies:
-    generate-function "^2.0.0"
-    generate-object-property "^1.1.0"
-    jsonpointer "^4.0.0"
-    xtend "^4.0.0"
-
-is-number@^2.0.2, is-number@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
-  dependencies:
-    kind-of "^3.0.2"
-
-is-posix-bracket@^0.1.0:
-  version "0.1.1"
-  resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
-
-is-primitive@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
-
-is-property@^1.0.0:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
-
-is-relative@^0.2.1:
-  version "0.2.1"
-  resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-0.2.1.tgz#d27f4c7d516d175fb610db84bbeef23c3bc97aa5"
-  dependencies:
-    is-unc-path "^0.1.1"
-
-is-typedarray@~1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
-
-is-unc-path@^0.1.1:
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-0.1.2.tgz#6ab053a72573c10250ff416a3814c35178af39b9"
-  dependencies:
-    unc-path-regex "^0.1.0"
-
-is-utf8@^0.2.0:
-  version "0.2.1"
-  resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
-
-is-windows@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c"
-
-isarray@~1.0.0, [email protected]:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
-
-  version "0.0.1"
-  resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
-
-isexe@^1.1.1:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0"
-
-isobject@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
-  dependencies:
-    isarray "1.0.0"
-
-isstream@~0.1.2:
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
-
-jodid25519@^1.0.0:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967"
-  dependencies:
-    jsbn "~0.1.0"
-
-js-base64@^2.1.9:
-  version "2.1.9"
-  resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce"
-
-jsbn@~0.1.0:
-  version "0.1.0"
-  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd"
-
-  version "0.2.3"
-  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
-
-json-stringify-safe@~5.0.1:
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
-
-jsonpointer@^4.0.0:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9"
-
-jsprim@^1.2.2:
-  version "1.3.1"
-  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252"
-  dependencies:
-    extsprintf "1.0.2"
-    json-schema "0.2.3"
-    verror "1.3.6"
-
-kind-of@^3.0.2:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47"
-  dependencies:
-    is-buffer "^1.0.2"
-
-lcid@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
-  dependencies:
-    invert-kv "^1.0.0"
-
-liftoff@^2.1.0:
-  version "2.3.0"
-  resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.3.0.tgz#a98f2ff67183d8ba7cfaca10548bd7ff0550b385"
-  dependencies:
-    extend "^3.0.0"
-    findup-sync "^0.4.2"
-    fined "^1.0.1"
-    flagged-respawn "^0.3.2"
-    lodash.isplainobject "^4.0.4"
-    lodash.isstring "^4.0.1"
-    lodash.mapvalues "^4.4.0"
-    rechoir "^0.6.2"
-    resolve "^1.1.7"
-
-load-json-file@^1.0.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
-  dependencies:
-    graceful-fs "^4.1.2"
-    parse-json "^2.2.0"
-    pify "^2.0.0"
-    pinkie-promise "^2.0.0"
-    strip-bom "^2.0.0"
-
-lodash._basecopy@^3.0.0:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36"
-
-lodash._basetostring@^3.0.0:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5"
-
-lodash._basevalues@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7"
-
-lodash._getnative@^3.0.0:
-  version "3.9.1"
-  resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
-
-lodash._isiterateecall@^3.0.0:
-  version "3.0.9"
-  resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c"
-
-lodash._reescape@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a"
-
-lodash._reevaluate@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed"
-
-lodash._reinterpolate@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
-
-lodash._root@^3.0.0:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
-
-lodash.assign@^4.0.3, lodash.assign@^4.0.6, lodash.assign@^4.2.0:
-  version "4.2.0"
-  resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
-
-lodash.assignwith@^4.0.7:
-  version "4.2.0"
-  resolved "https://registry.yarnpkg.com/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz#127a97f02adc41751a954d24b0de17e100e038eb"
-
-lodash.clonedeep@^4.3.2:
-  version "4.5.0"
-  resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
-
-lodash.escape@^3.0.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698"
-  dependencies:
-    lodash._root "^3.0.0"
-
-lodash.isarguments@^3.0.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
-
-lodash.isarray@^3.0.0:
-  version "3.0.4"
-  resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
-
-lodash.isempty@^4.2.1:
-  version "4.4.0"
-  resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e"
-
-lodash.isplainobject@^4.0.4:
-  version "4.0.6"
-  resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
-
-lodash.isstring@^4.0.1:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
-
-lodash.keys@^3.0.0:
-  version "3.1.2"
-  resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a"
-  dependencies:
-    lodash._getnative "^3.0.0"
-    lodash.isarguments "^3.0.0"
-    lodash.isarray "^3.0.0"
-
-lodash.mapvalues@^4.4.0:
-  version "4.6.0"
-  resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c"
-
-lodash.pick@^4.2.1:
-  version "4.4.0"
-  resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
-
-lodash.restparam@^3.0.0:
-  version "3.6.1"
-  resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
-
-lodash.template@^3.0.0:
-  version "3.6.2"
-  resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f"
-  dependencies:
-    lodash._basecopy "^3.0.0"
-    lodash._basetostring "^3.0.0"
-    lodash._basevalues "^3.0.0"
-    lodash._isiterateecall "^3.0.0"
-    lodash._reinterpolate "^3.0.0"
-    lodash.escape "^3.0.0"
-    lodash.keys "^3.0.0"
-    lodash.restparam "^3.0.0"
-    lodash.templatesettings "^3.0.0"
-
-lodash.templatesettings@^3.0.0:
-  version "3.1.1"
-  resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5"
-  dependencies:
-    lodash._reinterpolate "^3.0.0"
-    lodash.escape "^3.0.0"
-
-lodash@^4.0.0:
-  version "4.17.4"
-  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
-
-lodash@~1.0.1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551"
-
-lodash@~4.16.4:
-  version "4.16.6"
-  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.6.tgz#d22c9ac660288f3843e16ba7d2b5d06cca27d777"
-
-loud-rejection@^1.0.0:
-  version "1.6.0"
-  resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
-  dependencies:
-    currently-unhandled "^0.4.1"
-    signal-exit "^3.0.0"
-
-lru-cache@^4.0.1:
-  version "4.0.2"
-  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e"
-  dependencies:
-    pseudomap "^1.0.1"
-    yallist "^2.0.0"
-
-lru-cache@2:
-  version "2.7.3"
-  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952"
-
-map-cache@^0.2.0:
-  version "0.2.2"
-  resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
-
-map-obj@^1.0.0, map-obj@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
-
-meow@^3.7.0:
-  version "3.7.0"
-  resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
-  dependencies:
-    camelcase-keys "^2.0.0"
-    decamelize "^1.1.2"
-    loud-rejection "^1.0.0"
-    map-obj "^1.0.1"
-    minimist "^1.1.3"
-    normalize-package-data "^2.3.4"
-    object-assign "^4.0.1"
-    read-pkg-up "^1.0.1"
-    redent "^1.0.0"
-    trim-newlines "^1.0.0"
-
-micromatch@^2.3.7:
-  version "2.3.11"
-  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
-  dependencies:
-    arr-diff "^2.0.0"
-    array-unique "^0.2.1"
-    braces "^1.8.2"
-    expand-brackets "^0.1.4"
-    extglob "^0.3.1"
-    filename-regex "^2.0.0"
-    is-extglob "^1.0.0"
-    is-glob "^2.0.1"
-    kind-of "^3.0.2"
-    normalize-path "^2.0.1"
-    object.omit "^2.0.0"
-    parse-glob "^3.0.4"
-    regex-cache "^0.4.2"
-
-mime-db@~1.25.0:
-  version "1.25.0"
-  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.25.0.tgz#c18dbd7c73a5dbf6f44a024dc0d165a1e7b1c392"
-
-mime-types@^2.1.12, mime-types@~2.1.7:
-  version "2.1.13"
-  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.13.tgz#e07aaa9c6c6b9a7ca3012c69003ad25a39e92a88"
-  dependencies:
-    mime-db "~1.25.0"
-
-minimatch@^2.0.1:
-  version "2.0.10"
-  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7"
-  dependencies:
-    brace-expansion "^1.0.0"
-
-minimatch@^3.0.2, minimatch@~3.0.2:
-  version "3.0.3"
-  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
-  dependencies:
-    brace-expansion "^1.0.0"
-
-minimatch@~0.2.11:
-  version "0.2.14"
-  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.2.14.tgz#c74e780574f63c6f9a090e90efbe6ef53a6a756a"
-  dependencies:
-    lru-cache "2"
-    sigmund "~1.0.0"
-
-minimist@^1.1.0, minimist@^1.1.3:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
-
-  version "0.0.8"
-  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
-
-mkdirp@^0.5.0, mkdirp@^0.5.1, "mkdirp@>=0.5 0":
-  version "0.5.1"
-  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
-  dependencies:
-    minimist "0.0.8"
-
-multipipe@^0.1.2:
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b"
-  dependencies:
-    duplexer2 "0.0.2"
-
-nan@^2.3.2:
-  version "2.5.0"
-  resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.0.tgz#aa8f1e34531d807e9e27755b234b4a6ec0c152a8"
-
-natives@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31"
-
-node-gyp@^3.3.1:
-  version "3.5.0"
-  resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.5.0.tgz#a8fe5e611d079ec16348a3eb960e78e11c85274a"
-  dependencies:
-    fstream "^1.0.0"
-    glob "^7.0.3"
-    graceful-fs "^4.1.2"
-    minimatch "^3.0.2"
-    mkdirp "^0.5.0"
-    nopt "2 || 3"
-    npmlog "0 || 1 || 2 || 3 || 4"
-    osenv "0"
-    request "2"
-    rimraf "2"
-    semver "2.x || 3.x || 4 || 5"
-    tar "^2.0.0"
-    which "1"
-
-node-sass@^3.0.0:
-  version "3.13.1"
-  resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-3.13.1.tgz#7240fbbff2396304b4223527ed3020589c004fc2"
-  dependencies:
-    async-foreach "^0.1.3"
-    chalk "^1.1.1"
-    cross-spawn "^3.0.0"
-    gaze "^1.0.0"
-    get-stdin "^4.0.1"
-    glob "^7.0.3"
-    in-publish "^2.0.0"
-    lodash.assign "^4.2.0"
-    lodash.clonedeep "^4.3.2"
-    meow "^3.7.0"
-    mkdirp "^0.5.1"
-    nan "^2.3.2"
-    node-gyp "^3.3.1"
-    npmlog "^4.0.0"
-    request "^2.61.0"
-    sass-graph "^2.1.1"
-
-"nopt@2 || 3":
-  version "3.0.6"
-  resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
-  dependencies:
-    abbrev "1"
-
-normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
-  version "2.3.5"
-  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df"
-  dependencies:
-    hosted-git-info "^2.1.4"
-    is-builtin-module "^1.0.0"
-    semver "2 || 3 || 4 || 5"
-    validate-npm-package-license "^3.0.1"
-
-normalize-path@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a"
-
-normalize-range@^0.1.2:
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
-
-npmlog@^4.0.0, "npmlog@0 || 1 || 2 || 3 || 4":
-  version "4.0.2"
-  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f"
-  dependencies:
-    are-we-there-yet "~1.1.2"
-    console-control-strings "~1.1.0"
-    gauge "~2.7.1"
-    set-blocking "~2.0.0"
-
-num2fraction@^1.2.2:
-  version "1.2.2"
-  resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
-
-number-is-nan@^1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
-
-oauth-sign@~0.8.1:
-  version "0.8.2"
-  resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
-
-object-assign@^2.0.0:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-2.1.1.tgz#43c36e5d569ff8e4816c4efa8be02d26967c18aa"
-
-object-assign@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2"
-
-object-assign@^4.0.1, object-assign@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0"
-
-object.omit@^2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
-  dependencies:
-    for-own "^0.1.4"
-    is-extendable "^0.1.1"
-
-once@^1.3.0:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
-  dependencies:
-    wrappy "1"
-
-once@~1.3.0:
-  version "1.3.3"
-  resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20"
-  dependencies:
-    wrappy "1"
-
-orchestrator@^0.3.0:
-  version "0.3.8"
-  resolved "https://registry.yarnpkg.com/orchestrator/-/orchestrator-0.3.8.tgz#14e7e9e2764f7315fbac184e506c7aa6df94ad7e"
-  dependencies:
-    end-of-stream "~0.1.5"
-    sequencify "~0.0.7"
-    stream-consume "~0.1.0"
-
-ordered-read-streams@^0.1.0:
-  version "0.1.0"
-  resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz#fd565a9af8eb4473ba69b6ed8a34352cb552f126"
-
-os-homedir@^1.0.0, os-homedir@^1.0.1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
-
-os-locale@^1.4.0:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
-  dependencies:
-    lcid "^1.0.0"
-
-os-tmpdir@^1.0.0:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
-
-osenv@0:
-  version "0.1.4"
-  resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644"
-  dependencies:
-    os-homedir "^1.0.0"
-    os-tmpdir "^1.0.0"
-
-parse-filepath@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.1.tgz#159d6155d43904d16c10ef698911da1e91969b73"
-  dependencies:
-    is-absolute "^0.2.3"
-    map-cache "^0.2.0"
-    path-root "^0.1.1"
-
-parse-glob@^3.0.4:
-  version "3.0.4"
-  resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
-  dependencies:
-    glob-base "^0.3.0"
-    is-dotfile "^1.0.0"
-    is-extglob "^1.0.0"
-    is-glob "^2.0.0"
-
-parse-json@^2.2.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
-  dependencies:
-    error-ex "^1.2.0"
-
-parse-passwd@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
-
-path-exists@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
-  dependencies:
-    pinkie-promise "^2.0.0"
-
-path-is-absolute@^1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
-
-path-root-regex@^0.1.0:
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d"
-
-path-root@^0.1.1:
-  version "0.1.1"
-  resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7"
-  dependencies:
-    path-root-regex "^0.1.0"
-
-path-type@^1.0.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
-  dependencies:
-    graceful-fs "^4.1.2"
-    pify "^2.0.0"
-    pinkie-promise "^2.0.0"
-
-pify@^2.0.0:
-  version "2.3.0"
-  resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
-
-pinkie-promise@^2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
-  dependencies:
-    pinkie "^2.0.0"
-
-pinkie@^2.0.0:
-  version "2.0.4"
-  resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
-
-postcss-value-parser@^3.2.3:
-  version "3.3.0"
-  resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15"
-
-postcss@^5.0.4, postcss@^5.2.8:
-  version "5.2.10"
-  resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.10.tgz#b58b64e04f66f838b7bc7cb41f7dac168568a945"
-  dependencies:
-    chalk "^1.1.3"
-    js-base64 "^2.1.9"
-    source-map "^0.5.6"
-    supports-color "^3.1.2"
-
-preserve@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
-
-pretty-hrtime@^1.0.0:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
-
-process-nextick-args@~1.0.6:
-  version "1.0.7"
-  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
-
-pseudomap@^1.0.1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
-
-punycode@^1.4.1:
-  version "1.4.1"
-  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
-
-qs@~6.3.0:
-  version "6.3.0"
-  resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442"
-
-randomatic@^1.1.3:
-  version "1.1.6"
-  resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb"
-  dependencies:
-    is-number "^2.0.2"
-    kind-of "^3.0.2"
-
-read-pkg-up@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
-  dependencies:
-    find-up "^1.0.0"
-    read-pkg "^1.0.0"
-
-read-pkg@^1.0.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
-  dependencies:
-    load-json-file "^1.0.0"
-    normalize-package-data "^2.3.2"
-    path-type "^1.0.0"
-
-readable-stream@^1.0.33, readable-stream@~1.1.9:
-  version "1.1.14"
-  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
-  dependencies:
-    core-util-is "~1.0.0"
-    inherits "~2.0.1"
-    isarray "0.0.1"
-    string_decoder "~0.10.x"
-
-readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.1.5:
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e"
-  dependencies:
-    buffer-shims "^1.0.0"
-    core-util-is "~1.0.0"
-    inherits "~2.0.1"
-    isarray "~1.0.0"
-    process-nextick-args "~1.0.6"
-    string_decoder "~0.10.x"
-    util-deprecate "~1.0.1"
-
-"readable-stream@>=1.0.33-1 <1.1.0-0":
-  version "1.0.34"
-  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
-  dependencies:
-    core-util-is "~1.0.0"
-    inherits "~2.0.1"
-    isarray "0.0.1"
-    string_decoder "~0.10.x"
-
-rechoir@^0.6.2:
-  version "0.6.2"
-  resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
-  dependencies:
-    resolve "^1.1.6"
-
-redent@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
-  dependencies:
-    indent-string "^2.1.0"
-    strip-indent "^1.0.1"
-
-regex-cache@^0.4.2:
-  version "0.4.3"
-  resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145"
-  dependencies:
-    is-equal-shallow "^0.1.3"
-    is-primitive "^2.0.0"
-
-repeat-element@^1.1.2:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
-
-repeat-string@^1.5.2:
-  version "1.6.1"
-  resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
-
-repeating@^2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
-  dependencies:
-    is-finite "^1.0.0"
-
-  version "0.0.1"
-  resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924"
-
-request@^2.61.0, request@2:
-  version "2.79.0"
-  resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de"
-  dependencies:
-    aws-sign2 "~0.6.0"
-    aws4 "^1.2.1"
-    caseless "~0.11.0"
-    combined-stream "~1.0.5"
-    extend "~3.0.0"
-    forever-agent "~0.6.1"
-    form-data "~2.1.1"
-    har-validator "~2.0.6"
-    hawk "~3.1.3"
-    http-signature "~1.1.0"
-    is-typedarray "~1.0.0"
-    isstream "~0.1.2"
-    json-stringify-safe "~5.0.1"
-    mime-types "~2.1.7"
-    oauth-sign "~0.8.1"
-    qs "~6.3.0"
-    stringstream "~0.0.4"
-    tough-cookie "~2.3.0"
-    tunnel-agent "~0.4.1"
-    uuid "^3.0.0"
-
-require-directory@^2.1.1:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
-
-require-main-filename@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
-
-resolve-dir@^0.1.0:
-  version "0.1.1"
-  resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e"
-  dependencies:
-    expand-tilde "^1.2.2"
-    global-modules "^0.2.3"
-
-resolve@^1.1.6, resolve@^1.1.7:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.2.0.tgz#9589c3f2f6149d1417a40becc1663db6ec6bc26c"
-
-rimraf@2:
-  version "2.5.4"
-  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04"
-  dependencies:
-    glob "^7.0.5"
-
-sass-graph@^2.1.1:
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.1.2.tgz#965104be23e8103cb7e5f710df65935b317da57b"
-  dependencies:
-    glob "^7.0.0"
-    lodash "^4.0.0"
-    yargs "^4.7.1"
-
-semver@^4.1.0:
-  version "4.3.6"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da"
-
-"semver@2 || 3 || 4 || 5", "[email protected] || 3.x || 4 || 5":
-  version "5.3.0"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
-
-sequencify@~0.0.7:
-  version "0.0.7"
-  resolved "https://registry.yarnpkg.com/sequencify/-/sequencify-0.0.7.tgz#90cff19d02e07027fd767f5ead3e7b95d1e7380c"
-
-set-blocking@^2.0.0, set-blocking@~2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
-
-sigmund@~1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
-
-signal-exit@^3.0.0:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
-
-  version "1.0.9"
-  resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
-  dependencies:
-    hoek "2.x.x"
-
-source-map@^0.1.39:
-  version "0.1.43"
-  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346"
-  dependencies:
-    amdefine ">=0.0.4"
-
-source-map@^0.5.6:
-  version "0.5.6"
-  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
-
-  version "0.4.4"
-  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
-  dependencies:
-    amdefine ">=0.0.4"
-
-sparkles@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3"
-
-spdx-correct@~1.0.0:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
-  dependencies:
-    spdx-license-ids "^1.0.2"
-
-spdx-expression-parse@~1.0.0:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c"
-
-spdx-license-ids@^1.0.2:
-  version "1.2.2"
-  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57"
-
-sshpk@^1.7.0:
-  version "1.10.1"
-  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.1.tgz#30e1a5d329244974a1af61511339d595af6638b0"
-  dependencies:
-    asn1 "~0.2.3"
-    assert-plus "^1.0.0"
-    dashdash "^1.12.0"
-    getpass "^0.1.1"
-  optionalDependencies:
-    bcrypt-pbkdf "^1.0.0"
-    ecc-jsbn "~0.1.1"
-    jodid25519 "^1.0.0"
-    jsbn "~0.1.0"
-    tweetnacl "~0.14.0"
-
-stream-consume@~0.1.0:
-  version "0.1.0"
-  resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f"
-
-string_decoder@~0.10.x:
-  version "0.10.31"
-  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
-
-string-width@^1.0.1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
-  dependencies:
-    code-point-at "^1.0.0"
-    is-fullwidth-code-point "^1.0.0"
-    strip-ansi "^3.0.0"
-
-stringstream@~0.0.4:
-  version "0.0.5"
-  resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
-
-strip-ansi@^3.0.0, strip-ansi@^3.0.1:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
-  dependencies:
-    ansi-regex "^2.0.0"
-
-strip-bom@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-1.0.0.tgz#85b8862f3844b5a6d5ec8467a93598173a36f794"
-  dependencies:
-    first-chunk-stream "^1.0.0"
-    is-utf8 "^0.2.0"
-
-strip-bom@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
-  dependencies:
-    is-utf8 "^0.2.0"
-
-strip-indent@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
-  dependencies:
-    get-stdin "^4.0.1"
-
-supports-color@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a"
-
-supports-color@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
-
-supports-color@^3.1.2:
-  version "3.1.2"
-  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5"
-  dependencies:
-    has-flag "^1.0.0"
-
-tar@^2.0.0:
-  version "2.2.1"
-  resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
-  dependencies:
-    block-stream "*"
-    fstream "^1.0.2"
-    inherits "2"
-
-through2@^0.6.1, through2@^0.6.3, through2@~0.6:
-  version "0.6.5"
-  resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48"
-  dependencies:
-    readable-stream ">=1.0.33-1 <1.1.0-0"
-    xtend ">=4.0.0 <4.1.0-0"
-
-through2@^2.0.0:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"
-  dependencies:
-    readable-stream "^2.1.5"
-    xtend "~4.0.1"
-
-tildify@^1.0.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/tildify/-/tildify-1.2.0.tgz#dcec03f55dca9b7aa3e5b04f21817eb56e63588a"
-  dependencies:
-    os-homedir "^1.0.0"
-
-time-stamp@^1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.0.1.tgz#9f4bd23559c9365966f3302dbba2b07c6b99b151"
-
-tough-cookie@~2.3.0:
-  version "2.3.2"
-  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a"
-  dependencies:
-    punycode "^1.4.1"
-
-trim-newlines@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
-
-tunnel-agent@~0.4.1:
-  version "0.4.3"
-  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb"
-
-tweetnacl@^0.14.3, tweetnacl@~0.14.0:
-  version "0.14.5"
-  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
-
-unc-path-regex@^0.1.0:
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
-
-unique-stream@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-1.0.0.tgz#d59a4a75427447d9aa6c91e70263f8d26a4b104b"
-
-user-home@^1.1.1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190"
-
-util-deprecate@~1.0.1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
-
-uuid@^3.0.0:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
-
-v8flags@^2.0.2:
-  version "2.0.11"
-  resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.11.tgz#bca8f30f0d6d60612cc2c00641e6962d42ae6881"
-  dependencies:
-    user-home "^1.1.1"
-
-validate-npm-package-license@^3.0.1:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"
-  dependencies:
-    spdx-correct "~1.0.0"
-    spdx-expression-parse "~1.0.0"
-
-  version "1.3.6"
-  resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c"
-  dependencies:
-    extsprintf "1.0.2"
-
-vinyl-bufferstream@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/vinyl-bufferstream/-/vinyl-bufferstream-1.0.1.tgz#0537869f580effa4ca45acb47579e4b9fe63081a"
-  dependencies:
-    bufferstreams "1.0.1"
-
-vinyl-fs@^0.3.0:
-  version "0.3.14"
-  resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-0.3.14.tgz#9a6851ce1cac1c1cea5fe86c0931d620c2cfa9e6"
-  dependencies:
-    defaults "^1.0.0"
-    glob-stream "^3.1.5"
-    glob-watcher "^0.0.6"
-    graceful-fs "^3.0.0"
-    mkdirp "^0.5.0"
-    strip-bom "^1.0.0"
-    through2 "^0.6.1"
-    vinyl "^0.4.0"
-
-vinyl-sourcemaps-apply@^0.1.3, vinyl-sourcemaps-apply@^0.1.4, vinyl-sourcemaps-apply@~0.1.1:
-  version "0.1.4"
-  resolved "https://registry.yarnpkg.com/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.1.4.tgz#c5fcbd43e2f238423c2dc98bddd6f79b72bc345b"
-  dependencies:
-    source-map "^0.1.39"
-
-vinyl@^0.4.0:
-  version "0.4.6"
-  resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.4.6.tgz#2f356c87a550a255461f36bbeb2a5ba8bf784847"
-  dependencies:
-    clone "^0.2.0"
-    clone-stats "^0.0.1"
-
-vinyl@^0.5.0:
-  version "0.5.3"
-  resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde"
-  dependencies:
-    clone "^1.0.0"
-    clone-stats "^0.0.1"
-    replace-ext "0.0.1"
-
-which-module@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
-
-which@^1.2.12, which@^1.2.9, which@1:
-  version "1.2.12"
-  resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192"
-  dependencies:
-    isexe "^1.1.1"
-
-wide-align@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad"
-  dependencies:
-    string-width "^1.0.1"
-
-window-size@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075"
-
-wrap-ansi@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
-  dependencies:
-    string-width "^1.0.1"
-    strip-ansi "^3.0.1"
-
-wrappy@1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
-
-xtend@^4.0.0, "xtend@>=4.0.0 <4.1.0-0", xtend@~4.0.1:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
-
-y18n@^3.2.1:
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
-
-yallist@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.0.0.tgz#306c543835f09ee1a4cb23b7bce9ab341c91cdd4"
-
-yargs-parser@^2.4.1:
-  version "2.4.1"
-  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4"
-  dependencies:
-    camelcase "^3.0.0"
-    lodash.assign "^4.0.6"
-
-yargs@^4.7.1:
-  version "4.8.1"
-  resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0"
-  dependencies:
-    cliui "^3.2.0"
-    decamelize "^1.1.1"
-    get-caller-file "^1.0.1"
-    lodash.assign "^4.0.3"
-    os-locale "^1.4.0"
-    read-pkg-up "^1.0.1"
-    require-directory "^2.1.1"
-    require-main-filename "^1.0.1"
-    set-blocking "^2.0.0"
-    string-width "^1.0.1"
-    which-module "^1.0.0"
-    window-size "^0.2.0"
-    y18n "^3.2.1"
-    yargs-parser "^2.4.1"
-