diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 5214a41b5..f18de9ba8 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -21,13 +21,10 @@ jobs:
os:
- macos-latest
- ubuntu-latest
- - windows-latest
+ # The Server 8 / modern ppx stack (ocsigen-ppx-rpc needs ppxlib >= 0.37,
+ # pulled together with ppx_sexp_conv -> ppxlib_jane) requires OCaml >= 5.3.
ocaml-compiler:
- - "4.14"
- - "5.2"
- include:
- - os: ubuntu-latest
- ocaml-compiler: "4.12"
+ - "5"
runs-on: ${{ matrix.os }}
@@ -46,9 +43,22 @@ jobs:
ocaml-compiler: ${{ matrix.ocaml-compiler }}
opam-pin: false
+ # wasm_of_ocaml (pulled in via eliom) needs binaryen's wasm-merge.
+ - name: Set-up Binaryen
+ uses: Aandreba/setup-binaryen@v1.0.0
+ with:
+ token: ${{ github.token }}
+
+ # Pin the Ocsigen Server 8 development branches until 8.0 is released
+ # (the default branches of these repos are still the Server 7 line).
- run: |
- opam pin add -n eliom https://github.com/ocsigen/eliom.git
- opam pin add -n ocsigen-toolkit https://github.com/ocsigen/ocsigen-toolkit.git
+ opam pin -yn git+https://github.com/ocsigen/ocsigenserver#master
+ opam pin -yn git+https://github.com/ocsigen/ocsipersist#master
+ opam pin -yn git+https://github.com/ocsigen/eliom#deriving
+ opam pin -yn git+https://github.com/ocsigen/ocsigen-toolkit#modernize
+ opam pin -yn git+https://github.com/ocsigen/ocsigen-dune-rules#modernize
+ opam pin -yn git+https://github.com/ocsigen/ocsigen-ppx-rpc#modernize
+ opam pin -yn git+https://github.com/ocsigen/ocsigen-i18n#modernize
- run: opam pin add ocsigen-start.7.0.0 . --no-action
@@ -56,7 +66,14 @@ jobs:
- run: mkdir -p template
- - run: opam exec -- eliom-distillery -name template -template os.pgocaml
+ - run: opam exec -- eliom-distillery -name template -template os
+
+ # Make the generated project its own dune root. It lives inside the
+ # ocsigen-start checkout, which ships a dune-project; without this, dune
+ # would take ocsigen-start as the root and treat the project as a nested
+ # subdirectory, which breaks Eliom's client/server value linking
+ # ("Inferred type of client value not found. You need to regenerate ...").
+ - run: echo '(lang dune 3.0)' > template/dune-workspace
- run: opam install -y .
working-directory: template
diff --git a/.gitignore b/.gitignore
index 649e8d638..32d82fed8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@ local/
doc/client
doc/server
.*.sw*
+doc/manual/menu.wiki
diff --git a/.ocamlformat b/.ocamlformat
index a84459a47..5fb3439a0 100644
--- a/.ocamlformat
+++ b/.ocamlformat
@@ -1,4 +1,4 @@
-version=0.28.1
+version=0.29.0
parse-docstrings = false
wrap-comments = false
break-cases = fit
diff --git a/CHANGES b/CHANGES
index f6090651b..56fb5d189 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,36 @@
+===== 9.0.0~dev =====
+* Module namespace modernization
+** Public modules are now accessed as Os.Session, Os.User, Os.Tips,
+ Os.Mail, Os.Notif, ... instead of the legacy flat Os_xxx prefix.
+ Implemented with (include_subdirs qualified) + (wrapped false)
+ in dune.
+** New ocsigen-start-compat opam package: provides the legacy
+ Os_xxx module names as include-aliases of the new Os.Xxx
+ modules, to ease migration of existing code.
+* PROJECT_NAME_icons.eliom in the distillery template is now
+ parameterised on Eliom.Content.Html.T (the shared signature
+ exposed by Eliom 13) instead of an ad-hoc ICON_HTML signature.
+* Distillery template
+** Renamed from os.pgocaml to os.
+** Source directory renamed back to template.distillery/ (the
+ convention used by ocsigen-start's previous Makefile-based
+ build), and now installed via dune
+ (install (section lib_root) (files (glob_files_rec
+ (template.distillery/* with_prefix eliom/templates/os))))
+ so the template lands at lib/eliom/templates/os/, where
+ eliom-distillery picks it up at the standard location (Eliom
+ 13 dropped the per-package eliom-templates/ auto-discovery).
+* Migrated to the new Eliom 13 module names (Eliom.Service,
+ Eliom.Content, Eliom.Common, ...) and to the wrapped
+ ocsigenserver module names (Ocsigen.Server, Ocsigen.Extensions,
+ Ocsigen.Config, Ocsigen_base.Lib, ...).
+* Build system uses ocsigen-dune-rules (gen sub-command).
+* Os.Email: the default email-sending function now pipes an RFC-2822
+ message to the configured mailer ("sendmail" by default) via
+ Lwt_process, instead of printing to stdout. If the mailer is not on
+ PATH, the email is logged to stderr so the application stays usable
+ out of the box. The now-unused [Invalid_mailer] exception is removed.
+
===== 7.1.0 (2024-11) =====
* Compatibility with WASM
diff --git a/doc/client.indexdoc b/doc/client.indexdoc
new file mode 100644
index 000000000..9cd4542d0
--- /dev/null
+++ b/doc/client.indexdoc
@@ -0,0 +1,57 @@
+{1 Ocsigen Start client API}
+
+{2 User management}
+
+{!modules:
+User
+User_view
+User_proxy
+Current_user
+Session
+Connect_phone
+}
+
+{2 Persistence}
+
+{!modules:
+Types
+Email
+}
+
+{2 Notifications}
+
+{!modules:
+Notif
+Msg
+Fcm_notif
+}
+
+{2 Web pages and services}
+
+{!modules:
+Page
+Services
+Handlers
+Icons
+Tips
+Uploader
+Request_cache
+}
+
+{2 Real-time}
+
+{!modules:
+Comet
+}
+
+{2 Utilities}
+
+{!modules:
+Lib
+Date
+Platform
+}
+
+{2 Indexes}
+
+{!indexlist}
diff --git a/doc/dune b/doc/dune
index b2c4e3255..04835aee6 100644
--- a/doc/dune
+++ b/doc/dune
@@ -1,5 +1,6 @@
; Ocsigen Start manual pages (odoc .mld), compiled in place with the API by
; `dune build @doc` and installed with the package, so they appear on ocaml.org
; and resolve {{!page-X}} / {!Module} references against the API.
+
(documentation
(package ocsigen-start))
diff --git a/doc/index.mld b/doc/index.mld
index 61446453e..207a5b92e 100644
--- a/doc/index.mld
+++ b/doc/index.mld
@@ -6,19 +6,234 @@ client-server web and mobile applications with {{!/eliom/page-index}Eliom} and
notifications, a database schema and many code examples, so you can
focus on your own features from day one.
+Use it to learn Ocsigen or to quickly create your own Minimum Viable
+Product. The application is cross-platform: it works as a Web app or as
+a mobile app for iOS or Android (via {{:https://cordova.apache.org/}Cordova}).
+
Ocsigen Start is part of the {{:https://ocsigen.org}Ocsigen project}.
-{1 Documentation}
+{1 Demo}
+
+If you want to test the demo application before installing Ocsigen Start,
+{b a live version is running {{:https://ocsigen.org/ocsigen-start/demo/}here}}.
+
+You can also download the mobile app
+{{:https://play.google.com/store/apps/details?id=com.osdemo.mobile}on Google Play store} (for Android)
+or download the
+{{:files/osdemo.apk}APK for Android}
+or the
+{{:files/osdemo-ios.tgz}iOS version} (to be installed using XCode).
+
+{%wodoc:div class="screenshots"%}
+{{:files/screenshots/start1.png}
+{%wodoc:img src="files/screenshots/start1.png" alt="Ocsigen Start"%}}
+{{:files/screenshots/start2.png}
+{%wodoc:img src="files/screenshots/start2.png" alt="Ocsigen Start"%}}
+{%wodoc:end%}
+
+{%wodoc:div class="screenshots"%}
+{{:files/screenshots/start-mobile-1.png}
+{%wodoc:img src="files/screenshots/start-mobile-1.png" alt="Ocsigen Start"%}}
+{{:files/screenshots/start-mobile-2.png}
+{%wodoc:img src="files/screenshots/start-mobile-2.png" alt="Ocsigen Start"%}}
+{{:files/screenshots/start-mobile-4.png}
+{%wodoc:img src="files/screenshots/start-mobile-4.png" alt="Ocsigen Start"%}}
+{%wodoc:end%}
+
+
+
+Ocsigen Start is composed by two main parts:
+
+- The generated code which gives a default behaviour to your application. Adapt it to your needs and remove the parts you don't need. Feel free to redistribute it as you wish.{%html: %}
+It includes a demo of many features from Eliom, Js_of_ocaml, Tyxml, Ocsigen Toolkit. Use it to learn quickly the main principles of multi-tier programming.
+
+- A library with:
+- User management: authentication, registration of new users with activation links sent by email, recover lost password, page to update settings, etc.
+- Tips for new users
+- Push notifications to send information to other users
+- ...
+
+{%wodoc:div class="screenshots"%}
+{{:files/screenshots/start3.png}
+{%wodoc:img src="files/screenshots/start3.png" alt="Ocsigen Start"%}}
+{{:files/screenshots/start4.png}
+{%wodoc:img src="files/screenshots/start4.png" alt="Ocsigen Start"%}}
+{{:files/screenshots/start5.png}
+{%wodoc:img src="files/screenshots/start5.png" alt="Ocsigen Start"%}}
+{{:files/screenshots/start6.png}
+{%wodoc:img src="files/screenshots/start6.png" alt="Ocsigen Start"%}}
+{%wodoc:end%}
+
+{%wodoc:div class="screenshots"%}
+{{:files/screenshots/start-mobile-3.png}
+{%wodoc:img src="files/screenshots/start-mobile-3.png" alt="Ocsigen Start"%}}
+{{:files/screenshots/start-mobile-6.png}
+{%wodoc:img src="files/screenshots/start-mobile-6.png" alt="Ocsigen Start"%}}
+{{:files/screenshots/start-mobile-7.png}
+{%wodoc:img src="files/screenshots/start-mobile-7.png" alt="Ocsigen Start"%}}
+{{:files/screenshots/start-mobile-8.png}
+{%wodoc:img src="files/screenshots/start-mobile-8.png" alt="Ocsigen Start"%}}
+{%wodoc:end%}
+
+
+{1 Getting started}
+
+Read {{:https://ocsigen.org/tuto/start.html}this page} to learn how to build your first Ocsigen Start app in 5 minutes.
+
+{1 Implementation overview}
+
+{2 Template}
+
+The library portion of Ocsigen Start contains core functionality that
+is common across Ocsigen Start applications, while the template can be
+customized for the specific application at hand.
+
+The template additionally contains a demonstration of relevant
+{{:https://github.com/ocsigen/ocsigen-toolkit}Ocsigen Toolkit}
+widgets. The demo portion can easily be removed.
+
+{2 Database}
+
+For implementing users, a database is needed. Specifically, we use
+{{:https://www.postgresql.org/}PostgreSQL} via the
+{{:http://pgocaml.forge.ocamlcore.org/}PGOCaml} library. The template
+and the library make common assumptions about the database schema. The
+database thus needs to be instantiated in a certain way; this is
+automatically done by appropriate targets in the template's build
+system.
+
+The same database can used for the specific needs of the application
+at hand. For that, new tables can be added. The original ones should
+remain in place for Ocsigen Start to work correctly.
+
+{2 Internationalization (i18n)}
+
+The template is available in multiple languages (English and French) using
+{{:https://github.com/besport/ocsigen-i18n}ocsigen-i18n}. All translations used
+in the template are defined in the file [assets/PROJECT_NAME_i18n.tsv]. The
+Makefile rule [i18n-udpate] generates the i18n module. You need to use it
+every time the TSV file is updated.
+
+See [Makefile.i18n] for rules about i18n and [Makefile.options] to
+personalize the internalization of your application (for example add new
+languages, change default language, change TSV filename).
+
+{2 Managing e-mails}
+
+The template application keeps track of users' e-mails and implements
+e-mail validation. For that, [sendmail] (or another mail transfer
+agent compatible with it) needs to be installed on the host.
-- {{!page-intro}Introduction} — installation, getting started and an
- overview of the modules Ocsigen Start provides.
-- The server and client API of every module (use the {e Server API} /
- {e Client API} switch to move between the two sides).
+{2 Style}
+
+The application provides a standard style matching contemporary
+aesthetics. For this, we use {{:http://sass-lang.com/}SASS}. The style
+can be customized by modifying the SASS files that are part of the
+template.
{1 Installation}
-Ocsigen Start is available via OPAM:
+Ocsigen Start can be installed via
+{{:https://opam.ocaml.org/}OPAM}. The package name is [ocsigen-start].
+The template application can be instantiated via [eliom-distillery]:
-{[
-opam install ocsigen-start
+{@shell[
+eliom-distillery -name $APP_NAME -template os
]}
+
+(Replace $APP_NAME by the name of your application).
+
+For details on launching the application, refer to the template's
+{{:https://github.com/ocsigen/ocsigen-start/blob/master/template.distillery/README.md}README}.
+
+{1 Library overview}
+
+We provide a tour of the Ocsigen Start library. All modules have
+server- and client-side versions. (In the API documentation, there are
+links near the top of each module page for selecting the side.)
+
+The template uses all these modules, and can thus act as a good
+starting guide. Look around!
+
+{2 User interface}
+
+Various modules for producing icons, messages, custom pages, tips,
+connection forms, etc.
+
+- {!Os.Icons}:
+ manage CSS icons.
+- {!Os.Msg}:
+ write messages in the browser console.
+- {!Os.Page}:
+ utilities for building HTML pages that follow the standard Ocsigen
+ Start layout.
+- {!Os.Tips}:
+ display tips to the user.
+- {!Os.User_view}:
+ functions for creating password forms and other common UI elements
+ appearing in applications and for managing the user connection box.
+- {!Os.Uploader}:
+ ImageMagick-based tools for manipulating avatars.
+
+{2 Users and groups}
+
+- {!Os.User},
+ {!Os.Current_user},
+ {!Os.Group}:
+ manage users and groups thereof.
+
+- {!Os.Db}:
+ directly access the database. In many cases, it is a better idea to
+ use higher-level modules (e.g.,
+ {!Os.User}).
+
+- {!Os.Types}:
+ core types shared by {!Os.Db}
+ and the higher-level modules.
+
+{2 Communication}
+
+- {!Os.Notif}:
+ send notifications to connected users.
+
+- {!Os.Email}:
+ send e-mails.
+
+- {!Os.Fcm_notif}:
+ send push notifications to mobile devices.
+
+- {!Os.Comet}:
+ manage the bi-directional communication channel between client and
+ server. This is a low-level module that you probably don't need.
+
+{2 Services, handlers, sessions}
+
+- {!Os.Services}:
+ Eliom services pre-defined by Ocsigen Start. These produce the
+ default user interface of the template.
+ See {{!/eliom/page-"server-services"}the Eliom manual page on services} for
+ a general introduction to Eliom services.
+
+- {!Os.Handlers}:
+ The handlers (functions) that implement the services in
+ {!Os.Services}.
+ {{!/eliom/page-"server-outputs"}The Eliom manual page on service handlers}
+ explains how to implement handlers.
+
+- {!Os.Session}:
+ manage user sessions, e.g., execute actions when users connect or
+ disconnect.
+
+{2 Other utilities}
+
+- {!Os.Date}:
+ utilities for manipulating date and time values.
+
+- {!Os.Platform}:
+ obtain information about the platform we are on (Android, iOS, ...).
+
+- {!Os.Request_cache},
+ {!Os.User_proxy}:
+ different forms of caching data.
+
+- A {e ppx} syntax extension to implement RPC.
diff --git a/doc/intro.mld b/doc/intro.mld
deleted file mode 100644
index efa11ab28..000000000
--- a/doc/intro.mld
+++ /dev/null
@@ -1,241 +0,0 @@
-
-
-{0 Introduction}
-
-Ocsigen Start is an application template written with Eliom, Js_of_ocaml,
-Ocsigen Toolkit, etc.
-It contains many standard features like user management, notifications,
-and many code examples.
-
-Use it to learn Ocsigen or to quickly create your own Minimum Viable Product.
-It is probably the fastest way to get started with Ocsigen.
-
-The application is cross-platform: it works as a Web app or as a mobile app
-for iOS or Android (via {{:https://cordova.apache.org/}Cordova})..
-
-
-{1 Demo}
-
-If you want to test the demo application before installing Ocsigen Start,
-{b a live version is running {{:https://ocsigen.org/ocsigen-start/demo/}here}}.
-
-You can also download the mobile app
-{{:https://play.google.com/store/apps/details?id=com.osdemo.mobile}on Google Play store} (for Android)
-or download the
-{{:files/osdemo.apk}APK for Android}
-or the
-{{:files/osdemo-ios.tgz}iOS version} (to be installed using XCode).
-
-{%wodoc:div class="screenshots"%}
-{{:files/screenshots/start1.png}
-{%wodoc:img src="files/screenshots/start1.png" alt="Ocsigen Start"%}}
-{{:files/screenshots/start2.png}
-{%wodoc:img src="files/screenshots/start2.png" alt="Ocsigen Start"%}}
-{%wodoc:end%}
-
-{%wodoc:div class="screenshots"%}
-{{:files/screenshots/start-mobile-1.png}
-{%wodoc:img src="files/screenshots/start-mobile-1.png" alt="Ocsigen Start"%}}
-{{:files/screenshots/start-mobile-2.png}
-{%wodoc:img src="files/screenshots/start-mobile-2.png" alt="Ocsigen Start"%}}
-{{:files/screenshots/start-mobile-4.png}
-{%wodoc:img src="files/screenshots/start-mobile-4.png" alt="Ocsigen Start"%}}
-{%wodoc:end%}
-
-
-
-Ocsigen Start is composed by two main parts:
-
-- The generated code which gives a default behaviour to your application. Adapt it to your needs and remove the parts you don't need. Feel free to redistribute it as you wish.{%html: %}
-It includes a demo of many features from Eliom, Js_of_ocaml, Tyxml, Ocsigen Toolkit. Use it to learn quickly the main principles of multi-tier programming.
-
-- A library with:
-- User management: authentication, registration of new users with activation links sent by email, recover lost password, page to update settings, etc.
-- Tips for new users
-- Push notifications to send information to other users
-- ...
-
-{%wodoc:div class="screenshots"%}
-{{:files/screenshots/start3.png}
-{%wodoc:img src="files/screenshots/start3.png" alt="Ocsigen Start"%}}
-{{:files/screenshots/start4.png}
-{%wodoc:img src="files/screenshots/start4.png" alt="Ocsigen Start"%}}
-{{:files/screenshots/start5.png}
-{%wodoc:img src="files/screenshots/start5.png" alt="Ocsigen Start"%}}
-{{:files/screenshots/start6.png}
-{%wodoc:img src="files/screenshots/start6.png" alt="Ocsigen Start"%}}
-{%wodoc:end%}
-
-{%wodoc:div class="screenshots"%}
-{{:files/screenshots/start-mobile-3.png}
-{%wodoc:img src="files/screenshots/start-mobile-3.png" alt="Ocsigen Start"%}}
-{{:files/screenshots/start-mobile-6.png}
-{%wodoc:img src="files/screenshots/start-mobile-6.png" alt="Ocsigen Start"%}}
-{{:files/screenshots/start-mobile-7.png}
-{%wodoc:img src="files/screenshots/start-mobile-7.png" alt="Ocsigen Start"%}}
-{{:files/screenshots/start-mobile-8.png}
-{%wodoc:img src="files/screenshots/start-mobile-8.png" alt="Ocsigen Start"%}}
-{%wodoc:end%}
-
-
-{1 Getting started}
-
-Read {{:https://ocsigen.org/tuto/latest/start.html}this page} to learn how to build your first Ocsigen Start app in 5 minutes.
-
-{1 Implementation overview}
-
-{2 Template}
-
-The library portion of Ocsigen Start contains core functionality that
-is common across Ocsigen Start applications, while the template can be
-customized for the specific application at hand.
-
-The template additionally contains a demonstration of relevant
-{{:https://github.com/ocsigen/ocsigen-toolkit}Ocsigen Toolkit}
-widgets. The demo portion can easily be removed.
-
-{2 Database}
-
-For implementing users, a database is needed. Specifically, we use
-{{:https://www.postgresql.org/}PostgreSQL} via the
-{{:http://pgocaml.forge.ocamlcore.org/}PGOCaml} library. The template
-and the library make common assumptions about the database schema. The
-database thus needs to be instantiated in a certain way; this is
-automatically done by appropriate targets in the template's build
-system.
-
-The same database can used for the specific needs of the application
-at hand. For that, new tables can be added. The original ones should
-remain in place for Ocsigen Start to work correctly.
-
-{2 Internationalization (i18n)}
-
-The template is available in multiple languages (English and French) using
-{{:https://github.com/besport/ocsigen-i18n}ocsigen-i18n}. All translations used
-in the template are defined in the file [assets/PROJECT_NAME_i18n.tsv]. The
-Makefile rule [i18n-udpate] generates the i18n module. You need to use it
-every time the TSV file is updated.
-
-See [Makefile.i18n] for rules about i18n and [Makefile.options] to
-personalize the internalization of your application (for example add new
-languages, change default language, change TSV filename).
-
-{2 Managing e-mails}
-
-The template application keeps track of users' e-mails and implements
-e-mail validation. For that, [sendmail] (or another mail transfer
-agent compatible with it) needs to be installed on the host.
-
-{2 Style}
-
-The application provides a standard style matching contemporary
-aesthetics. For this, we use {{:http://sass-lang.com/}SASS}. The style
-can be customized by modifying the SASS files that are part of the
-template.
-
-{1 Installation}
-
-Ocsigen Start can be installed via
-{{:https://opam.ocaml.org/}OPAM}. The package name is [ocsigen-start].
-The template application can be instantiated via [eliom-distillery]:
-
-{@shell[
-eliom-distillery -name $APP_NAME -template os.pgocaml
-]}
-
-(Replace $APP_NAME by the name of your application).
-
-For details on launching the application, refer to the template's
-{{:https://github.com/ocsigen/ocsigen-start/blob/master/template.distillery/README.md}README}.
-
-{1 Library overview}
-
-We provide a tour of the Ocsigen Start library. All modules have
-server- and client-side versions. (In the API documentation, there are
-links near the top of each module page for selecting the side.)
-
-The template uses all these modules, and can thus act as a good
-starting guide. Look around!
-
-{2 User interface}
-
-Various modules for producing icons, messages, custom pages, tips,
-connection forms, etc.
-
-- {!Os_icons}:
- manage CSS icons.
-- {!Os_msg}:
- write messages in the browser console.
-- {!Os_page}:
- utilities for building HTML pages that follow the standard Ocsigen
- Start layout.
-- {!Os_tips}:
- display tips to the user.
-- {!Os_user_view}:
- functions for creating password forms and other common UI elements
- appearing in applications and for managing the user connection box.
-- {!Os_uploader}:
- ImageMagick-based tools for manipulating avatars.
-
-{2 Users and groups}
-
-- {!Os_user},
- {!Os_current_user},
- {!Os_group}:
- manage users and groups thereof.
-
-- {!Os_db}:
- directly access the database. In many cases, it is a better idea to
- use higher-level modules (e.g.,
- {!Os_user}).
-
-- {!Os_types}:
- core types shared by {!Os_db}
- and the higher-level modules.
-
-{2 Communication}
-
-- {!Os_notif}:
- send notifications to connected users.
-
-- {!Os_email}:
- send e-mails.
-
-- {!Os_fcm_notif}:
- send push notifications to mobile devices.
-
-- {!Os_comet}:
- manage the bi-directional communication channel between client and
- server. This is a low-level module that you probably don't need.
-
-{2 Services, handlers, sessions}
-
-- {!Os_services}:
- Eliom services pre-defined by Ocsigen Start. These produce the
- default user interface of the template.
- See {{!/eliom/page-"server-services"}the Eliom manual page on services} for
- a general introduction to Eliom services.
-
-- {!Os_handlers}:
- The handlers (functions) that implement the services in
- {!Os_services}.
- {{!/eliom/page-"server-outputs"}The Eliom manual page on service handlers}
- explains how to implement handlers.
-
-- {!Os_session}:
- manage user sessions, e.g., execute actions when users connect or
- disconnect.
-
-{2 Other utilities}
-
-- {!Os_date}:
- utilities for manipulating date and time values.
-
-- {!Os_platform}:
- obtain information about the platform we are on (Android, iOS, ...).
-
-- {!Os_request_cache},
- {!Os_user_proxy}:
- different forms of caching data.
-
-- A {e ppx} syntax extension to implement RPC.
diff --git a/doc/server.indexdoc b/doc/server.indexdoc
new file mode 100644
index 000000000..5cb58a89d
--- /dev/null
+++ b/doc/server.indexdoc
@@ -0,0 +1,60 @@
+{1 Ocsigen Start server API}
+
+{2 User management}
+
+{!modules:
+User
+User_view
+User_proxy
+Current_user
+Group
+Session
+Connect_phone
+}
+
+{2 Persistence}
+
+{!modules:
+Db
+Core_db
+Types
+Email
+}
+
+{2 Notifications}
+
+{!modules:
+Notif
+Msg
+Fcm_notif
+}
+
+{2 Web pages and services}
+
+{!modules:
+Page
+Services
+Handlers
+Icons
+Tips
+Uploader
+Request_cache
+}
+
+{2 Real-time}
+
+{!modules:
+Comet
+}
+
+{2 Utilities}
+
+{!modules:
+Lib
+Date
+Platform
+}
+
+{2 Indexes}
+
+{!indexlist}
diff --git a/doc/wodoc b/doc/wodoc
index f5d6588f8..9a5328ec1 100644
--- a/doc/wodoc
+++ b/doc/wodoc
@@ -1,28 +1,21 @@
;; Declarative wodoc config for the Ocsigen Start documentation (client/server).
;; wodoc build --config doc/wodoc --out
/ --label \
-;; --menu https://ocsigen.org/doc/menu.html [--local]
+;; --menu https://ocsigen.org/wodoc/menu.html [--local]
;; ocsigen-start ships server and client libraries (ocsigen-start.server /
;; ocsigen-start.client) with the same module names, so the API is built with
-;; `odoc_driver ocsigen-start --remap` on the INSTALLED package. Modules are flat
-;; (Os_*), so no wrapper. Each side gets its own API nav, a body colour and a
-;; switch; the manual (index/intro) is shared.
+;; `odoc_driver ocsigen-start --remap` on the INSTALLED package. Each side gets
+;; its own API nav, a body colour and a switch; the manual nav is shared.
(project ocsigen-start)
(title Start)
-(url-prefix /ocsigen-start)
-(css /css/style.css /css/ocsigen-odoc.css) ; shared Ocsigen theme (wodoc css default changed)
-(landing intro.html)
-
-;; The shared manual nav (the two manual pages; the API module lists come from
-;; the per-side (indexdoc …) below). Only `dev` is rebuilt, so this static nav
-;; always matches the current manual.
+(pub /ocsigen-start)
+(odoc-driver ocsigen-start)
+(landing index.html)
(nav
(section "Manual"
- (link "Introduction" intro.html intro)
(link "Overview" index.html index)))
-
(client-server
- (server (lib ocsigen-start.server) (indexdoc doc/indexdoc.server) (heading "Server API"))
- (client (lib ocsigen-start.client) (indexdoc doc/indexdoc.client) (heading "Client API")))
+ (server (lib ocsigen-start.server) (indexdoc doc/server.indexdoc) (heading "Server API") (wrapper Os))
+ (client (lib ocsigen-start.client) (indexdoc doc/client.indexdoc) (heading "Client API") (wrapper Os)))
;; Sibling Ocsigen projects whose ocaml.org xrefs are rewritten to relative
;; links into their wodoc docs: (pkg deploy-dir layout wrapper-module)
;; layout = true/multilib (./) | false/root (modules at version
diff --git a/dune b/dune
index 59a829dbe..b0be6f9bc 100644
--- a/dune
+++ b/dune
@@ -1,9 +1,11 @@
-(vendored_dirs ocsigen-dune-rules)
-
(data_only_dirs template.distillery)
+; Install the distillery template into lib/eliom/templates/os/ so that
+; eliom-distillery picks it up at the standard location.
+
(install
+ (package ocsigen-start)
(section lib_root)
(files
(glob_files_rec
- (template.distillery/* with_prefix eliom/templates/os.pgocaml))))
+ (template.distillery/* with_prefix eliom/templates/os))))
diff --git a/dune-project b/dune-project
index b93df334a..97ae2995b 100644
--- a/dune-project
+++ b/dune-project
@@ -2,6 +2,8 @@
(name ocsigen-start)
+(version 9.0.0~dev)
+
(generate_opam_files true)
(using dune_site 0.1)
@@ -44,11 +46,10 @@
(ocsigen-i18n
(>= "4.0.0"))
(eliom
- (and
- (>= "12.0.0")
- (< "13.0.0")))
+ (>= "13.0~"))
(ocsigen-toolkit
(>= "2.7.0"))
+ ocsigen-dune-rules
(ocsigen-ppx-rpc
(>= "1.1"))
(yojson
@@ -59,7 +60,7 @@
(< "2.0")))
cohttp-lwt-unix
(js_of_ocaml
- (>= "6.3.2"))
+ (>= "6.4.0"))
(re
(>= "1.7.2"))
(ocsipersist-pgsql-config
@@ -67,3 +68,12 @@
(>= "2.0")
(< "3.0")))
conf-postgresql))
+
+(package
+ (name ocsigen-start-compat)
+ (synopsis "Backward-compatible Os_xxx module names for ocsigen-start")
+ (description
+ "Provides the old Os_xxx module names (e.g. Os_session, Os_user) as aliases to the new Os.Xxx modules. Use this package to ease migration of existing code.")
+ (depends
+ (ocsigen-start
+ (= :version))))
diff --git a/ocsigen-dune-rules/.gitignore b/ocsigen-dune-rules/.gitignore
deleted file mode 100644
index e35d8850c..000000000
--- a/ocsigen-dune-rules/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-_build
diff --git a/ocsigen-dune-rules/.ocamlformat b/ocsigen-dune-rules/.ocamlformat
deleted file mode 100644
index dbc03d392..000000000
--- a/ocsigen-dune-rules/.ocamlformat
+++ /dev/null
@@ -1 +0,0 @@
-version = 0.28.1
diff --git a/ocsigen-dune-rules/LICENSE b/ocsigen-dune-rules/LICENSE
deleted file mode 100644
index 877734eb3..000000000
--- a/ocsigen-dune-rules/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-# MIT License
-
-Copyright (c) 2026 Tarides, Jules Aguillon
-
-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/ocsigen-dune-rules/README.md b/ocsigen-dune-rules/README.md
deleted file mode 100644
index f204f9c1c..000000000
--- a/ocsigen-dune-rules/README.md
+++ /dev/null
@@ -1,58 +0,0 @@
-# ocsigen-dune-rules
-
-Generate Dune rules for building a client/server application or library.
-
-## Usage
-
-The following `dune` file builds the client and server parts of your library.
-Place it in a directory containing `*.eliom` files.
-
-`lib/dune`:
-```dune
-(library
- (public_name my_lib.server)
- (name my_lib)
- (modes byte native)
- (wrapped false)
- (preprocess
- (pps
- eliom.ppx.server
- ocsigen-ppx-rpc
- --rpc-raw))
- (libraries eliom.server js_of_ocaml))
-
-(subdir
- client
- (library
- (public_name my_lib.client)
- (name my_lib)
- (modes byte)
- (wrapped false)
- (preprocess
- (pps eliom.ppx.client js_of_ocaml-ppx))
- (libraries eliom.client js_of_ocaml js_of_ocaml-lwt))
- (dynamic_include ../dune.client))
-
-(rule
- (deps
- (glob_files *.eliom)
- (glob_files *.eliomi))
- (action
- (with-stdout-to
- dune.client
- (run ocsigen-dune-rules .))))
-```
-
-You must also tell Dune that `*.eliom` files contain source code by adding this to your `dune-project` file:
-
-`dune-project`:
-```dune
-(dialect
- (name "eliom-server")
- (implementation
- (extension "eliom"))
- (interface
- (extension "eliomi")))
-```
-
-See [ocsigen-toolkit](https://github.com/ocsigen/ocsigen-toolkit/tree/master) for a working example.
diff --git a/ocsigen-dune-rules/dune-project b/ocsigen-dune-rules/dune-project
deleted file mode 100644
index 313fc1ce9..000000000
--- a/ocsigen-dune-rules/dune-project
+++ /dev/null
@@ -1,19 +0,0 @@
-(lang dune 3.14)
-
-(name ocsigen-dune-rules)
-
-(cram enable)
-
-(generate_opam_files true)
-
-(authors "Jules Aguillon ")
-
-(maintainers "Jules Aguillon ")
-
-(license MIT)
-
-(package
- (name ocsigen-dune-rules)
- (synopsis
- "Generate Dune rules for building a client/server application or library.")
- (depends ocaml cmdliner ocsigen-ppx-rpc eliom))
diff --git a/ocsigen-dune-rules/ocsigen-dune-rules.opam b/ocsigen-dune-rules/ocsigen-dune-rules.opam
deleted file mode 100644
index 8914b4cd1..000000000
--- a/ocsigen-dune-rules/ocsigen-dune-rules.opam
+++ /dev/null
@@ -1,29 +0,0 @@
-# This file is generated by dune, edit dune-project instead
-opam-version: "2.0"
-synopsis:
- "Generate Dune rules for building a client/server application or library."
-maintainer: ["Jules Aguillon "]
-authors: ["Jules Aguillon "]
-license: "MIT"
-depends: [
- "dune" {>= "3.14"}
- "ocaml"
- "cmdliner"
- "ocsigen-ppx-rpc"
- "eliom"
- "odoc" {with-doc}
-]
-build: [
- ["dune" "subst"] {dev}
- [
- "dune"
- "build"
- "-p"
- name
- "-j"
- jobs
- "@install"
- "@runtest" {with-test}
- "@doc" {with-doc}
- ]
-]
diff --git a/ocsigen-dune-rules/ocsigen-dune-rules/dune b/ocsigen-dune-rules/ocsigen-dune-rules/dune
deleted file mode 100644
index 778b68e6b..000000000
--- a/ocsigen-dune-rules/ocsigen-dune-rules/dune
+++ /dev/null
@@ -1,4 +0,0 @@
-(executable
- (public_name ocsigen-dune-rules)
- (name main)
- (libraries cmdliner))
diff --git a/ocsigen-dune-rules/ocsigen-dune-rules/gen_rules.ml b/ocsigen-dune-rules/ocsigen-dune-rules/gen_rules.ml
deleted file mode 100644
index ff0049663..000000000
--- a/ocsigen-dune-rules/ocsigen-dune-rules/gen_rules.ml
+++ /dev/null
@@ -1,38 +0,0 @@
-let pf = Printf.printf
-let spf = Printf.sprintf
-
-let gen_eliom_ppx_rule ~target ~input ~args =
- (* The [chdir] instruction is needed to obtain the correct path for
- [-loc-filename] to be used in error messages. *)
- pf
- {|(rule
- (with-stdout-to %s
- (chdir %%{workspace_root}
- (run ocsigen-ppx-client -as-pp -loc-filename %%{dep:%s} %s %%{dep:%s}))))
-|}
- target input (String.concat " " args) input
-
-let gen_rule_for_module ~server_rel_prefix ~impl fname =
- let target = Filename.basename fname in
- let fname_no_ext = Filename.remove_extension fname in
- let input = Filename.concat server_rel_prefix fname in
- if Filename.extension fname_no_ext = ".pp" then ()
- else
- let args =
- if impl then
- let server_cmo = Filename.concat server_rel_prefix fname_no_ext in
- [ "--impl"; "-server-cmo"; spf "%%{cmo:%s}" server_cmo ]
- else [ "--intf" ]
- in
- gen_eliom_ppx_rule ~target ~input ~args
-
-(** Relative path to server modules from the generated client modules. *)
-let server_rel_prefix = ".."
-
-let gen_rule_for_file fname =
- match Filename.extension fname with
- | ".eliom" -> gen_rule_for_module ~server_rel_prefix ~impl:true fname
- | ".eliomi" -> gen_rule_for_module ~server_rel_prefix ~impl:false fname
- | _ -> ()
-
-let run files = List.iter gen_rule_for_file files
diff --git a/ocsigen-dune-rules/ocsigen-dune-rules/main.ml b/ocsigen-dune-rules/ocsigen-dune-rules/main.ml
deleted file mode 100644
index 7b608f240..000000000
--- a/ocsigen-dune-rules/ocsigen-dune-rules/main.ml
+++ /dev/null
@@ -1,20 +0,0 @@
-let run dir =
- let files = Utils.list_dir dir in
- let files = List.filter (Fun.negate Utils.is_dir) files in
- Gen_rules.run files
-
-open Cmdliner
-
-let arg_dir =
- let doc = "Directory containing the Eliom modules." in
- Arg.(required & pos 0 (some dir) None & info ~doc ~docv:"DIR" [])
-
-let cmd =
- let term = Term.(const run $ arg_dir) in
- let doc =
- "Generate dune rules for building an ocsigen application or library."
- in
- let info = Cmd.info "ocsigen-dune-rules" ~version:"%%VERSION%%" ~doc in
- Cmd.v info term
-
-let () = exit (Cmd.eval cmd)
diff --git a/ocsigen-dune-rules/ocsigen-dune-rules/utils.ml b/ocsigen-dune-rules/ocsigen-dune-rules/utils.ml
deleted file mode 100644
index 0b9e1825a..000000000
--- a/ocsigen-dune-rules/ocsigen-dune-rules/utils.ml
+++ /dev/null
@@ -1,13 +0,0 @@
-(** List the content of a directory. Returns qualified paths. Returned path
- doesn't contain [./] if [p] is equal to ["."]. *)
-let list_dir p =
- (* Let [Sys_error] escape. *)
- let files = Sys.readdir p in
- (* Sorted for reproducibility. *)
- Array.sort String.compare files;
- let concat_p = if p = "." then Fun.id else Filename.concat p in
- Array.iteri (fun i fname -> files.(i) <- concat_p fname) files;
- Array.to_list files
-
-(** Do not raise. *)
-let is_dir p = try Sys.is_directory p with Sys_error _ -> false
diff --git a/ocsigen-dune-rules/ocsigen-ppx-client/dune b/ocsigen-dune-rules/ocsigen-ppx-client/dune
deleted file mode 100644
index ff7a6d26c..000000000
--- a/ocsigen-dune-rules/ocsigen-ppx-client/dune
+++ /dev/null
@@ -1,5 +0,0 @@
-(executable
- (public_name ocsigen-ppx-client)
- (package ocsigen-dune-rules)
- (name main)
- (libraries ocsigen-ppx-rpc eliom.ppx.client))
diff --git a/ocsigen-dune-rules/ocsigen-ppx-client/main.ml b/ocsigen-dune-rules/ocsigen-ppx-client/main.ml
deleted file mode 100644
index e3cba4049..000000000
--- a/ocsigen-dune-rules/ocsigen-ppx-client/main.ml
+++ /dev/null
@@ -1 +0,0 @@
-let () = Ppxlib.Driver.standalone ()
diff --git a/ocsigen-dune-rules/test/dune b/ocsigen-dune-rules/test/dune
deleted file mode 100644
index 58b3ec1e9..000000000
--- a/ocsigen-dune-rules/test/dune
+++ /dev/null
@@ -1,2 +0,0 @@
-(cram
- (deps %{bin:ocsigen-dune-rules}))
diff --git a/ocsigen-dune-rules/test/rules.t/b.eliom b/ocsigen-dune-rules/test/rules.t/b.eliom
deleted file mode 100644
index e69de29bb..000000000
diff --git a/ocsigen-dune-rules/test/rules.t/b.eliomi b/ocsigen-dune-rules/test/rules.t/b.eliomi
deleted file mode 100644
index e69de29bb..000000000
diff --git a/ocsigen-dune-rules/test/rules.t/not_eliom.ml b/ocsigen-dune-rules/test/rules.t/not_eliom.ml
deleted file mode 100644
index e69de29bb..000000000
diff --git a/ocsigen-dune-rules/test/rules.t/run.t b/ocsigen-dune-rules/test/rules.t/run.t
deleted file mode 100644
index cd8b0a53b..000000000
--- a/ocsigen-dune-rules/test/rules.t/run.t
+++ /dev/null
@@ -1,13 +0,0 @@
- $ ocsigen-dune-rules .
- (rule
- (with-stdout-to a.eliom
- (chdir %{workspace_root}
- (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../a.eliom} --impl -server-cmo %{cmo:../a} %{dep:../a.eliom}))))
- (rule
- (with-stdout-to b.eliom
- (chdir %{workspace_root}
- (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../b.eliom} --impl -server-cmo %{cmo:../b} %{dep:../b.eliom}))))
- (rule
- (with-stdout-to b.eliomi
- (chdir %{workspace_root}
- (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../b.eliomi} --intf %{dep:../b.eliomi}))))
diff --git a/ocsigen-dune-rules/test/rules.t/subdir/.keep b/ocsigen-dune-rules/test/rules.t/subdir/.keep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/ocsigen-start-compat.opam b/ocsigen-start-compat.opam
new file mode 100644
index 000000000..9e29b302e
--- /dev/null
+++ b/ocsigen-start-compat.opam
@@ -0,0 +1,34 @@
+# This file is generated by dune, edit dune-project instead
+opam-version: "2.0"
+version: "9.0.0~dev"
+synopsis: "Backward-compatible Os_xxx module names for ocsigen-start"
+description:
+ "Provides the old Os_xxx module names (e.g. Os_session, Os_user) as aliases to the new Os.Xxx modules. Use this package to ease migration of existing code."
+maintainer: ["dev@ocsigen.org"]
+authors: ["dev@ocsigen.org"]
+license: "LGPL-2.1-only WITH OCaml-LGPL-linking-exception"
+homepage: "https://ocsigen.org/ocsigen-start/"
+bug-reports: "https://github.com/ocsigen/ocsigen-start/issues"
+depends: [
+ "dune" {>= "3.18"}
+ "ocsigen-start" {= version}
+ "odoc" {with-doc}
+]
+build: [
+ ["dune" "subst"] {dev}
+ [
+ "dune"
+ "build"
+ "-p"
+ name
+ "-j"
+ jobs
+ "--promote-install-files=false"
+ "@install"
+ "@runtest" {with-test}
+ "@doc" {with-doc}
+ ]
+ ["dune" "install" "-p" name "--create-install-files" name]
+]
+dev-repo: "git+https://github.com/ocsigen/ocsigen-start.git"
+x-maintenance-intent: ["(latest)"]
diff --git a/ocsigen-start.opam b/ocsigen-start.opam
index 3eb530408..e0e1f6cf6 100644
--- a/ocsigen-start.opam
+++ b/ocsigen-start.opam
@@ -1,5 +1,6 @@
# This file is generated by dune, edit dune-project instead
opam-version: "2.0"
+version: "9.0.0~dev"
synopsis:
"Higher-level library for developing Web and mobile applications with users, registration, notifications, etc"
description: """
@@ -20,13 +21,14 @@ depends: [
"pgocaml_ppx" {>= "4.0"}
"safepass" {>= "3.0"}
"ocsigen-i18n" {>= "4.0.0"}
- "eliom" {>= "12.0.0" & < "13.0.0"}
+ "eliom" {>= "13.0~"}
"ocsigen-toolkit" {>= "2.7.0"}
+ "ocsigen-dune-rules"
"ocsigen-ppx-rpc" {>= "1.1"}
"yojson" {>= "1.6.0"}
"resource-pooling" {>= "1.0" & < "2.0"}
"cohttp-lwt-unix"
- "js_of_ocaml" {>= "6.3.2"}
+ "js_of_ocaml" {>= "6.4.0"}
"re" {>= "1.7.2"}
"ocsipersist-pgsql-config" {>= "2.0" & < "3.0"}
"conf-postgresql"
@@ -54,6 +56,3 @@ depexts: [
["imagemagick" "ruby-sass"] {os-family = "debian"}
["md5sha1sum" "sassc"] {os = "macos" & os-distribution = "homebrew"}
]
-pin-depends: [
- ["ocsigen-toolkit.dev" "git+https://github.com/ocsigen/ocsigen-toolkit.git#d3361b2969cc94a9fdc3e5bc0282184777894b98"]
-]
diff --git a/ocsigen-start.opam.template b/ocsigen-start.opam.template
index c238ae6a6..594c63f1e 100644
--- a/ocsigen-start.opam.template
+++ b/ocsigen-start.opam.template
@@ -2,6 +2,3 @@ depexts: [
["imagemagick" "ruby-sass"] {os-family = "debian"}
["md5sha1sum" "sassc"] {os = "macos" & os-distribution = "homebrew"}
]
-pin-depends: [
- ["ocsigen-toolkit.dev" "git+https://github.com/ocsigen/ocsigen-toolkit.git#d3361b2969cc94a9fdc3e5bc0282184777894b98"]
-]
diff --git a/src/os_comet.eliom b/src/Os/comet.eliom
similarity index 73%
rename from src/os_comet.eliom
rename to src/Os/comet.eliom
index fe034207b..757691d3b 100644
--- a/src/os_comet.eliom
+++ b/src/Os/comet.eliom
@@ -36,10 +36,10 @@ let%client cookies_enabled () =
with _ -> false
let%client restart_process () =
- if Eliom_client.is_client_app ()
+ if Eliom.Client.is_client_app ()
then
- Eliom_client.exit_to ~absolute:false
- ~service:(Eliom_service.static_dir ())
+ Eliom.Client.exit_to ~absolute:false
+ ~service:(Eliom.Service.static_dir ())
["index.html"] ()
else if
(* If cookies do not work,
@@ -48,10 +48,10 @@ let%client restart_process () =
if cookies are deactivated of if the app is running in an iframe
and the browser forbids third party cookies. *)
cookies_enabled ()
- then Eliom_client.exit_to ~service:Eliom_service.reload_action () ()
+ then Eliom.Client.exit_to ~service:Eliom.Service.reload_action () ()
let%client _ =
- Eliom_comet.set_handle_exn_function (fun ?exn:_ () ->
+ Eliom.Comet.set_handle_exn_function (fun ?exn:_ () ->
restart_process (); Lwt.return_unit)
(* We create a channel on scope user_indep_process_scope,
@@ -67,8 +67,8 @@ type%shared msg =
let create_monitor_channel () =
let monitor_stream, monitor_send = React.E.create () in
let channel =
- Eliom_comet.Channel.create_from_events
- ~scope:Os_session.user_indep_process_scope ~name:"monitor" monitor_stream
+ Eliom.Comet.Channel.create_from_events
+ ~scope:Session.user_indep_process_scope ~name:"monitor" monitor_stream
in
channel, fun ev -> monitor_send ev
@@ -79,16 +79,16 @@ let create_monitor_channel () =
after timeout.
*)
let monitor_channel_ref =
- Eliom_reference.Volatile.eref ~scope:Os_session.user_indep_process_scope None
+ Eliom.Reference.Volatile.eref ~scope:Session.user_indep_process_scope None
let already_send_ref =
- Eliom_reference.Volatile.eref ~scope:Eliom_common.request_scope false
+ Eliom.Reference.Volatile.eref ~scope:Eliom.Common.request_scope false
let%client handle_error =
ref (fun exn ->
Logs.info (fun fmt ->
fmt
- ("Exception received on Os_comet's monitor channel: " ^^ "@\n%s")
+ ("Exception received on Comet's monitor channel: " ^^ "@\n%s")
(Printexc.to_string exn));
restart_process ();
Lwt.return_unit)
@@ -101,23 +101,23 @@ let%client handle_message = function
Logs.info (fun fmt -> fmt "poum");
Lwt.return_unit
| Ok Connection_changed ->
- Os_msg.msg ~level:`Err
+ Msg.msg ~level:`Err
"Connection has changed from outside. Program will restart.";
let* () = Lwt_js.sleep 2. in
restart_process (); Lwt.return_unit
let%server warn_state c state =
- match Eliom_reference.Volatile.Ext.get state monitor_channel_ref with
+ match Eliom.Reference.Volatile.Ext.get state monitor_channel_ref with
| Some (_, send) -> send c
| None -> ()
let%server _ =
- Os_session.set_warn_connection_change (warn_state Connection_changed)
+ Session.set_warn_connection_change (warn_state Connection_changed)
let%server _ =
- Os_session.on_start_process (fun _ ->
+ Session.on_start_process (fun _ ->
let channel = create_monitor_channel () in
- Eliom_reference.Volatile.set monitor_channel_ref (Some channel);
+ Eliom.Reference.Volatile.set monitor_channel_ref (Some channel);
ignore
[%client
(Lwt.async (fun () ->
@@ -128,19 +128,19 @@ let%server _ =
let warn c =
(* User connected or disconnected.
I want to send the message on all tabs of the browser: *)
- if not (Eliom_reference.Volatile.get already_send_ref)
+ if not (Eliom.Reference.Volatile.get already_send_ref)
then (
- Eliom_reference.Volatile.set already_send_ref true;
- let cur = Eliom_reference.Volatile.get monitor_channel_ref in
- Eliom_state.Ext.iter_volatile_sub_states
+ Eliom.Reference.Volatile.set already_send_ref true;
+ let cur = Eliom.Reference.Volatile.get monitor_channel_ref in
+ Eliom.State.Ext.iter_volatile_sub_states
~state:
- (Eliom_state.Ext.current_volatile_data_state
- ~scope:Os_session.user_indep_session_scope ()) (fun state ->
- match Eliom_reference.Volatile.Ext.get state monitor_channel_ref with
+ (Eliom.State.Ext.current_volatile_data_state
+ ~scope:Session.user_indep_session_scope ()) (fun state ->
+ match Eliom.Reference.Volatile.Ext.get state monitor_channel_ref with
| Some (_, send) as v -> if not (v == cur) then send c
| None -> ()));
Lwt.return_unit
in
let warn_connection_change _ = warn Connection_changed in
- Os_session.on_open_session warn_connection_change;
- Os_session.on_post_close_session warn_connection_change
+ Session.on_open_session warn_connection_change;
+ Session.on_post_close_session warn_connection_change
diff --git a/src/os_comet.eliomi b/src/Os/comet.eliomi
similarity index 92%
rename from src/os_comet.eliomi
rename to src/Os/comet.eliomi
index d19c83beb..ebe1e5f99 100644
--- a/src/os_comet.eliomi
+++ b/src/Os/comet.eliomi
@@ -34,7 +34,7 @@ val restart_process : unit -> unit
(** [restart_process ()] restarts the client.
For mobile application, it restarts the application by going to
["index.html"].
- For other types of clients, {!Eliom_service.reload_action} is used as argument of {!Eliom_client.exit_to}
+ For other types of clients, {!Eliom.Service.reload_action} is used as argument of {!Eliom.Client.exit_to}
*)
val set_error_handler : (exn -> unit Lwt.t) -> unit
diff --git a/src/os_connect_phone.eliom b/src/Os/connect_phone.eliom
similarity index 73%
rename from src/os_connect_phone.eliom
rename to src/Os/connect_phone.eliom
index ff8543587..75d62ab93 100644
--- a/src/os_connect_phone.eliom
+++ b/src/Os/connect_phone.eliom
@@ -23,7 +23,7 @@ open%server Lwt.Syntax
type%shared sms_error_core = [`Unknown | `Send | `Limit | `Invalid_number]
type%shared sms_error = [`Ownership | sms_error_core]
-(* adapted from Ocsigen_lib.make_cryptographic_safe_string *)
+(* adapted from Ocsigen_base.Lib.make_cryptographic_safe_string *)
let activation_code =
let rng = Cryptokit.Random.device_rng "/dev/urandom" in
fun () ->
@@ -36,15 +36,15 @@ let activation_code =
Printf.sprintf "%04Ld" n
let activation_code_ref =
- Eliom_reference.eref ~scope:Eliom_common.default_process_scope None
+ Eliom.Reference.eref ~scope:Eliom.Common.default_process_scope None
let recovery_code_ref =
- Eliom_reference.eref ~scope:Eliom_common.default_process_scope None
+ Eliom.Reference.eref ~scope:Eliom.Common.default_process_scope None
let send_sms_handler =
ref @@ fun ~number message ->
Printf.printf
- "INFO: send SMS %s to %s\nYou have not defined an SMS handler.\nPlease see Os_connect_phone.set_send_sms_handler\n%!"
+ "INFO: send SMS %s to %s\nYou have not defined an SMS handler.\nPlease see Connect_phone.set_send_sms_handler\n%!"
message number;
Lwt.return (Error `Send)
@@ -57,7 +57,7 @@ let%server request_code reference number =
Lwt.catch
(fun () ->
let* attempt =
- Lwt.bind (Eliom_reference.get reference) (function
+ Lwt.bind (Eliom.Reference.get reference) (function
| Some (_, _, attempt) -> Lwt.return attempt
| None -> Lwt.return 0)
in
@@ -65,7 +65,7 @@ let%server request_code reference number =
then
let attempt = attempt + 1 and code = activation_code () in
let* () =
- Eliom_reference.set reference (Some (number, code, attempt))
+ Eliom.Reference.set reference (Some (number, code, attempt))
in
Lwt.catch
(fun () -> (send_sms ~number code :> (unit, sms_error) result Lwt.t))
@@ -74,28 +74,28 @@ let%server request_code reference number =
(fun _ -> Lwt.return (Error `Unknown))
let%server request_wrapper number f =
- if Re.Str.string_match Os_lib.phone_regexp number 0
+ if Re.Str.string_match Lib.phone_regexp number 0
then f number
else Lwt.return (Error `Invalid_number)
let%rpc request_recovery_code (number : string) : (unit, sms_error) result Lwt.t
=
request_wrapper number @@ fun number ->
- let* b = Os_db.Phone.exists number in
+ let* b = Db.Phone.exists number in
if not b
then Lwt.return (Error `Ownership)
else request_code recovery_code_ref number
let%rpc request_code (number : string) : (unit, sms_error) result Lwt.t =
request_wrapper number @@ fun number ->
- let* b = Os_db.Phone.exists number in
+ let* b = Db.Phone.exists number in
if b
then Lwt.return (Error `Ownership)
else request_code activation_code_ref number
let%server confirm_code myid code =
- Lwt.bind (Eliom_reference.get activation_code_ref) (function
- | Some (number, code', _) when code = code' -> Os_db.Phone.add myid number
+ Lwt.bind (Eliom.Reference.get activation_code_ref) (function
+ | Some (number, code', _) when code = code' -> Db.Phone.add myid number
| _ -> Lwt.return_false)
let%rpc confirm_code_extra myid (code : string) : bool Lwt.t =
@@ -104,14 +104,14 @@ let%rpc confirm_code_extra myid (code : string) : bool Lwt.t =
let%server
confirm_code_signup_no_connect ~first_name ~last_name ~code ~password ()
=
- Lwt.bind (Eliom_reference.get activation_code_ref) (function
+ Lwt.bind (Eliom.Reference.get activation_code_ref) (function
| Some (number, code', _) when code = code' ->
- let* () = Eliom_reference.set activation_code_ref None in
+ let* () = Eliom.Reference.set activation_code_ref None in
let* user =
- Os_user.create ~password ~firstname:first_name ~lastname:last_name ()
+ User.create ~password ~firstname:first_name ~lastname:last_name ()
in
- let userid = Os_user.userid_of_user user in
- let* _ = Os_db.Phone.add userid number in
+ let userid = User.userid_of_user user in
+ let* _ = Db.Phone.add userid number in
Lwt.return_some userid
| _ -> Lwt.return_none)
@@ -128,15 +128,15 @@ let%rpc
(function
| None -> Lwt.return_false
| Some userid ->
- let* () = Os_session.connect userid in
+ let* () = Session.connect userid in
Lwt.return_true)
let%rpc confirm_code_recovery (code : string) : bool Lwt.t =
- Lwt.bind (Eliom_reference.get recovery_code_ref) (function
+ Lwt.bind (Eliom.Reference.get recovery_code_ref) (function
| Some (number, code', _) when code = code' ->
- Lwt.bind (Os_db.Phone.userid number) (function
+ Lwt.bind (Db.Phone.userid number) (function
| Some userid ->
- let* () = Os_session.connect userid in
+ let* () = Session.connect userid in
Lwt.return_true
| None -> Lwt.return_false)
| _ -> Lwt.return_false)
@@ -146,12 +146,11 @@ let%rpc connect ~(keepmeloggedin : bool) ~(password : string) (number : string)
=
Lwt.catch
(fun () ->
- let* userid = Os_db.User.verify_password_phone ~password ~number in
- let* () = Os_session.connect ~expire:(not keepmeloggedin) userid in
+ let* userid = Db.User.verify_password_phone ~password ~number in
+ let* () = Session.connect ~expire:(not keepmeloggedin) userid in
Lwt.return `Login_ok)
(function
- | Os_db.Empty_password | Os_db.Wrong_password ->
- Lwt.return `Wrong_password
- | Os_db.No_such_user -> Lwt.return `No_such_user
- | Os_db.Password_not_set -> Lwt.return `Password_not_set
+ | Db.Empty_password | Db.Wrong_password -> Lwt.return `Wrong_password
+ | Db.No_such_user -> Lwt.return `No_such_user
+ | Db.Password_not_set -> Lwt.return `Password_not_set
| exc -> Lwt.reraise exc)
diff --git a/src/os_connect_phone.eliomi b/src/Os/connect_phone.eliomi
similarity index 96%
rename from src/os_connect_phone.eliomi
rename to src/Os/connect_phone.eliomi
index 296f3ee8b..a4fc0ee32 100644
--- a/src/os_connect_phone.eliomi
+++ b/src/Os/connect_phone.eliomi
@@ -38,10 +38,10 @@ val confirm_code_signup_no_connect :
-> code:string
-> password:string
-> unit
- -> Os_types.User.id option Lwt.t
+ -> Types.User.id option Lwt.t
(** Confirm validation code and create corresponding user. *)
-val confirm_code : Os_types.User.id -> string -> bool Lwt.t
+val confirm_code : Types.User.id -> string -> bool Lwt.t
(** Confirm validation code and add extra phone to account of the given
user *)
diff --git a/src/os_core_db.ml b/src/Os/core_db.ml
similarity index 100%
rename from src/os_core_db.ml
rename to src/Os/core_db.ml
diff --git a/src/os_core_db.mli b/src/Os/core_db.mli
similarity index 100%
rename from src/os_core_db.mli
rename to src/Os/core_db.mli
diff --git a/src/os_current_user.eliom b/src/Os/current_user.eliom
similarity index 70%
rename from src/os_current_user.eliom
rename to src/Os/current_user.eliom
index 4a18996cb..976e19840 100644
--- a/src/os_current_user.eliom
+++ b/src/Os/current_user.eliom
@@ -21,18 +21,15 @@
open%server Lwt.Syntax
[%%shared
-type current_user =
- | CU_idontknown
- | CU_notconnected
- | CU_user of Os_types.User.t]
+type current_user = CU_idontknown | CU_notconnected | CU_user of Types.User.t]
let%shared please_use_connected_fun =
- "ERROR: Os_current_user is usable only with connected functions (see Os_session)"
+ "ERROR: Current_user is usable only with connected functions (see Session)"
(* current user *)
-let%server me : current_user Eliom_reference.Volatile.eref =
+let%server me : current_user Eliom.Reference.Volatile.eref =
(* This is a request cache of current user *)
- Eliom_reference.Volatile.eref ~scope:Eliom_common.request_scope CU_idontknown
+ Eliom.Reference.Volatile.eref ~scope:Eliom.Common.request_scope CU_idontknown
let%client me : current_user ref = ref CU_notconnected
(*on client side the default is not connected *)
@@ -52,64 +49,64 @@ let%client get_current_user () =
prerr_endline please_use_connected_fun;
failwith please_use_connected_fun
| _ ->
- prerr_endline "Not connected error in Os_current_user";
- raise Os_session.Not_connected
+ prerr_endline "Not connected error in Current_user";
+ raise Session.Not_connected
(* SECURITY: We can trust these functions on server side,
because the user is set at every request from the session cookie value.
But do not trust a user sent by the client ...
*)
let%server get_current_user () =
- match Eliom_reference.Volatile.get me with
+ match Eliom.Reference.Volatile.get me with
| CU_user a -> a
| CU_idontknown ->
prerr_endline please_use_connected_fun;
failwith please_use_connected_fun
- | CU_notconnected -> raise Os_session.Not_connected
+ | CU_notconnected -> raise Session.Not_connected
let%server get_current_user_option () =
- let u = Eliom_reference.Volatile.get me in
+ let u = Eliom.Reference.Volatile.get me in
match u with
| CU_user a -> Some a
| CU_idontknown -> failwith please_use_connected_fun
| CU_notconnected -> None
-let%shared get_current_userid () = Os_user.userid_of_user (get_current_user ())
+let%shared get_current_userid () = User.userid_of_user (get_current_user ())
[%%shared
module Opt = struct
let get_current_user = get_current_user_option
let get_current_userid () =
- Eliom_lib.Option.map Os_user.userid_of_user (get_current_user_option ())
+ Option.map User.userid_of_user (get_current_user_option ())
end]
-let%client _ = Os_session.get_current_userid_o := Opt.get_current_userid
+let%client _ = Session.get_current_userid_o := Opt.get_current_userid
let%server set_user_server myid =
- let* u = Os_user.user_of_userid myid in
- Eliom_reference.Volatile.set me (CU_user u);
+ let* u = User.user_of_userid myid in
+ Eliom.Reference.Volatile.set me (CU_user u);
Lwt.return_unit
let%server unset_user_server () =
- Eliom_reference.Volatile.set me CU_notconnected
+ Eliom.Reference.Volatile.set me CU_notconnected
let%server set_user_client () =
- let u = Eliom_reference.Volatile.get me in
+ let u = Eliom.Reference.Volatile.get me in
ignore [%client (me := ~%u : unit)]
let%server unset_user_client () =
ignore [%client (me := CU_notconnected : unit)]
let%server () =
- Os_session.on_request (fun myid_o ->
+ Session.on_request (fun myid_o ->
match myid_o with
| Some myid -> set_user_server myid
| None -> unset_user_server (); Lwt.return_unit);
- Os_session.on_start_connected_process (fun myid ->
+ Session.on_start_connected_process (fun myid ->
let* () = set_user_server myid in
set_user_client (); Lwt.return_unit);
- Os_session.on_pre_close_session (fun () ->
+ Session.on_pre_close_session (fun () ->
unset_user_client ();
(*VVV!!! will affect only current tab!! *)
unset_user_server ();
@@ -118,20 +115,20 @@ let%server () =
let%rpc remove_email_from_user (email : string) : unit Lwt.t =
let myid = get_current_userid () in
- Os_user.remove_email_from_user ~userid:myid ~email
+ User.remove_email_from_user ~userid:myid ~email
let%rpc update_main_email (email : string) : unit Lwt.t =
let myid = get_current_userid () in
- Os_user.update_main_email ~userid:myid ~email
+ User.update_main_email ~userid:myid ~email
let%server is_email_validated email =
let myid = get_current_userid () in
- Os_user.is_email_validated ~userid:myid ~email
+ User.is_email_validated ~userid:myid ~email
let%server is_main_email email =
let myid = get_current_userid () in
- Os_user.is_main_email ~userid:myid ~email
+ User.is_main_email ~userid:myid ~email
let%rpc update_language (language : string) : unit Lwt.t =
let myid = get_current_userid () in
- Os_user.update_language ~userid:myid ~language
+ User.update_language ~userid:myid ~language
diff --git a/src/os_current_user.eliomi b/src/Os/current_user.eliomi
similarity index 69%
rename from src/os_current_user.eliomi
rename to src/Os/current_user.eliomi
index ea473c0c7..bb7df2bcd 100644
--- a/src/os_current_user.eliomi
+++ b/src/Os/current_user.eliomi
@@ -23,31 +23,28 @@
(** This module provides functions and types to manage the current user. *)
(** On server side, this will work only if the current request in wrapped
- in {!Os_session.connected_wrapper}, or {!Os_session.connected_fun},
+ in {!Session.connected_wrapper}, or {!Session.connected_fun},
etc.
Otherwise, an exception is raised.
*)
-type current_user =
- | CU_idontknown
- | CU_notconnected
- | CU_user of Os_types.User.t
+type current_user = CU_idontknown | CU_notconnected | CU_user of Types.User.t
-val get_current_user : unit -> Os_types.User.t
-(** [get_current_user ()] returns the current user as a {!Os_types.User.t} type.
- If no user is connected, it fails with {!Os_session.Not_connected}. *)
+val get_current_user : unit -> Types.User.t
+(** [get_current_user ()] returns the current user as a {!Types.User.t} type.
+ If no user is connected, it fails with {!Session.Not_connected}. *)
-val get_current_userid : unit -> Os_types.User.id
+val get_current_userid : unit -> Types.User.id
(** [get_current_userid ()] returns the ID of the current user.
- If no user is connected, it fails with {!Os_session.Not_connected}. *)
+ If no user is connected, it fails with {!Session.Not_connected}. *)
(** Instead of exception, the module [Opt] returns an option. *)
module Opt : sig
- val get_current_user : unit -> Os_types.User.t option
- (** [get_current_user ()] returns the current user as a [Os_types.User.t option]
+ val get_current_user : unit -> Types.User.t option
+ (** [get_current_user ()] returns the current user as a [Types.User.t option]
type. If no user is connected, [None] is returned. *)
- val get_current_userid : unit -> Os_types.User.id option
+ val get_current_userid : unit -> Types.User.id option
(** [get_current_userid ()] returns the ID of the current user as an option.
If no user is connected, [None] is returned. *)
end
@@ -55,20 +52,20 @@ end
val remove_email_from_user : string -> unit Lwt.t
(** [remove_email_from_user email] removes the email [email] of the current
user.
- If no user is connected, it fails with {!Os_session.Not_connected}. If
+ If no user is connected, it fails with {!Session.Not_connected}. If
[email] is the main email of the current user, it fails with
- {!Os_db.Main_email_removal_attempt}.
+ {!Db.Main_email_removal_attempt}.
*)
val update_main_email : string -> unit Lwt.t
(** [update_main_email email] sets the main email of the current user to
[email].
- If no user is connected, it fails with {!Os_session.Not_connected}.
+ If no user is connected, it fails with {!Session.Not_connected}.
*)
val update_language : string -> unit Lwt.t
(** [update_language language] updates the language of the current user.
- If no user is connected, it fails with {!Os_session.Not_connected}.
+ If no user is connected, it fails with {!Session.Not_connected}.
*)
[%%server.start]
@@ -76,7 +73,7 @@ val update_language : string -> unit Lwt.t
val is_email_validated : string -> bool Lwt.t
(** [is_email_validated email] returns [true] if [email] is a valided email for
the current user.
- If no user is connected, it fails with {!Os_session.Not_connected}.
+ If no user is connected, it fails with {!Session.Not_connected}.
It returns [false] in all other cases.
*)
diff --git a/src/os_date.eliom b/src/Os/date.eliom
similarity index 91%
rename from src/os_date.eliom
rename to src/Os/date.eliom
index dcd8f0917..ff2904683 100644
--- a/src/os_date.eliom
+++ b/src/Os/date.eliom
@@ -48,10 +48,10 @@ let%client timezone =
Printf.sprintf "Etc/GMT%+d" ((new%js Js.date_now)##getTimezoneOffset / 60)
let user_tz_sr =
- Eliom_reference.Volatile.eref ~scope:Os_session.user_indep_session_scope None
+ Eliom.Reference.Volatile.eref ~scope:Session.user_indep_session_scope None
let user_tz_gr =
- Eliom_reference.Volatile.eref ~scope:Eliom_common.default_group_scope None
+ Eliom.Reference.Volatile.eref ~scope:Eliom.Common.default_group_scope None
(* We use 2 scopes in order to have the timezone set asap:
- if user connected, we use last tz set by user
- if not connected but new tab, we use same scope as other tabs
@@ -59,9 +59,9 @@ let user_tz_gr =
let user_tz_opt () =
(* We take by default the timezone of the browser (session), if already set *)
- let tz = Eliom_reference.Volatile.get user_tz_sr in
+ let tz = Eliom.Reference.Volatile.get user_tz_sr in
if tz = None (* not set *)
- then Eliom_reference.Volatile.get user_tz_gr
+ then Eliom.Reference.Volatile.get user_tz_gr
else tz
let user_tz () = match user_tz_opt () with None -> "UTC" | Some v -> v
@@ -71,8 +71,8 @@ let%client user_tz () = timezone
the time zone of the client *)
let initialize tz =
let tz = Some tz in
- Eliom_reference.Volatile.set user_tz_gr tz;
- Eliom_reference.Volatile.set user_tz_sr tz
+ Eliom.Reference.Volatile.set user_tz_gr tz;
+ Eliom.Reference.Volatile.set user_tz_sr tz
(* When the browser is loaded, we init the timezone *)
let%rpc init_time_rpc (tz : string) : unit Lwt.t =
@@ -83,7 +83,7 @@ let%client disable_auto_init () = auto_init := false
let%client _ =
(* We wait for the client process to be fully loaded: *)
- Eliom_client.onload (fun () ->
+ Eliom.Client.onload (fun () ->
if !auto_init then Lwt.async (fun () -> init_time_rpc timezone))
[%%shared
@@ -91,6 +91,13 @@ open CalendarLib
type local_calendar = CalendarLib.Calendar.t]
+let%server local_calendar_json : local_calendar Deriving_Json.t =
+ Deriving_Json.convert [%json: float] CalendarLib.Calendar.from_unixfloat
+ CalendarLib.Calendar.to_unixfloat
+
+let%server local_calendar_of_json = Deriving_Json.read local_calendar_json
+let%server local_calendar_to_json = Deriving_Json.write local_calendar_json
+
(* Same as Unix.mktime when TZ=UTC, but avoid modifying this variable. *)
let timegm =
let days = [|0; 31; 59; 90; 120; 151; 181; 212; 243; 273; 304; 334|] in
diff --git a/src/os_date.eliomi b/src/Os/date.eliomi
similarity index 92%
rename from src/os_date.eliomi
rename to src/Os/date.eliomi
index f1176185f..1d4510e52 100644
--- a/src/os_date.eliomi
+++ b/src/Os/date.eliomi
@@ -38,6 +38,16 @@ type local_calendar
[%%server.start]
+val local_calendar_of_json : Deriving_Json_lexer.lexbuf -> local_calendar
+val local_calendar_to_json : Buffer.t -> local_calendar -> unit
+
+val local_calendar_json : local_calendar Deriving_Json.t
+(** JSON codec for {!local_calendar} (the [_of_json]/[_to_json] pair
+ follows the {!Deriving_Json} convention so that
+ [\[%json: local_calendar\]] resolves to {!local_calendar_json}).
+ Suitable for persisting values through Ocsipersist. Encodes as a
+ Unix float. *)
+
val to_utc : ?timezone:string -> local_calendar -> CalendarLib.Calendar.t
(** Convert a local calendar to a UTC calendar. Use the client's
timezone unless the optional [timezone] argument is provided. *)
diff --git a/src/os_db.ml b/src/Os/db.ml
similarity index 99%
rename from src/os_db.ml
rename to src/Os/db.ml
index 42c1e8b61..f65fff93f 100644
--- a/src/os_db.ml
+++ b/src/Os/db.ml
@@ -1,6 +1,6 @@
(* GENERATED CODE, DO NOT EDIT! *)
open Lwt.Syntax
-include Os_core_db
+include Core_db
exception No_such_resource
exception Wrong_password
@@ -111,7 +111,7 @@ module Email = struct
end
module User = struct
- exception Invalid_action_link_key of Os_types.User.id
+ exception Invalid_action_link_key of Types.User.id
let userid_of_email email =
one without_transaction
@@ -777,9 +777,7 @@ module User = struct
then Lwt.fail_with "empty password"
else
full_transaction_block (fun dbh ->
- let password_o =
- Eliom_lib.Option.map (fun p -> fst !pwd_crypt_ref p) password
- in
+ let password_o = Option.map (fun p -> fst !pwd_crypt_ref p) password in
let* userid =
Lwt.bind
(PGOCaml.bind
@@ -1921,7 +1919,7 @@ module User = struct
(fun _rows -> PGOCaml.return ())
in
Lwt.return
- (let open Os_types.Action_link_key in
+ (let open Types.Action_link_key in
{userid; email; validity; expiry; action; data; autoconnect})))
let emails_of_userid userid =
diff --git a/src/os_db.mli b/src/Os/db.mli
similarity index 82%
rename from src/os_db.mli
rename to src/Os/db.mli
index cfc8ae551..547f67376 100644
--- a/src/os_db.mli
+++ b/src/Os/db.mli
@@ -21,7 +21,7 @@
(** This module defines low level functions for database requests. *)
-include module type of Os_core_db
+include module type of Core_db
exception No_such_resource
(** Exception raised when no resource corresponds to the database request. *)
@@ -45,7 +45,7 @@ exception Account_not_activated
(** Exception raised when the account is not activated. *)
val pwd_crypt_ref :
- ((string -> string) * (Os_types.User.id -> string -> string -> bool)) ref
+ ((string -> string) * (Types.User.id -> string -> string -> bool)) ref
(** [pwd_crypt_ref] is a reference to [(f_crypt, f_check)] where
- [f_crypt pwd] is used to encrypt the password [pwd].
- [f_check userid pwd hashed_pwd] returns [true] if the hash of [pwd] and
@@ -63,9 +63,9 @@ end
(** This module is used for low-level user management with database. *)
module User : sig
- exception Invalid_action_link_key of Os_types.User.id
+ exception Invalid_action_link_key of Types.User.id
- val userid_of_email : string -> Os_types.User.id Lwt.t
+ val userid_of_email : string -> Types.User.id Lwt.t
(** [userid_of_email email] returns the userid of the user which has the email
[email]. *)
@@ -73,11 +73,11 @@ module User : sig
(** [is_registered email] returns [true] if the email is already registered.
Else, it returns [false]. *)
- val is_email_validated : Os_types.User.id -> string -> bool Lwt.t
+ val is_email_validated : Types.User.id -> string -> bool Lwt.t
(** [is_email_validated userid email] returns [true] if [email] has been
validated by the user with id [userid]. *)
- val set_email_validated : Os_types.User.id -> string -> unit Lwt.t
+ val set_email_validated : Types.User.id -> string -> unit Lwt.t
(** [set_email_validated userid email] valids [email] for the user with id
[userid]. *)
@@ -91,7 +91,7 @@ module User : sig
-> ?validity:int64
-> ?expiry:CalendarLib.Calendar.t
-> act_key:string
- -> userid:Os_types.User.id
+ -> userid:Types.User.id
-> email:string
-> unit
-> unit Lwt.t
@@ -118,7 +118,7 @@ module User : sig
-> firstname:string
-> lastname:string
-> unit
- -> Os_types.User.id Lwt.t
+ -> Types.User.id Lwt.t
(** [create ?password ?avatar ?language ~firstname ~lastname email] creates a new user
in the database and returns the userid of the new user.
Email, first name, last name and language are mandatory to create a new
@@ -133,7 +133,7 @@ module User : sig
-> ?language:string
-> firstname:string
-> lastname:string
- -> Os_types.User.id
+ -> Types.User.id
-> unit Lwt.t
(** [update ?password ?avatar ?language ~firstname ~lastname userid] updates the user
profile with [userid].
@@ -141,30 +141,27 @@ module User : sig
["empty password"]. TODO: change it to an exception?
*)
- val update_password : userid:Os_types.User.id -> password:string -> unit Lwt.t
+ val update_password : userid:Types.User.id -> password:string -> unit Lwt.t
(** [update_password ~userid ~new_password] updates the password of the user
with ID [userid].
If [password] is passed as an empty string, it fails with the message
["empty password"]. TODO: change it to an exception?
*)
- val update_avatar : userid:Os_types.User.id -> avatar:string -> unit Lwt.t
+ val update_avatar : userid:Types.User.id -> avatar:string -> unit Lwt.t
(** [update_avatar ~userid ~avatar] updates the avatar of the user
with ID [userid]. *)
- val update_main_email : userid:Os_types.User.id -> email:string -> unit Lwt.t
+ val update_main_email : userid:Types.User.id -> email:string -> unit Lwt.t
(** [update_main_email ~userid ~email] updates the main email of the user
with ID [userid]. *)
- val update_language : userid:Os_types.User.id -> language:string -> unit Lwt.t
+ val update_language : userid:Types.User.id -> language:string -> unit Lwt.t
(** [update_language ~userid ~language] updates the language of the user with
ID [userid].
*)
- val verify_password :
- email:string
- -> password:string
- -> Os_types.User.id Lwt.t
+ val verify_password : email:string -> password:string -> Types.User.id Lwt.t
(** [verify_password ~email ~password] returns the userid if user with email
[email] is registered with the password [password].
If [password] the password is wrong,
@@ -178,7 +175,7 @@ module User : sig
val verify_password_phone :
number:string
-> password:string
- -> Os_types.User.id Lwt.t
+ -> Types.User.id Lwt.t
(** [verify_password_phone ~number ~password]
returns the userid if user
who owns [number] and whose password is [password].
@@ -189,13 +186,8 @@ module User : sig
If password is empty, it fails with exception {!Empty_password}. *)
val user_of_userid :
- Os_types.User.id
- -> (Os_types.User.id
- * string
- * string
- * string option
- * bool
- * string option)
+ Types.User.id
+ -> (Types.User.id * string * string * string option * bool * string option)
Lwt.t
(** [user_of_userid userid] returns a tuple [(userid, firstname, lastname,
avatar, bool_password, language)] describing the information about
@@ -205,43 +197,41 @@ module User : sig
If there is no such user, it fails with {!No_such_resource}.
*)
- val get_actionlinkkey_info : string -> Os_types.Action_link_key.info Lwt.t
+ val get_actionlinkkey_info : string -> Types.Action_link_key.info Lwt.t
(** [get_actionlinkkey_info key] returns the information about the
- action link [key] as a type {!Os_types.Action_link_key.info}. *)
+ action link [key] as a type {!Types.Action_link_key.info}. *)
- val emails_of_userid : Os_types.User.id -> string list Lwt.t
+ val emails_of_userid : Types.User.id -> string list Lwt.t
(** [emails_of_userid userid] returns all emails registered for the user with
ID [userid].
If there is no user with [userid] as ID, it fails with
{!No_such_resource}.
*)
- val emails_of_userid_with_status :
- Os_types.User.id
- -> (string * bool) list Lwt.t
+ val emails_of_userid_with_status : Types.User.id -> (string * bool) list Lwt.t
(** Like [emails_of_userid], but also returns validation
status. This way we perform fewer DB queries. *)
- val email_of_userid : Os_types.User.id -> string option Lwt.t
+ val email_of_userid : Types.User.id -> string option Lwt.t
(** [email_of_userid userid] returns the main email registered for the user
with ID [userid].
If there is no such user, it fails with
{!No_such_resource}.
*)
- val is_main_email : userid:Os_types.User.id -> email:string -> bool Lwt.t
+ val is_main_email : userid:Types.User.id -> email:string -> bool Lwt.t
(** [is_main_email ~email ~userid] returns [true] if the main email of the
user with ID [userid] is [email].
If there is no such user or if [email] is not the main
email, it returns [false].
*)
- val add_email_to_user : userid:Os_types.User.id -> email:string -> unit Lwt.t
+ val add_email_to_user : userid:Types.User.id -> email:string -> unit Lwt.t
(** [add_email_to_user ~userid ~email] add [email] to user with ID [userid].
*)
val remove_email_from_user :
- userid:Os_types.User.id
+ userid:Types.User.id
-> email:string
-> unit Lwt.t
(** [remove_email_from_user ~userid ~email] removes the email [email] from the
@@ -249,18 +239,13 @@ module User : sig
If [email] is the main email, it fails with {!Main_email_removal_attempt}.
*)
- val get_language : Os_types.User.id -> string option Lwt.t
+ val get_language : Types.User.id -> string option Lwt.t
(** [get_language userid] returns the language of the user with ID [userid] *)
val get_users :
?pattern:string
-> unit
- -> (Os_types.User.id
- * string
- * string
- * string option
- * bool
- * string option)
+ -> (Types.User.id * string * string * string option * bool * string option)
list
Lwt.t
(** [get_users ~pattern ()] returns all users matching the pattern [pattern]
@@ -275,38 +260,36 @@ module Groups : sig
(** [create ?description name] creates a new group with name [name] and with
description [description]. *)
- val group_of_name :
- string
- -> (Os_types.Group.id * string * string option) Lwt.t
+ val group_of_name : string -> (Types.Group.id * string * string option) Lwt.t
(** [group_of_name name] returns a tuple [(groupid, name, description)]
describing the group.
If no group has the name [name], it fails with {!No_such_resource}.
*)
val add_user_in_group :
- groupid:Os_types.Group.id
- -> userid:Os_types.User.id
+ groupid:Types.Group.id
+ -> userid:Types.User.id
-> unit Lwt.t
(** [add_user_in_group ~groupid ~userid] adds the user with ID [userid] in the
group with ID [groupid] *)
val remove_user_in_group :
- groupid:Os_types.Group.id
- -> userid:Os_types.User.id
+ groupid:Types.Group.id
+ -> userid:Types.User.id
-> unit Lwt.t
(** [remove_user_in_group ~groupid ~userid] removes the user with ID [userid]
in the group with ID [groupid] *)
val in_group :
?dbh:PGOCaml.pa_pg_data PGOCaml.t
- -> groupid:Os_types.Group.id
- -> userid:Os_types.User.id
+ -> groupid:Types.Group.id
+ -> userid:Types.User.id
-> unit
-> bool Lwt.t
(** [in_group ~groupid ~userid] returns [true] if the user with ID [userid] is
in the group with ID [groupid]. *)
- val all : unit -> (Os_types.Group.id * string * string option) list Lwt.t
+ val all : unit -> (Types.Group.id * string * string option) list Lwt.t
(** [all ()] returns all groups as list of tuple [(groupid, name,
description)]. *)
end
@@ -320,7 +303,7 @@ module Phone : sig
val exists : string -> bool Lwt.t
(** Does the number exist in the database? *)
- val userid : string -> Os_types.User.id option Lwt.t
+ val userid : string -> Types.User.id option Lwt.t
(** The user corresponding to a phone number (if any). *)
val delete : int64 -> string -> unit Lwt.t
diff --git a/src/os_db.ppx.ml b/src/Os/db.ppx.ml
similarity index 98%
rename from src/os_db.ppx.ml
rename to src/Os/db.ppx.ml
index e61c52333..560b08bd0 100644
--- a/src/os_db.ppx.ml
+++ b/src/Os/db.ppx.ml
@@ -19,7 +19,7 @@
*)
open Lwt.Syntax
-include Os_core_db
+include Core_db
exception No_such_resource
exception Wrong_password
@@ -56,7 +56,7 @@ module Email = struct
end
module User = struct
- exception Invalid_action_link_key of Os_types.User.id
+ exception Invalid_action_link_key of Types.User.id
let userid_of_email email =
one without_transaction
@@ -146,9 +146,7 @@ module User = struct
then Lwt.fail_with "empty password"
else
full_transaction_block (fun dbh ->
- let password_o =
- Eliom_lib.Option.map (fun p -> fst !pwd_crypt_ref p) password
- in
+ let password_o = Option.map (fun p -> fst !pwd_crypt_ref p) password in
let* userid =
Lwt.bind
[%pgsql
@@ -332,7 +330,7 @@ module User = struct
SET validity = $v WHERE activationkey = $act_key"]
in
Lwt.return
- Os_types.Action_link_key.
+ Types.Action_link_key.
{userid; email; validity; expiry; action; data; autoconnect}))
let emails_of_userid userid =
diff --git a/src/Os/email.eliom b/src/Os/email.eliom
new file mode 100644
index 000000000..fc29bf6b1
--- /dev/null
+++ b/src/Os/email.eliom
@@ -0,0 +1,103 @@
+(* Ocsigen-start
+ * http://www.ocsigen.org/ocsigen-start
+ *
+ * Copyright (C) Université Paris Diderot, CNRS, INRIA, Be Sport.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, with linking exception;
+ * either version 2.1 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *)
+
+open Lwt.Syntax
+
+let log_section = Logs.Src.create "os:email"
+let email_pattern = "^[A-Z0-9._%+-]+@[A-Z0-9.-]+[.][A-Z]+$"
+let from_addr = ref ("team DEFAULT", "noreply@DEFAULT.DEFAULT")
+let mailer = ref "sendmail"
+let set_from_addr s = from_addr := s
+let set_mailer s = mailer := s
+let get_mailer () = !mailer
+let email_pattern = email_pattern
+let email_regexp = Str.regexp_case_fold email_pattern
+let is_valid email = Str.string_match email_regexp email 0
+
+(* Pipes an RFC-2822 message to a sendmail-compatible MTA. If the
+ mailer is not on PATH, the email is logged to stderr instead so
+ the application stays usable out of the box. Applications needing
+ finer control (HTTP API, queue, etc.) can override via [set_send]. *)
+let default_send ?url ~from_addr ~to_addrs ~subject content =
+ let format_addr (name, email) =
+ if name = "" then email else Printf.sprintf "\"%s\" <%s>" name email
+ in
+ let from_header = format_addr from_addr in
+ let to_header = String.concat ", " (List.map format_addr to_addrs) in
+ let body =
+ let base = String.concat "\n" content in
+ match url with None -> base | Some u -> base ^ u
+ in
+ let message =
+ Printf.sprintf
+ ("From: %s\r\n\
+ To: %s\r\n\
+ Subject: %s\r\n\
+ MIME-Version: 1.0\r\n\
+ Content-Type: text/plain; charset=UTF-8\r\n\
+ Content-Transfer-Encoding: 8bit\r\n\
+ \r\n\
+ %s\r\n" [@ocamlformat "disable"])
+ from_header to_header subject body
+ in
+ let dump_to_stderr () =
+ Logs.warn ~src:log_section (fun fmt ->
+ fmt
+ ("mailer %S not found; dumping email to stderr so the \
+ application remains usable. Configure a sendmail-compatible \
+ MTA, or call [Os.Email.set_mailer] / [Os.Email.set_send].@\n\
+ ---8<--- begin email ---8<---@\n\
+ %s\
+ ---8<--- end email ---8<---" [@ocamlformat "disable"])
+ !mailer message)
+ in
+ Lwt.catch
+ (fun () ->
+ let cmd = "", [|!mailer; "-t"; "-i"|] in
+ Lwt_process.with_process_out cmd (fun proc ->
+ let* () = Lwt_io.write proc#stdin message in
+ let* status = proc#close in
+ match status with
+ | Unix.WEXITED 0 -> Lwt.return_unit
+ | Unix.WEXITED 127 -> dump_to_stderr (); Lwt.return_unit
+ | _ ->
+ let descr =
+ match status with
+ | Unix.WEXITED n -> Printf.sprintf "exited with code %d" n
+ | Unix.WSIGNALED s -> Printf.sprintf "killed by signal %d" s
+ | Unix.WSTOPPED s -> Printf.sprintf "stopped by signal %d" s
+ in
+ Logs.err ~src:log_section (fun fmt ->
+ fmt "%s %s for %s" !mailer descr to_header);
+ Lwt.return_unit))
+ (function
+ | Unix.Unix_error (Unix.ENOENT, _, _) ->
+ dump_to_stderr (); Lwt.return_unit
+ | exn ->
+ Logs.err ~src:log_section (fun fmt ->
+ fmt "send exception: %s" (Printexc.to_string exn));
+ Lwt.return_unit)
+
+let send_ref = ref default_send
+
+let send ?url ?(from_addr = !from_addr) ~to_addrs ~subject content =
+ !send_ref ?url ~from_addr ~to_addrs ~subject content
+
+let set_send s = send_ref := s
diff --git a/src/os_email.eliomi b/src/Os/email.eliomi
similarity index 93%
rename from src/os_email.eliomi
rename to src/Os/email.eliomi
index 2c395e302..daa1abc9a 100644
--- a/src/os_email.eliomi
+++ b/src/Os/email.eliomi
@@ -33,11 +33,6 @@ val set_mailer : string -> unit
val get_mailer : unit -> string
(** [get_mailer ()] returns the name of mailer program. *)
-exception Invalid_mailer of string
-(** Exception raised if the mailer is invalid. You can raise an exception of
- this type in email sending function if you use {!set_send}.
- *)
-
val email_pattern : string
(** The pattern used to check the validity of an e-mail address. *)
diff --git a/src/os_fcm_notif.eliom b/src/Os/fcm_notif.eliom
similarity index 100%
rename from src/os_fcm_notif.eliom
rename to src/Os/fcm_notif.eliom
diff --git a/src/os_fcm_notif.eliomi b/src/Os/fcm_notif.eliomi
similarity index 99%
rename from src/os_fcm_notif.eliomi
rename to src/Os/fcm_notif.eliomi
index 52960d0d2..3f3eb7c9a 100644
--- a/src/os_fcm_notif.eliomi
+++ b/src/Os/fcm_notif.eliomi
@@ -263,7 +263,7 @@ module Data : sig
val add_badge : int -> t -> t
(** Add a badge to the icon of the notification in the launcher. Only
available for some launcher. The integer parameter is the number of
- the badge. For iOS, use [Os_fcm_notif.Notification.Ios.add_badge].
+ the badge. For iOS, use [Fcm_notif.Notification.Ios.add_badge].
*)
module Priority : sig
diff --git a/src/os_group.ml b/src/Os/group.ml
similarity index 60%
rename from src/os_group.ml
rename to src/Os/group.ml
index b44da362a..c35d7f8e2 100644
--- a/src/os_group.ml
+++ b/src/Os/group.ml
@@ -22,81 +22,81 @@ open Lwt.Syntax
exception No_such_group
-type id = Os_types.Group.id [@@deriving json]
+type id = Types.Group.id [@@deriving json]
-type t = Os_types.Group.t = {id : id; name : string; desc : string option}
+type t = Types.Group.t = {id : id; name : string; desc : string option}
[@@deriving json]
-(** Create a group of type [Os_types.Group.t] using db information. *)
-let create_group_from_db (groupid, name, description) : Os_types.Group.t =
+(** Create a group of type [Types.Group.t] using db information. *)
+let create_group_from_db (groupid, name, description) : Types.Group.t =
{id = groupid; name; desc = description}
-let id_of_group (g : Os_types.Group.t) = g.id
-let name_of_group (g : Os_types.Group.t) = g.name
-let desc_of_group (g : Os_types.Group.t) = g.desc
+let id_of_group (g : Types.Group.t) = g.id
+let name_of_group (g : Types.Group.t) = g.name
+let desc_of_group (g : Types.Group.t) = g.desc
(* Using cache tools to prevent multiple same database queries
during the request. *)
-module MCache = Os_request_cache.Make (struct
+module MCache = Request_cache.Make (struct
type key = string
- type value = Os_types.Group.t
+ type value = Types.Group.t
let compare = compare
let get key =
Lwt.catch
(fun () ->
- let* g = Os_db.Groups.group_of_name key in
+ let* g = Db.Groups.group_of_name key in
Lwt.return (create_group_from_db g))
(function
- | Os_db.No_such_resource -> Lwt.fail No_such_group
+ | Db.No_such_resource -> Lwt.fail No_such_group
| exc -> Lwt.reraise exc)
end)
(** Helper function which creates a new group and return it as
- * a record of type [Os_types.Group.t]. *)
+ * a record of type [Types.Group.t]. *)
let create ?description name =
let group_of_name name =
- let* g = Os_db.Groups.group_of_name name in
+ let* g = Db.Groups.group_of_name name in
Lwt.return (create_group_from_db g)
in
Lwt.catch
(fun () -> group_of_name name)
(function
- | Os_db.No_such_resource ->
- let* () = Os_db.Groups.create ?description name in
+ | Db.No_such_resource ->
+ let* () = Db.Groups.create ?description name in
Lwt.catch
(fun () ->
let* g = group_of_name name in
Lwt.return g)
(function
- | Os_db.No_such_resource -> Lwt.fail No_such_group
+ | Db.No_such_resource -> Lwt.fail No_such_group
| exc -> Lwt.reraise exc)
| exc -> Lwt.reraise exc)
(* Should never happen *)
-(** Overwrite the function [group_of_name] of [Os_db.Group] and use
+(** Overwrite the function [group_of_name] of [Db.Group] and use
* the [get] function of the cache module. *)
let group_of_name = MCache.get
(* -----------------------------------------------------------------
*
* All the following functions are only helpers/wrappers around db
- * functions ones. They generally use the type [Os_types.Group.t] of the module
- * and get rid of the part of picking each field of the record [Os_types.Group.t].
+ * functions ones. They generally use the type [Types.Group.t] of the module
+ * and get rid of the part of picking each field of the record [Types.Group.t].
*
*)
-let add_user_in_group ~(group : Os_types.Group.t) =
- Os_db.Groups.add_user_in_group ~groupid:group.id
+let add_user_in_group ~(group : Types.Group.t) =
+ Db.Groups.add_user_in_group ~groupid:group.id
-let remove_user_in_group ~(group : Os_types.Group.t) =
- Os_db.Groups.remove_user_in_group ~groupid:group.id
+let remove_user_in_group ~(group : Types.Group.t) =
+ Db.Groups.remove_user_in_group ~groupid:group.id
-let in_group ?dbh ~(group : Os_types.Group.t) ~userid () =
- Os_db.Groups.in_group ?dbh ~groupid:group.id ~userid ()
+let in_group ?dbh ~(group : Types.Group.t) ~userid () =
+ Db.Groups.in_group ?dbh ~groupid:group.id ~userid ()
(** Returns all the groups of the database. *)
let all () =
- let* groups = Os_db.Groups.all () in
+ let* groups = Db.Groups.all () in
Lwt.return (List.map create_group_from_db groups)
diff --git a/src/os_group.mli b/src/Os/group.mli
similarity index 70%
rename from src/os_group.mli
rename to src/Os/group.mli
index b32c583f5..4a70984d9 100644
--- a/src/os_group.mli
+++ b/src/Os/group.mli
@@ -34,60 +34,60 @@ exception No_such_group
useful for example to allow or deny access to functions or pages.
*)
-type id = Os_types.Group.id [@@deriving json]
-(** Type alias to {!Os_types.Group.id} to allow to use [Os_group.id]. *)
+type id = Types.Group.id [@@deriving json]
+(** Type alias to {!Types.Group.id} to allow to use [Group.id]. *)
-type t = Os_types.Group.t = {id : id; name : string; desc : string option}
+type t = Types.Group.t = {id : id; name : string; desc : string option}
[@@deriving json]
-(** Type alias to {!Os_types.Group.t} to allow to use [Os_group.t]. *)
+(** Type alias to {!Types.Group.t} to allow to use [Group.t]. *)
-val id_of_group : Os_types.Group.t -> Os_types.Group.id
+val id_of_group : Types.Group.t -> Types.Group.id
(** [id_of_group group] returns the group ID. *)
-val name_of_group : Os_types.Group.t -> string
+val name_of_group : Types.Group.t -> string
(** [name_of_group group] returns the group name. *)
-val desc_of_group : Os_types.Group.t -> string option
+val desc_of_group : Types.Group.t -> string option
(** [desc_of_group group] returns the group description. *)
-val create : ?description:string -> string -> Os_types.Group.t Lwt.t
+val create : ?description:string -> string -> Types.Group.t Lwt.t
(** [create ~description name] creates a new group in the database and returns
- it as a record of type [Os_types.Group.t]. *)
+ it as a record of type [Types.Group.t]. *)
-val group_of_name : string -> Os_types.Group.t Lwt.t
-(** Overwrites the function [group_of_name] of [Os_db.Group] and use
+val group_of_name : string -> Types.Group.t Lwt.t
+(** Overwrites the function [group_of_name] of [Db.Group] and use
the [get] function of the cache module. *)
(* -----------------------------------------------------------------
All the following functions are only helpers/wrappers around db
- functions ones. They generally use the type {!Os_types.group} of the module
+ functions ones. They generally use the type {!Types.group} of the module
and get rid of the part of picking each field of the record
{!os_types.group}.
*)
val add_user_in_group :
- group:Os_types.Group.t
- -> userid:Os_types.User.id
+ group:Types.Group.t
+ -> userid:Types.User.id
-> unit Lwt.t
(** [add_user_in_group ~group ~userid] adds the user with ID [userid] to
[group]. *)
val remove_user_in_group :
- group:Os_types.Group.t
- -> userid:Os_types.User.id
+ group:Types.Group.t
+ -> userid:Types.User.id
-> unit Lwt.t
(** [remove_user_in_group ~group ~userid] removes the user with ID [userid] from
[group]. *)
val in_group :
- ?dbh:Os_db.PGOCaml.pa_pg_data Os_db.PGOCaml.t
- -> group:Os_types.Group.t
- -> userid:Os_types.User.id
+ ?dbh:Db.PGOCaml.pa_pg_data Db.PGOCaml.t
+ -> group:Types.Group.t
+ -> userid:Types.User.id
-> unit
-> bool Lwt.t
(** [in_group ~group ~userid] returns [true] if the user with ID [userid] is in
[group]. *)
-val all : unit -> Os_types.Group.t list Lwt.t
+val all : unit -> Types.Group.t list Lwt.t
(** [all ()] returns all the groups of the database. *)
diff --git a/src/os_handlers.eliom b/src/Os/handlers.eliom
similarity index 67%
rename from src/os_handlers.eliom
rename to src/Os/handlers.eliom
index cdcde01bd..3ea1ff563 100644
--- a/src/os_handlers.eliom
+++ b/src/Os/handlers.eliom
@@ -21,7 +21,7 @@
(** Registration of default services *)
open%shared Lwt.Syntax
-open%client Eliom_content.Html.F
+open%client Eliom.Content.Html.F
open%client Js_of_ocaml
let%client storage () =
@@ -39,23 +39,23 @@ let%server
=
if firstname = "" || lastname = "" || pwd <> pwd2
then (
- Eliom_reference.Volatile.set Os_msg.wrong_pdata (Some pd);
+ Eliom.Reference.Volatile.set Msg.wrong_pdata (Some pd);
Lwt.return_unit)
else
- let* user = Os_user.user_of_userid myid in
- let open Os_types.User in
+ let* user = User.user_of_userid myid in
+ let open Types.User in
let record = {user with fn = firstname; ln = lastname} in
- Os_user.update' ~password:pwd record
+ User.update' ~password:pwd record
(* Set password handler *)
let%server set_password_handler myid () (pwd, pwd2) =
if pwd <> pwd2
then (
- Os_msg.msg ~level:`Err ~onload:true "Passwords do not match";
+ Msg.msg ~level:`Err ~onload:true "Passwords do not match";
Lwt.return_unit)
else
- let* user = Os_user.user_of_userid myid in
- Os_user.update' ~password:pwd user
+ let* user = User.user_of_userid myid in
+ User.update' ~password:pwd user
(* Set password RPC *)
let%rpc set_password_rpc myid (p : string * string) : unit Lwt.t =
@@ -63,34 +63,36 @@ let%rpc set_password_rpc myid (p : string * string) : unit Lwt.t =
let%server
generate_action_link_key
- ?(act_key = Ocsigen_lib.make_cryptographic_safe_string ())
+ ?(act_key = Ocsigen_base.Lib.make_cryptographic_safe_string ())
?(send_email = true)
~service
~text
email
=
let service =
- Eliom_service.attach ~fallback:service
- ~service:Os_services.action_link_service ()
+ Eliom.Service.attach ~fallback:service ~service:Services.action_link_service
+ ()
+ in
+ let act_link =
+ Eliom.Eliom_uri.make_string_uri ~absolute:true ~service act_key
in
- let act_link = Eliom_uri.make_string_uri ~absolute:true ~service act_key in
(* For debugging we print the action link on standard output
to make possible to connect even if the mail transport is not
configured. *)
- if Ocsigen_config.get_debugmode ()
+ if Ocsigen.Config.get_debugmode ()
then print_endline ("Debug: action link created: " ^ act_link);
if send_email
then
Lwt.async (fun () ->
Lwt.catch
(fun () ->
- Os_email.send
+ Email.send
~to_addrs:["", email]
~subject:"creation" ~url:act_link [text])
(fun _ -> Lwt.return_unit));
act_key
-(** For default value of [autoconnect], cf. [Os_user.add_actionlinkkey]. *)
+(** For default value of [autoconnect], cf. [User.add_actionlinkkey]. *)
let%server
send_action_link
?autoconnect
@@ -103,9 +105,9 @@ let%server
userid
=
let act_key = generate_action_link_key ~service ~text:msg email in
- Eliom_reference.Volatile.set Os_msg.action_link_key_created true;
+ Eliom.Reference.Volatile.set Msg.action_link_key_created true;
let* () =
- Os_user.add_actionlinkkey ?autoconnect ?action ?validity ?expiry ~act_key
+ User.add_actionlinkkey ?autoconnect ?action ?validity ?expiry ~act_key
~userid ~email ()
in
Lwt.return_unit
@@ -118,29 +120,29 @@ let%server sign_up_handler () email =
in
send_action_link ~validity:1L
~expiry:CalendarLib.Calendar.(add (now ()) (Period.hour 1))
- ~autoconnect:true msg Os_services.main_service email userid
+ ~autoconnect:true msg Services.main_service email userid
in
Lwt.catch
(fun () ->
- let* user = Os_user.create ~firstname:"" ~lastname:"" ~email () in
- let userid = Os_user.userid_of_user user in
- Os_msg.msg ~onload:true ~level:`Msg ~duration:6.
+ let* user = User.create ~firstname:"" ~lastname:"" ~email () in
+ let userid = User.userid_of_user user in
+ Msg.msg ~onload:true ~level:`Msg ~duration:6.
"An e-mail was sent to this address. Click on the link it contains to activate your account.";
send_action_link email userid)
(function
- | Os_user.Already_exists userid ->
+ | User.Already_exists userid ->
let*
(* If email is not validated, the user never logged in,
I send an action link, as if it were a new user. *)
validated
=
- Os_db.User.is_email_validated userid email
+ Db.User.is_email_validated userid email
in
if not validated
then send_action_link email userid
else (
- Eliom_reference.Volatile.set Os_user.user_already_exists true;
- Os_msg.msg ~level:`Err ~onload:true "E-mail already exists";
+ Eliom.Reference.Volatile.set User.user_already_exists true;
+ Msg.msg ~level:`Err ~onload:true "E-mail already exists";
Lwt.return_unit)
| exc -> Lwt.reraise exc)
@@ -153,17 +155,17 @@ let%client sign_up_handler () v = sign_up_handler_rpc v
let%server forgot_password_handler service () email =
Lwt.catch
(fun () ->
- let* userid = Os_user.userid_of_email email in
+ let* userid = User.userid_of_email email in
let msg = "Hi,\r\nTo set a new password, please click on this link: " in
- Os_msg.msg ~level:`Msg ~onload:true
+ Msg.msg ~level:`Msg ~onload:true
"An email was sent to this address. Click on the link it contains to reset your password.";
send_action_link ~autoconnect:true ~action:`PasswordReset ~validity:1L
~expiry:CalendarLib.Calendar.(add (now ()) (Period.hour 1))
msg service email userid)
(function
- | Os_db.No_such_resource ->
- Eliom_reference.Volatile.set Os_user.user_does_not_exist true;
- Os_msg.msg ~level:`Err ~onload:true "User does not exist";
+ | Db.No_such_resource ->
+ Eliom.Reference.Volatile.set User.user_does_not_exist true;
+ Msg.msg ~level:`Err ~onload:true "User does not exist";
Lwt.return_unit
| exc -> Lwt.reraise exc)
@@ -172,7 +174,7 @@ let%client restart ?url () =
On a Web app, it is just reloading the page.
On a mobile app, we want to restart from eliom.html.
*)
- if Eliom_client.is_client_app ()
+ if Eliom.Client.is_client_app ()
then (
(match url with
| Some url ->
@@ -182,7 +184,7 @@ let%client restart ?url () =
else
match url with
| Some url ->
- (* [Eliom_client.exit_to] ends up setting [.href], so we do the
+ (* [Eliom.Client.exit_to] ends up setting [.href], so we do the
same. We do not have an "untyped" [exit_to], and
reconstructing the params from the URL only to rebuild the
URL would be crazy *)
@@ -190,7 +192,7 @@ let%client restart ?url () =
| None ->
(* By default, we restart at main page, to have the same behaviour
as in the app. *)
- Eliom_client.exit_to ~service:Os_services.main_service () ()
+ Eliom.Client.exit_to ~service:Services.main_service () ()
(* Disconnection *)
(* By default, disconnect_handler stays on the same page.
@@ -201,7 +203,7 @@ let disconnect_handler ?(main_page = false) () () =
(* SECURITY: no check here because we disconnect the session cookie owner. *)
()
=
- Os_session.disconnect ()
+ Session.disconnect ()
in
ignore
[%client
@@ -211,7 +213,7 @@ let disconnect_handler ?(main_page = false) () () =
then None
else
Some
- (make_uri ~absolute:true ~service:Eliom_service.reload_action ()))
+ (make_uri ~absolute:true ~service:Eliom.Service.reload_action ()))
()
: unit)];
Lwt.return_unit
@@ -230,22 +232,22 @@ let connect_handler () ((login, pwd), keepmeloggedin) =
(* SECURITY: no check here. *)
userid
=
- Os_user.verify_password ~email:login ~password:pwd
+ User.verify_password ~email:login ~password:pwd
in
let* () = disconnect_handler () () in
- Os_session.connect ~expire:(not keepmeloggedin) userid)
+ Session.connect ~expire:(not keepmeloggedin) userid)
(function
- | Os_db.Account_not_activated ->
- Eliom_reference.Volatile.set Os_user.account_not_activated true;
- Os_msg.msg ~level:`Err ~onload:true "Account not activated";
+ | Db.Account_not_activated ->
+ Eliom.Reference.Volatile.set User.account_not_activated true;
+ Msg.msg ~level:`Err ~onload:true "Account not activated";
Lwt.return_unit
- | Os_db.Empty_password | Os_db.Password_not_set | Os_db.Wrong_password ->
- Eliom_reference.Volatile.set Os_user.wrong_password true;
- Os_msg.msg ~level:`Err ~onload:true "Wrong password";
+ | Db.Empty_password | Db.Password_not_set | Db.Wrong_password ->
+ Eliom.Reference.Volatile.set User.wrong_password true;
+ Msg.msg ~level:`Err ~onload:true "Wrong password";
Lwt.return_unit
- | Os_db.No_such_user ->
- Eliom_reference.Volatile.set Os_user.no_such_user true;
- Os_msg.msg ~level:`Err ~onload:true "No such user";
+ | Db.No_such_user ->
+ Eliom.Reference.Volatile.set User.no_such_user true;
+ Msg.msg ~level:`Err ~onload:true "No such user";
Lwt.return_unit
| exc -> Lwt.reraise exc)
@@ -254,26 +256,26 @@ let%rpc connect_handler_rpc (v : (string * string) * bool) : unit Lwt.t =
let%client connect_handler () v = connect_handler_rpc v
-exception%shared Custom_action_link of Os_types.Action_link_key.info * bool
+exception%shared Custom_action_link of Types.Action_link_key.info * bool
(* If true, the link corresponds to a phantom user
(user who never created its account).
In that case, you probably want to display a sign-up form,
and in the other case a login form. *)
exception%shared
- Account_already_activated_unconnected of Os_types.Action_link_key.info
+ Account_already_activated_unconnected of Types.Action_link_key.info
exception%server
Account_already_activated_connected of
- Os_types.Action_link_key.info * Os_types.User.id
+ Types.Action_link_key.info * Types.User.id
-exception%shared Invalid_action_key of Os_types.Action_link_key.info
+exception%shared Invalid_action_key of Types.Action_link_key.info
exception%shared No_such_resource
let%rpc action_link_handler_common myid_o (akey : string) :
- [ `Account_already_activated_unconnected of Os_types.Action_link_key.info
- | `Custom_action_link of Os_types.Action_link_key.info * bool
- | `Invalid_action_key of Os_types.Action_link_key.info
+ [ `Account_already_activated_unconnected of Types.Action_link_key.info
+ | `Custom_action_link of Types.Action_link_key.info * bool
+ | `Invalid_action_key of Types.Action_link_key.info
| `No_such_resource
| `Reload
| `Restart_if_app ]
@@ -281,11 +283,11 @@ let%rpc action_link_handler_common myid_o (akey : string) :
=
Lwt.catch
(fun () ->
- let open Os_types.Action_link_key in
+ let open Types.Action_link_key in
let* ({userid; email; validity; expiry; action; data = _; autoconnect} as
action_link)
=
- Os_user.get_actionlinkkey_info akey
+ User.get_actionlinkkey_info akey
in
let* () =
if action = `AccountActivation && validity <= 0L
@@ -310,29 +312,29 @@ let%rpc action_link_handler_common myid_o (akey : string) :
in
let* () =
if action = `AccountActivation || action = `PasswordReset
- then Os_db.User.set_email_validated userid email
+ then Db.User.set_email_validated userid email
else Lwt.return_unit
in
if autoconnect && myid_o <> Some userid
then
- let* () = Os_session.connect userid in
+ let* () = Session.connect userid in
Lwt.return `Restart_if_app
else
match action with
| `Custom _s ->
- let* existing_user = Os_db.User.is_email_validated userid email in
+ let* existing_user = Db.User.is_email_validated userid email in
Lwt.return (`Custom_action_link (action_link, not existing_user))
| _ -> Lwt.return `Reload)
(function
- | Os_db.No_such_resource -> Lwt.return `No_such_resource
+ | Db.No_such_resource -> Lwt.return `No_such_resource
| Invalid_action_key action_link ->
- Eliom_reference.Volatile.set Os_user.action_link_key_outdated true;
+ Eliom.Reference.Volatile.set User.action_link_key_outdated true;
Lwt.return (`Invalid_action_key action_link)
| Account_already_activated_unconnected action_link ->
- Eliom_reference.Volatile.set Os_user.action_link_key_outdated true;
+ Eliom.Reference.Volatile.set User.action_link_key_outdated true;
Lwt.return (`Account_already_activated_unconnected action_link)
| Account_already_activated_connected (_action_link, _) ->
- Eliom_reference.Volatile.set Os_user.action_link_key_outdated true;
+ Eliom.Reference.Volatile.set User.action_link_key_outdated true;
(* Just reload the page without the GET parameters to get rid of the key.
If the user wasn't already logged in, let the exception pass to the
next exception handler. *)
@@ -341,7 +343,7 @@ let%rpc action_link_handler_common myid_o (akey : string) :
let%client restart_if_client_side () =
restart
- ~url:(make_uri ~absolute:true ~service:Eliom_service.reload_action ())
+ ~url:(make_uri ~absolute:true ~service:Eliom.Service.reload_action ())
()
let%server restart_if_client_side () = ()
@@ -350,14 +352,14 @@ let%shared action_link_handler _myid_o akey () =
let* a = action_link_handler_common akey in
match a with
| `Reload ->
- Eliom_registration.(
+ Eliom.Registration.(
appl_self_redirect Redirection.send
- (Redirection Eliom_service.reload_action))
+ (Redirection Eliom.Service.reload_action))
| `No_such_resource -> Lwt.fail No_such_resource
| `Invalid_action_key action_link -> Lwt.fail (Invalid_action_key action_link)
| `Restart_if_app ->
restart_if_client_side ();
- Eliom_registration.(appl_self_redirect Action.send) ()
+ Eliom.Registration.(appl_self_redirect Action.send) ()
| `Custom_action_link (action_link, phantom_user) ->
Lwt.fail (Custom_action_link (action_link, phantom_user))
| `Account_already_activated_unconnected action_link ->
@@ -365,14 +367,14 @@ let%shared action_link_handler _myid_o akey () =
(* Preregister *)
let preregister_handler () email =
- let* is_preregistered = Os_user.is_preregistered email in
- let* is_registered = Os_user.is_registered email in
+ let* is_preregistered = User.is_preregistered email in
+ let* is_registered = User.is_registered email in
Printf.printf "%b:%b%!\n" is_preregistered is_registered;
if not (is_preregistered || is_registered)
- then Os_user.add_preregister email
+ then User.add_preregister email
else (
- Eliom_reference.Volatile.set Os_user.user_already_preregistered true;
- Os_msg.msg ~level:`Err ~onload:true "E-mail already preregistered";
+ Eliom.Reference.Volatile.set User.user_already_preregistered true;
+ Msg.msg ~level:`Err ~onload:true "E-mail already preregistered";
Lwt.return_unit)
(* Add email *)
@@ -382,41 +384,41 @@ let add_email_handler =
in
let send_act () =
send_action_link ~autoconnect:true msg
- (match Os_services.settings_service () with
+ (match Services.settings_service () with
| Some service -> service
- | None -> Os_services.main_service)
+ | None -> Services.main_service)
in
let add_email myid () email =
- let* available = Os_db.Email.available email in
+ let* available = Db.Email.available email in
if available
then
- let* () = Os_db.User.add_email_to_user ~userid:myid ~email in
+ let* () = Db.User.add_email_to_user ~userid:myid ~email in
send_act () email myid
else (
- Eliom_reference.Volatile.set Os_user.user_already_exists true;
+ Eliom.Reference.Volatile.set User.user_already_exists true;
Lwt.return_unit)
in
- Os_session.connected_fun add_email
+ Session.connected_fun add_email
let%rpc add_email_rpc (email : string) : unit Lwt.t = add_email_handler () email
let%client add_email_handler () = add_email_rpc
-let%shared _ = Os_comet.__link (* to make sure os_comet is linked *)
+let%shared _ = Comet.__link (* to make sure os_comet is linked *)
let%client input_popup ?(button_label = "OK") f =
let w, u = Lwt.wait () in
let content close =
- let open Eliom_content.Html in
+ let open Eliom.Content.Html in
let button = D.button ~a:[D.a_class ["button"]] [D.txt button_label] in
let inp =
let f code =
let* () = close () in
Lwt.wakeup u (); f code
in
- Os_lib.lwt_bound_input_enter ~button f
+ Lib.lwt_bound_input_enter ~button f
in
Lwt.return (D.div [button; inp])
in
- let* _ = Ot_popup.popup ~close_button:[Os_icons.F.close ()] content in
+ let* _ = Ot.Popup.popup ~close_button:[Icons.F.close ()] content in
w
let%client confirm_code_popup ~dest f =
@@ -426,38 +428,37 @@ let%client confirm_code_popup ~dest f =
then
let service =
match dest with
- | `Settings -> Os_services.settings_service ()
- | `Main -> Some Os_services.main_service
+ | `Settings -> Services.settings_service ()
+ | `Main -> Some Services.main_service
in
match service with
- | Some service -> Eliom_client.change_page ~service () ()
+ | Some service -> Eliom.Client.change_page ~service () ()
| None -> Lwt.fail_with "confirm_popup: settings service unknown"
else (
- Os_msg.msg ~level:`Err ~duration:2. "Wrong SMS activation code";
+ Msg.msg ~level:`Err ~duration:2. "Wrong SMS activation code";
Lwt.return_unit)
(* We only need confirm_code_*_service to implement the activation
UI. Assuming normal user behavior, we will only ever call them via
- a client-side Eliom_client.change_page, so no server implementation
+ a client-side Eliom.Client.change_page, so no server implementation
is needed. Currently we can't register a service only on the
client. Until we fix Eliom, we define dummy server-side
handlers. *)
let%server confirm_code_handler _ _ =
- Lwt.fail_with
- "Os_handlers.confirm_code_*_handler not implemented on the server"
+ Lwt.fail_with "Handlers.confirm_code_*_handler not implemented on the server"
let%server confirm_code_signup_handler = confirm_code_handler
let%server confirm_code_extra_handler = confirm_code_handler
let%server confirm_code_recovery_handler = confirm_code_handler
let%client request_activation_code_wrapper number f =
- Lwt.bind (Os_connect_phone.request_code number) (function
+ Lwt.bind (Connect_phone.request_code number) (function
| Ok () -> f ()
| Error `Ownership ->
- Os_msg.msg ~level:`Err ~duration:2. "Phone taken";
+ Msg.msg ~level:`Err ~duration:2. "Phone taken";
Lwt.return_unit
| Error (`Unknown | `Send | `Limit | `Invalid_number) ->
- Os_msg.msg ~level:`Err ~duration:2. "SMS error";
+ Msg.msg ~level:`Err ~duration:2. "SMS error";
Lwt.return_unit)
let%client
@@ -465,17 +466,16 @@ let%client
=
request_activation_code_wrapper number @@ fun () ->
confirm_code_popup ~dest:`Main @@ fun code ->
- Os_connect_phone.confirm_code_signup ~first_name ~last_name ~code ~password ()
+ Connect_phone.confirm_code_signup ~first_name ~last_name ~code ~password ()
let%client confirm_code_extra_handler () number =
request_activation_code_wrapper number @@ fun () ->
- confirm_code_popup ~dest:`Settings Os_connect_phone.confirm_code_extra
+ confirm_code_popup ~dest:`Settings Connect_phone.confirm_code_extra
let%client confirm_code_recovery_handler () number =
- Lwt.bind (Os_connect_phone.request_recovery_code number) (function
+ Lwt.bind (Connect_phone.request_recovery_code number) (function
| Ok () ->
- confirm_code_popup ~dest:`Settings
- Os_connect_phone.confirm_code_recovery
+ confirm_code_popup ~dest:`Settings Connect_phone.confirm_code_recovery
| Error (`Unknown | `Send | `Limit | _) ->
- Os_msg.msg ~level:`Err ~duration:2. "SMS error";
+ Msg.msg ~level:`Err ~duration:2. "SMS error";
Lwt.return ())
diff --git a/src/os_handlers.eliomi b/src/Os/handlers.eliomi
similarity index 86%
rename from src/os_handlers.eliomi
rename to src/Os/handlers.eliomi
index e73bf7aec..b09c5d173 100644
--- a/src/os_handlers.eliomi
+++ b/src/Os/handlers.eliomi
@@ -22,7 +22,7 @@
(** This module contains pre-defined handlers for connect, disconnect, sign up,
add a new email, etc. Each handler has a corresponding service in
- {!Os_services}.
+ {!Services}.
*)
val connect_handler : unit -> (string * string) * bool -> unit Lwt.t
@@ -39,14 +39,14 @@ val sign_up_handler : unit -> string -> unit Lwt.t
val add_email_handler : unit -> string -> unit Lwt.t
(** [add_email_handler () email] adds a new e-mail address
for the current user and sends an activation link.
- Eliom reference [Os_user.user_already_exists] is set
+ Eliom reference [User.user_already_exists] is set
to [true] if the e-mail address already exists in database.
*)
-exception Custom_action_link of Os_types.Action_link_key.info * bool
+exception Custom_action_link of Types.Action_link_key.info * bool
(** Exception raised when something went wrong with an action link key. The
action link key is given as parameter as a type
- {!Os_types.actionlinkkey_info}.
+ {!Types.actionlinkkey_info}.
*)
(* If true, the link corresponds to a phantom user
@@ -54,12 +54,12 @@ exception Custom_action_link of Os_types.Action_link_key.info * bool
In that case, you probably want to display a sign-up form,
and in the other case a login form. *)
-exception Account_already_activated_unconnected of Os_types.Action_link_key.info
+exception Account_already_activated_unconnected of Types.Action_link_key.info
(** Exception raised when an account has been already activated and no user is
connected.
*)
-exception Invalid_action_key of Os_types.Action_link_key.info
+exception Invalid_action_key of Types.Action_link_key.info
(** Exception raised when the key is oudated. *)
exception No_such_resource
@@ -71,7 +71,7 @@ val action_link_handler :
int64 option
-> string
-> unit
- -> 'a Eliom_registration.application_content Eliom_registration.kind Lwt.t
+ -> 'a Eliom.Registration.application_content Eliom.Registration.kind Lwt.t
(** [action_link_handler userid_o activation_key ()] is the handler for
activation keys.
@@ -105,41 +105,41 @@ val confirm_code_recovery_handler : unit -> string -> unit Lwt.t
val forgot_password_handler :
( unit
, unit
- , Eliom_service.get
- , Eliom_service.att
+ , Eliom.Service.get
+ , Eliom.Service.att
, _
- , Eliom_service.non_ext
+ , Eliom.Service.non_ext
, _
, _
, unit
, unit
, 'c )
- Eliom_service.t
+ Eliom.Service.t
-> unit
-> string
-> unit Lwt.t
(** [forgot_password_handler service () email] creates and sends an action link
to [email] if the user forgot his password and redirects to [service].
- If [email] doesn't correspond to any user, {!Os_user.user_does_not_exist}
- is set to [true] and {!Os_msg.msg} is called with the level [`Err].
+ If [email] doesn't correspond to any user, {!User.user_does_not_exist}
+ is set to [true] and {!Msg.msg} is called with the level [`Err].
*)
val preregister_handler : unit -> string -> unit Lwt.t
(** [preregister_handler () email] preregisters the email [email]. *)
val set_password_handler :
- Os_types.User.id
+ Types.User.id
-> unit
-> string * string
-> unit Lwt.t
(** [set_password_handler userid () (password, confirmation_password)] updates
the password of the user with ID [userid] with the hashed value of
[password] if [confirmation_password] corresponds to [password]. If they
- don't correspond, {!Os_msg.msg} is called with the level [`Err].
+ don't correspond, {!Msg.msg} is called with the level [`Err].
*)
val set_personal_data_handler :
- Os_types.User.id
+ Types.User.id
-> unit
-> (string * string) * (string * string)
-> unit Lwt.t
diff --git a/src/os_icons.eliom b/src/Os/icons.eliom
similarity index 57%
rename from src/os_icons.eliom
rename to src/Os/icons.eliom
index 157d7dc1a..96c645fb4 100644
--- a/src/os_icons.eliom
+++ b/src/Os/icons.eliom
@@ -21,61 +21,61 @@
[%%shared
module type ICSIG = sig
val user :
- ?a:Html_types.i_attrib Eliom_content.Html.D.attrib list
+ ?a:Html_types.i_attrib Eliom.Content.Html.D.attrib list
-> unit
- -> [> Html_types.i] Eliom_content.Html.D.elt
+ -> [> Html_types.i] Eliom.Content.Html.D.elt
val signout :
- ?a:Html_types.i_attrib Eliom_content.Html.D.attrib list
+ ?a:Html_types.i_attrib Eliom.Content.Html.D.attrib list
-> unit
- -> [> Html_types.i] Eliom_content.Html.D.elt
+ -> [> Html_types.i] Eliom.Content.Html.D.elt
val close :
- ?a:Html_types.i_attrib Eliom_content.Html.D.attrib list
+ ?a:Html_types.i_attrib Eliom.Content.Html.D.attrib list
-> unit
- -> [> Html_types.i] Eliom_content.Html.D.elt
+ -> [> Html_types.i] Eliom.Content.Html.D.elt
end
module D = struct
- let user_r = ref Ot_icons.D.user
- let signout_r = ref Ot_icons.D.signout
- let close_r = ref Ot_icons.D.close
+ let user_r = ref Ot.Icons.D.user
+ let signout_r = ref Ot.Icons.D.signout
+ let close_r = ref Ot.Icons.D.close
let user ?a () =
(!user_r ?a ()
- : Html_types.i Eliom_content.Html.D.elt
- :> [> Html_types.i] Eliom_content.Html.D.elt)
+ : Html_types.i Eliom.Content.Html.D.elt
+ :> [> Html_types.i] Eliom.Content.Html.D.elt)
let signout ?a () =
(!signout_r ?a ()
- : Html_types.i Eliom_content.Html.D.elt
- :> [> Html_types.i] Eliom_content.Html.D.elt)
+ : Html_types.i Eliom.Content.Html.D.elt
+ :> [> Html_types.i] Eliom.Content.Html.D.elt)
let close ?a () =
(!close_r ?a ()
- : Html_types.i Eliom_content.Html.D.elt
- :> [> Html_types.i] Eliom_content.Html.D.elt)
+ : Html_types.i Eliom.Content.Html.D.elt
+ :> [> Html_types.i] Eliom.Content.Html.D.elt)
end
module F = struct
- let user_r = ref Ot_icons.F.user
- let signout_r = ref Ot_icons.F.signout
- let close_r = ref Ot_icons.F.close
+ let user_r = ref Ot.Icons.F.user
+ let signout_r = ref Ot.Icons.F.signout
+ let close_r = ref Ot.Icons.F.close
let user ?a () =
(!user_r ?a ()
- : Html_types.i Eliom_content.Html.D.elt
- :> [> Html_types.i] Eliom_content.Html.D.elt)
+ : Html_types.i Eliom.Content.Html.D.elt
+ :> [> Html_types.i] Eliom.Content.Html.D.elt)
let signout ?a () =
(!signout_r ?a ()
- : Html_types.i Eliom_content.Html.D.elt
- :> [> Html_types.i] Eliom_content.Html.D.elt)
+ : Html_types.i Eliom.Content.Html.D.elt
+ :> [> Html_types.i] Eliom.Content.Html.D.elt)
let close ?a () =
(!close_r ?a ()
- : Html_types.i Eliom_content.Html.D.elt
- :> [> Html_types.i] Eliom_content.Html.D.elt)
+ : Html_types.i Eliom.Content.Html.D.elt
+ :> [> Html_types.i] Eliom.Content.Html.D.elt)
end
module Register (FF : ICSIG) (DD : ICSIG) = struct
diff --git a/src/os_icons.eliomi b/src/Os/icons.eliomi
similarity index 78%
rename from src/os_icons.eliomi
rename to src/Os/icons.eliomi
index 53a50a632..f3696c557 100644
--- a/src/os_icons.eliomi
+++ b/src/Os/icons.eliomi
@@ -25,19 +25,19 @@
module type ICSIG = sig
val user :
- ?a:Html_types.i_attrib Eliom_content.Html.D.attrib list
+ ?a:Html_types.i_attrib Eliom.Content.Html.D.attrib list
-> unit
- -> [> Html_types.i] Eliom_content.Html.D.elt
+ -> [> Html_types.i] Eliom.Content.Html.D.elt
val signout :
- ?a:Html_types.i_attrib Eliom_content.Html.D.attrib list
+ ?a:Html_types.i_attrib Eliom.Content.Html.D.attrib list
-> unit
- -> [> Html_types.i] Eliom_content.Html.D.elt
+ -> [> Html_types.i] Eliom.Content.Html.D.elt
val close :
- ?a:Html_types.i_attrib Eliom_content.Html.D.attrib list
+ ?a:Html_types.i_attrib Eliom.Content.Html.D.attrib list
-> unit
- -> [> Html_types.i] Eliom_content.Html.D.elt
+ -> [> Html_types.i] Eliom.Content.Html.D.elt
end
module D : ICSIG
diff --git a/src/os_lib.eliom b/src/Os/lib.eliom
similarity index 83%
rename from src/os_lib.eliom
rename to src/Os/lib.eliom
index e92d4a8f1..07c0d7a0c 100644
--- a/src/os_lib.eliom
+++ b/src/Os/lib.eliom
@@ -23,8 +23,8 @@ open%client Js_of_ocaml
open%client Js_of_ocaml_lwt
let%client reload () =
- Eliom_client.change_page ~replace:true
- ~service:Eliom_service.reload_action_hidden () ()
+ Eliom.Client.change_page ~replace:true
+ ~service:Eliom.Service.reload_action_hidden () ()
let%shared memoizator f =
let value_ref = ref None in
@@ -136,19 +136,19 @@ let%client on_enter ~f inp =
Lwt_js_events.keydowns inp @@ fun ev _ ->
if ev##.keyCode = 13 then f (Js.to_string inp##.value) else Lwt.return_unit
-(* TODO: Build a nice Ot_form module with such functions *)
+(* TODO: Build a nice Ot.Form module with such functions *)
let%shared
lwt_bind_input_enter
- ?(validate : (string -> bool) Eliom_client_value.t option)
- ?(button : [< `Button | `Input] Eliom_content.Html.elt option)
- (e : [`Input] Eliom_content.Html.elt)
- (f : (string -> unit Lwt.t) Eliom_client_value.t)
+ ?(validate : (string -> bool) Eliom.Client_value.t option)
+ ?(button : [< `Button | `Input] Eliom.Content.Html.elt option)
+ (e : [`Input] Eliom.Content.Html.elt)
+ (f : (string -> unit Lwt.t) Eliom.Client_value.t)
=
ignore
[%client
- (let e = Eliom_content.Html.To_dom.of_input ~%e in
+ (let e = Eliom.Content.Html.To_dom.of_input ~%e in
let f =
- let f = ~%(f : (string -> unit Lwt.t) Eliom_client_value.t) in
+ let f = ~%(f : (string -> unit Lwt.t) Eliom.Client_value.t) in
match ~%validate with
| Some validate ->
fun v ->
@@ -159,16 +159,16 @@ let%shared
| None -> f
in
on_enter ~f e;
- match ~%(button :> [`Button | `Input] Eliom_content.Html.elt option) with
+ match ~%(button :> [`Button | `Input] Eliom.Content.Html.elt option) with
| Some button ->
Lwt.async @@ fun () ->
- Lwt_js_events.clicks (Eliom_content.Html.To_dom.of_element button)
+ Lwt_js_events.clicks (Eliom.Content.Html.To_dom.of_element button)
@@ fun _ _ -> f (Js.to_string e##.value)
| None -> ()
: unit)]
let%shared lwt_bound_input_enter ?(a = []) ?button ?validate f =
- let e = Eliom_content.Html.D.Raw.input ~a () in
+ let e = Eliom.Content.Html.D.Raw.input ~a () in
lwt_bind_input_enter ?button ?validate e f;
e
@@ -178,11 +178,12 @@ module Http = struct
let string_of_stream ?(len = 16384) contents =
Lwt.try_bind
(fun () ->
- Ocsigen_stream.string_of_stream len (Ocsigen_stream.get contents))
+ Ocsigen_base.Ocsigen_stream.string_of_stream len
+ (Ocsigen_base.Ocsigen_stream.get contents))
(fun r ->
- let* () = Ocsigen_stream.finalize contents `Success in
+ let* () = Ocsigen_base.Ocsigen_stream.finalize contents `Success in
Lwt.return r)
(fun e ->
- let* () = Ocsigen_stream.finalize contents `Failure in
+ let* () = Ocsigen_base.Ocsigen_stream.finalize contents `Failure in
Lwt.fail e)
end
diff --git a/src/os_lib.eliomi b/src/Os/lib.eliomi
similarity index 81%
rename from src/os_lib.eliomi
rename to src/Os/lib.eliomi
index 57ff0c809..26c3b8d03 100644
--- a/src/os_lib.eliomi
+++ b/src/Os/lib.eliomi
@@ -61,19 +61,19 @@ val string_repeat : string -> int -> string
val string_filter : (char -> bool) -> string -> string
val lwt_bound_input_enter :
- ?a:[< Html_types.input_attrib] Eliom_content.Html.attrib list
- -> ?button:[< `Button | `Input] Eliom_content.Html.elt
- -> ?validate:(string -> bool) Eliom_client_value.t
- -> (string -> unit Lwt.t) Eliom_client_value.t
- -> [> `Input] Eliom_content.Html.elt
+ ?a:[< Html_types.input_attrib] Eliom.Content.Html.attrib list
+ -> ?button:[< `Button | `Input] Eliom.Content.Html.elt
+ -> ?validate:(string -> bool) Eliom.Client_value.t
+ -> (string -> unit Lwt.t) Eliom.Client_value.t
+ -> [> `Input] Eliom.Content.Html.elt
(** [lwt_bound_input_enter f] produces an input element bound to [f],
i.e., when the user submits the input, we call [f]. *)
val lwt_bind_input_enter :
- ?validate:(string -> bool) Eliom_client_value.t
- -> ?button:[< `Button | `Input] Eliom_content.Html.elt
- -> [`Input] Eliom_content.Html.elt
- -> (string -> unit Lwt.t) Eliom_client_value.t
+ ?validate:(string -> bool) Eliom.Client_value.t
+ -> ?button:[< `Button | `Input] Eliom.Content.Html.elt
+ -> [`Input] Eliom.Content.Html.elt
+ -> (string -> unit Lwt.t) Eliom.Client_value.t
-> unit
(** [lwt_bound_input_enter inp f] calls f whenever the user submits
the contents of [inp]. *)
@@ -82,7 +82,10 @@ val lwt_bind_input_enter :
(** This module contains functions about HTTP request. *)
module Http : sig
- val string_of_stream : ?len:int -> string Ocsigen_stream.t -> string Lwt.t
+ val string_of_stream :
+ ?len:int
+ -> string Ocsigen_base.Ocsigen_stream.t
+ -> string Lwt.t
(** [string_of_stream ?len stream] creates a string of maximum length [len]
(default is [16384]) from the stream [stream].
*)
diff --git a/src/os_msg.eliom b/src/Os/msg.eliom
similarity index 88%
rename from src/os_msg.eliom
rename to src/Os/msg.eliom
index 3524fab07..174c6fb66 100644
--- a/src/os_msg.eliom
+++ b/src/Os/msg.eliom
@@ -19,8 +19,8 @@
*)
open%client Lwt.Syntax
-open%client Eliom_content.Html
-open%client Eliom_content.Html.F
+open%client Eliom.Content.Html
+open%client Eliom.Content.Html.F
open%client Js_of_ocaml
let%client msgbox () =
@@ -47,7 +47,7 @@ let%shared
let message_dom = To_dom.of_p (D.p ~a:[a_class c] [txt ~%message]) in
Lwt.async (fun () ->
let* () =
- if ~%onload then Eliom_client.lwt_onload () else Lwt.return_unit
+ if ~%onload then Eliom.Client.lwt_onload () else Lwt.return_unit
in
let msgbox = msgbox () in
Logs.info (fun fmt -> fmt "%s" ~%message);
@@ -58,8 +58,8 @@ let%shared
: unit)]
let action_link_key_created =
- Eliom_reference.Volatile.eref ~scope:Eliom_common.request_scope false
+ Eliom.Reference.Volatile.eref ~scope:Eliom.Common.request_scope false
let wrong_pdata =
- Eliom_reference.Volatile.eref ~scope:Eliom_common.request_scope
+ Eliom.Reference.Volatile.eref ~scope:Eliom.Common.request_scope
(None : ((string * string) * (string * string)) option)
diff --git a/src/os_msg.eliomi b/src/Os/msg.eliomi
similarity index 92%
rename from src/os_msg.eliomi
rename to src/Os/msg.eliomi
index 7d0a0e97e..34fa5ed96 100644
--- a/src/os_msg.eliomi
+++ b/src/Os/msg.eliomi
@@ -37,7 +37,7 @@ val msg :
It is displayed during a short amount of time then disappears. You may
change the duration in seconds with the parameter [duration] (default can
- be set using function {!Os_msg.set_default_duration}).
+ be set using function {!Msg.set_default_duration}).
The two levels correspond to different classes that you can
personalize by modifying the CSS class ["os_err"] (added for error messages
@@ -53,12 +53,12 @@ val msg :
val set_default_duration : float -> unit
(** Set default message duration (default 4s) *)
-val action_link_key_created : bool Eliom_reference.Volatile.eref
+val action_link_key_created : bool Eliom.Reference.Volatile.eref
(** Set to [true] if an action link key has been already created and sent to the
user email, else [false]. Default is [false]. *)
val wrong_pdata :
- ((string * string) * (string * string)) option Eliom_reference.Volatile.eref
+ ((string * string) * (string * string)) option Eliom.Reference.Volatile.eref
(** [((firstname, lastname), (password, password_confirmation)) option]
is a reference used to remember information about the user during a
request when something went wrong (for example in a form when the password
diff --git a/src/os_notif.eliom b/src/Os/notif.eliom
similarity index 82%
rename from src/os_notif.eliom
rename to src/Os/notif.eliom
index ab7d26b25..13a299f60 100644
--- a/src/os_notif.eliom
+++ b/src/Os/notif.eliom
@@ -18,13 +18,13 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*)
-open Os_types
+open Types
module type S = sig
- include Eliom_notif.S with type identity = User.id option
+ include Eliom.Notif.S with type identity = User.id option
val unlisten_user :
- ?sitedata:Eliom_common.sitedata
+ ?sitedata:Eliom.Common.sitedata
-> userid:User.id
-> key
-> unit
@@ -48,7 +48,7 @@ module Make (A : ARG) :
with type key = A.key
and type server_notif = A.server_notif
and type client_notif = A.client_notif = struct
- include Eliom_notif.Make (struct
+ include Eliom.Notif.Make (struct
type identity = User.id option
type key = A.key
type server_notif = A.server_notif
@@ -57,24 +57,21 @@ module Make (A : ARG) :
let prepare = A.prepare
let equal_key = A.equal_key
let equal_identity = ( = )
-
- let get_identity () =
- Lwt.return @@ Os_current_user.Opt.get_current_userid ()
-
+ let get_identity () = Lwt.return @@ Current_user.Opt.get_current_userid ()
let max_resource = A.max_resource
let max_identity_per_resource = A.max_identity_per_resource
end)
let unlisten_user ?sitedata ~userid (id : A.key) =
let state =
- Eliom_state.Ext.volatile_data_group_state
- ~scope:Eliom_common.default_group_scope (Int64.to_string userid)
+ Eliom.State.Ext.volatile_data_group_state
+ ~scope:Eliom.Common.default_group_scope (Int64.to_string userid)
in
Lwt.async @@ fun () ->
(* Iterating on all sessions in group: *)
- Eliom_state.Ext.iter_sub_states ?sitedata ~state @@ fun state ->
+ Eliom.State.Ext.iter_sub_states ?sitedata ~state @@ fun state ->
(* Iterating on all client processes in session: *)
- Eliom_state.Ext.iter_sub_states ?sitedata ~state (fun state ->
+ Eliom.State.Ext.iter_sub_states ?sitedata ~state (fun state ->
Ext.unlisten state id; Lwt.return_unit)
let notify ?notfor key notif =
@@ -87,8 +84,8 @@ module Make (A : ARG) :
notify ?notfor key notif
let _ =
- Os_session.on_start_process (fun _ -> init ());
- Os_session.on_post_close_session (fun () -> deinit (); Lwt.return_unit)
+ Session.on_start_process (fun _ -> init ());
+ Session.on_post_close_session (fun () -> deinit (); Lwt.return_unit)
end
module type ARG_SIMPLE = sig
diff --git a/src/os_notif.eliomi b/src/Os/notif.eliomi
similarity index 85%
rename from src/os_notif.eliomi
rename to src/Os/notif.eliomi
index bbd531b3a..5baaeea9f 100644
--- a/src/os_notif.eliomi
+++ b/src/Os/notif.eliomi
@@ -20,20 +20,20 @@
(** Server to client notifications.
- This module is a version of [Eliom_notif] that fixes the types [identity] of
- [Eliom_notif.S] to [Os_types.User.id option] ([option] so that users can be
+ This module is a version of [Eliom.Notif] that fixes the types [identity] of
+ [Eliom.Notif.S] to [Types.User.id option] ([option] so that users can be
notified that are not logged in). It takes care of (de)initialisation so
[init] and [deinit] need not be called anymore. Also it adds a specialised
version of [unlisten_user].
*)
-open Os_types
+open Types
module type S = sig
- include Eliom_notif.S with type identity = User.id option
+ include Eliom.Notif.S with type identity = User.id option
val unlisten_user :
- ?sitedata:Eliom_common.sitedata
+ ?sitedata:Eliom.Common.sitedata
-> userid:User.id
-> key
-> unit
@@ -45,7 +45,7 @@ module type S = sig
end
(** [ARG] is for making [Make].
- It is a simplified version of [Eliom_notif.ARG]. *)
+ It is a simplified version of [Eliom.Notif.ARG]. *)
module type ARG = sig
type key
type server_notif
@@ -57,7 +57,7 @@ module type ARG = sig
val max_identity_per_resource : int
end
-(** see [Eliom_notif.Make] *)
+(** see [Eliom.Notif.Make] *)
module Make (A : ARG) :
S
with type key = A.key
@@ -65,7 +65,7 @@ module Make (A : ARG) :
and type client_notif = A.client_notif
(** [ARG_SIMPLE] is for making [Make_Simple].
- It is a simplified version of [Eliom_notif.ARG_SIMPLE] *)
+ It is a simplified version of [Eliom.Notif.ARG_SIMPLE] *)
module type ARG_SIMPLE = sig
type key
type notification
diff --git a/src/os_page.eliom b/src/Os/page.eliom
similarity index 82%
rename from src/os_page.eliom
rename to src/Os/page.eliom
index 67eddbbc5..ed91be439 100644
--- a/src/os_page.eliom
+++ b/src/Os/page.eliom
@@ -19,22 +19,22 @@
*)
open%shared Lwt.Syntax
-open%shared Eliom_content.Html.F
+open%shared Eliom.Content.Html.F
open%client Js_of_ocaml
[%%shared
exception Predicate_failed of exn option
type content =
- { html_attrs : Html_types.html_attrib Eliom_content.Html.attrib list
+ { html_attrs : Html_types.html_attrib Eliom.Content.Html.attrib list
; title : string option
; head : Html_types.head_content_fun elt list
- ; body_attrs : Html_types.body_attrib Eliom_content.Html.attrib list
+ ; body_attrs : Html_types.body_attrib Eliom.Content.Html.attrib list
; body : Html_types.body_content elt list }]
let%shared content ?(html_a = []) ?(a = []) ?title ?(head = []) body =
let html_attrs =
- if Eliom_client.is_client_app ()
+ if Eliom.Client.is_client_app ()
then a_class ["os-client-app"] :: html_a
else html_a
in
@@ -51,11 +51,15 @@ module type PAGE = sig
val local_js : string list list
val css : string list list
val local_css : string list list
- val other_head : unit -> Html_types.head_content_fun Eliom_content.Html.elt list
+
+ val other_head :
+ unit
+ -> Html_types.head_content_fun Eliom.Content.Html.elt list
+
val default_error_page : 'a -> 'b -> exn -> content Lwt.t
val default_connected_error_page :
- Os_types.User.id option
+ Types.User.id option
-> 'a
-> 'b
-> exn
@@ -64,7 +68,7 @@ module type PAGE = sig
val default_predicate : 'a -> 'b -> bool Lwt.t
val default_connected_predicate :
- Os_types.User.id option
+ Types.User.id option
-> 'a
-> 'b
-> bool Lwt.t
@@ -76,17 +80,19 @@ module Default_config = struct
let css : string list list = []
let local_js : string list list = []
let local_css : string list list = []
- let other_head () : Html_types.head_content_fun Eliom_content.Html.elt list = []
+
+ let other_head () : Html_types.head_content_fun Eliom.Content.Html.elt list =
+ []
let err_page exn =
let de =
- if ~%(Ocsigen_config.get_debugmode ())
+ if ~%(Ocsigen.Config.get_debugmode ())
then [p [txt "Debug info: "; em [txt (Printexc.to_string exn)]]]
else []
in
let l =
match exn with
- | Os_session.Not_connected ->
+ | Session.Not_connected ->
p [txt "You must be connected to see this page."] :: de
| _ -> de
in
@@ -106,10 +112,10 @@ module Make (C : PAGE) = struct
let local_css =
List.map
(fun cssname ->
- Eliom_content.Html.F.css_link
+ Eliom.Content.Html.F.css_link
~uri:
(make_uri ~absolute:false
- ~service:(Eliom_service.static_dir ())
+ ~service:(Eliom.Service.static_dir ())
("css" :: cssname))
())
C.local_css
@@ -117,11 +123,11 @@ module Make (C : PAGE) = struct
let local_js =
List.map
(fun cssname ->
- Eliom_content.Html.F.js_script
+ Eliom.Content.Html.F.js_script
~a:[a_defer ()]
~uri:
(make_uri ~absolute:false
- ~service:(Eliom_service.static_dir ())
+ ~service:(Eliom.Service.static_dir ())
("js" :: cssname))
())
C.local_js
@@ -129,7 +135,7 @@ module Make (C : PAGE) = struct
let make_page content =
let title = match content.title with Some t -> t | None -> C.title in
let connected_attr =
- if Os_current_user.Opt.get_current_userid () <> None
+ if Current_user.Opt.get_current_userid () <> None
then a_class ["os-connected"]
else a_class ["os-not-connected"]
in
@@ -137,13 +143,11 @@ module Make (C : PAGE) = struct
a_onload
[%client
fun _ : unit ->
- let platform =
- Js.string (Os_platform.css_class (Os_platform.get ()))
- in
+ let platform = Js.string (Platform.css_class (Platform.get ())) in
Dom_html.document##.documentElement##.classList##add platform]
in
html ~a:content.html_attrs
- (Eliom_tools.F.head ~title ~css ~js
+ (Eliom.Tools.F.head ~title ~css ~js
~other:(local_css @ local_js @ content.head @ C.other_head ())
())
(body
@@ -194,12 +198,12 @@ module Make (C : PAGE) = struct
let* content =
Lwt.catch
(fun () ->
- Os_session.connected_fun ?allow ?deny
+ Session.connected_fun ?allow ?deny
~deny_fun:(fun myid_o ->
- fallback myid_o gp pp Os_session.Permission_denied)
+ fallback myid_o gp pp Session.Permission_denied)
f_wrapped gp pp)
(function
- | Os_session.Not_connected as exc -> fallback None gp pp exc
+ | Session.Not_connected as exc -> fallback None gp pp exc
| exc -> Lwt.reraise exc)
in
Lwt.return (make_page content)
@@ -214,7 +218,7 @@ module Make (C : PAGE) = struct
gp
pp
=
- let f_wrapped (myid_o : Os_types.User.id option) gp pp =
+ let f_wrapped (myid_o : Types.User.id option) gp pp =
Lwt.catch
(fun () ->
let* b = predicate myid_o gp pp in
@@ -229,9 +233,9 @@ module Make (C : PAGE) = struct
| exc -> fallback myid_o gp pp (Predicate_failed (Some exc)))
in
let* content =
- Os_session.Opt.connected_fun ?allow ?deny
+ Session.Opt.connected_fun ?allow ?deny
~deny_fun:(fun myid_o ->
- fallback myid_o gp pp Os_session.Permission_denied)
+ fallback myid_o gp pp Session.Permission_denied)
f_wrapped gp pp
in
Lwt.return (make_page content)
diff --git a/src/os_page.eliomi b/src/Os/page.eliomi
similarity index 79%
rename from src/os_page.eliomi
rename to src/Os/page.eliomi
index fb2d52aed..d3cb7cecb 100644
--- a/src/os_page.eliomi
+++ b/src/Os/page.eliomi
@@ -27,11 +27,11 @@ type content
(** An abstract type describing the content of a page *)
val content :
- ?html_a:Html_types.html_attrib Eliom_content.Html.attrib list
- -> ?a:Html_types.body_attrib Eliom_content.Html.attrib list
+ ?html_a:Html_types.html_attrib Eliom.Content.Html.attrib list
+ -> ?a:Html_types.body_attrib Eliom.Content.Html.attrib list
-> ?title:string
- -> ?head:[< Html_types.head_content_fun] Eliom_content.Html.elt list
- -> [< Html_types.body_content] Eliom_content.Html.elt list
+ -> ?head:[< Html_types.head_content_fun] Eliom.Content.Html.elt list
+ -> [< Html_types.body_content] Eliom.Content.Html.elt list
-> content
(** Specifies a page with an optional title (with the argument [?title]), some
optional extra metadata (with the argument [?head]) and a given body.
@@ -66,7 +66,9 @@ module type PAGE = sig
a mobile application.
Os will automatically prepend the suffix ["css/"] as directory. *)
- val other_head : unit -> Html_types.head_content_fun Eliom_content.Html.elt list
+ val other_head :
+ unit
+ -> Html_types.head_content_fun Eliom.Content.Html.elt list
(** [other_head] is a list of custom elements to add in the head section.
It can be used to add elements, for example. *)
@@ -79,7 +81,7 @@ module type PAGE = sig
*)
val default_connected_error_page :
- Os_types.User.id option
+ Types.User.id option
-> 'a
-> 'b
-> exn
@@ -92,7 +94,7 @@ module type PAGE = sig
(** [default_predicate get_param post_param] is the default predicate. *)
val default_connected_predicate :
- Os_types.User.id option
+ Types.User.id option
-> 'a
-> 'b
-> bool Lwt.t
@@ -108,11 +110,11 @@ module Default_config : PAGE
- error page prints debug information about the exception.
- a div is returned in case of an error with class ["errormsg"] containing a
h2 with value ["Error"] and a paragraph if the exception is
- {!Os_session.Not_connected}.
+ {!Session.Not_connected}.
*)
module Make (_ : PAGE) : sig
- val make_page : content -> [> Html_types.html] Eliom_content.Html.elt
+ val make_page : content -> [> Html_types.html] Eliom.Content.Html.elt
(** Builds a valid html page from body content by adding headers
for this app *)
@@ -122,7 +124,7 @@ module Make (_ : PAGE) : sig
-> ('a -> 'b -> content Lwt.t)
-> 'a
-> 'b
- -> Html_types.html Eliom_content.Html.elt Lwt.t
+ -> Html_types.html Eliom.Content.Html.elt Lwt.t
(** Default wrapper for service handler generating pages.
It takes as parameter a function generating page content
(body content) and transforms it into a function generating
@@ -136,29 +138,29 @@ module Make (_ : PAGE) : sig
module Opt : sig
val connected_page :
- ?allow:Os_types.Group.t list
- -> ?deny:Os_types.Group.t list
- -> ?predicate:(Os_types.User.id option -> 'a -> 'b -> bool Lwt.t)
- -> ?fallback:(Os_types.User.id option -> 'a -> 'b -> exn -> content Lwt.t)
- -> (Os_types.User.id option -> 'a -> 'b -> content Lwt.t)
+ ?allow:Types.Group.t list
+ -> ?deny:Types.Group.t list
+ -> ?predicate:(Types.User.id option -> 'a -> 'b -> bool Lwt.t)
+ -> ?fallback:(Types.User.id option -> 'a -> 'b -> exn -> content Lwt.t)
+ -> (Types.User.id option -> 'a -> 'b -> content Lwt.t)
-> 'a
-> 'b
- -> Html_types.html Eliom_content.Html.elt Lwt.t
+ -> Html_types.html Eliom.Content.Html.elt Lwt.t
(** Wrapper for pages that first checks if the user is connected.
- See {!Os_session.Opt.connected_fun}.
+ See {!Session.Opt.connected_fun}.
*)
end
val connected_page :
- ?allow:Os_types.Group.t list
- -> ?deny:Os_types.Group.t list
- -> ?predicate:(Os_types.User.id option -> 'a -> 'b -> bool Lwt.t)
- -> ?fallback:(Os_types.User.id option -> 'a -> 'b -> exn -> content Lwt.t)
- -> (Os_types.User.id -> 'a -> 'b -> content Lwt.t)
+ ?allow:Types.Group.t list
+ -> ?deny:Types.Group.t list
+ -> ?predicate:(Types.User.id option -> 'a -> 'b -> bool Lwt.t)
+ -> ?fallback:(Types.User.id option -> 'a -> 'b -> exn -> content Lwt.t)
+ -> (Types.User.id -> 'a -> 'b -> content Lwt.t)
-> 'a
-> 'b
- -> Html_types.html Eliom_content.Html.elt Lwt.t
+ -> Html_types.html Eliom.Content.Html.elt Lwt.t
(** Wrapper for pages that first checks if the user is connected.
- See {!Os_session.connected_fun}.
+ See {!Session.connected_fun}.
*)
end
diff --git a/src/os_platform.eliom b/src/Os/platform.eliom
similarity index 100%
rename from src/os_platform.eliom
rename to src/Os/platform.eliom
diff --git a/src/os_platform.eliomi b/src/Os/platform.eliomi
similarity index 100%
rename from src/os_platform.eliomi
rename to src/Os/platform.eliomi
diff --git a/src/os_request_cache.eliom b/src/Os/request_cache.eliom
similarity index 73%
rename from src/os_request_cache.eliom
rename to src/Os/request_cache.eliom
index 2a62b4986..229fdfa83 100644
--- a/src/os_request_cache.eliom
+++ b/src/Os/request_cache.eliom
@@ -51,32 +51,32 @@ struct
(* we use an eliom reference with the restrictive request scope, which is
sufficient and safe (SECURITY) *)
let cache =
- Eliom_reference.Volatile.eref ~scope:Eliom_common.request_scope MMap.empty
+ Eliom.Reference.Volatile.eref ~scope:Eliom.Common.request_scope MMap.empty
let has k =
- Eliom_common.get_sp_option () <> None
- && MMap.mem k (Eliom_reference.Volatile.get cache)
+ Eliom.Common.get_sp_option () <> None
+ && MMap.mem k (Eliom.Reference.Volatile.get cache)
let set k v =
- if Eliom_common.get_sp_option () <> None
+ if Eliom.Common.get_sp_option () <> None
then
- let table = Eliom_reference.Volatile.get cache in
- Eliom_reference.Volatile.set cache (MMap.add k v table)
+ let table = Eliom.Reference.Volatile.get cache in
+ Eliom.Reference.Volatile.set cache (MMap.add k v table)
let reset (k : M.key) =
- if Eliom_common.get_sp_option () <> None
+ if Eliom.Common.get_sp_option () <> None
then
- let table = Eliom_reference.Volatile.get cache in
- Eliom_reference.Volatile.set cache (MMap.remove k table)
+ let table = Eliom.Reference.Volatile.get cache in
+ Eliom.Reference.Volatile.set cache (MMap.remove k table)
let get (k : M.key) =
- if Eliom_common.get_sp_option () = None
+ if Eliom.Common.get_sp_option () = None
then M.get k (* Not during a request. No cache. *)
else
- let table = Eliom_reference.Volatile.get cache in
+ let table = Eliom.Reference.Volatile.get cache in
try Lwt.return (MMap.find k table)
with Not_found ->
let* ret = M.get k in
- Eliom_reference.Volatile.set cache (MMap.add k ret table);
+ Eliom.Reference.Volatile.set cache (MMap.add k ret table);
Lwt.return ret
end
diff --git a/src/os_request_cache.eliomi b/src/Os/request_cache.eliomi
similarity index 100%
rename from src/os_request_cache.eliomi
rename to src/Os/request_cache.eliomi
diff --git a/src/os_services.eliom b/src/Os/services.eliom
similarity index 62%
rename from src/os_services.eliom
rename to src/Os/services.eliom
index 9c7983160..5811d5ef5 100644
--- a/src/os_services.eliom
+++ b/src/Os/services.eliom
@@ -20,121 +20,121 @@
(** This module defines services which are mostly used for actions like the
signup process, to update user data, when a user forgot his password, etc.
- Some of them are used in forms defined in Os_user_view.
+ Some of them are used in forms defined in User_view.
Predefined handlers for each service are defined in the module
- Os_handlers. *)
+ Handlers. *)
-[%%server open Eliom_parameter]
+[%%server open Eliom.Parameter]
(** The main service. *)
let%server main_service =
- Eliom_service.create ~path:(Eliom_service.Path [])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path [])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
(** A POST service to preregister a user. By default, an email is
enough. *)
let%server preregister_service =
- Eliom_service.create ~name:"preregister_service" ~path:Eliom_service.No_path
+ Eliom.Service.create ~name:"preregister_service" ~path:Eliom.Service.No_path
~meth:
- (Eliom_service.Post (Eliom_parameter.unit, Eliom_parameter.string "email"))
+ (Eliom.Service.Post (Eliom.Parameter.unit, Eliom.Parameter.string "email"))
()
(** A POST service when the user forgot his password.
- See {!Os_handlers.forgot_password_handler for a default handler. *)
+ See {!Handlers.forgot_password_handler for a default handler. *)
let%server forgot_password_service =
- Eliom_service.create ~name:"lost_password" ~path:Eliom_service.No_path
+ Eliom.Service.create ~name:"lost_password" ~path:Eliom.Service.No_path
~meth:
- (Eliom_service.Post (Eliom_parameter.unit, Eliom_parameter.string "email"))
+ (Eliom.Service.Post (Eliom.Parameter.unit, Eliom.Parameter.string "email"))
()
(** A POST service to update the basic user data like first name, last name and
password.
- See {!Os_handlers.set_personal_data_handler for a default handler. *)
+ See {!Handlers.set_personal_data_handler for a default handler. *)
let%server set_personal_data_service =
- Eliom_service.create ~name:"set_data" ~path:Eliom_service.No_path
+ Eliom.Service.create ~name:"set_data" ~path:Eliom.Service.No_path
~meth:
- (Eliom_service.Post
- ( Eliom_parameter.unit
+ (Eliom.Service.Post
+ ( Eliom.Parameter.unit
, (string "firstname" ** string "lastname")
** string "password" ** string "password2" ))
()
(** A POST service to sign up with only an email address.
- See {!Os_handlers.sign_up_handler for a default handler. *)
+ See {!Handlers.sign_up_handler for a default handler. *)
let%server sign_up_service =
- Eliom_service.create ~name:"sign_up" ~path:Eliom_service.No_path
+ Eliom.Service.create ~name:"sign_up" ~path:Eliom.Service.No_path
~meth:
- (Eliom_service.Post (Eliom_parameter.unit, Eliom_parameter.string "email"))
+ (Eliom.Service.Post (Eliom.Parameter.unit, Eliom.Parameter.string "email"))
()
(** A POST service to connect a user with username and password.
- See {!Os_handlers.connect_handler for a default handler. *)
+ See {!Handlers.connect_handler for a default handler. *)
let%server connect_service =
- Eliom_service.create ~name:"connect" ~path:Eliom_service.No_path
+ Eliom.Service.create ~name:"connect" ~path:Eliom.Service.No_path
~meth:
- (Eliom_service.Post
- ( Eliom_parameter.unit
+ (Eliom.Service.Post
+ ( Eliom.Parameter.unit
, (string "username" ** string "password") ** bool "keepmeloggedin" ))
()
(** A POST service to disconnect the current user.
- See {!Os_handlers.disconnect_handler} for a default handler. *)
+ See {!Handlers.disconnect_handler} for a default handler. *)
let%server disconnect_service =
- Eliom_service.create ~name:"disconnect" ~path:Eliom_service.No_path
- ~meth:(Eliom_service.Post (Eliom_parameter.unit, Eliom_parameter.unit))
+ Eliom.Service.create ~name:"disconnect" ~path:Eliom.Service.No_path
+ ~meth:(Eliom.Service.Post (Eliom.Parameter.unit, Eliom.Parameter.unit))
()
(** A GET service for action link keys.
- See {!Os_handlers.action_link_handler} for a default handler and
- {!Os_db.action_link_table} for more information about the action
+ See {!Handlers.action_link_handler} for a default handler and
+ {!Db.action_link_table} for more information about the action
process. *)
let%server action_link_service =
- Eliom_service.create ~name:"action_link" ~path:Eliom_service.No_path
- ~meth:(Eliom_service.Get (Eliom_parameter.string "actionkey"))
+ Eliom.Service.create ~name:"action_link" ~path:Eliom.Service.No_path
+ ~meth:(Eliom.Service.Get (Eliom.Parameter.string "actionkey"))
()
(** A POST service to update the password. An update password action is
associated with the confirmation password.
- See {!Os_handlers.set_password_handler} for a default handler. *)
+ See {!Handlers.set_password_handler} for a default handler. *)
let%server set_password_service =
- Eliom_service.create ~name:"set_password" ~path:Eliom_service.No_path
+ Eliom.Service.create ~name:"set_password" ~path:Eliom.Service.No_path
~meth:
- (Eliom_service.Post
- (Eliom_parameter.unit, string "password" ** string "password2"))
+ (Eliom.Service.Post
+ (Eliom.Parameter.unit, string "password" ** string "password2"))
()
(** A POST service to add an email to a user.
- See {!Os_handlers.add_email_handler} for a default handler. *)
+ See {!Handlers.add_email_handler} for a default handler. *)
let%server add_email_service =
- Eliom_service.create ~name:"add_email" ~path:Eliom_service.No_path
+ Eliom.Service.create ~name:"add_email" ~path:Eliom.Service.No_path
~meth:
- (Eliom_service.Post (Eliom_parameter.unit, Eliom_parameter.string "email"))
+ (Eliom.Service.Post (Eliom.Parameter.unit, Eliom.Parameter.string "email"))
()
let%server update_language_service =
- Eliom_service.create ~name:"update_language" ~path:Eliom_service.No_path
+ Eliom.Service.create ~name:"update_language" ~path:Eliom.Service.No_path
~meth:
- (Eliom_service.Post
- (Eliom_parameter.unit, Eliom_parameter.string "language"))
+ (Eliom.Service.Post
+ (Eliom.Parameter.unit, Eliom.Parameter.string "language"))
()
let confirm_code_signup_service =
- Eliom_service.create ~name:"confirm_code_signup" ~path:Eliom_service.No_path
+ Eliom.Service.create ~name:"confirm_code_signup" ~path:Eliom.Service.No_path
~meth:
- (Eliom_service.Post
+ (Eliom.Service.Post
( unit
, string "first_name" ** string "last_name" ** string "password"
** string "number" ))
()
let confirm_code_extra_service =
- Eliom_service.create ~name:"confirm_code_extra" ~path:Eliom_service.No_path
- ~meth:(Eliom_service.Post (unit, string "number"))
+ Eliom.Service.create ~name:"confirm_code_extra" ~path:Eliom.Service.No_path
+ ~meth:(Eliom.Service.Post (unit, string "number"))
()
let confirm_code_recovery_service =
- Eliom_service.create ~name:"confirm_code_recovery" ~path:Eliom_service.No_path
- ~meth:(Eliom_service.Post (unit, string "number"))
+ Eliom.Service.create ~name:"confirm_code_recovery" ~path:Eliom.Service.No_path
+ ~meth:(Eliom.Service.Post (unit, string "number"))
()
let%client main_service = ~%main_service
@@ -152,7 +152,7 @@ let%client confirm_code_signup_service = ~%confirm_code_signup_service
let%client confirm_code_extra_service = ~%confirm_code_extra_service
let%client confirm_code_recovery_service = ~%confirm_code_recovery_service
-(* [Os_handlers.add_email_handler] needs access to the settings
+(* [Handlers.add_email_handler] needs access to the settings
service, but the latter needs to be defined in the template. So we
use the reference [settings_service_ref]. The template needs to
call [set_settings_service]. *)
diff --git a/src/Os/services.eliomi b/src/Os/services.eliomi
new file mode 100644
index 000000000..aa56eb7eb
--- /dev/null
+++ b/src/Os/services.eliomi
@@ -0,0 +1,321 @@
+(* Ocsigen-start
+
+ * http://www.ocsigen.org/ocsigen-start
+ *
+ * Copyright (C) Université Paris Diderot, CNRS, INRIA, Be Sport.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, with linking exception;
+ * either version 2.1 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *)
+
+[%%shared.start]
+(** This module provides pre-defined services for connect, disconnect, sign up,
+ add a new email, etc. Each service has a corresponding handler in
+ {!Handlers}.
+ *)
+
+val main_service :
+ ( unit
+ , unit
+ , Eliom.Service.get
+ , Eliom.Service.att
+ , Eliom.Service.non_co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
+ , [`WithoutSuffix]
+ , unit
+ , unit
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
+(** The main service. *)
+
+val preregister_service :
+ ( unit
+ , string
+ , Eliom.Service.post
+ , Eliom.Service.non_att
+ , Eliom.Service.co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
+ , [`WithoutSuffix]
+ , unit
+ , [`One of string] Eliom.Parameter.param_name
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
+(** A POST service to preregister a user. By default, an email is
+ enough. *)
+
+val forgot_password_service :
+ ( unit
+ , string
+ , Eliom.Service.post
+ , Eliom.Service.non_att
+ , Eliom.Service.co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
+ , [`WithoutSuffix]
+ , unit
+ , [`One of string] Eliom.Parameter.param_name
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
+(** A POST service when the user forgot his password.
+ See {!Handlers.forgot_password_handler} for a default handler.
+ *)
+
+val set_personal_data_service :
+ ( unit
+ , (string * string) * (string * string)
+ , Eliom.Service.post
+ , Eliom.Service.non_att
+ , Eliom.Service.co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
+ , [`WithoutSuffix]
+ , unit
+ , ([`One of string] Eliom.Parameter.param_name
+ * [`One of string] Eliom.Parameter.param_name)
+ * ([`One of string] Eliom.Parameter.param_name
+ * [`One of string] Eliom.Parameter.param_name)
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
+(** A POST service to update the basic user data like first name, last name and
+ password.
+ See {!Handlers.set_personal_data_handler'} for a default handler.
+ *)
+
+val sign_up_service :
+ ( unit
+ , string
+ , Eliom.Service.post
+ , Eliom.Service.non_att
+ , Eliom.Service.co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
+ , [`WithoutSuffix]
+ , unit
+ , [`One of string] Eliom.Parameter.param_name
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
+(** A POST service to sign up with only an email address.
+ See {!Handlers.sign_up_handler} for a default handler.
+ *)
+
+val connect_service :
+ ( unit
+ , (string * string) * bool
+ , Eliom.Service.post
+ , Eliom.Service.non_att
+ , Eliom.Service.co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
+ , [`WithoutSuffix]
+ , unit
+ , ([`One of string] Eliom.Parameter.param_name
+ * [`One of string] Eliom.Parameter.param_name)
+ * [`One of bool] Eliom.Parameter.param_name
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
+(** A POST service to connect a user with username and password.
+ See {!Handlers.connect_handler} for a default handler.
+ *)
+
+val disconnect_service :
+ ( unit
+ , unit
+ , Eliom.Service.post
+ , Eliom.Service.non_att
+ , Eliom.Service.co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
+ , [`WithoutSuffix]
+ , unit
+ , unit
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
+(** A POST service to disconnect the current user.
+ See {!Handlers.disconnect_handler} for a default handler.
+ *)
+
+val action_link_service :
+ ( string
+ , unit
+ , Eliom.Service.get
+ , Eliom.Service.non_att
+ , Eliom.Service.co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
+ , [`WithoutSuffix]
+ , [`One of string] Eliom.Parameter.param_name
+ , unit
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
+(** A GET service for action link keys.
+ See {!Handlers.action_link_handler} for a default handler and
+ {!Db.action_link_table} for more information about the action
+ process.
+ *)
+
+val set_password_service :
+ ( unit
+ , string * string
+ , Eliom.Service.post
+ , Eliom.Service.non_att
+ , Eliom.Service.co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
+ , [`WithoutSuffix]
+ , unit
+ , [`One of string] Eliom.Parameter.param_name
+ * [`One of string] Eliom.Parameter.param_name
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
+(** A POST service to update the password. An update password action is
+ associated with the confirmation password.
+ See {!Handlers.set_password_handler'} for a default handler.
+ *)
+
+val add_email_service :
+ ( unit
+ , string
+ , Eliom.Service.post
+ , Eliom.Service.non_att
+ , Eliom.Service.co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
+ , [`WithoutSuffix]
+ , unit
+ , [`One of string] Eliom.Parameter.param_name
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
+(** A POST service to add an email to a user.
+ See {!Handlers.add_email_handler} for a default handler.
+ *)
+
+val update_language_service :
+ ( unit
+ , string
+ , Eliom.Service.post
+ , Eliom.Service.non_att
+ , Eliom.Service.co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
+ , [`WithoutSuffix]
+ , unit
+ , [`One of string] Eliom.Parameter.param_name
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
+(** A POST service to update the language of the current user.
+ See {!Handlers.update_language_handler} for a default handler.
+*)
+
+val confirm_code_signup_service :
+ ( unit
+ , string * (string * (string * string))
+ , Eliom.Service.post
+ , Eliom.Service.non_att
+ , Eliom.Service.co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
+ , [`WithoutSuffix]
+ , unit
+ , [`One of string] Eliom.Parameter.param_name
+ * ([`One of string] Eliom.Parameter.param_name
+ * ([`One of string] Eliom.Parameter.param_name
+ * [`One of string] Eliom.Parameter.param_name))
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
+(** Confirm SMS activation code and (if valid) register new user. *)
+
+val confirm_code_extra_service :
+ ( unit
+ , string
+ , Eliom.Service.post
+ , Eliom.Service.non_att
+ , Eliom.Service.co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
+ , [`WithoutSuffix]
+ , unit
+ , [`One of string] Eliom.Parameter.param_name
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
+(** Confirm SMS activation code and (if valid) add new phone number to
+ user's account. *)
+
+val confirm_code_recovery_service :
+ ( unit
+ , string
+ , Eliom.Service.post
+ , Eliom.Service.non_att
+ , Eliom.Service.co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
+ , [`WithoutSuffix]
+ , unit
+ , [`One of string] Eliom.Parameter.param_name
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
+(** Confirm SMS activation code and (if valid) allow the user to set a
+ new password. *)
+
+val confirm_code_remind_service :
+ ( unit
+ , string
+ , Eliom.Service.post
+ , Eliom.Service.non_att
+ , Eliom.Service.co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
+ , [`WithoutSuffix]
+ , unit
+ , [`One of string] Eliom.Parameter.param_name
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
+(** Temporary alternate name for [confirm_code_recovery_handler] to
+ facilite the transition. *)
+
+val register_settings_service :
+ ( unit
+ , unit
+ , Eliom.Service.get
+ , Eliom.Service.att
+ , Eliom.Service.non_co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
+ , [`WithoutSuffix]
+ , unit
+ , unit
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
+ -> unit
+(** Register the settings service (defined in the app rather than in
+ the OS lib) because we need to perform redirections to it. *)
+
+(**/**)
+
+val settings_service :
+ unit
+ -> ( unit
+ , unit
+ , Eliom.Service.get
+ , Eliom.Service.att
+ , Eliom.Service.non_co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
+ , [`WithoutSuffix]
+ , unit
+ , unit
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
+ option
diff --git a/src/os_session.eliom b/src/Os/session.eliom
similarity index 79%
rename from src/os_session.eliom
rename to src/Os/session.eliom
index c966f1cc5..fbc3aedb7 100644
--- a/src/os_session.eliom
+++ b/src/Os/session.eliom
@@ -21,16 +21,16 @@
open Lwt.Syntax
let log_section = Logs.Src.create "os:session"
-let user_indep_state_hierarchy = Eliom_common.create_scope_hierarchy "userindep"
+let user_indep_state_hierarchy = Eliom.Common.create_scope_hierarchy "userindep"
let user_indep_process_scope = `Client_process user_indep_state_hierarchy
let user_indep_session_scope = `Session user_indep_state_hierarchy
(* We make it possible to acces the user_indep scope from connected scope *)
let current_user_indep_session_state =
- Eliom_reference.Volatile.eref ~scope:Eliom_common.default_session_scope None
+ Eliom.Reference.Volatile.eref ~scope:Eliom.Common.default_session_scope None
let new_process_eref =
- Eliom_reference.Volatile.eref ~scope:user_indep_process_scope true
+ Eliom.Reference.Volatile.eref ~scope:user_indep_process_scope true
let mk_action_queue name =
let r = ref (fun _ -> Lwt.return_unit) in
@@ -76,19 +76,19 @@ exception Not_connected
exception Permission_denied]
let connect_volatile uid =
- Eliom_state.set_volatile_data_session_group
- ~scope:Eliom_common.default_session_scope uid;
+ Eliom.State.set_volatile_data_session_group
+ ~scope:Eliom.Common.default_session_scope uid;
let uid = Int64.of_string uid in
- Eliom_reference.Volatile.set current_user_indep_session_state
+ Eliom.Reference.Volatile.set current_user_indep_session_state
(Some
- (Eliom_state.Ext.current_volatile_data_state
+ (Eliom.State.Ext.current_volatile_data_state
~scope:user_indep_session_scope ()));
open_session_action uid
let connect_string uid =
let* () =
- Eliom_state.set_persistent_data_session_group
- ~scope:Eliom_common.default_session_scope uid
+ Eliom.State.set_persistent_data_session_group
+ ~scope:Eliom.Common.default_session_scope uid
in
let* () = connect_volatile uid in
let uid = Int64.of_string uid in
@@ -96,9 +96,9 @@ let connect_string uid =
let disconnect () =
let* () = pre_close_session_action () in
- let* () = Eliom_state.discard ~scope:Eliom_common.default_session_scope () in
- let* () = Eliom_state.discard ~scope:Eliom_common.default_process_scope () in
- let* () = Eliom_state.discard ~scope:Eliom_common.request_scope () in
+ let* () = Eliom.State.discard ~scope:Eliom.Common.default_session_scope () in
+ let* () = Eliom.State.discard ~scope:Eliom.Common.default_process_scope () in
+ let* () = Eliom.State.discard ~scope:Eliom.Common.request_scope () in
post_close_session_action ()
let connect ?(expire = false) userid =
@@ -106,11 +106,11 @@ let connect ?(expire = false) userid =
let* () =
if expire
then (
- let open Eliom_common in
+ let open Eliom.Common in
let cookie_scope = (default_session_scope :> cookie_scope) in
- Eliom_state.set_service_cookie_exp_date ~cookie_scope None;
- Eliom_state.set_volatile_data_cookie_exp_date ~cookie_scope None;
- Eliom_state.set_persistent_data_cookie_exp_date ~cookie_scope None)
+ Eliom.State.set_service_cookie_exp_date ~cookie_scope None;
+ Eliom.State.set_volatile_data_cookie_exp_date ~cookie_scope None;
+ Eliom.State.set_persistent_data_cookie_exp_date ~cookie_scope None)
else Lwt.return_unit
in
connect_string (Int64.to_string userid)
@@ -133,8 +133,8 @@ let disconnect_all
let userid =
match userid with
| None -> (
- let uid = Eliom_state.get_volatile_data_session_group () in
- try Eliom_lib.Option.map Int64.of_string uid with Failure _ -> None)
+ let uid = Eliom.State.get_volatile_data_session_group () in
+ try Option.map Int64.of_string uid with Failure _ -> None)
| Some userid -> Some userid
in
match userid with
@@ -144,34 +144,34 @@ let disconnect_all
We close all sessions from group instead. *)
let group_name = Int64.to_string userid in
let states =
- [ Eliom_state.Ext.volatile_data_group_state
- ~scope:Eliom_common.default_group_scope group_name
- ; Eliom_state.Ext.persistent_data_group_state
- ~scope:Eliom_common.default_group_scope group_name
- ; Eliom_state.Ext.service_group_state
- ~scope:Eliom_common.default_group_scope group_name ]
+ [ Eliom.State.Ext.volatile_data_group_state
+ ~scope:Eliom.Common.default_group_scope group_name
+ ; Eliom.State.Ext.persistent_data_group_state
+ ~scope:Eliom.Common.default_group_scope group_name
+ ; Eliom.State.Ext.service_group_state
+ ~scope:Eliom.Common.default_group_scope group_name ]
in
let* ui_states =
List.fold_left
(fun acc state ->
Lwt.bind
- (Eliom_reference.Ext.get state
+ (Eliom.Reference.Ext.get state
(current_user_indep_session_state
:> ( [< `Session_group | `Session | `Client_process]
, [< `Data | `Pers] )
- Eliom_state.Ext.state
+ Eliom.State.Ext.state
option
- Eliom_reference.eref))
+ Eliom.Reference.eref))
(function
| None -> acc
| Some s ->
let* acc = acc in
Lwt.return (s :: acc)))
Lwt.return_nil
- (Eliom_state.Ext.fold_volatile_sub_states ?sitedata
+ (Eliom.State.Ext.fold_volatile_sub_states ?sitedata
~state:
- (Eliom_state.Ext.volatile_data_group_state
- ~scope:Eliom_common.default_group_scope group_name)
+ (Eliom.State.Ext.volatile_data_group_state
+ ~scope:Eliom.Common.default_group_scope group_name)
(fun acc s -> s :: acc)
[])
in
@@ -181,8 +181,8 @@ let disconnect_all
=
Lwt_list.iter_s
(fun state ->
- Eliom_state.Ext.iter_sub_states ?sitedata ~state @@ fun state ->
- Eliom_state.Ext.discard_state ?sitedata ~state ())
+ Eliom.State.Ext.iter_sub_states ?sitedata ~state @@ fun state ->
+ Eliom.State.Ext.discard_state ?sitedata ~state ())
states
in
let* () =
@@ -196,7 +196,7 @@ let disconnect_all
=
Lwt_list.iter_s
(fun state ->
- Eliom_state.Ext.iter_sub_states ?sitedata ~state
+ Eliom.State.Ext.iter_sub_states ?sitedata ~state
warn_connection_changed)
ui_states
in
@@ -207,12 +207,12 @@ let disconnect_all
if user_indep
then
Lwt_list.iter_s
- (fun state -> Eliom_state.Ext.discard_state ?sitedata ~state ())
+ (fun state -> Eliom.State.Ext.discard_state ?sitedata ~state ())
ui_states
else Lwt.return_unit
in
let () =
- if with_restart then ignore [%client (Os_handlers.restart () : unit)]
+ if with_restart then ignore [%client (Handlers.restart () : unit)]
in
Lwt.return_unit
@@ -224,7 +224,7 @@ let check_allow_deny userid allow deny =
(* allow only users from one of the groups of list l *)
Lwt_list.fold_left_s
(fun b group ->
- let* b2 = Os_group.in_group ~userid ~group () in
+ let* b2 = Group.in_group ~userid ~group () in
Lwt.return (b || b2))
false l
in
@@ -236,7 +236,7 @@ let check_allow_deny userid allow deny =
in one of the groups of list l *)
Lwt_list.fold_left_s
(fun b group ->
- let* b2 = Os_group.in_group ~userid ~group () in
+ let* b2 = Group.in_group ~userid ~group () in
Lwt.return (b && not b2))
b l
in
@@ -247,14 +247,14 @@ let check_allow_deny userid allow deny =
Lwt.fail Permission_denied
let get_session () =
- let uids = Eliom_state.get_volatile_data_session_group () in
+ let uids = Eliom.State.get_volatile_data_session_group () in
let get_uid uid =
- try Eliom_lib.Option.map Int64.of_string uid with Failure _ -> None
+ try Option.map Int64.of_string uid with Failure _ -> None
in
let* uid =
match get_uid uids with
| None -> (
- let* uids = Eliom_state.get_persistent_data_session_group () in
+ let* uids = Eliom.State.get_persistent_data_session_group () in
match get_uid uids with
| Some uid ->
let*
@@ -277,10 +277,10 @@ let get_session () =
| Some uid ->
Lwt.catch
(fun () ->
- let* _user = Os_user.user_of_userid uid in
+ let* _user = User.user_of_userid uid in
Lwt.return_some uid)
(function
- | Os_user.No_such_user ->
+ | User.No_such_user ->
let*
(* If session exists and no user in DB, close the session *)
()
@@ -322,14 +322,14 @@ let%server
pp
=
let new_process =
- (not force_unconnected) && Eliom_reference.Volatile.get new_process_eref
+ (not force_unconnected) && Eliom.Reference.Volatile.get new_process_eref
in
let* uid = if force_unconnected then Lwt.return_none else get_session () in
let* () = request_action uid in
let* () =
if new_process
then (
- Eliom_reference.Volatile.set new_process_eref false;
+ Eliom.Reference.Volatile.set new_process_eref false;
start_process_action uid)
else Lwt.return_unit
in
@@ -401,11 +401,10 @@ module Opt = struct
end]
let%client disconnect =
- ~%(Eliom_client.server_function ~name:"Os_session.disconnect" [%json: unit]
+ ~%(Eliom.Client.server_function ~name:"Session.disconnect" [%json: unit]
(connected_wrapper disconnect))
let%client disconnect_all ?(user_indep = true) () =
- ~%(Eliom_client.server_function ~name:"Os_session.disconnect_all"
- [%json: bool]
+ ~%(Eliom.Client.server_function ~name:"Session.disconnect_all" [%json: bool]
(connected_wrapper (fun user_indep -> disconnect_all ~user_indep ())))
user_indep
diff --git a/src/os_session.eliomi b/src/Os/session.eliomi
similarity index 76%
rename from src/os_session.eliomi
rename to src/Os/session.eliomi
index 0858a0d26..063362298 100644
--- a/src/os_session.eliomi
+++ b/src/Os/session.eliomi
@@ -22,11 +22,11 @@
restrict access to services or server functions,
define actions to be executed at some points of the session. *)
-val on_start_process : (Os_types.User.id option -> unit Lwt.t) -> unit
+val on_start_process : (Types.User.id option -> unit Lwt.t) -> unit
(** Call this to add an action to be done on server side
when the process starts *)
-val on_start_connected_process : (Os_types.User.id -> unit Lwt.t) -> unit
+val on_start_connected_process : (Types.User.id -> unit Lwt.t) -> unit
(** Call this to add an action to be done
when the process starts in connected mode, or when the user logs in *)
@@ -34,14 +34,14 @@ val on_start_unconnected_process : (unit -> unit Lwt.t) -> unit
(** Call this to add an action to be done on server side
when the process starts but only when not in connected mode *)
-val on_connected_request : (Os_types.User.id -> unit Lwt.t) -> unit
+val on_connected_request : (Types.User.id -> unit Lwt.t) -> unit
(** Call this to add an action to be done at each connected request.
The function takes the user id as parameter. *)
val on_unconnected_request : (unit -> unit Lwt.t) -> unit
(** Call this to add an action to be done at each unconnected request. *)
-val on_open_session : (Os_types.User.id -> unit Lwt.t) -> unit
+val on_open_session : (Types.User.id -> unit Lwt.t) -> unit
(** Call this to add an action to be done just after opening a session
The function takes the user id as parameter. *)
@@ -51,10 +51,10 @@ val on_pre_close_session : (unit -> unit Lwt.t) -> unit
val on_post_close_session : (unit -> unit Lwt.t) -> unit
(** Call this to add an action to be done just after closing the session *)
-val on_request : (Os_types.User.id option -> unit Lwt.t) -> unit
+val on_request : (Types.User.id option -> unit Lwt.t) -> unit
(** Call this to add an action to be done just before handling a request *)
-val on_denied_request : (Os_types.User.id option -> unit Lwt.t) -> unit
+val on_denied_request : (Types.User.id option -> unit Lwt.t) -> unit
(** Call this to add an action to be done just for each denied request.
The function takes the user id as parameter, if some user is connected. *)
@@ -63,9 +63,9 @@ val on_denied_request : (Os_types.User.id option -> unit Lwt.t) -> unit
server side data for one browser or tab, but not user dependent.
(Remains when user logs out). *)
-val user_indep_state_hierarchy : Eliom_common.scope_hierarchy
-val user_indep_process_scope : [> Eliom_common.client_process_scope]
-val user_indep_session_scope : [> Eliom_common.session_scope]
+val user_indep_state_hierarchy : Eliom.Common.scope_hierarchy
+val user_indep_process_scope : [> Eliom.Common.client_process_scope]
+val user_indep_session_scope : [> Eliom.Common.session_scope]
[%%shared.start]
@@ -74,7 +74,7 @@ exception Permission_denied
[%%server.start]
-val connect : ?expire:bool -> Os_types.User.id -> unit Lwt.t
+val connect : ?expire:bool -> Types.User.id -> unit Lwt.t
(** Close current session (if any) by calling disconnect,
then open a new session for a user by setting a session group for the browser
which initiated the current request.
@@ -86,8 +86,8 @@ val connect : ?expire:bool -> Os_types.User.id -> unit Lwt.t
*)
val disconnect_all :
- ?sitedata:Eliom_common.sitedata
- -> ?userid:Os_types.User.id
+ ?sitedata:Eliom.Common.sitedata
+ -> ?userid:Types.User.id
-> ?user_indep:bool
-> ?with_restart:bool
-> unit
@@ -103,7 +103,7 @@ val disconnect_all :
- [?userid] must not be [None]
- [?with_restart] must be [false]
- you must provide the extra parameter [?sitedata],
- that you can get by calling [Eliom_request_info.get_sitedata]
+ that you can get by calling [Eliom.Request_info.get_sitedata]
during the initialisation phase of the Eliom module.
*)
@@ -127,10 +127,10 @@ val disconnect : unit -> unit Lwt.t
*)
val connected_fun :
- ?allow:Os_types.Group.t list
- -> ?deny:Os_types.Group.t list
- -> ?deny_fun:(Os_types.User.id option -> 'c Lwt.t)
- -> (Os_types.User.id -> 'a -> 'b -> 'c Lwt.t)
+ ?allow:Types.Group.t list
+ -> ?deny:Types.Group.t list
+ -> ?deny_fun:(Types.User.id option -> 'c Lwt.t)
+ -> (Types.User.id -> 'a -> 'b -> 'c Lwt.t)
-> 'a
-> 'b
-> 'c Lwt.t
@@ -141,7 +141,7 @@ val connected_fun :
If no user is connected, the service will fail by raising [Not_connected].
Otherwise it calls function [f].
To provide another behaviour in case the user is not connected,
- have a look at {!Opt.connected_fun} or module {!Os_page}.
+ have a look at {!Opt.connected_fun} or module {!Page}.
Arguments [?allow] and [?deny] make possible to restrict access to some
user groups. If access is denied, function [?deny_fun] will be called.
@@ -152,25 +152,25 @@ val connected_fun :
If optional argument [force_unconnected] is [true],
it will not try to find session information, and behave as if user were
not connected (default is [false]). This allows to use functions
- from module {!Os_current_user} in functions outside application
+ from module {!Current_user} in functions outside application
without failing.
Use only one connection wrapper for each request!
*)
val connected_rpc :
- ?allow:Os_types.Group.t list
- -> ?deny:Os_types.Group.t list
- -> ?deny_fun:(Os_types.User.id option -> 'b Lwt.t)
- -> (Os_types.User.id -> 'a -> 'b Lwt.t)
+ ?allow:Types.Group.t list
+ -> ?deny:Types.Group.t list
+ -> ?deny_fun:(Types.User.id option -> 'b Lwt.t)
+ -> (Types.User.id -> 'a -> 'b Lwt.t)
-> 'a
-> 'b Lwt.t
(** Wrapper for server functions (see {!connected_fun}). *)
val connected_wrapper :
- ?allow:Os_types.Group.t list
- -> ?deny:Os_types.Group.t list
- -> ?deny_fun:(Os_types.User.id option -> 'b Lwt.t)
+ ?allow:Types.Group.t list
+ -> ?deny:Types.Group.t list
+ -> ?deny_fun:(Types.User.id option -> 'b Lwt.t)
-> ?force_unconnected:bool
-> ('a -> 'b Lwt.t)
-> 'a
@@ -181,29 +181,29 @@ val connected_wrapper :
module Opt : sig
val connected_fun :
- ?allow:Os_types.Group.t list
- -> ?deny:Os_types.Group.t list
- -> ?deny_fun:(Os_types.User.id option -> 'c Lwt.t)
+ ?allow:Types.Group.t list
+ -> ?deny:Types.Group.t list
+ -> ?deny_fun:(Types.User.id option -> 'c Lwt.t)
-> ?force_unconnected:bool
- -> (Os_types.User.id option -> 'a -> 'b -> 'c Lwt.t)
+ -> (Types.User.id option -> 'a -> 'b -> 'c Lwt.t)
-> 'a
-> 'b
-> 'c Lwt.t
(** Same as {!connected_fun} but instead of failing in case the user is
- not connected, the function given as parameter takes an [Os_types.User.id
+ not connected, the function given as parameter takes an [Types.User.id
option] for user id.
*)
val connected_rpc :
- ?allow:Os_types.Group.t list
- -> ?deny:Os_types.Group.t list
- -> ?deny_fun:(Os_types.User.id option -> 'b Lwt.t)
+ ?allow:Types.Group.t list
+ -> ?deny:Types.Group.t list
+ -> ?deny_fun:(Types.User.id option -> 'b Lwt.t)
-> ?force_unconnected:bool
- -> (Os_types.User.id option -> 'a -> 'b Lwt.t)
+ -> (Types.User.id option -> 'a -> 'b Lwt.t)
-> 'a
-> 'b Lwt.t
(** Same as {!connected_rpc} but instead of failing in case the user is
- not connected, the function given as parameter takes an [Os_types.User.id
+ not connected, the function given as parameter takes an [Types.User.id
option] for user id.
*)
end
@@ -212,11 +212,11 @@ end
[%%client.start]
-val get_current_userid_o : (unit -> Os_types.User.id option) ref
+val get_current_userid_o : (unit -> Types.User.id option) ref
(** internal. Do not use *)
[%%server.start]
val set_warn_connection_change :
- (([`Session], [`Data]) Eliom_state.Ext.state -> unit)
+ (([`Session], [`Data]) Eliom.State.Ext.state -> unit)
-> unit
diff --git a/src/os_tips.eliom b/src/Os/tips.eliom
similarity index 76%
rename from src/os_tips.eliom
rename to src/Os/tips.eliom
index 83ee76f28..5e068b7ba 100644
--- a/src/os_tips.eliom
+++ b/src/Os/tips.eliom
@@ -19,17 +19,23 @@
*)
open%shared Lwt.Syntax
-open%shared Eliom_content.Html
-open%shared Eliom_content.Html.F
+open%shared Eliom.Content.Html
+open%shared Eliom.Content.Html.F
open%client Js_of_ocaml
open%client Js_of_ocaml_lwt
module%shared Stringset = Set.Make (String)
+(* Stringset values are persisted as sorted string lists. *)
+let%server stringset_json : Stringset.t Deriving_Json.t =
+ Deriving_Json.convert [%json: string list] Stringset.of_list
+ Stringset.elements
+
(* tips_seen is a group persistent reference recording which tips have
already been seen by user *)
let tips_seen =
- Eliom_reference.eref ~persistent:"tips_seen1"
- ~scope:Eliom_common.default_group_scope Stringset.empty
+ Eliom.Reference.eref
+ ~persistent:("tips_seen1", stringset_json)
+ ~scope:Eliom.Common.default_group_scope Stringset.empty
(*VVV TODO: What if not connected? We don't want to keep the eref
for all non-connected users. This is a weakness of persistent
group eref. Use posgresql instead? *)
@@ -46,19 +52,20 @@ let tips_seen =
For now, I'm using a session reference for not connected users ...
*)
let tips_seen_not_connected =
- Eliom_reference.eref ~persistent:"tips_seen_not_connected1"
- ~scope:Os_session.user_indep_session_scope Stringset.empty
+ Eliom.Reference.eref
+ ~persistent:("tips_seen_not_connected1", stringset_json)
+ ~scope:Session.user_indep_session_scope Stringset.empty
(* We cache the set during a request *)
let seen_by_user =
- Eliom_reference.Volatile.eref_from_fun ~scope:Eliom_common.request_scope
+ Eliom.Reference.Volatile.eref_from_fun ~scope:Eliom.Common.request_scope
(fun () ->
- match Os_current_user.Opt.get_current_userid () with
- | None -> Eliom_reference.get tips_seen_not_connected
- | _ -> Eliom_reference.get tips_seen)
+ match Current_user.Opt.get_current_userid () with
+ | None -> Eliom.Reference.get tips_seen_not_connected
+ | _ -> Eliom.Reference.get tips_seen)
(* Get the set of seen tips *)
-let%server get_tips_seen () = Eliom_reference.Volatile.get seen_by_user
+let%server get_tips_seen () = Eliom.Reference.Volatile.get seen_by_user
(* We cache the set of seen tips to avoid doing the request several times.
Warning: it is not updated if the user is using several devices or
@@ -68,18 +75,18 @@ let%client tips_seen_client_ref = ref Stringset.empty
let%client get_tips_seen () = Lwt.return !tips_seen_client_ref
let%server () =
- Os_session.on_start_connected_process (fun _ ->
+ Session.on_start_connected_process (fun _ ->
let* tips = get_tips_seen () in
ignore [%client (tips_seen_client_ref := ~%tips : unit)];
Lwt.return_unit)
(* notify the server that a user has seen a tip *)
let%rpc set_tip_seen (name : string) : unit Lwt.t =
- let* prev = Eliom_reference.Volatile.get seen_by_user in
+ let* prev = Eliom.Reference.Volatile.get seen_by_user in
let newset = Stringset.add (name : string) prev in
- match Os_current_user.Opt.get_current_userid () with
- | None -> Eliom_reference.set tips_seen_not_connected newset
- | _ -> Eliom_reference.set tips_seen newset
+ match Current_user.Opt.get_current_userid () with
+ | None -> Eliom.Reference.set tips_seen_not_connected newset
+ | _ -> Eliom.Reference.set tips_seen newset
let%client set_tip_seen name =
tips_seen_client_ref := Stringset.add name !tips_seen_client_ref;
@@ -87,11 +94,11 @@ let%client set_tip_seen name =
(* counterpart of set_tip_seen *)
let%rpc unset_tip_seen (name : string) : unit Lwt.t =
- let* prev = Eliom_reference.Volatile.get seen_by_user in
+ let* prev = Eliom.Reference.Volatile.get seen_by_user in
let newset = Stringset.remove name prev in
- match Os_current_user.Opt.get_current_userid () with
- | None -> Eliom_reference.set tips_seen_not_connected newset
- | _ -> Eliom_reference.set tips_seen newset
+ match Current_user.Opt.get_current_userid () with
+ | None -> Eliom.Reference.set tips_seen_not_connected newset
+ | _ -> Eliom.Reference.set tips_seen newset
let%client unset_tip_seen name =
tips_seen_client_ref := Stringset.remove name !tips_seen_client_ref;
@@ -104,21 +111,21 @@ let%shared tip_seen name =
(* I want to see the tips again *)
let%server reset_tips_user myid_o =
match myid_o with
- | None -> Eliom_reference.set tips_seen_not_connected Stringset.empty
- | _ -> Eliom_reference.set tips_seen Stringset.empty
+ | None -> Eliom.Reference.set tips_seen_not_connected Stringset.empty
+ | _ -> Eliom.Reference.set tips_seen Stringset.empty
let%rpc reset_tips myid_o () : unit Lwt.t = reset_tips_user myid_o
let%server reset_tips_service =
- Eliom_service.create ~name:"resettips" ~path:Eliom_service.No_path
- ~meth:(Eliom_service.Post (Eliom_parameter.unit, Eliom_parameter.unit))
+ Eliom.Service.create ~name:"resettips" ~path:Eliom.Service.No_path
+ ~meth:(Eliom.Service.Post (Eliom.Parameter.unit, Eliom.Parameter.unit))
()
let%client reset_tips_service = ~%reset_tips_service
let%server _ =
- Eliom_registration.Action.register ~service:reset_tips_service
- (Os_session.Opt.connected_fun (fun myid_o () () -> reset_tips_user myid_o))
+ Eliom.Registration.Action.register ~service:reset_tips_service
+ (Session.Opt.connected_fun (fun myid_o () () -> reset_tips_user myid_o))
let%client reset_tips () =
tips_seen_client_ref := Stringset.empty;
@@ -135,7 +142,7 @@ let%shared
~content
()
=
- let myid_o = Os_current_user.Opt.get_current_userid () in
+ let myid_o = Current_user.Opt.get_current_userid () in
match recipient, myid_o with
| `All, _ | `Not_connected, None | `Connected, Some _ ->
let* seen = get_tips_seen () in
@@ -143,7 +150,7 @@ let%shared
then Lwt.return_none
else
let box_ref = ref None in
- let close : (unit -> unit Lwt.t) Eliom_client_value.t =
+ let close : (unit -> unit Lwt.t) Eliom.Client_value.t =
[%client
fun () ->
let* () = ~%onclose () in
@@ -159,7 +166,7 @@ let%shared
let box =
D.div
~a:(a_class ["os-tip"; "os-tip-block"] :: a)
- (Os_icons.D.close
+ (Icons.D.close
~a:
[ a_class ["os-tip-close"]
; a_onclick [%client fun _ -> Lwt.async ~%close] ]
@@ -171,7 +178,7 @@ let%shared
| _ -> Lwt.return_none
let%client onload_waiter () =
- let* _ = Eliom_client.lwt_onload () in
+ let* _ = Eliom.Client.lwt_onload () in
Lwt.return_unit
(* This thread is used to display only one tip at a time *)
@@ -182,10 +189,10 @@ let%client rec onchangepage_handler _ =
waiter := onload_waiter ();
(* onchangepage handlers are one-off, register ourselves again for
next time *)
- Eliom_client.onchangepage onchangepage_handler;
+ Eliom.Client.onchangepage onchangepage_handler;
Lwt.return_unit
-let%client () = Eliom_client.onchangepage onchangepage_handler
+let%client () = Eliom.Client.onchangepage onchangepage_handler
(* Display a tip bubble *)
let%client
@@ -222,7 +229,7 @@ let%client
let box =
D.div
~a:(a_class ["os-tip"; "os-tip-bubble"] :: a)
- (Os_icons.D.close
+ (Icons.D.close
~a:[a_class ["os-tip-close"]; a_onclick (fun _ -> Lwt.async close)]
()
:: (match arrow with None -> c | _ -> bec :: c))
@@ -233,30 +240,30 @@ let%client
| None -> Dom_html.document##.body
| Some p -> To_dom.of_element p
in
- let* () = Ot_nodeready.nodeready parent_node in
+ let* () = Ot.Nodeready.nodeready parent_node in
let* () = Lwt_js.sleep delay in
let box = To_dom.of_element box in
Dom.appendChild parent_node box;
box##.style##.opacity := Js.string "0";
- Eliom_lib.Option.iter
+ Option.iter
(fun v -> box##.style##.top := Js.string (Printf.sprintf "%ipx" v))
top;
- Eliom_lib.Option.iter
+ Option.iter
(fun v -> box##.style##.left := Js.string (Printf.sprintf "%ipx" v))
left;
- Eliom_lib.Option.iter
+ Option.iter
(fun v -> box##.style##.right := Js.string (Printf.sprintf "%ipx" v))
right;
- Eliom_lib.Option.iter
+ Option.iter
(fun v -> box##.style##.bottom := Js.string (Printf.sprintf "%ipx" v))
bottom;
- Eliom_lib.Option.iter
+ Option.iter
(fun v -> box##.style##.width := Js.string (Printf.sprintf "%ipx" v))
width;
- Eliom_lib.Option.iter
+ Option.iter
(fun v -> box##.style##.height := Js.string (Printf.sprintf "%ipx" v))
height;
- Eliom_lib.Option.iter
+ Option.iter
(fun a ->
let bec = To_dom.of_element bec in
let bec_size = bec##.offsetWidth in
@@ -291,40 +298,40 @@ let%client
let%shared
bubble
?(a :
- [< Html_types.div_attrib > `Class] Eliom_content.Html.D.attrib list
+ [< Html_types.div_attrib > `Class] Eliom.Content.Html.D.attrib list
option)
?(recipient = `All)
?(arrow :
[`left of int | `right of int | `top of int | `bottom of int]
- Eliom_client_value.t
+ Eliom.Client_value.t
option)
- ?(top : int Eliom_client_value.t option)
- ?(left : int Eliom_client_value.t option)
- ?(right : int Eliom_client_value.t option)
- ?(bottom : int Eliom_client_value.t option)
- ?(height : int Eliom_client_value.t option)
- ?(width : int Eliom_client_value.t option)
+ ?(top : int Eliom.Client_value.t option)
+ ?(left : int Eliom.Client_value.t option)
+ ?(right : int Eliom.Client_value.t option)
+ ?(bottom : int Eliom.Client_value.t option)
+ ?(height : int Eliom.Client_value.t option)
+ ?(width : int Eliom.Client_value.t option)
?(parent_node :
- [< `Body | Html_types.body_content] Eliom_content.Html.elt option)
+ [< `Body | Html_types.body_content] Eliom.Content.Html.elt option)
?delay
?onclose
~(name : string)
~(content :
((unit -> unit Lwt.t)
- -> Html_types.div_content Eliom_content.Html.elt list Lwt.t)
- Eliom_client_value.t)
+ -> Html_types.div_content Eliom.Content.Html.elt list Lwt.t)
+ Eliom.Client_value.t)
()
=
let a =
- (a :> Html_types.div_attrib Eliom_content.Html.D.attrib list option)
+ (a :> Html_types.div_attrib Eliom.Content.Html.D.attrib list option)
in
let parent_node =
(parent_node
- :> [`Body | Html_types.body_content] Eliom_content.Html.elt option)
+ :> [`Body | Html_types.body_content] Eliom.Content.Html.elt option)
in
let delay : float option = delay in
- let onclose : (unit -> unit Lwt.t) Eliom_client_value.t option = onclose in
- let myid_o = Os_current_user.Opt.get_current_userid () in
+ let onclose : (unit -> unit Lwt.t) Eliom.Client_value.t option = onclose in
+ let myid_o = Current_user.Opt.get_current_userid () in
match recipient, myid_o with
| `All, _ | `Not_connected, None | `Connected, Some _ ->
let* seen = get_tips_seen () in
diff --git a/src/os_tips.eliomi b/src/Os/tips.eliomi
similarity index 75%
rename from src/os_tips.eliomi
rename to src/Os/tips.eliomi
index 53d9d9677..bdea54875 100644
--- a/src/os_tips.eliomi
+++ b/src/Os/tips.eliomi
@@ -23,25 +23,25 @@
[%%shared.start]
val bubble :
- ?a:[< Html_types.div_attrib > `Class] Eliom_content.Html.D.attrib list
+ ?a:[< Html_types.div_attrib > `Class] Eliom.Content.Html.D.attrib list
-> ?recipient:[> `All | `Connected | `Not_connected]
-> ?arrow:
[`left of int | `right of int | `top of int | `bottom of int]
- Eliom_client_value.t
- -> ?top:int Eliom_client_value.t
- -> ?left:int Eliom_client_value.t
- -> ?right:int Eliom_client_value.t
- -> ?bottom:int Eliom_client_value.t
- -> ?height:int Eliom_client_value.t
- -> ?width:int Eliom_client_value.t
- -> ?parent_node:[< `Body | Html_types.body_content] Eliom_content.Html.elt
+ Eliom.Client_value.t
+ -> ?top:int Eliom.Client_value.t
+ -> ?left:int Eliom.Client_value.t
+ -> ?right:int Eliom.Client_value.t
+ -> ?bottom:int Eliom.Client_value.t
+ -> ?height:int Eliom.Client_value.t
+ -> ?width:int Eliom.Client_value.t
+ -> ?parent_node:[< `Body | Html_types.body_content] Eliom.Content.Html.elt
-> ?delay:float
- -> ?onclose:(unit -> unit Lwt.t) Eliom_client_value.t
+ -> ?onclose:(unit -> unit Lwt.t) Eliom.Client_value.t
-> name:string
-> content:
((unit -> unit Lwt.t)
- -> Html_types.div_content Eliom_content.Html.elt list Lwt.t)
- Eliom_client_value.t
+ -> Html_types.div_content Eliom.Content.Html.elt list Lwt.t)
+ Eliom.Client_value.t
-> unit
-> unit Lwt.t
(** Display tips in pages, as a speech bubble.
@@ -67,15 +67,15 @@ val bubble :
*)
val block :
- ?a:[< Html_types.div_attrib > `Class] Eliom_content.Html.D.attrib list
+ ?a:[< Html_types.div_attrib > `Class] Eliom.Content.Html.D.attrib list
-> ?recipient:[> `All | `Connected | `Not_connected]
- -> ?onclose:(unit -> unit Lwt.t) Eliom_client_value.t
+ -> ?onclose:(unit -> unit Lwt.t) Eliom.Client_value.t
-> name:string
-> content:
- ((unit -> unit Lwt.t) Eliom_client_value.t
- -> Html_types.div_content Eliom_content.Html.elt list Lwt.t)
+ ((unit -> unit Lwt.t) Eliom.Client_value.t
+ -> Html_types.div_content Eliom.Content.Html.elt list Lwt.t)
-> unit
- -> [> `Div] Eliom_content.Html.elt option Lwt.t
+ -> [> `Div] Eliom.Content.Html.elt option Lwt.t
(** Return a box containing a tip, to be inserted where you want in a page.
The box contains a close button. Once it is closed, it is never displayed
again for this user. In that case the function returns [None].
@@ -101,16 +101,16 @@ val tip_seen : string -> bool Lwt.t
val reset_tips_service :
( unit
, unit
- , Eliom_service.post
- , Eliom_service.non_att
- , Eliom_service.co
- , Eliom_service.non_ext
- , Eliom_service.reg
+ , Eliom.Service.post
+ , Eliom.Service.non_att
+ , Eliom.Service.co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
, [`WithoutSuffix]
, unit
, unit
- , Eliom_service.non_ocaml )
- Eliom_service.t
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
(** A non-attached service that will reset tips.
- Call it with [Eliom_client.exit_to] to restart the application and
+ Call it with [Eliom.Client.exit_to] to restart the application and
see tips again. *)
diff --git a/src/os_types.eliom b/src/Os/types.eliom
similarity index 91%
rename from src/os_types.eliom
rename to src/Os/types.eliom
index ebeace2ee..9cbc327b1 100644
--- a/src/os_types.eliom
+++ b/src/Os/types.eliom
@@ -21,7 +21,7 @@
(** Data types
This module defines types used in ocsigen-start in multiple files. It
- gives a more readable interface (for example by using [Os_types.User.id]
+ gives a more readable interface (for example by using [Types.User.id]
instead of [int64]). Put all most used types in this file avoids to have
dependencies between different modules for only one type.
**)
@@ -39,7 +39,7 @@ module User = struct
; avatar : string option
; language : string option }
[@@deriving json]
- (** Type representing a user. See {!Os_user}. *)
+ (** Type representing a user. See {!User}. *)
end
module Action_link_key = struct
@@ -59,5 +59,5 @@ module Group = struct
(** Type representing a group ID *)
type t = {id : id; name : string; desc : string option}
- (** Type representing a group. See {!Os_group} *)
+ (** Type representing a group. See {!Group} *)
end
diff --git a/src/os_types.eliomi b/src/Os/types.eliomi
similarity index 91%
rename from src/os_types.eliomi
rename to src/Os/types.eliomi
index 8c6812c70..14179ab93 100644
--- a/src/os_types.eliomi
+++ b/src/Os/types.eliomi
@@ -21,7 +21,7 @@
(** Data types
This module defines types used in ocsigen-start in multiple files. It
- gives a more readable interface (for example by using [Os_types.User.id]
+ gives a more readable interface (for example by using [Types.User.id]
instead of [int64]). Put all most used types in this file avoids to have
dependencies between different modules for only one type.
**)
@@ -41,7 +41,7 @@ module User : sig
; avatar : string option
; language : string option }
[@@deriving json]
- (** Type representing a user. See {!Os_user}. *)
+ (** Type representing a user. See {!User}. *)
end
(** Types related to action link keys *)
@@ -63,5 +63,5 @@ module Group : sig
(** Type representing a group ID *)
type t = {id : id; name : string; desc : string option}
- (** Type representing a group. See {!Os_group} *)
+ (** Type representing a group. See {!Group} *)
end
diff --git a/src/os_uploader.eliom b/src/Os/uploader.eliom
similarity index 97%
rename from src/os_uploader.eliom
rename to src/Os/uploader.eliom
index 04b88f689..59ede096e 100644
--- a/src/os_uploader.eliom
+++ b/src/Os/uploader.eliom
@@ -97,13 +97,13 @@ let%server crop_image ~src ?(dst = src) ?ratio ~top ~right ~bottom ~left () =
let%server record_image directory ?ratio ?cropping file =
let make_file_saver cp () =
let new_filename () =
- Ocsigen_lib.make_cryptographic_safe_string ()
+ Ocsigen_base.Lib.make_cryptographic_safe_string ()
|> String.map (function '+' -> '-' | '/' -> '_' | c -> c)
in
fun file_info ->
let fname = new_filename () in
let fpath = directory ^ "/" ^ fname in
- let* () = cp (Eliom_request_info.get_tmp_filename file_info) fpath in
+ let* () = cp (Eliom.Request_info.get_tmp_filename file_info) fpath in
Lwt.return fname
in
let cp =
diff --git a/src/os_uploader.eliomi b/src/Os/uploader.eliomi
similarity index 98%
rename from src/os_uploader.eliomi
rename to src/Os/uploader.eliomi
index eff8e5228..c974044fc 100644
--- a/src/os_uploader.eliomi
+++ b/src/Os/uploader.eliomi
@@ -70,7 +70,7 @@ val record_image :
string
-> ?ratio:float
-> ?cropping:float * float * float * float
- -> Ocsigen_extensions.file_info
+ -> Ocsigen.Extensions.file_info
-> string Lwt.t
(** [record_image directory ?ratio ?cropping:(top, right, bottom, left) file]
crops the image like [crop_image] and save it in the directory [directory].
diff --git a/src/os_user.eliom b/src/Os/user.eliom
similarity index 65%
rename from src/os_user.eliom
rename to src/Os/user.eliom
index 372619b22..72df6381e 100644
--- a/src/os_user.eliom
+++ b/src/Os/user.eliom
@@ -21,9 +21,9 @@
open Lwt.Syntax
[%%shared
-type id = Os_types.User.id [@@deriving json]
+type id = Types.User.id [@@deriving json]
-type t = Os_types.User.t =
+type t = Types.User.t =
{ userid : id
; fn : string
; ln : string
@@ -32,29 +32,29 @@ type t = Os_types.User.t =
[@@deriving json]]
[%%server
-exception Already_exists of Os_types.User.id
+exception Already_exists of Types.User.id
exception No_such_user]
let%server wrong_password =
- Eliom_reference.Volatile.eref ~scope:Eliom_common.request_scope false
+ Eliom.Reference.Volatile.eref ~scope:Eliom.Common.request_scope false
let%server no_such_user =
- Eliom_reference.Volatile.eref ~scope:Eliom_common.request_scope false
+ Eliom.Reference.Volatile.eref ~scope:Eliom.Common.request_scope false
let%server account_not_activated =
- Eliom_reference.Volatile.eref ~scope:Eliom_common.request_scope false
+ Eliom.Reference.Volatile.eref ~scope:Eliom.Common.request_scope false
let%server user_already_exists =
- Eliom_reference.Volatile.eref ~scope:Eliom_common.request_scope false
+ Eliom.Reference.Volatile.eref ~scope:Eliom.Common.request_scope false
let%server user_does_not_exist =
- Eliom_reference.Volatile.eref ~scope:Eliom_common.request_scope false
+ Eliom.Reference.Volatile.eref ~scope:Eliom.Common.request_scope false
let%server user_already_preregistered =
- Eliom_reference.Volatile.eref ~scope:Eliom_common.request_scope false
+ Eliom.Reference.Volatile.eref ~scope:Eliom.Common.request_scope false
let%server action_link_key_outdated =
- Eliom_reference.Volatile.eref ~scope:Eliom_common.request_scope false
+ Eliom.Reference.Volatile.eref ~scope:Eliom.Common.request_scope false
(** Create a user of type [t] using db information. *)
let create_user_from_db0 (userid, fn, ln, avatar, pwdset, language) =
@@ -63,7 +63,7 @@ let create_user_from_db0 (userid, fn, ln, avatar, pwdset, language) =
let create_user_from_db d = fst (create_user_from_db0 d)
(** Getters functions. *)
-let%shared userid_of_user (u : Os_types.User.t) = u.userid
+let%shared userid_of_user (u : Types.User.t) = u.userid
let%shared firstname_of_user u = u.fn
let%shared lastname_of_user u = u.ln
@@ -71,14 +71,12 @@ let%shared avatar_of_user u = u.avatar
let%shared language_of_user u = u.language
let%shared avatar_uri_of_avatar ?absolute_path avatar =
- Eliom_content.Html.F.make_uri ?absolute_path
- ~service:(Eliom_service.static_dir ())
+ Eliom.Content.Html.F.make_uri ?absolute_path
+ ~service:(Eliom.Service.static_dir ())
["avatars"; avatar]
let%shared avatar_uri_of_user ?absolute_path user =
- Eliom_lib.Option.map
- (avatar_uri_of_avatar ?absolute_path)
- (avatar_of_user user)
+ Option.map (avatar_uri_of_avatar ?absolute_path) (avatar_of_user user)
let%shared fullname_of_user user =
String.concat " " [firstname_of_user user; lastname_of_user user]
@@ -86,30 +84,30 @@ let%shared fullname_of_user user =
let%shared is_complete user =
not (firstname_of_user user = "" || lastname_of_user user = "")
-let emails_of_user user = Os_db.User.emails_of_userid (userid_of_user user)
-let email_of_user user = Os_db.User.email_of_userid (userid_of_user user)
+let emails_of_user user = Db.User.emails_of_userid (userid_of_user user)
+let email_of_user user = Db.User.email_of_userid (userid_of_user user)
-include Os_db.User
+include Db.User
(* Using cache tools to prevent multiple same database queries
during the request. *)
-module MCache = Os_request_cache.Make (struct
- type key = Os_types.User.id
- type value = Os_types.User.t * bool
+module MCache = Request_cache.Make (struct
+ type key = Types.User.id
+ type value = Types.User.t * bool
let compare = compare
let get key =
Lwt.catch
(fun () ->
- let* g = Os_db.User.user_of_userid key in
+ let* g = Db.User.user_of_userid key in
Lwt.return (create_user_from_db0 g))
(function
- | Os_db.No_such_resource -> Lwt.fail No_such_user
+ | Db.No_such_resource -> Lwt.fail No_such_user
| exc -> Lwt.reraise exc)
end)
-(* Overwrite the function [user_of_userid] of [Os_db.User] and use
+(* Overwrite the function [user_of_userid] of [Db.User] and use
the [get] function of the cache module. *)
let user_of_userid userid =
let* u, _ = MCache.get userid in
@@ -131,8 +129,7 @@ let create ?password ?avatar ?language ?email ~firstname ~lastname () =
let password = match password with Some "" -> None | _ -> password in
let really_create () =
let* userid =
- Os_db.User.create ~firstname ~lastname ?password ?avatar ?language ?email
- ()
+ Db.User.create ~firstname ~lastname ?password ?avatar ?language ?email ()
in
user_of_userid userid
in
@@ -140,17 +137,17 @@ let create ?password ?avatar ?language ?email ~firstname ~lastname () =
| Some email ->
Lwt.catch
(fun () ->
- let* userid = Os_db.User.userid_of_email email in
+ let* userid = Db.User.userid_of_email email in
Lwt.fail (Already_exists userid))
(function
- | Os_db.No_such_resource -> really_create () | exc -> Lwt.reraise exc)
+ | Db.No_such_resource -> really_create () | exc -> Lwt.reraise exc)
| None -> really_create ()
-(* Overwrites the function [update] of [Os_db.User]
+(* Overwrites the function [update] of [Db.User]
to reset the cache *)
let update ?password ?avatar ?language ~firstname ~lastname userid =
let* () =
- Os_db.User.update ?password ?avatar ?language ~firstname ~lastname userid
+ Db.User.update ?password ?avatar ?language ~firstname ~lastname userid
in
MCache.reset userid; Lwt.return_unit
@@ -160,26 +157,23 @@ let update' ?password user =
~lastname:(lastname_of_user user) (userid_of_user user)
let update_password ~userid ~password =
- let* () = Os_db.User.update_password ~userid ~password in
+ let* () = Db.User.update_password ~userid ~password in
MCache.reset userid; Lwt.return_unit
let update_language ~userid ~language =
- let* () = Os_db.User.update_language ~userid ~language in
+ let* () = Db.User.update_language ~userid ~language in
MCache.reset userid; Lwt.return_unit
let update_avatar ~userid ~avatar =
- let* () = Os_db.User.update_avatar ~userid ~avatar in
+ let* () = Db.User.update_avatar ~userid ~avatar in
MCache.reset userid; Lwt.return_unit
-let get_language userid = Os_db.User.get_language userid
+let get_language userid = Db.User.get_language userid
let get_users ?pattern () =
- let* users = Os_db.User.get_users ?pattern () in
+ let* users = Db.User.get_users ?pattern () in
Lwt.return (List.map create_user_from_db users)
-let set_pwd_crypt_fun a = Os_db.pwd_crypt_ref := a
-
-let is_email_validated ~userid ~email =
- Os_db.User.is_email_validated userid email
-
-let is_main_email ~userid ~email = Os_db.User.is_main_email ~email ~userid
+let set_pwd_crypt_fun a = Db.pwd_crypt_ref := a
+let is_email_validated ~userid ~email = Db.User.is_email_validated userid email
+let is_main_email ~userid ~email = Db.User.is_main_email ~email ~userid
diff --git a/src/os_user.eliomi b/src/Os/user.eliomi
similarity index 72%
rename from src/os_user.eliomi
rename to src/Os/user.eliomi
index 22b638311..f2044eb2a 100644
--- a/src/os_user.eliomi
+++ b/src/Os/user.eliomi
@@ -22,21 +22,21 @@
[%%shared.start]
-type id = Os_types.User.id [@@deriving json]
-(** Type alias to {!Os_types.User.id} to allow to use [Os_user.id]. *)
+type id = Types.User.id [@@deriving json]
+(** Type alias to {!Types.User.id} to allow to use [User.id]. *)
-type t = Os_types.User.t =
+type t = Types.User.t =
{ userid : id
; fn : string
; ln : string
; avatar : string option
; language : string option }
[@@deriving json]
-(** Type alias to {!Os_types.User.t} to allow to use [Os_user.t]. *)
+(** Type alias to {!Types.User.t} to allow to use [User.t]. *)
[%%server.start]
-exception Already_exists of Os_types.User.id
+exception Already_exists of Types.User.id
(** Exception used if an user already exists. The parameter is the userid of the
existing user.
*)
@@ -44,44 +44,44 @@ exception Already_exists of Os_types.User.id
exception No_such_user
(** Exception used if an user doesn't exist. *)
-val password_set : Os_types.User.id -> bool Lwt.t
+val password_set : Types.User.id -> bool Lwt.t
(** [password_set userid] returns [true] if the user with ID [userid] has set
a password. Else [false].
*)
-val wrong_password : bool Eliom_reference.Volatile.eref
+val wrong_password : bool Eliom.Reference.Volatile.eref
(** Reference used to remember if a wrong password has been already typed. *)
-val no_such_user : bool Eliom_reference.Volatile.eref
+val no_such_user : bool Eliom.Reference.Volatile.eref
(** Reference used to remember if a wrong user has already been typed. *)
-val account_not_activated : bool Eliom_reference.Volatile.eref
+val account_not_activated : bool Eliom.Reference.Volatile.eref
(** Reference used to remember if the account is activated. *)
-val user_already_exists : bool Eliom_reference.Volatile.eref
+val user_already_exists : bool Eliom.Reference.Volatile.eref
(** Reference used to remember if the user already exists. *)
-val user_does_not_exist : bool Eliom_reference.Volatile.eref
+val user_does_not_exist : bool Eliom.Reference.Volatile.eref
(** Reference used to remember if the user exists. *)
-val user_already_preregistered : bool Eliom_reference.Volatile.eref
+val user_already_preregistered : bool Eliom.Reference.Volatile.eref
(** Reference used to remember if the user is already preregistered. *)
-val action_link_key_outdated : bool Eliom_reference.Volatile.eref
+val action_link_key_outdated : bool Eliom.Reference.Volatile.eref
(** Reference used to remember if an action link key is outdated. *)
[%%shared.start]
-val userid_of_user : Os_types.User.t -> Os_types.User.id
+val userid_of_user : Types.User.t -> Types.User.id
(** [userid_of_user user] returns the userid of the user [user]. *)
-val firstname_of_user : Os_types.User.t -> string
+val firstname_of_user : Types.User.t -> string
(** [firstname_of_user user] returns the first name of the user [user] *)
-val lastname_of_user : Os_types.User.t -> string
+val lastname_of_user : Types.User.t -> string
(** [lastname_of_user user] returns the last name of the user [user] *)
-val avatar_of_user : Os_types.User.t -> string option
+val avatar_of_user : Types.User.t -> string option
(** [avatar_of_user user] returns the avatar of the user [user] as [Some
avatar_uri]. It returns [None] if the user [user] has no avatar.
*)
@@ -89,7 +89,7 @@ val avatar_of_user : Os_types.User.t -> string option
val avatar_uri_of_avatar :
?absolute_path:bool
-> string
- -> Eliom_content.Xml.uri
+ -> Eliom.Content.Xml.uri
(** [avatar_uri_of_avatar ?absolute_path avatar] returns the URI (absolute or
relative) depending on the value of [absolute_path]) of the avatar
[avatar].
@@ -97,29 +97,29 @@ val avatar_uri_of_avatar :
val avatar_uri_of_user :
?absolute_path:bool
- -> Os_types.User.t
- -> Eliom_content.Xml.uri option
+ -> Types.User.t
+ -> Eliom.Content.Xml.uri option
(** [avatar_uri_of_user user] returns the avatar URI (absolute or relative)
depending on the value of [absolute_path]) of the avatar of the user [user].
It returns [None] is the user [user] has no avatar.
*)
-val language_of_user : Os_types.User.t -> string option
+val language_of_user : Types.User.t -> string option
(** [language_of_user user] returns the language of the user [user] *)
-val fullname_of_user : Os_types.User.t -> string
+val fullname_of_user : Types.User.t -> string
(** Retrieve the full name of user (which is the concatenation of the first name
and last name).
*)
-val is_complete : Os_types.User.t -> bool
+val is_complete : Types.User.t -> bool
(** [is_complete user] returns [true] if the first name and the last name of
- {!Os_types.user} have been completed yet.
+ {!Types.user} have been completed yet.
*)
[%%server.start]
-(* Use {!Os_types.actionlinkkey_info} instead of each parameter? *)
+(* Use {!Types.actionlinkkey_info} instead of each parameter? *)
val add_actionlinkkey :
?autoconnect:
(* by default, an action_link key is just an activation key *)
@@ -130,7 +130,7 @@ val add_actionlinkkey :
-> ?validity:int64 (** default: 1L *)
-> ?expiry:CalendarLib.Calendar.t
-> act_key:string
- -> userid:Os_types.User.id
+ -> userid:Types.User.id
-> email:string
-> unit
-> unit Lwt.t
@@ -138,7 +138,7 @@ val add_actionlinkkey :
~email ()] adds the action key in the database.
*)
-val verify_password : email:string -> password:string -> Os_types.User.id Lwt.t
+val verify_password : email:string -> password:string -> Types.User.id Lwt.t
(** [verify_password ~email ~password] returns the userid if user with email
[email] is registered with the password [password].
If [password] the password is wrong,
@@ -149,47 +149,47 @@ val verify_password : email:string -> password:string -> Os_types.User.id Lwt.t
If user is not found, it fails with exception {!No_such_user}.
If password is empty, it fails with exception {!Empty_password}. *)
-val user_of_userid : Os_types.User.id -> Os_types.User.t Lwt.t
+val user_of_userid : Types.User.id -> Types.User.t Lwt.t
(** [user_of_userid userid] returns the information about the user with ID
[userid].
*)
-val get_actionlinkkey_info : string -> Os_types.Action_link_key.info Lwt.t
+val get_actionlinkkey_info : string -> Types.Action_link_key.info Lwt.t
(** Retrieve the data corresponding to an action link key, each
call decrements the validity of the key by [1] if it exists and
[validity > 0] (it remains at [0] if it's already [0]). It is up to
you to adapt the actions according to the value of validity!
- Raises {!Os_db.No_such_resource} if the action link key is not found.
+ Raises {!Db.No_such_resource} if the action link key is not found.
*)
-val userid_of_email : string -> Os_types.User.id Lwt.t
+val userid_of_email : string -> Types.User.id Lwt.t
(** [userid_of_email email] returns the userid of the user with email [email].
- It raises the exception {!Os_db.No_such_resource} if the email [email] is
+ It raises the exception {!Db.No_such_resource} if the email [email] is
not used.
*)
-val emails_of_userid : Os_types.User.id -> string list Lwt.t
+val emails_of_userid : Types.User.id -> string list Lwt.t
(** [emails_of_userid userid] returns the emails list of user with ID
[userid].
*)
-val email_of_userid : Os_types.User.id -> string option Lwt.t
+val email_of_userid : Types.User.id -> string option Lwt.t
(** [email_of_userid userid] returns the main email of user with ID
[userid].
*)
-val emails_of_user : Os_types.User.t -> string list Lwt.t
+val emails_of_user : Types.User.t -> string list Lwt.t
(** [emails_of_user user] returns the emails list of user [user]. *)
-val email_of_user : Os_types.User.t -> string option Lwt.t
+val email_of_user : Types.User.t -> string option Lwt.t
(** [email_of_user user] returns the main email of user [user]. *)
-val get_language : Os_types.User.id -> string option Lwt.t
+val get_language : Types.User.id -> string option Lwt.t
(** [get_language userid] returns the language of the user with ID [userid]. The
language is retrieved from the database.
*)
-val get_users : ?pattern:string -> unit -> Os_types.User.t list Lwt.t
+val get_users : ?pattern:string -> unit -> Types.User.t list Lwt.t
(** [get_users ?pattern ()] gets users who match the [pattern] (useful for
completion).
*)
@@ -202,7 +202,7 @@ val create :
-> firstname:string
-> lastname:string
-> unit
- -> Os_types.User.t Lwt.t
+ -> Types.User.t Lwt.t
(** [create ?password ?avatar ?language ~firstname ~lastname email] creates a new user
with the given information. An email, the first name and the last name are mandatory.
*)
@@ -213,30 +213,30 @@ val update :
-> ?language:string
-> firstname:string
-> lastname:string
- -> Os_types.User.id
+ -> Types.User.id
-> unit Lwt.t
(** [update ?password ?avatar ?language ~firstname ~lastname userid] update the
given information of the user with ID [userid]. Only given information are
updated.
*)
-val update' : ?password:string -> Os_types.User.t -> unit Lwt.t
-(** Another version of [update] using a type {!Os_types.User.t} instead of
+val update' : ?password:string -> Types.User.t -> unit Lwt.t
+(** Another version of [update] using a type {!Types.User.t} instead of
label.
*)
-val update_password : userid:Os_types.User.id -> password:string -> unit Lwt.t
+val update_password : userid:Types.User.id -> password:string -> unit Lwt.t
(** [update_password ~userid ~password] updates the password only. [password]
must not be hashed: it is done by the function [f_crypt] of the tuple
- {!Os_db.pwd_crypt_ref}.
+ {!Db.pwd_crypt_ref}.
*)
-val update_avatar : userid:Os_types.User.id -> avatar:string -> unit Lwt.t
+val update_avatar : userid:Types.User.id -> avatar:string -> unit Lwt.t
(** [update_avatar ~userid ~avatar] updates the avatar of the user with ID
[userid].
*)
-val update_language : userid:Os_types.User.id -> language:string -> unit Lwt.t
+val update_language : userid:Types.User.id -> language:string -> unit Lwt.t
(** [update_language ~userid ~language] updates the language of the user with ID
[userid].
*)
@@ -263,7 +263,7 @@ val all : ?limit:int64 -> unit -> string list Lwt.t
(** Get [limit] (default: 10) emails from the preregister collections. *)
val set_pwd_crypt_fun :
- (string -> string) * (Os_types.User.id -> string -> string -> bool)
+ (string -> string) * (Types.User.id -> string -> string -> bool)
-> unit
(** By default, passwords are encrypted using Bcrypt.
You can customize this by calling this function
@@ -274,26 +274,23 @@ val set_pwd_crypt_fun :
by user, and as third parameter the hash found in database.
*)
-val remove_email_from_user :
- userid:Os_types.User.id
- -> email:string
- -> unit Lwt.t
+val remove_email_from_user : userid:Types.User.id -> email:string -> unit Lwt.t
(** [remove_email_from_user ~userid ~email] removes the email [email] from the
user with the id [userid]. If the email is registered as the main email for
- the user it fails with the exception {!Os_db.Main_email_removal_attempt}.
+ the user it fails with the exception {!Db.Main_email_removal_attempt}.
*)
-val is_email_validated : userid:Os_types.User.id -> email:string -> bool Lwt.t
+val is_email_validated : userid:Types.User.id -> email:string -> bool Lwt.t
(** [is_email_validated ~userid ~email] returns whether for a user designated by
its id the given email has been validated.
*)
-val is_main_email : userid:Os_types.User.id -> email:string -> bool Lwt.t
+val is_main_email : userid:Types.User.id -> email:string -> bool Lwt.t
(** [is_main_email ~userid ~email] returns whether an email is the main email
registered for a given user designated by its id.
*)
-val update_main_email : userid:Os_types.User.id -> email:string -> unit Lwt.t
+val update_main_email : userid:Types.User.id -> email:string -> unit Lwt.t
(** [update_mail_email ~userid ~email] sets the main email for a user with the
ID [userid] as the email [email].
*)
diff --git a/src/os_user_proxy.eliom b/src/Os/user_proxy.eliom
similarity index 67%
rename from src/os_user_proxy.eliom
rename to src/Os/user_proxy.eliom
index f32328b60..efb9e790f 100644
--- a/src/os_user_proxy.eliom
+++ b/src/Os/user_proxy.eliom
@@ -18,26 +18,26 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*)
-(** This module implements a cache of user using {!Eliom_cscache} which allows to keep synchronized the cache between
+(** This module implements a cache of user using {!Eliom.Cscache} which allows to keep synchronized the cache between
the client and the server.
- Even if there is a cache implementing in {!Os_user} to avoid to do database
+ Even if there is a cache implementing in {!User} to avoid to do database
requests, this last one is implementing only server side.
- TODO: This module must be compared to [Os_request_cache], [Eliom_cscache]
- and [Os_user.MCache]. The idea behind these different modules must be
+ TODO: This module must be compared to [Request_cache], [Eliom.Cscache]
+ and [User.MCache]. The idea behind these different modules must be
compared.
*)
-let%server cache : (Os_types.User.id, Os_types.User.t) Eliom_cscache.t =
- Eliom_cscache.create ()
+let%server cache : (Types.User.id, Types.User.t) Eliom.Cscache.t =
+ Eliom.Cscache.create ()
-let%server get_data_from_db _myid_o userid = Os_user.user_of_userid userid
+let%server get_data_from_db _myid_o userid = User.user_of_userid userid
-let%rpc get_data myid_o (userid : Os_types.User.id) : Os_types.User.t Lwt.t =
+let%rpc get_data myid_o (userid : Types.User.id) : Types.User.t Lwt.t =
get_data_from_db myid_o userid
let%server get_data_from_db_for_client myid_o userid =
get_data_from_db myid_o userid
let%shared get_data_from_cache userid =
- Eliom_cscache.find ~%cache get_data userid
+ Eliom.Cscache.find ~%cache get_data userid
diff --git a/src/os_user_proxy.eliomi b/src/Os/user_proxy.eliomi
similarity index 74%
rename from src/os_user_proxy.eliomi
rename to src/Os/user_proxy.eliomi
index 8f1a25dab..68de54761 100644
--- a/src/os_user_proxy.eliomi
+++ b/src/Os/user_proxy.eliomi
@@ -19,29 +19,26 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*)
-(** This module implements a cache of user using {!Eliom_cscache} which allows to keep synchronized the cache between
+(** This module implements a cache of user using {!Eliom.Cscache} which allows to keep synchronized the cache between
the client and the server.
- Even if there is a cache implemented in {!Os_user} to avoid to do database
+ Even if there is a cache implemented in {!User} to avoid to do database
requests, this last one is implementing only server side. Same for
- {!Os_request_cache} which is also only server-side.
+ {!Request_cache} which is also only server-side.
*)
[%%server.start]
-val cache : (Os_types.User.id, Os_types.User.t) Eliom_cscache.t
-(** Cache keeping userid and user information as a {!Os_types.user} type. *)
+val cache : (Types.User.id, Types.User.t) Eliom.Cscache.t
+(** Cache keeping userid and user information as a {!Types.user} type. *)
-val get_data_from_db : 'a -> Os_types.User.id -> Os_types.User.t Lwt.t
+val get_data_from_db : 'a -> Types.User.id -> Types.User.t Lwt.t
(** [get_data_from_db myid_o userid] returns the user which has ID [userid].
For the moment, [myid_o] is not used but it will be use later.
Data comes from the database, not the cache.
*)
-val get_data_from_db_for_client :
- 'a
- -> Os_types.User.id
- -> Os_types.User.t Lwt.t
+val get_data_from_db_for_client : 'a -> Types.User.id -> Types.User.t Lwt.t
(** [get_data_from_db_for_client myid_o userid] returns the user which has ID
[userid]. For the moment, [myid_o] is not used but it will be use later.
@@ -50,14 +47,14 @@ val get_data_from_db_for_client :
[%%shared.start]
-val get_data : Os_types.User.id -> Os_types.User.t Lwt.t
+val get_data : Types.User.id -> Types.User.t Lwt.t
(** [get_data userid] returns the user which has ID [userid].
For the moment, [myid_o] is not used but it will be use later.
Data comes from the database, not the cache.
*)
-val get_data_from_cache : Os_types.User.id -> Os_types.User.t Lwt.t
+val get_data_from_cache : Types.User.id -> Types.User.t Lwt.t
(** [get_data_from_cache userid] returns the user with ID [userid] saved in
cache.
*)
diff --git a/src/os_user_view.eliom b/src/Os/user_view.eliom
similarity index 84%
rename from src/os_user_view.eliom
rename to src/Os/user_view.eliom
index f012544b1..f510c82e6 100644
--- a/src/os_user_view.eliom
+++ b/src/Os/user_view.eliom
@@ -19,8 +19,8 @@
*)
open%client Lwt.Syntax
-open%shared Eliom_content.Html
-open%shared Eliom_content.Html.F
+open%shared Eliom.Content.Html
+open%shared Eliom.Content.Html.F
open%client Js_of_ocaml
open%client Js_of_ocaml_lwt
@@ -78,17 +78,17 @@ let%client form_override_phone phone_input form =
(Js.Unsafe.coerce form)##.keepmeloggedin##.checked |> Js.to_bool
in
Dom.preventDefault ev;
- Os_connect_phone.connect ~keepmeloggedin ~password number)
+ Connect_phone.connect ~keepmeloggedin ~password number)
(function
- | `Login_ok -> Os_lib.reload ()
+ | `Login_ok -> Lib.reload ()
| `Wrong_password ->
- Os_msg.msg ~level:`Err "Wrong password";
+ Msg.msg ~level:`Err "Wrong password";
Lwt.return_unit
| `No_such_user ->
- Os_msg.msg ~level:`Err "No such user";
+ Msg.msg ~level:`Err "No such user";
Lwt.return_unit
| `Password_not_set ->
- Os_msg.msg ~level:`Err "User password not set";
+ Msg.msg ~level:`Err "User password not set";
Lwt.return_unit)
else Lwt.return_unit
@@ -111,7 +111,7 @@ let%shared
else None
in
let form =
- D.Form.post_form ?a ~service:Os_services.connect_service
+ D.Form.post_form ?a ~service:Services.connect_service
(fun ((login, password), keepmeloggedin) ->
let pwd_input =
D.Form.input
@@ -119,7 +119,7 @@ let%shared
~name:password ~input_type:`Password D.Form.string
in
let l =
- [ Ot_form.password_toggle pwd_input
+ [ Ot.Form.password_toggle pwd_input
; label
[ D.Form.bool_checkbox_one
~a:[a_checked ()]
@@ -145,25 +145,25 @@ let%shared
form
let%shared disconnect_button ?a ?(text_logout = "Logout") () =
- D.Form.post_form ?a ~service:Os_services.disconnect_service
+ D.Form.post_form ?a ~service:Services.disconnect_service
(fun _ ->
[ D.Form.button_no_value
~a:[a_class ["button"]]
~button_type:`Submit
- [Os_icons.F.signout (); txt text_logout] ])
+ [Icons.F.signout (); txt text_logout] ])
()
let%shared sign_up_form ?a ?a_placeholder_email ?text ?email () =
generic_email_form ?a ?a_placeholder_email ?text ?email
- ~service:Os_services.sign_up_service ()
+ ~service:Services.sign_up_service ()
let%shared forgot_password_form ?a () =
- generic_email_form ?a ~service:Os_services.forgot_password_service ()
+ generic_email_form ?a ~service:Services.forgot_password_service ()
let%client phone_input ~placeholder ~label f =
let button = D.button ~a:[a_class ["button"]] [txt label] in
let inp =
- Os_lib.lwt_bound_input_enter
+ Lib.lwt_bound_input_enter
~a:[D.a_placeholder placeholder; D.a_input_type `Tel]
~button f
in
@@ -171,13 +171,12 @@ let%client phone_input ~placeholder ~label f =
let%client sign_up_by_phone_input ~placeholder label =
phone_input ~placeholder ~label @@ fun number ->
- Eliom_client.change_page ~service:Os_services.confirm_code_signup_service ()
+ Eliom.Client.change_page ~service:Services.confirm_code_signup_service ()
("", ("", ("", number)))
let%client forgot_password_phone_input ~placeholder label =
phone_input ~placeholder ~label
- (Eliom_client.change_page ~service:Os_services.confirm_code_remind_service
- ())
+ (Eliom.Client.change_page ~service:Services.confirm_code_remind_service ())
let%shared
information_form
@@ -193,7 +192,7 @@ let%shared
?(password2 = "")
()
=
- D.Form.post_form ?a ~service:Os_services.set_personal_data_service
+ D.Form.post_form ?a ~service:Services.set_personal_data_service
(fun ((fname, lname), (passwordn1, passwordn2)) ->
let pass1 =
D.Form.input
@@ -224,24 +223,24 @@ let%shared
()
let%shared preregister_form ?a label =
- generic_email_form ?a ~service:Os_services.preregister_service ~label ()
+ generic_email_form ?a ~service:Services.preregister_service ~label ()
let%shared home_button ?a () =
- D.Form.get_form ?a ~service:Os_services.main_service (fun _ ->
+ D.Form.get_form ?a ~service:Services.main_service (fun _ ->
[D.Form.input ~input_type:`Submit ~value:"home" D.Form.string])
let%shared avatar user =
- match Os_user.avatar_uri_of_user user with
+ match User.avatar_uri_of_user user with
| Some src -> img ~alt:"picture" ~a:[a_class ["os-avatar"]] ~src ()
- | None -> Os_icons.F.user ()
+ | None -> Icons.F.user ()
let%shared username user =
let n =
- match Os_user.firstname_of_user user with
+ match User.firstname_of_user user with
| "" ->
- let userid = Os_user.userid_of_user user in
+ let userid = User.userid_of_user user in
[txt ("User " ^ Int64.to_string userid)]
- | s -> [txt s; txt " "; txt (Os_user.lastname_of_user user)]
+ | s -> [txt s; txt " "; txt (User.lastname_of_user user)]
in
div ~a:[a_class ["os_username"]] n
@@ -289,16 +288,16 @@ let%shared
?(content = [txt "Change profile picture"])
?(crop = Some 1.)
?(input :
- Html_types.label_attrib Eliom_content.Html.D.Raw.attrib list
- * Html_types.label_content_fun Eliom_content.Html.D.Raw.elt list =
+ Html_types.label_attrib Eliom.Content.Html.D.Raw.attrib list
+ * Html_types.label_content_fun Eliom.Content.Html.D.Raw.elt list =
[], [])
?(submit :
- Html_types.button_attrib Eliom_content.Html.D.Raw.attrib list
- * Html_types.button_content_fun Eliom_content.Html.D.Raw.elt list =
+ Html_types.button_attrib Eliom.Content.Html.D.Raw.attrib list
+ * Html_types.button_content_fun Eliom.Content.Html.D.Raw.elt list =
[], [txt "Submit"])
- ?(onclick : (unit -> unit) Eliom_client_value.t =
+ ?(onclick : (unit -> unit) Eliom.Client_value.t =
[%client (fun () -> () : unit -> unit)])
- (service : (unit, unit) Ot_picture_uploader.service)
+ (service : (unit, unit) Ot.Picture_uploader.service)
=
D.Raw.a
~a:
@@ -308,24 +307,24 @@ let%shared
Lwt.async (fun () ->
~%onclick ();
let upload_service ?progress ?cropping file =
- Ot_picture_uploader.ocaml_service_upload ?progress ?cropping
+ Ot.Picture_uploader.ocaml_service_upload ?progress ?cropping
~service:~%service ~arg:() file
in
Lwt.catch
(fun () ->
ignore
- @@ Ot_popup.popup
- ~close_button:[Os_icons.F.close ()]
+ @@ Ot.Popup.popup
+ ~close_button:[Icons.F.close ()]
~onclose:(fun () ->
- Eliom_client.change_page
- ~service:Eliom_service.reload_action () ())
+ Eliom.Client.change_page
+ ~service:Eliom.Service.reload_action () ())
(fun close ->
- Ot_picture_uploader.mk_form ~crop:~%crop
+ Ot.Picture_uploader.mk_form ~crop:~%crop
~input:~%input ~submit:~%submit
~after_submit:close upload_service);
Lwt.return_unit)
(fun exn ->
- Os_msg.msg ~level:`Err "Error while uploading the picture";
+ Msg.msg ~level:`Err "Error while uploading the picture";
Logs.info (fun fmt -> fmt "→ %s" (Printexc.to_string exn));
Lwt.return_unit))
: _)]
@@ -335,7 +334,7 @@ let%shared
let%shared
reset_tips_link
?(text_link = "See help again from beginning")
- ?(close : (unit -> unit) Eliom_client_value.t =
+ ?(close : (unit -> unit) Eliom.Client_value.t =
[%client (fun () -> () : unit -> unit)])
()
=
@@ -346,7 +345,7 @@ let%shared
async (fun () ->
clicks (To_dom.of_element ~%l) (fun _ _ ->
~%close ();
- Eliom_client.exit_to ~service:Os_tips.reset_tips_service () ();
+ Eliom.Client.exit_to ~service:Tips.reset_tips_service () ();
Lwt.return_unit)))
: unit)];
l
@@ -357,8 +356,7 @@ let%shared disconnect_all_link ?(text_link = "Logout on all my devices") () =
[%client
(Lwt_js_events.(
async (fun () ->
- clicks (To_dom.of_element ~%l) (fun _ _ ->
- Os_session.disconnect_all ())))
+ clicks (To_dom.of_element ~%l) (fun _ _ -> Session.disconnect_all ())))
: unit)];
l
@@ -368,18 +366,18 @@ let%shared
~button
~(popup_content :
((unit -> unit Lwt.t)
- -> [< Html_types.div_content] Eliom_content.Html.elt Lwt.t)
- Eliom_client_value.t)
+ -> [< Html_types.div_content] Eliom.Content.Html.elt Lwt.t)
+ Eliom.Client_value.t)
()
=
ignore
[%client
(Lwt.async (fun () ->
- Lwt_js_events.clicks (Eliom_content.Html.To_dom.of_element ~%button)
+ Lwt_js_events.clicks (Eliom.Content.Html.To_dom.of_element ~%button)
(fun _ _ ->
let* _ =
- Ot_popup.popup ?a:~%a
- ~close_button:[Os_icons.F.close ()]
+ Ot.Popup.popup ?a:~%a
+ ~close_button:[Icons.F.close ()]
~%popup_content
in
Lwt.return_unit))
@@ -484,16 +482,16 @@ let%shared
button
let%shared disconnect_link ?(text_logout = "Logout") ?(a = []) () =
- Eliom_content.Html.D.Raw.a
+ Eliom.Content.Html.D.Raw.a
~a:
(a_onclick
[%client
fun _ ->
Lwt.async (fun () ->
- Eliom_client.change_page ~service:Os_services.disconnect_service
- () ())]
+ Eliom.Client.change_page ~service:Services.disconnect_service ()
+ ())]
:: a)
- [Os_icons.F.signout (); txt text_logout]
+ [Icons.F.signout (); txt text_logout]
let%shared connected_user_box ~user =
let username = username user in
diff --git a/src/os_user_view.eliomi b/src/Os/user_view.eliomi
similarity index 73%
rename from src/os_user_view.eliomi
rename to src/Os/user_view.eliomi
index 69ca0840d..b3eaab463 100644
--- a/src/os_user_view.eliomi
+++ b/src/Os/user_view.eliomi
@@ -21,15 +21,15 @@
(** This module defines functions to create password forms, connection forms,
settings buttons and other common contents arising in applications.
- As Eliom_content.Html.F is opened by default, if the module D is not
+ As Eliom.Content.Html.F is opened by default, if the module D is not
explicitly used, HTML tags will be functional.
*)
[%%client.start]
val check_password_confirmation :
- password:[< Html_types.input] Eliom_content.Html.elt
- -> confirmation:[< Html_types.input] Eliom_content.Html.elt
+ password:[< Html_types.input] Eliom.Content.Html.elt
+ -> confirmation:[< Html_types.input] Eliom.Content.Html.elt
-> unit
(** [check_password_confirmation ~password ~confirmation] adds a listener to
the element [confirmation] which checks if the value of [password] and
@@ -39,26 +39,26 @@ val check_password_confirmation :
[%%shared.start]
val generic_email_form :
- ?a:[< Html_types.form_attrib] Eliom_content.Html.D.attrib list
- -> ?label:string Eliom_content.Html.F.wrap
+ ?a:[< Html_types.form_attrib] Eliom.Content.Html.D.attrib list
+ -> ?label:string Eliom.Content.Html.F.wrap
-> ?a_placeholder_email:string
-> ?text:string
-> ?email:string
-> service:
( unit
, 'a
- , Eliom_service.post
+ , Eliom.Service.post
, 'b
, 'c
, 'd
, 'e
, [< `WithSuffix | `WithoutSuffix]
, 'f
- , [< string Eliom_parameter.setoneradio] Eliom_parameter.param_name
- , Eliom_service.non_ocaml )
- Eliom_service.t
+ , [< string Eliom.Parameter.setoneradio] Eliom.Parameter.param_name
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
-> unit
- -> [> Html_types.form] Eliom_content.Html.D.elt
+ -> [> Html_types.form] Eliom.Content.Html.D.elt
(** [generic_email_form ?a ?label ?text ?email ~service ()] creates an email
POST form with an input of type email and a submit button. Placeholder value
["e-mail address"] is used for the email input.
@@ -76,16 +76,16 @@ val connect_form :
-> ?a_placeholder_pwd:string
-> ?text_keep_me_logged_in:string
-> ?text_sign_in:string
- -> ?a:[< Html_types.form_attrib] Eliom_content.Html.D.attrib list
+ -> ?a:[< Html_types.form_attrib] Eliom.Content.Html.D.attrib list
-> ?email:string
-> unit
- -> [> Html_types.form] Eliom_content.Html.D.elt
+ -> [> Html_types.form] Eliom.Content.Html.D.elt
(** [connect_form ?a ?email ()] creates a POST login form with email, password,
a checkbox to stay logged in (with default text to ["keep me logged in"] in
a span) and a submit button. Default placeholders for input email (resp.
password) is ["Your email"] (resp. ["Your password"]).
- The data is sent to {!Os_services.connect_service}.
+ The data is sent to {!Services.connect_service}.
@param a_placeholder_email text for the placeholder of the email input.
@param a_placeholder_pwd text for the placeholder of the password input.
@@ -96,41 +96,41 @@ val connect_form :
*)
val disconnect_button :
- ?a:[< Html_types.form_attrib] Eliom_content.Html.F.attrib list
+ ?a:[< Html_types.form_attrib] Eliom.Content.Html.F.attrib list
-> ?text_logout:string
-> unit
- -> [> Html_types.form] Eliom_content.Html.F.elt
+ -> [> Html_types.form] Eliom.Content.Html.F.elt
(** [disconnect_button ?a ()] creates a disconnect POST form with a button
without value, a signout icon and a text message ["logout"].
@param a attributes of the form. *)
val sign_up_form :
- ?a:[< Html_types.form_attrib] Eliom_content.Html.D.attrib list
+ ?a:[< Html_types.form_attrib] Eliom.Content.Html.D.attrib list
-> ?a_placeholder_email:string
-> ?text:string
-> ?email:string
-> unit
- -> [> Html_types.form] Eliom_content.Html.D.elt
+ -> [> Html_types.form] Eliom.Content.Html.D.elt
(** [sign_up_form ?a ?email ()] creates a {!generic_email_form} with the service
- {!Os_services.sign_up_service}.
+ {!Services.sign_up_service}.
@param a attributes of the form.
@param email the default value of the email input (default is empty).
*)
val forgot_password_form :
- ?a:[< Html_types.form_attrib] Eliom_content.Html.D.attrib list
+ ?a:[< Html_types.form_attrib] Eliom.Content.Html.D.attrib list
-> unit
- -> [> Html_types.form] Eliom_content.Html.D.elt
+ -> [> Html_types.form] Eliom.Content.Html.D.elt
(** [forgot_password_form ~a ()] creates a {!generic_email_form} with the
- service {!Os_services.forgot_password_service}.
+ service {!Services.forgot_password_service}.
@param a attributes of the form.
*)
val information_form :
- ?a:[< Html_types.form_attrib] Eliom_content.Html.D.attrib list
+ ?a:[< Html_types.form_attrib] Eliom.Content.Html.D.attrib list
-> ?a_placeholder_password:string
-> ?a_placeholder_retype_password:string
-> ?a_placeholder_firstname:string
@@ -141,13 +141,13 @@ val information_form :
-> ?password1:string
-> ?password2:string
-> unit
- -> [> Html_types.form] Eliom_content.Html.D.elt
+ -> [> Html_types.form] Eliom.Content.Html.D.elt
(** [information_form ~a ~firstname ~lastname ~password1 ~password2 ()] creates
a POST form to update the user information like first name, last name and
password.
It also checks (client-side) if the passwords match when the send button is
pressed and a custom validity message is showed if they don't match.
- The data is sent to {!Os_services.set_personal_data_service}.
+ The data is sent to {!Services.set_personal_data_service}.
@param a attributes of the form.
@param a_placeholder_password text for the placeholder of the password input.
@@ -162,33 +162,33 @@ val information_form :
password). *)
val preregister_form :
- ?a:[< Html_types.form_attrib > `OnSubmit] Eliom_content.Html.D.attrib list
- -> string Eliom_content.Html.F.wrap
- -> [> Html_types.form] Eliom_content.Html.D.elt
+ ?a:[< Html_types.form_attrib > `OnSubmit] Eliom.Content.Html.D.attrib list
+ -> string Eliom.Content.Html.F.wrap
+ -> [> Html_types.form] Eliom.Content.Html.D.elt
(** [preregister_form ~a label] creates a {!generic_email_form} with the service
- {!Os_services.preregister_service} and add the label [label] to the email
+ {!Services.preregister_service} and add the label [label] to the email
input form.
@param a attributes of the form.
@param label label for the email input. *)
val home_button :
- ?a:[< Html_types.form_attrib] Eliom_content.Html.F.attrib list
+ ?a:[< Html_types.form_attrib] Eliom.Content.Html.F.attrib list
-> unit
- -> [> Html_types.form] Eliom_content.Html.F.elt
+ -> [> Html_types.form] Eliom.Content.Html.F.elt
(** [home_button ~a ()] creates an input button with value "home" which
redirects to the main service.
@param a attributes of the form. *)
-val avatar : Os_types.User.t -> [> `I | `Img] Eliom_content.Html.F.elt
-(** [avatar user] creates an image HTML tag (with Eliom_content.HTML.F) with an
+val avatar : Types.User.t -> [> `I | `Img] Eliom.Content.Html.F.elt
+(** [avatar user] creates an image HTML tag (with Eliom.Content.HTML.F) with an
alt attribute to ["picture"] and with class ["os-avatar"]. If the user has
- no avatar, the default icon representing the user (see {!Ot_icons.F.user}) is returned.
+ no avatar, the default icon representing the user (see {!Ot.Icons.F.user}) is returned.
@param user the user. *)
-val username : Os_types.User.t -> [> Html_types.div] Eliom_content.Html.F.elt
+val username : Types.User.t -> [> Html_types.div] Eliom.Content.Html.F.elt
(** [username user] creates a div with class ["os_username"] containing:
- [firstname] [lastname] if the user has a firstname.
- ["User "] concatenated with the userid in other cases.
@@ -202,23 +202,23 @@ val password_form :
?a_placeholder_pwd:string
-> ?a_placeholder_confirmation:string
-> ?text_send_button:string
- -> ?a:[< Html_types.form_attrib] Eliom_content.Html.D.attrib list
+ -> ?a:[< Html_types.form_attrib] Eliom.Content.Html.D.attrib list
-> service:
( unit
, 'a
- , Eliom_service.post
+ , Eliom.Service.post
, 'b
, 'c
, 'd
, 'e
, [< `WithSuffix | `WithoutSuffix]
, 'f
- , [< string Eliom_parameter.setoneradio] Eliom_parameter.param_name
- * [< string Eliom_parameter.setoneradio] Eliom_parameter.param_name
- , Eliom_service.non_ocaml )
- Eliom_service.t
+ , [< string Eliom.Parameter.setoneradio] Eliom.Parameter.param_name
+ * [< string Eliom.Parameter.setoneradio] Eliom.Parameter.param_name
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
-> unit
- -> [> Html_types.form] Eliom_content.Html.D.elt
+ -> [> Html_types.form] Eliom.Content.Html.D.elt
(** [password_form ~a ~service ()] defines a POST form with two inputs for a
password form (password and password confirmation) and a send button.
It also checks (client-side) if the passwords match when the send button is
@@ -231,18 +231,18 @@ val password_form :
@param service service which the data is sent to. *)
val upload_pic_link :
- ?a:[< Html_types.a_attrib > `OnClick] Eliom_content.Html.D.Raw.attrib list
- -> ?content:Html_types.a_content Eliom_content.Html.D.Raw.elt list
+ ?a:[< Html_types.a_attrib > `OnClick] Eliom.Content.Html.D.Raw.attrib list
+ -> ?content:Html_types.a_content Eliom.Content.Html.D.Raw.elt list
-> ?crop:float option
-> ?input:
- Html_types.label_attrib Eliom_content.Html.D.Raw.attrib list
- * Html_types.label_content_fun Eliom_content.Html.D.Raw.elt list
+ Html_types.label_attrib Eliom.Content.Html.D.Raw.attrib list
+ * Html_types.label_content_fun Eliom.Content.Html.D.Raw.elt list
-> ?submit:
- Html_types.button_attrib Eliom_content.Html.D.Raw.attrib list
- * Html_types.button_content_fun Eliom_content.Html.D.Raw.elt list
- -> ?onclick:(unit -> unit) Eliom_client_value.t
- -> (unit, unit) Ot_picture_uploader.service
- -> [> `A of Html_types.a_content] Eliom_content.Html.D.Raw.elt
+ Html_types.button_attrib Eliom.Content.Html.D.Raw.attrib list
+ * Html_types.button_content_fun Eliom.Content.Html.D.Raw.elt list
+ -> ?onclick:(unit -> unit) Eliom.Client_value.t
+ -> (unit, unit) Ot.Picture_uploader.service
+ -> [> `A of Html_types.a_content] Eliom.Content.Html.D.Raw.elt
(** [upload_pic_link ?a ?content ?crop ?input ?submit action_after_submit
service userid]
@@ -266,9 +266,9 @@ val upload_pic_link :
val reset_tips_link :
?text_link:string
- -> ?close:(unit -> unit) Eliom_client_value.t
+ -> ?close:(unit -> unit) Eliom.Client_value.t
-> unit
- -> [> `A of [> `PCDATA]] Eliom_content.Html.D.Raw.elt
+ -> [> `A of [> `PCDATA]] Eliom.Content.Html.D.Raw.elt
(** Link to start to see the help from the beginning.
The client function given as first parameter will be called first,
for example to close the menu containing the link.
@@ -279,7 +279,7 @@ val reset_tips_link :
val disconnect_all_link :
?text_link:string
-> unit
- -> [> `A of [> `PCDATA]] Eliom_content.Html.D.Raw.elt
+ -> [> `A of [> `PCDATA]] Eliom.Content.Html.D.Raw.elt
(** Link to disconnect all user sessions.
@param text_link link text.
@@ -287,18 +287,18 @@ val disconnect_all_link :
val disconnect_link :
?text_logout:string
- -> ?a:[< Html_types.a_attrib > `OnClick] Eliom_content.Html.attrib list
+ -> ?a:[< Html_types.a_attrib > `OnClick] Eliom.Content.Html.attrib list
-> unit
- -> [> `A of Html_types.flow5_without_interactive] Eliom_content.Html.F.elt
-(** A link to {!Os_services.disconnect_service}.
+ -> [> `A of Html_types.flow5_without_interactive] Eliom.Content.Html.F.elt
+(** A link to {!Services.disconnect_service}.
@param text_logout the link text.
@param a attributes for the link.
*)
val connected_user_box :
- user:Os_types.User.t
- -> [> Html_types.div] Eliom_content.Html.D.elt
+ user:Types.User.t
+ -> [> Html_types.div] Eliom.Content.Html.D.elt
(** An userbox (in a div with the CSS class ["connected-user-box"]) for connected
users with an icon and the username.
*)
@@ -314,7 +314,7 @@ val connection_box :
-> ?text_sign_up:string
-> ?text_send_button:string
-> unit
- -> [> Html_types.div] Eliom_content.Html.D.elt Lwt.t
+ -> [> Html_types.div] Eliom.Content.Html.D.elt Lwt.t
(** A box (in a div with the CSS class ["os-connection-box"]) with a sign in and
a sign out button. [?text_sign_in] (resp. [text_sign_up]) is the text for the
sign in (resp. sign up) button, default is ["Sign in"] (resp. ["Sign up"]).
@@ -329,9 +329,9 @@ val user_box :
-> ?text_sign_in:string
-> ?text_sign_up:string
-> ?text_send_button:string
- -> ?user:Os_types.User.t
+ -> ?user:Types.User.t
-> unit
- -> [> Html_types.div] Eliom_content.Html.F.elt Lwt.t
+ -> [> Html_types.div] Eliom.Content.Html.F.elt Lwt.t
(** Return {!connection_box} if no user is connected (i.e. [user] is [None]).
Else {!connected_user_box}.
*)
diff --git a/src/client/dune b/src/client/dune
new file mode 100644
index 000000000..cdfd97e37
--- /dev/null
+++ b/src/client/dune
@@ -0,0 +1,32 @@
+(include_subdirs qualified)
+
+(library
+ (public_name ocsigen-start.client)
+ (name ocsigen_start_client)
+ (modes byte)
+ (wrapped false)
+ (preprocess
+ (pps js_of_ocaml-ppx js_of_ocaml-ppx_deriving_json))
+ (libraries eliom.client calendar ocsigen-toolkit.client re.str js_of_ocaml))
+
+(include dune.client)
+
+(rule
+ (target dune.client)
+ (mode promote)
+ (deps
+ (glob_files ../Os/*.eliom)
+ (glob_files ../Os/*.eliomi))
+ (action
+ (with-stdout-to
+ %{target}
+ (run
+ ocsigen-dune-rules
+ gen
+ --subdir
+ Os
+ --internal-prefix
+ Os
+ --server-objs-dir
+ ../.ocsigen_start_server.objs/byte
+ ../Os))))
diff --git a/src/client/dune.client b/src/client/dune.client
new file mode 100644
index 000000000..274418dd6
--- /dev/null
+++ b/src/client/dune.client
@@ -0,0 +1,220 @@
+(subdir Os
+ (rule
+ (with-stdout-to comet.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/comet.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Comet.cmo} %{dep:../../Os/comet.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to comet.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/comet.eliomi} -internal-prefix Os --intf %{dep:../../Os/comet.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to connect_phone.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/connect_phone.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Connect_phone.cmo} %{dep:../../Os/connect_phone.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to connect_phone.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/connect_phone.eliomi} -internal-prefix Os --intf %{dep:../../Os/connect_phone.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to current_user.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/current_user.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Current_user.cmo} %{dep:../../Os/current_user.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to current_user.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/current_user.eliomi} -internal-prefix Os --intf %{dep:../../Os/current_user.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to date.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/date.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Date.cmo} %{dep:../../Os/date.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to date.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/date.eliomi} -internal-prefix Os --intf %{dep:../../Os/date.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to email.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/email.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Email.cmo} %{dep:../../Os/email.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to email.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/email.eliomi} -internal-prefix Os --intf %{dep:../../Os/email.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to fcm_notif.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/fcm_notif.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Fcm_notif.cmo} %{dep:../../Os/fcm_notif.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to fcm_notif.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/fcm_notif.eliomi} -internal-prefix Os --intf %{dep:../../Os/fcm_notif.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to handlers.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/handlers.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Handlers.cmo} %{dep:../../Os/handlers.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to handlers.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/handlers.eliomi} -internal-prefix Os --intf %{dep:../../Os/handlers.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to icons.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/icons.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Icons.cmo} %{dep:../../Os/icons.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to icons.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/icons.eliomi} -internal-prefix Os --intf %{dep:../../Os/icons.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to lib.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/lib.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Lib.cmo} %{dep:../../Os/lib.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to lib.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/lib.eliomi} -internal-prefix Os --intf %{dep:../../Os/lib.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to msg.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/msg.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Msg.cmo} %{dep:../../Os/msg.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to msg.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/msg.eliomi} -internal-prefix Os --intf %{dep:../../Os/msg.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to notif.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/notif.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Notif.cmo} %{dep:../../Os/notif.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to notif.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/notif.eliomi} -internal-prefix Os --intf %{dep:../../Os/notif.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to page.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/page.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Page.cmo} %{dep:../../Os/page.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to page.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/page.eliomi} -internal-prefix Os --intf %{dep:../../Os/page.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to platform.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/platform.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Platform.cmo} %{dep:../../Os/platform.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to platform.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/platform.eliomi} -internal-prefix Os --intf %{dep:../../Os/platform.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to request_cache.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/request_cache.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Request_cache.cmo} %{dep:../../Os/request_cache.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to request_cache.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/request_cache.eliomi} -internal-prefix Os --intf %{dep:../../Os/request_cache.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to services.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/services.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Services.cmo} %{dep:../../Os/services.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to services.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/services.eliomi} -internal-prefix Os --intf %{dep:../../Os/services.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to session.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/session.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Session.cmo} %{dep:../../Os/session.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to session.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/session.eliomi} -internal-prefix Os --intf %{dep:../../Os/session.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to tips.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/tips.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Tips.cmo} %{dep:../../Os/tips.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to tips.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/tips.eliomi} -internal-prefix Os --intf %{dep:../../Os/tips.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to types.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/types.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Types.cmo} %{dep:../../Os/types.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to types.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/types.eliomi} -internal-prefix Os --intf %{dep:../../Os/types.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to uploader.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/uploader.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__Uploader.cmo} %{dep:../../Os/uploader.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to uploader.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/uploader.eliomi} -internal-prefix Os --intf %{dep:../../Os/uploader.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to user.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/user.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__User.cmo} %{dep:../../Os/user.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to user.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/user.eliomi} -internal-prefix Os --intf %{dep:../../Os/user.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to user_proxy.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/user_proxy.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__User_proxy.cmo} %{dep:../../Os/user_proxy.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to user_proxy.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/user_proxy.eliomi} -internal-prefix Os --intf %{dep:../../Os/user_proxy.eliomi})))))
+(subdir Os
+ (rule
+ (with-stdout-to user_view.eliom
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/user_view.eliom} -internal-prefix Os --impl -server-cmo %{dep:../../.ocsigen_start_server.objs/byte/os__User_view.cmo} %{dep:../../Os/user_view.eliom})))))
+(subdir Os
+ (rule
+ (with-stdout-to user_view.eliomi
+ (chdir %{workspace_root}
+ (run ocsigen-ppx-client -as-pp -loc-filename %{dep:../../Os/user_view.eliomi} -internal-prefix Os --intf %{dep:../../Os/user_view.eliomi})))))
diff --git a/src/compat/client/dune b/src/compat/client/dune
new file mode 100644
index 000000000..ae7179993
--- /dev/null
+++ b/src/compat/client/dune
@@ -0,0 +1,11 @@
+(include_subdirs no)
+
+(library
+ (name ocsigen_start_compat_client)
+ (public_name ocsigen-start-compat.client)
+ (synopsis "Backward-compatible Os_xxx module names (client-side)")
+ (wrapped false)
+ (modes byte)
+ (flags
+ (:standard -w -70))
+ (libraries ocsigen-start.client))
diff --git a/src/compat/client/os_comet.ml b/src/compat/client/os_comet.ml
new file mode 100644
index 000000000..df03b001d
--- /dev/null
+++ b/src/compat/client/os_comet.ml
@@ -0,0 +1 @@
+include Os.Comet
diff --git a/src/compat/client/os_connect_phone.ml b/src/compat/client/os_connect_phone.ml
new file mode 100644
index 000000000..701d6baad
--- /dev/null
+++ b/src/compat/client/os_connect_phone.ml
@@ -0,0 +1 @@
+include Os.Connect_phone
diff --git a/src/compat/client/os_current_user.ml b/src/compat/client/os_current_user.ml
new file mode 100644
index 000000000..8e3e3c5cc
--- /dev/null
+++ b/src/compat/client/os_current_user.ml
@@ -0,0 +1 @@
+include Os.Current_user
diff --git a/src/compat/client/os_date.ml b/src/compat/client/os_date.ml
new file mode 100644
index 000000000..b54b725d6
--- /dev/null
+++ b/src/compat/client/os_date.ml
@@ -0,0 +1 @@
+include Os.Date
diff --git a/src/compat/client/os_email.ml b/src/compat/client/os_email.ml
new file mode 100644
index 000000000..f0cb1ba9b
--- /dev/null
+++ b/src/compat/client/os_email.ml
@@ -0,0 +1 @@
+include Os.Email
diff --git a/src/compat/client/os_fcm_notif.ml b/src/compat/client/os_fcm_notif.ml
new file mode 100644
index 000000000..394513b1d
--- /dev/null
+++ b/src/compat/client/os_fcm_notif.ml
@@ -0,0 +1 @@
+include Os.Fcm_notif
diff --git a/src/compat/client/os_handlers.ml b/src/compat/client/os_handlers.ml
new file mode 100644
index 000000000..1df93cb5e
--- /dev/null
+++ b/src/compat/client/os_handlers.ml
@@ -0,0 +1 @@
+include Os.Handlers
diff --git a/src/compat/client/os_icons.ml b/src/compat/client/os_icons.ml
new file mode 100644
index 000000000..55e1e8745
--- /dev/null
+++ b/src/compat/client/os_icons.ml
@@ -0,0 +1 @@
+include Os.Icons
diff --git a/src/compat/client/os_lib.ml b/src/compat/client/os_lib.ml
new file mode 100644
index 000000000..4d7f87eb2
--- /dev/null
+++ b/src/compat/client/os_lib.ml
@@ -0,0 +1 @@
+include Os.Lib
diff --git a/src/compat/client/os_msg.ml b/src/compat/client/os_msg.ml
new file mode 100644
index 000000000..fa78625c6
--- /dev/null
+++ b/src/compat/client/os_msg.ml
@@ -0,0 +1 @@
+include Os.Msg
diff --git a/src/compat/client/os_notif.ml b/src/compat/client/os_notif.ml
new file mode 100644
index 000000000..1fc21157f
--- /dev/null
+++ b/src/compat/client/os_notif.ml
@@ -0,0 +1 @@
+include Os.Notif
diff --git a/src/compat/client/os_page.ml b/src/compat/client/os_page.ml
new file mode 100644
index 000000000..dc4f6e4d2
--- /dev/null
+++ b/src/compat/client/os_page.ml
@@ -0,0 +1 @@
+include Os.Page
diff --git a/src/compat/client/os_platform.ml b/src/compat/client/os_platform.ml
new file mode 100644
index 000000000..4909a4944
--- /dev/null
+++ b/src/compat/client/os_platform.ml
@@ -0,0 +1 @@
+include Os.Platform
diff --git a/src/compat/client/os_request_cache.ml b/src/compat/client/os_request_cache.ml
new file mode 100644
index 000000000..1f03b65a8
--- /dev/null
+++ b/src/compat/client/os_request_cache.ml
@@ -0,0 +1 @@
+include Os.Request_cache
diff --git a/src/compat/client/os_services.ml b/src/compat/client/os_services.ml
new file mode 100644
index 000000000..97ccd33a9
--- /dev/null
+++ b/src/compat/client/os_services.ml
@@ -0,0 +1 @@
+include Os.Services
diff --git a/src/compat/client/os_session.ml b/src/compat/client/os_session.ml
new file mode 100644
index 000000000..5741a4e93
--- /dev/null
+++ b/src/compat/client/os_session.ml
@@ -0,0 +1 @@
+include Os.Session
diff --git a/src/compat/client/os_tips.ml b/src/compat/client/os_tips.ml
new file mode 100644
index 000000000..83a41bb9f
--- /dev/null
+++ b/src/compat/client/os_tips.ml
@@ -0,0 +1 @@
+include Os.Tips
diff --git a/src/compat/client/os_types.ml b/src/compat/client/os_types.ml
new file mode 100644
index 000000000..0d4de9ddb
--- /dev/null
+++ b/src/compat/client/os_types.ml
@@ -0,0 +1 @@
+include Os.Types
diff --git a/src/compat/client/os_uploader.ml b/src/compat/client/os_uploader.ml
new file mode 100644
index 000000000..3bf79d2c9
--- /dev/null
+++ b/src/compat/client/os_uploader.ml
@@ -0,0 +1 @@
+include Os.Uploader
diff --git a/src/compat/client/os_user.ml b/src/compat/client/os_user.ml
new file mode 100644
index 000000000..5452f5dc8
--- /dev/null
+++ b/src/compat/client/os_user.ml
@@ -0,0 +1 @@
+include Os.User
diff --git a/src/compat/client/os_user_proxy.ml b/src/compat/client/os_user_proxy.ml
new file mode 100644
index 000000000..c87cc63df
--- /dev/null
+++ b/src/compat/client/os_user_proxy.ml
@@ -0,0 +1 @@
+include Os.User_proxy
diff --git a/src/compat/client/os_user_view.ml b/src/compat/client/os_user_view.ml
new file mode 100644
index 000000000..2ea459c3b
--- /dev/null
+++ b/src/compat/client/os_user_view.ml
@@ -0,0 +1 @@
+include Os.User_view
diff --git a/src/compat/server/dune b/src/compat/server/dune
new file mode 100644
index 000000000..364ef85fd
--- /dev/null
+++ b/src/compat/server/dune
@@ -0,0 +1,10 @@
+(include_subdirs no)
+
+(library
+ (name ocsigen_start_compat_server)
+ (public_name ocsigen-start-compat.server)
+ (synopsis "Backward-compatible Os_xxx module names (server-side)")
+ (wrapped false)
+ (flags
+ (:standard -w -70))
+ (libraries ocsigen-start.server))
diff --git a/src/compat/server/os_comet.ml b/src/compat/server/os_comet.ml
new file mode 100644
index 000000000..df03b001d
--- /dev/null
+++ b/src/compat/server/os_comet.ml
@@ -0,0 +1 @@
+include Os.Comet
diff --git a/src/compat/server/os_connect_phone.ml b/src/compat/server/os_connect_phone.ml
new file mode 100644
index 000000000..701d6baad
--- /dev/null
+++ b/src/compat/server/os_connect_phone.ml
@@ -0,0 +1 @@
+include Os.Connect_phone
diff --git a/src/compat/server/os_core_db.ml b/src/compat/server/os_core_db.ml
new file mode 100644
index 000000000..0bcebb0b9
--- /dev/null
+++ b/src/compat/server/os_core_db.ml
@@ -0,0 +1 @@
+include Os.Core_db
diff --git a/src/compat/server/os_current_user.ml b/src/compat/server/os_current_user.ml
new file mode 100644
index 000000000..8e3e3c5cc
--- /dev/null
+++ b/src/compat/server/os_current_user.ml
@@ -0,0 +1 @@
+include Os.Current_user
diff --git a/src/compat/server/os_date.ml b/src/compat/server/os_date.ml
new file mode 100644
index 000000000..b54b725d6
--- /dev/null
+++ b/src/compat/server/os_date.ml
@@ -0,0 +1 @@
+include Os.Date
diff --git a/src/compat/server/os_db.ml b/src/compat/server/os_db.ml
new file mode 100644
index 000000000..9f8d8457f
--- /dev/null
+++ b/src/compat/server/os_db.ml
@@ -0,0 +1 @@
+include Os.Db
diff --git a/src/compat/server/os_email.ml b/src/compat/server/os_email.ml
new file mode 100644
index 000000000..f0cb1ba9b
--- /dev/null
+++ b/src/compat/server/os_email.ml
@@ -0,0 +1 @@
+include Os.Email
diff --git a/src/compat/server/os_fcm_notif.ml b/src/compat/server/os_fcm_notif.ml
new file mode 100644
index 000000000..394513b1d
--- /dev/null
+++ b/src/compat/server/os_fcm_notif.ml
@@ -0,0 +1 @@
+include Os.Fcm_notif
diff --git a/src/compat/server/os_group.ml b/src/compat/server/os_group.ml
new file mode 100644
index 000000000..66f4f2f99
--- /dev/null
+++ b/src/compat/server/os_group.ml
@@ -0,0 +1 @@
+include Os.Group
diff --git a/src/compat/server/os_handlers.ml b/src/compat/server/os_handlers.ml
new file mode 100644
index 000000000..1df93cb5e
--- /dev/null
+++ b/src/compat/server/os_handlers.ml
@@ -0,0 +1 @@
+include Os.Handlers
diff --git a/src/compat/server/os_icons.ml b/src/compat/server/os_icons.ml
new file mode 100644
index 000000000..55e1e8745
--- /dev/null
+++ b/src/compat/server/os_icons.ml
@@ -0,0 +1 @@
+include Os.Icons
diff --git a/src/compat/server/os_lib.ml b/src/compat/server/os_lib.ml
new file mode 100644
index 000000000..4d7f87eb2
--- /dev/null
+++ b/src/compat/server/os_lib.ml
@@ -0,0 +1 @@
+include Os.Lib
diff --git a/src/compat/server/os_msg.ml b/src/compat/server/os_msg.ml
new file mode 100644
index 000000000..fa78625c6
--- /dev/null
+++ b/src/compat/server/os_msg.ml
@@ -0,0 +1 @@
+include Os.Msg
diff --git a/src/compat/server/os_notif.ml b/src/compat/server/os_notif.ml
new file mode 100644
index 000000000..1fc21157f
--- /dev/null
+++ b/src/compat/server/os_notif.ml
@@ -0,0 +1 @@
+include Os.Notif
diff --git a/src/compat/server/os_page.ml b/src/compat/server/os_page.ml
new file mode 100644
index 000000000..dc4f6e4d2
--- /dev/null
+++ b/src/compat/server/os_page.ml
@@ -0,0 +1 @@
+include Os.Page
diff --git a/src/compat/server/os_platform.ml b/src/compat/server/os_platform.ml
new file mode 100644
index 000000000..4909a4944
--- /dev/null
+++ b/src/compat/server/os_platform.ml
@@ -0,0 +1 @@
+include Os.Platform
diff --git a/src/compat/server/os_request_cache.ml b/src/compat/server/os_request_cache.ml
new file mode 100644
index 000000000..1f03b65a8
--- /dev/null
+++ b/src/compat/server/os_request_cache.ml
@@ -0,0 +1 @@
+include Os.Request_cache
diff --git a/src/compat/server/os_services.ml b/src/compat/server/os_services.ml
new file mode 100644
index 000000000..97ccd33a9
--- /dev/null
+++ b/src/compat/server/os_services.ml
@@ -0,0 +1 @@
+include Os.Services
diff --git a/src/compat/server/os_session.ml b/src/compat/server/os_session.ml
new file mode 100644
index 000000000..5741a4e93
--- /dev/null
+++ b/src/compat/server/os_session.ml
@@ -0,0 +1 @@
+include Os.Session
diff --git a/src/compat/server/os_tips.ml b/src/compat/server/os_tips.ml
new file mode 100644
index 000000000..83a41bb9f
--- /dev/null
+++ b/src/compat/server/os_tips.ml
@@ -0,0 +1 @@
+include Os.Tips
diff --git a/src/compat/server/os_types.ml b/src/compat/server/os_types.ml
new file mode 100644
index 000000000..0d4de9ddb
--- /dev/null
+++ b/src/compat/server/os_types.ml
@@ -0,0 +1 @@
+include Os.Types
diff --git a/src/compat/server/os_uploader.ml b/src/compat/server/os_uploader.ml
new file mode 100644
index 000000000..3bf79d2c9
--- /dev/null
+++ b/src/compat/server/os_uploader.ml
@@ -0,0 +1 @@
+include Os.Uploader
diff --git a/src/compat/server/os_user.ml b/src/compat/server/os_user.ml
new file mode 100644
index 000000000..5452f5dc8
--- /dev/null
+++ b/src/compat/server/os_user.ml
@@ -0,0 +1 @@
+include Os.User
diff --git a/src/compat/server/os_user_proxy.ml b/src/compat/server/os_user_proxy.ml
new file mode 100644
index 000000000..c87cc63df
--- /dev/null
+++ b/src/compat/server/os_user_proxy.ml
@@ -0,0 +1 @@
+include Os.User_proxy
diff --git a/src/compat/server/os_user_view.ml b/src/compat/server/os_user_view.ml
new file mode 100644
index 000000000..2ea459c3b
--- /dev/null
+++ b/src/compat/server/os_user_view.ml
@@ -0,0 +1 @@
+include Os.User_view
diff --git a/src/dune b/src/dune
index 3154c3c18..42934dae6 100644
--- a/src/dune
+++ b/src/dune
@@ -1,3 +1,5 @@
+(include_subdirs qualified)
+
(env
(_
(flags
@@ -5,11 +7,19 @@
(library
(public_name ocsigen-start.server)
- (name ocsigen_start)
+ (name ocsigen_start_server)
(modes byte native)
(wrapped false)
(preprocess
- (pps eliom.ppx.server js_of_ocaml-ppx_deriving_json ocsigen-ppx-rpc))
+ (pps
+ eliom.ppx.server
+ js_of_ocaml-ppx_deriving_json
+ ocsigen-ppx-rpc
+ --
+ --rpc-internal))
+ (flags
+ (:standard
+ (:include type_includes)))
(libraries
eliom.server
calendar
@@ -21,23 +31,10 @@
pgocaml
resource-pooling))
-(subdir
- client
- (library
- (public_name ocsigen-start.client)
- (name ocsigen_start)
- (modes byte)
- (wrapped false)
- (preprocess
- (pps js_of_ocaml-ppx js_of_ocaml-ppx_deriving_json))
- (libraries eliom.client calendar ocsigen-toolkit.client re.str js_of_ocaml))
- (dynamic_include ../dune.client))
-
(rule
- (deps
- (glob_files *.eliom)
- (glob_files *.eliomi))
+ (target type_includes)
+ (deps (universe))
(action
(with-stdout-to
- dune.client
- (run ocsigen-dune-rules .))))
+ %{target}
+ (system "printf '('; ocamlfind query -i-format js_of_ocaml; printf ')'"))))
diff --git a/src/os_email.eliom b/src/os_email.eliom
deleted file mode 100644
index 63c81560d..000000000
--- a/src/os_email.eliom
+++ /dev/null
@@ -1,64 +0,0 @@
-(* Ocsigen-start
- * http://www.ocsigen.org/ocsigen-start
- *
- * Copyright (C) Université Paris Diderot, CNRS, INRIA, Be Sport.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, with linking exception;
- * either version 2.1 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *)
-
-open Printf
-
-let email_pattern = "^[A-Z0-9._%+-]+@[A-Z0-9.-]+[.][A-Z]+$"
-let from_addr = ref ("team DEFAULT", "noreply@DEFAULT.DEFAULT")
-let mailer = ref "sendmail"
-let set_from_addr s = from_addr := s
-let set_mailer s = mailer := s
-let get_mailer () = !mailer
-
-exception Invalid_mailer of string
-
-let email_pattern = email_pattern
-let email_regexp = Str.regexp_case_fold email_pattern
-let is_valid email = Str.string_match email_regexp email 0
-
-let default_send ?url:_ ~from_addr ~to_addrs ~subject:_ content =
- let echo = printf "%s\n" in
- let flush () = printf "%!" in
- let print_tuple (a, b) = printf " (%s,%s)\n" a b in
- let content =
- if List.length content = 0
- then ""
- else
- List.fold_left
- (fun s1 s2 -> s1 ^ "\n" ^ s2)
- (List.hd content) (List.tl content)
- in
- echo "Sending e-mail:";
- echo "[from_addr]: ";
- print_tuple from_addr;
- echo "[to_addrs]: [";
- List.iter print_tuple to_addrs;
- echo "]";
- printf "[content]:\n%s\n" content;
- echo "Please set your own sendmail function using Os_email.set_send";
- flush ();
- Lwt.return ()
-
-let send_ref = ref default_send
-
-let send ?url ?(from_addr = !from_addr) ~to_addrs ~subject content =
- !send_ref ?url ~from_addr ~to_addrs ~subject content
-
-let set_send s = send_ref := s
diff --git a/src/os_services.eliomi b/src/os_services.eliomi
deleted file mode 100644
index 36de3c9da..000000000
--- a/src/os_services.eliomi
+++ /dev/null
@@ -1,321 +0,0 @@
-(* Ocsigen-start
-
- * http://www.ocsigen.org/ocsigen-start
- *
- * Copyright (C) Université Paris Diderot, CNRS, INRIA, Be Sport.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, with linking exception;
- * either version 2.1 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *)
-
-[%%shared.start]
-(** This module provides pre-defined services for connect, disconnect, sign up,
- add a new email, etc. Each service has a corresponding handler in
- {!Os_handlers}.
- *)
-
-val main_service :
- ( unit
- , unit
- , Eliom_service.get
- , Eliom_service.att
- , Eliom_service.non_co
- , Eliom_service.non_ext
- , Eliom_service.reg
- , [`WithoutSuffix]
- , unit
- , unit
- , Eliom_service.non_ocaml )
- Eliom_service.t
-(** The main service. *)
-
-val preregister_service :
- ( unit
- , string
- , Eliom_service.post
- , Eliom_service.non_att
- , Eliom_service.co
- , Eliom_service.non_ext
- , Eliom_service.reg
- , [`WithoutSuffix]
- , unit
- , [`One of string] Eliom_parameter.param_name
- , Eliom_service.non_ocaml )
- Eliom_service.t
-(** A POST service to preregister a user. By default, an email is
- enough. *)
-
-val forgot_password_service :
- ( unit
- , string
- , Eliom_service.post
- , Eliom_service.non_att
- , Eliom_service.co
- , Eliom_service.non_ext
- , Eliom_service.reg
- , [`WithoutSuffix]
- , unit
- , [`One of string] Eliom_parameter.param_name
- , Eliom_service.non_ocaml )
- Eliom_service.t
-(** A POST service when the user forgot his password.
- See {!Os_handlers.forgot_password_handler} for a default handler.
- *)
-
-val set_personal_data_service :
- ( unit
- , (string * string) * (string * string)
- , Eliom_service.post
- , Eliom_service.non_att
- , Eliom_service.co
- , Eliom_service.non_ext
- , Eliom_service.reg
- , [`WithoutSuffix]
- , unit
- , ([`One of string] Eliom_parameter.param_name
- * [`One of string] Eliom_parameter.param_name)
- * ([`One of string] Eliom_parameter.param_name
- * [`One of string] Eliom_parameter.param_name)
- , Eliom_service.non_ocaml )
- Eliom_service.t
-(** A POST service to update the basic user data like first name, last name and
- password.
- See {!Os_handlers.set_personal_data_handler'} for a default handler.
- *)
-
-val sign_up_service :
- ( unit
- , string
- , Eliom_service.post
- , Eliom_service.non_att
- , Eliom_service.co
- , Eliom_service.non_ext
- , Eliom_service.reg
- , [`WithoutSuffix]
- , unit
- , [`One of string] Eliom_parameter.param_name
- , Eliom_service.non_ocaml )
- Eliom_service.t
-(** A POST service to sign up with only an email address.
- See {!Os_handlers.sign_up_handler} for a default handler.
- *)
-
-val connect_service :
- ( unit
- , (string * string) * bool
- , Eliom_service.post
- , Eliom_service.non_att
- , Eliom_service.co
- , Eliom_service.non_ext
- , Eliom_service.reg
- , [`WithoutSuffix]
- , unit
- , ([`One of string] Eliom_parameter.param_name
- * [`One of string] Eliom_parameter.param_name)
- * [`One of bool] Eliom_parameter.param_name
- , Eliom_service.non_ocaml )
- Eliom_service.t
-(** A POST service to connect a user with username and password.
- See {!Os_handlers.connect_handler} for a default handler.
- *)
-
-val disconnect_service :
- ( unit
- , unit
- , Eliom_service.post
- , Eliom_service.non_att
- , Eliom_service.co
- , Eliom_service.non_ext
- , Eliom_service.reg
- , [`WithoutSuffix]
- , unit
- , unit
- , Eliom_service.non_ocaml )
- Eliom_service.t
-(** A POST service to disconnect the current user.
- See {!Os_handlers.disconnect_handler} for a default handler.
- *)
-
-val action_link_service :
- ( string
- , unit
- , Eliom_service.get
- , Eliom_service.non_att
- , Eliom_service.co
- , Eliom_service.non_ext
- , Eliom_service.reg
- , [`WithoutSuffix]
- , [`One of string] Eliom_parameter.param_name
- , unit
- , Eliom_service.non_ocaml )
- Eliom_service.t
-(** A GET service for action link keys.
- See {!Os_handlers.action_link_handler} for a default handler and
- {!Os_db.action_link_table} for more information about the action
- process.
- *)
-
-val set_password_service :
- ( unit
- , string * string
- , Eliom_service.post
- , Eliom_service.non_att
- , Eliom_service.co
- , Eliom_service.non_ext
- , Eliom_service.reg
- , [`WithoutSuffix]
- , unit
- , [`One of string] Eliom_parameter.param_name
- * [`One of string] Eliom_parameter.param_name
- , Eliom_service.non_ocaml )
- Eliom_service.t
-(** A POST service to update the password. An update password action is
- associated with the confirmation password.
- See {!Os_handlers.set_password_handler'} for a default handler.
- *)
-
-val add_email_service :
- ( unit
- , string
- , Eliom_service.post
- , Eliom_service.non_att
- , Eliom_service.co
- , Eliom_service.non_ext
- , Eliom_service.reg
- , [`WithoutSuffix]
- , unit
- , [`One of string] Eliom_parameter.param_name
- , Eliom_service.non_ocaml )
- Eliom_service.t
-(** A POST service to add an email to a user.
- See {!Os_handlers.add_email_handler} for a default handler.
- *)
-
-val update_language_service :
- ( unit
- , string
- , Eliom_service.post
- , Eliom_service.non_att
- , Eliom_service.co
- , Eliom_service.non_ext
- , Eliom_service.reg
- , [`WithoutSuffix]
- , unit
- , [`One of string] Eliom_parameter.param_name
- , Eliom_service.non_ocaml )
- Eliom_service.t
-(** A POST service to update the language of the current user.
- See {!Os_handlers.update_language_handler} for a default handler.
-*)
-
-val confirm_code_signup_service :
- ( unit
- , string * (string * (string * string))
- , Eliom_service.post
- , Eliom_service.non_att
- , Eliom_service.co
- , Eliom_service.non_ext
- , Eliom_service.reg
- , [`WithoutSuffix]
- , unit
- , [`One of string] Eliom_parameter.param_name
- * ([`One of string] Eliom_parameter.param_name
- * ([`One of string] Eliom_parameter.param_name
- * [`One of string] Eliom_parameter.param_name))
- , Eliom_service.non_ocaml )
- Eliom_service.t
-(** Confirm SMS activation code and (if valid) register new user. *)
-
-val confirm_code_extra_service :
- ( unit
- , string
- , Eliom_service.post
- , Eliom_service.non_att
- , Eliom_service.co
- , Eliom_service.non_ext
- , Eliom_service.reg
- , [`WithoutSuffix]
- , unit
- , [`One of string] Eliom_parameter.param_name
- , Eliom_service.non_ocaml )
- Eliom_service.t
-(** Confirm SMS activation code and (if valid) add new phone number to
- user's account. *)
-
-val confirm_code_recovery_service :
- ( unit
- , string
- , Eliom_service.post
- , Eliom_service.non_att
- , Eliom_service.co
- , Eliom_service.non_ext
- , Eliom_service.reg
- , [`WithoutSuffix]
- , unit
- , [`One of string] Eliom_parameter.param_name
- , Eliom_service.non_ocaml )
- Eliom_service.t
-(** Confirm SMS activation code and (if valid) allow the user to set a
- new password. *)
-
-val confirm_code_remind_service :
- ( unit
- , string
- , Eliom_service.post
- , Eliom_service.non_att
- , Eliom_service.co
- , Eliom_service.non_ext
- , Eliom_service.reg
- , [`WithoutSuffix]
- , unit
- , [`One of string] Eliom_parameter.param_name
- , Eliom_service.non_ocaml )
- Eliom_service.t
-(** Temporary alternate name for [confirm_code_recovery_handler] to
- facilite the transition. *)
-
-val register_settings_service :
- ( unit
- , unit
- , Eliom_service.get
- , Eliom_service.att
- , Eliom_service.non_co
- , Eliom_service.non_ext
- , Eliom_service.reg
- , [`WithoutSuffix]
- , unit
- , unit
- , Eliom_service.non_ocaml )
- Eliom_service.t
- -> unit
-(** Register the settings service (defined in the app rather than in
- the OS lib) because we need to perform redirections to it. *)
-
-(**/**)
-
-val settings_service :
- unit
- -> ( unit
- , unit
- , Eliom_service.get
- , Eliom_service.att
- , Eliom_service.non_co
- , Eliom_service.non_ext
- , Eliom_service.reg
- , [`WithoutSuffix]
- , unit
- , unit
- , Eliom_service.non_ocaml )
- Eliom_service.t
- option
diff --git a/template.distillery/.ocamlformat b/template.distillery/.ocamlformat
index 78fc5bfbf..0f2fcdf5e 100644
--- a/template.distillery/.ocamlformat
+++ b/template.distillery/.ocamlformat
@@ -1,5 +1,5 @@
-version=0.28.1
parse-docstrings = false
+wrap-comments = false
break-cases = fit
break-collection-expressions = fit-or-vertical
break-fun-decl = wrap
diff --git a/template.distillery/PROJECT_NAME.eliom b/template.distillery/PROJECT_NAME.eliom
index 40a605273..30c6734eb 100644
--- a/template.distillery/PROJECT_NAME.eliom
+++ b/template.distillery/PROJECT_NAME.eliom
@@ -4,38 +4,38 @@
let%client add_email_notif () = ()
let%server add_email_notif () =
- if Eliom_reference.Volatile.get Os_user.user_already_exists
- then Os_msg.msg ~level:`Err ~onload:true [%i18n S.email_already_exists]
+ if Eliom.Reference.Volatile.get Os.User.user_already_exists
+ then Os.Msg.msg ~level:`Err ~onload:true [%i18n S.email_already_exists]
let%shared () =
(* Registering services. Feel free to customize handlers. *)
- Eliom_registration.Action.register
- ~service:Os_services.set_personal_data_service
+ Eliom.Registration.Action.register
+ ~service:Os.Services.set_personal_data_service
%%%MODULE_NAME%%%_handlers.set_personal_data_handler;
- Eliom_registration.Redirection.register
- ~service:Os_services.set_password_service
+ Eliom.Registration.Redirection.register
+ ~service:Os.Services.set_password_service
%%%MODULE_NAME%%%_handlers.set_password_handler;
- Eliom_registration.Action.register
- ~service:Os_services.forgot_password_service
+ Eliom.Registration.Action.register
+ ~service:Os.Services.forgot_password_service
%%%MODULE_NAME%%%_handlers.forgot_password_handler;
- Eliom_registration.Action.register ~service:Os_services.preregister_service
+ Eliom.Registration.Action.register ~service:Os.Services.preregister_service
%%%MODULE_NAME%%%_handlers.preregister_handler;
- Eliom_registration.Action.register ~service:Os_services.sign_up_service
- Os_handlers.sign_up_handler;
- Eliom_registration.Action.register ~service:Os_services.connect_service
- Os_handlers.connect_handler;
- Eliom_registration.Unit.register ~service:Os_services.disconnect_service
- (Os_handlers.disconnect_handler ~main_page:true);
- Eliom_registration.Any.register ~service:Os_services.action_link_service
- (Os_session.Opt.connected_fun %%%MODULE_NAME%%%_handlers.action_link_handler);
- Eliom_registration.Action.register ~service:Os_services.add_email_service
+ Eliom.Registration.Action.register ~service:Os.Services.sign_up_service
+ Os.Handlers.sign_up_handler;
+ Eliom.Registration.Action.register ~service:Os.Services.connect_service
+ Os.Handlers.connect_handler;
+ Eliom.Registration.Unit.register ~service:Os.Services.disconnect_service
+ (Os.Handlers.disconnect_handler ~main_page:true);
+ Eliom.Registration.Any.register ~service:Os.Services.action_link_service
+ (Os.Session.Opt.connected_fun %%%MODULE_NAME%%%_handlers.action_link_handler);
+ Eliom.Registration.Action.register ~service:Os.Services.add_email_service
(fun () email ->
- let%lwt () = Os_handlers.add_email_handler () email in
+ let%lwt () = Os.Handlers.add_email_handler () email in
add_email_notif (); Lwt.return_unit);
- Eliom_registration.Action.register
- ~service:Os_services.update_language_service
+ Eliom.Registration.Action.register
+ ~service:Os.Services.update_language_service
%%%MODULE_NAME%%%_handlers.update_language_handler;
- %%%MODULE_NAME%%%_base.App.register ~service:Os_services.main_service
+ %%%MODULE_NAME%%%_base.App.register ~service:Os.Services.main_service
(%%%MODULE_NAME%%%_page.Opt.connected_page
%%%MODULE_NAME%%%_handlers.main_service_handler);
%%%MODULE_NAME%%%_base.App.register ~service:%%%MODULE_NAME%%%_services.about_service
@@ -44,9 +44,9 @@ let%shared () =
(%%%MODULE_NAME%%%_page.Opt.connected_page %%%MODULE_NAME%%%_handlers.settings_handler)
let%server () =
- Eliom_registration.Ocaml.register
+ Eliom.Registration.Ocaml.register
~service:%%%MODULE_NAME%%%_services.upload_user_avatar_service
- (Os_session.connected_fun %%%MODULE_NAME%%%_handlers.upload_user_avatar_handler)
+ (Os.Session.connected_fun %%%MODULE_NAME%%%_handlers.upload_user_avatar_handler)
(* Print more debugging information when is in config file
(DEBUG = yes in Makefile.options).
@@ -58,11 +58,11 @@ let%server () =
(or Log.debug, Log.warn, Log.err etc.)
*)
let%server _ =
- if Eliom_config.get_debugmode ()
+ if Eliom.Config.get_debugmode ()
then (
ignore
[%client
- ((* Eliom_config.debug_timings := true; *)
+ ((* Eliom.Config.debug_timings := true; *)
Logs.set_level (Some Logs.Debug)
: unit)];
(* Enable Debug level only for ocsigenserver, eliom and %%%PROJECT_NAME%%% logs *)
diff --git a/template.distillery/PROJECT_NAME.opam b/template.distillery/PROJECT_NAME.opam
index 707c0315b..74f2694f8 100644
--- a/template.distillery/PROJECT_NAME.opam
+++ b/template.distillery/PROJECT_NAME.opam
@@ -4,7 +4,7 @@ version: "0.1"
synopsis: "%%%PROJECT_NAME%%%"
depends: [
- "eliom" {>= "11.0.0" & < "12.0.0"}
+ "eliom" {>= "13.0~" & < "14.0.0"}
"ocsipersist-pgsql-config" {>= "2.0" & < "3.0"}
- "ocsigen-start" {>= "7.0.0" & < "8.0.0"}
+ "ocsigen-start" {>= "9.0~" & < "10.0.0"}
]
diff --git a/template.distillery/PROJECT_NAME_base.eliom b/template.distillery/PROJECT_NAME_base.eliom
index cad39868f..4e70afec0 100644
--- a/template.distillery/PROJECT_NAME_base.eliom
+++ b/template.distillery/PROJECT_NAME_base.eliom
@@ -3,12 +3,12 @@
let%server () = %%%MODULE_NAME%%%_static_config.set_static_config ()
let%server application_name = !%%%MODULE_NAME%%%_config.app_name
-let%client application_name = Eliom_client.get_application_name ()
+let%client application_name = Eliom.Client.get_application_name ()
let%shared displayed_app_name = "%%%PROJECT_NAME%%%"
(* Database initialization *)
let () =
- Os_db.init
+ Os.Db.init
?host:!%%%MODULE_NAME%%%_config.os_db_host
?port:!%%%MODULE_NAME%%%_config.os_db_port
?user:!%%%MODULE_NAME%%%_config.os_db_user
@@ -17,13 +17,13 @@ let () =
?unix_domain_socket_dir:!%%%MODULE_NAME%%%_config.os_db_unix_domain_socket_dir
()
-let () = Os_email.set_mailer "/usr/sbin/sendmail"
-let () = Os_email.set_from_addr ("%%%PROJECT_NAME%%% team", "noreply@DEFAULT.DEFAULT")
+let () = Os.Email.set_mailer "/usr/sbin/sendmail"
+let () = Os.Email.set_from_addr ("%%%PROJECT_NAME%%% team", "noreply@DEFAULT.DEFAULT")
(* Create a module for the application. See
https://ocsigen.org/eliom/manual/clientserver-applications for more
information. *)
-module%shared App = Eliom_registration.App (struct
+module%shared App = Eliom.Registration.App (struct
let application_name = application_name
let global_data_path = Some ["__global_data__"]
end)
@@ -31,4 +31,4 @@ module%shared App = Eliom_registration.App (struct
(* As the headers (stylesheets, etc) won't change, we ask Eliom not to
update the of the page when changing page. (This also avoids
blinking when changing page in iOS). *)
-let%client _ = Eliom_client.persist_document_head ()
+let%client _ = Eliom.Client.persist_document_head ()
diff --git a/template.distillery/PROJECT_NAME_config.eliom b/template.distillery/PROJECT_NAME_config.eliom
index 9b9b720b6..2cbe0ce8e 100644
--- a/template.distillery/PROJECT_NAME_config.eliom
+++ b/template.distillery/PROJECT_NAME_config.eliom
@@ -36,7 +36,7 @@ let os_db_unix_domain_socket_dir = ref None
(* Application configuration *)
let app =
- let open Ocsigen_extensions.Configuration in
+ let open Ocsigen.Extensions.Configuration in
let attributes =
[ attribute ~name:"name" ~obligatory:true (fun h -> app_name := h)
; attribute ~name:"css" ~obligatory:true (fun h -> css_name := h)
@@ -46,16 +46,16 @@ let app =
(* Avatars configuration *)
let avatars =
- let open Ocsigen_extensions.Configuration in
+ let open Ocsigen.Extensions.Configuration in
let attributes =
[ attribute ~name:"dir" ~obligatory:true (fun h ->
- avatar_dir := Eliom_lib.String.split '/' h) ]
+ avatar_dir := Eliom.Lib.String.split '/' h) ]
in
element ~name:"avatars" ~obligatory:true ~attributes ()
(* Database configuration *)
let os_db =
- let open Ocsigen_extensions.Configuration in
+ let open Ocsigen.Extensions.Configuration in
let attributes =
[ attribute ~name:"host" (fun h -> os_db_host := Some h)
; attribute ~name:"port" (fun h ->
@@ -63,7 +63,7 @@ let os_db =
try Some (int_of_string h)
with Failure _ ->
raise
- @@ Ocsigen_extensions.Error_in_config_file "port is not an integer")
+ @@ Ocsigen.Extensions.Error_in_config_file "port is not an integer")
; attribute ~name:"user" (fun h -> os_db_user := Some h)
; attribute ~name:"password" (fun h -> os_db_password := Some h)
; attribute ~name:"database" (fun h -> os_db_database := Some h)
@@ -73,5 +73,5 @@ let os_db =
element ~name:"os-db" ~attributes ()
let _ =
- if Ocsigen_config.has_configuration_file ()
- then Eliom_config.parse_config [app; avatars; os_db]
+ if Ocsigen.Config.has_configuration_file ()
+ then Eliom.Config.parse_config [app; avatars; os_db]
diff --git a/template.distillery/PROJECT_NAME_config.eliomi b/template.distillery/PROJECT_NAME_config.eliomi
index 30c95567b..301e607c9 100644
--- a/template.distillery/PROJECT_NAME_config.eliomi
+++ b/template.distillery/PROJECT_NAME_config.eliomi
@@ -11,6 +11,6 @@ val os_db_user : string option ref
val os_db_password : string option ref
val os_db_database : string option ref
val os_db_unix_domain_socket_dir : string option ref
-val app : Ocsigen_extensions.Configuration.element
-val avatars : Ocsigen_extensions.Configuration.element
-val os_db : Ocsigen_extensions.Configuration.element
+val app : Ocsigen.Extensions.Configuration.element
+val avatars : Ocsigen.Extensions.Configuration.element
+val os_db : Ocsigen.Extensions.Configuration.element
diff --git a/template.distillery/PROJECT_NAME_container.eliom b/template.distillery/PROJECT_NAME_container.eliom
index 06290d97a..ab6abb051 100644
--- a/template.distillery/PROJECT_NAME_container.eliom
+++ b/template.distillery/PROJECT_NAME_container.eliom
@@ -2,9 +2,9 @@
Feel free to use it, modify it, and redistribute it as you wish. *)
let%shared os_header ?user () =
- let open Eliom_content.Html.F in
+ let open Eliom.Content.Html.F in
let%lwt user_box =
- Os_user_view.user_box ~a_placeholder_email:[%i18n S.your_email]
+ Os.User_view.user_box ~a_placeholder_email:[%i18n S.your_email]
~a_placeholder_pwd:[%i18n S.your_password]
~text_keep_me_logged_in:[%i18n S.keep_logged_in]
~content_popup_forgotpwd:[%i18n S.recover_password ~capitalize:true]
@@ -18,13 +18,13 @@ let%shared os_header ?user () =
~a:[a_class ["os-page-header"]]
[ a
~a:[a_class ["os-page-header-app-name"]]
- ~service:Os_services.main_service
+ ~service:Os.Services.main_service
[txt %%%MODULE_NAME%%%_base.displayed_app_name]
()
; user_box ])
let%shared os_footer () =
- let open Eliom_content.Html.F in
+ let open Eliom.Content.Html.F in
footer
~a:[a_class ["os-page-footer"]]
[ p
@@ -39,10 +39,10 @@ let%shared os_footer () =
let%rpc get_wrong_pdata () :
((string * string) * (string * string)) option Lwt.t
=
- Lwt.return @@ Eliom_reference.Volatile.get Os_msg.wrong_pdata
+ Lwt.return @@ Eliom.Reference.Volatile.get Os.Msg.wrong_pdata
let%shared connected_welcome_box () =
- let open Eliom_content.Html.F in
+ let open Eliom.Content.Html.F in
let%lwt wrong_pdata = get_wrong_pdata () in
let info, ((fn, ln), (p1, p2)) =
match wrong_pdata with
@@ -58,7 +58,7 @@ let%shared connected_welcome_box () =
@@ div
~a:[a_class ["os-welcome-box"]]
[ div [h2 [%i18n welcome ~capitalize:true]; info]
- ; Os_user_view.information_form
+ ; Os.User_view.information_form
~a_placeholder_password:[%i18n S.password]
~a_placeholder_retype_password:[%i18n S.retype_password]
~a_placeholder_firstname:[%i18n S.your_first_name]
@@ -69,22 +69,22 @@ let%shared connected_welcome_box () =
let%shared get_user_data = function
| None -> Lwt.return_none
| Some myid ->
- let%lwt u = Os_user_proxy.get_data myid in
+ let%lwt u = Os.User_proxy.get_data myid in
Lwt.return_some u
let%shared page ?html_a ?a ?title ?head myid_o content =
let%lwt me = get_user_data myid_o in
let%lwt content =
match me with
- | Some me when not (Os_user.is_complete me) ->
+ | Some me when not (Os.User.is_complete me) ->
let%lwt cwb = connected_welcome_box () in
Lwt.return @@ (cwb :: content)
| _ -> Lwt.return @@ content
in
let%lwt h = os_header ?user:me () in
Lwt.return
- (Os_page.content ?html_a ?a ?title ?head
+ (Os.Page.content ?html_a ?a ?title ?head
[ h
- ; Eliom_content.Html.F.(div ~a:[a_class ["os-body"]] content)
+ ; Eliom.Content.Html.F.(div ~a:[a_class ["os-body"]] content)
; os_footer ()
; %%%MODULE_NAME%%%_drawer.make ?user:me () ])
diff --git a/template.distillery/PROJECT_NAME_container.eliomi b/template.distillery/PROJECT_NAME_container.eliomi
index acc076584..9659115df 100644
--- a/template.distillery/PROJECT_NAME_container.eliomi
+++ b/template.distillery/PROJECT_NAME_container.eliomi
@@ -4,32 +4,32 @@
(** This module defines the default template for application pages *)
val%shared os_header :
- ?user:Os_types.User.t
+ ?user:Os.Types.User.t
-> unit
- -> [> `Header] Eliom_content.Html.F.elt Lwt.t
+ -> [> `Header] Eliom.Content.Html.F.elt Lwt.t
(** [os_header ?user ()] defines the header for all pages. In this
template, it's a userbox and the user name is displayed. *)
-val%shared os_footer : unit -> [> `Footer] Eliom_content.Html.F.elt
+val%shared os_footer : unit -> [> `Footer] Eliom.Content.Html.F.elt
(** [os_footer ()] defines a footer for the page. *)
val%shared connected_welcome_box :
unit
- -> [> Html_types.div] Eliom_content.Html.F.elt Lwt.t
+ -> [> Html_types.div] Eliom.Content.Html.F.elt Lwt.t
val%shared get_user_data :
- Os_types.User.id option
- -> Os_types.User.t option Lwt.t
+ Os.Types.User.id option
+ -> Os.Types.User.t option Lwt.t
val%shared page :
- ?html_a:Html_types.html_attrib Eliom_content.Html.attrib list
- -> ?a:Html_types.body_attrib Eliom_content.Html.attrib list
+ ?html_a:Html_types.html_attrib Eliom.Content.Html.attrib list
+ -> ?a:Html_types.body_attrib Eliom.Content.Html.attrib list
-> ?title:string
- -> ?head:[< Html_types.head_content_fun] Eliom_content.Html.elt list
- -> Os_types.User.id option
- -> [< Html_types.div_content_fun > `Div] Eliom_content.Html.F.elt
- Eliom_content.Html.F.list_wrap
- -> Os_page.content Lwt.t
+ -> ?head:[< Html_types.head_content_fun] Eliom.Content.Html.elt list
+ -> Os.Types.User.id option
+ -> [< Html_types.div_content_fun > `Div] Eliom.Content.Html.F.elt
+ Eliom.Content.Html.F.list_wrap
+ -> Os.Page.content Lwt.t
(** [page userid_o content] returns a page personalized for the user
with id [myid_o] and with the content [content]. It adds a header,
a footer, and a drawer menu. If the user profile is not
diff --git a/template.distillery/PROJECT_NAME_drawer.eliom b/template.distillery/PROJECT_NAME_drawer.eliom
index 52a18fef2..4181afd80 100644
--- a/template.distillery/PROJECT_NAME_drawer.eliom
+++ b/template.distillery/PROJECT_NAME_drawer.eliom
@@ -1,7 +1,7 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
-open%shared Eliom_content.Html.F
+open%shared Eliom.Content.Html.F
(** This module defines the drawer menu *)
@@ -12,8 +12,8 @@ let%shared user_menu () =
[ item
[%i18n S.settings ~capitalize:true]
%%%MODULE_NAME%%%_services.settings_service
- ; Eliom_content.Html.F.li
- [ Os_user_view.disconnect_link
+ ; Eliom.Content.Html.F.li
+ [ Os.User_view.disconnect_link
~text_logout:[%i18n S.logout ~capitalize:true]
~a:[a_class ["os-drawer-item"]]
() ] ]
@@ -21,7 +21,7 @@ let%shared user_menu () =
let%shared make ?user () =
let items = if user = None then [] else user_menu () in
let items =
- item [%i18n S.home ~capitalize:true] Os_services.main_service
+ item [%i18n S.home ~capitalize:true] Os.Services.main_service
:: item [%i18n S.about ~capitalize:true] %%%MODULE_NAME%%%_services.about_service
:: Demo_tools.drawer_contents ()
:: items
@@ -31,8 +31,8 @@ let%shared make ?user () =
match user with
| None -> [menu]
| Some user ->
- let user_box = Os_user_view.connected_user_box ~user in
+ let user_box = Os.User_view.connected_user_box ~user in
[user_box; menu]
in
- let drawer, _, _ = Ot_drawer.drawer contents in
+ let drawer, _, _ = Ot.Drawer.drawer contents in
drawer
diff --git a/template.distillery/PROJECT_NAME_handlers.eliom b/template.distillery/PROJECT_NAME_handlers.eliom
index 6820f48f0..633fbb9bb 100644
--- a/template.distillery/PROJECT_NAME_handlers.eliom
+++ b/template.distillery/PROJECT_NAME_handlers.eliom
@@ -1,7 +1,7 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
-open%shared Eliom_content.Html.F
+open%shared Eliom.Content.Html.F
(* Upload user avatar *)
let upload_user_avatar_handler myid () ((), (cropping, photo)) =
@@ -11,11 +11,11 @@ let upload_user_avatar_handler myid () ((), (cropping, photo)) =
(List.tl !%%%MODULE_NAME%%%_config.avatar_dir)
in
let%lwt avatar =
- Os_uploader.record_image avatar_dir ~ratio:1. ?cropping photo
+ Os.Uploader.record_image avatar_dir ~ratio:1. ?cropping photo
in
- let%lwt user = Os_user.user_of_userid myid in
- let old_avatar = Os_user.avatar_of_user user in
- let%lwt () = Os_user.update_avatar ~userid:myid ~avatar in
+ let%lwt user = Os.User.user_of_userid myid in
+ let old_avatar = Os.User.avatar_of_user user in
+ let%lwt () = Os.User.update_avatar ~userid:myid ~avatar in
match old_avatar with
| None -> Lwt.return_unit
| Some old_avatar -> Lwt_unix.unlink (Filename.concat avatar_dir old_avatar)
@@ -23,7 +23,7 @@ let upload_user_avatar_handler myid () ((), (cropping, photo)) =
(* Set personal data *)
let%server set_personal_data_handler =
- Os_session.connected_fun Os_handlers.set_personal_data_handler
+ Os.Session.connected_fun Os.Handlers.set_personal_data_handler
let%rpc set_personal_data_rpc (data : (string * string) * (string * string)) :
unit Lwt.t
@@ -35,7 +35,7 @@ let%client set_personal_data_handler () = set_personal_data_rpc
(* Forgot password *)
let%server forgot_password_handler =
- Os_handlers.forgot_password_handler %%%MODULE_NAME%%%_services.settings_service
+ Os.Handlers.forgot_password_handler %%%MODULE_NAME%%%_services.settings_service
let%rpc forgot_password_rpc (email : string) : unit Lwt.t =
forgot_password_handler () email
@@ -49,23 +49,23 @@ let%client forgot_password_handler () = forgot_password_rpc
let%shared action_link_handler myid_o akey () =
(* We try first the default actions (activation link, reset
password) *)
- try%lwt Os_handlers.action_link_handler myid_o akey () with
- | Os_handlers.No_such_resource | Os_handlers.Invalid_action_key _ ->
- Os_msg.msg ~level:`Err ~onload:true [%i18n S.invalid_action_key];
- Eliom_registration.(appl_self_redirect Action.send) ()
+ try%lwt Os.Handlers.action_link_handler myid_o akey () with
+ | Os.Handlers.No_such_resource | Os.Handlers.Invalid_action_key _ ->
+ Os.Msg.msg ~level:`Err ~onload:true [%i18n S.invalid_action_key];
+ Eliom.Registration.(appl_self_redirect Action.send) ()
| e ->
let%lwt email, phantom_user =
match e with
- | Os_handlers.Account_already_activated_unconnected
- { Os_types.Action_link_key.userid = _
+ | Os.Handlers.Account_already_activated_unconnected
+ { Os.Types.Action_link_key.userid = _
; email
; validity = _
; action = _
; data = _
; autoconnect = _ } ->
Lwt.return (email, false)
- | Os_handlers.Custom_action_link
- ( { Os_types.Action_link_key.userid = _
+ | Os.Handlers.Custom_action_link
+ ( { Os.Types.Action_link_key.userid = _
; email
; validity = _
; action = _
@@ -91,46 +91,46 @@ let%shared action_link_handler myid_o akey () =
let page =
[ div
~a:[a_class ["login-signup-box"]]
- [ Os_user_view.sign_up_form
+ [ Os.User_view.sign_up_form
~a_placeholder_email:[%i18n S.your_email]
~text:[%i18n S.sign_up] ~email () ] ]
in
%%%MODULE_NAME%%%_base.App.send
- (%%%MODULE_NAME%%%_page.make_page (Os_page.content page))
+ (%%%MODULE_NAME%%%_page.make_page (Os.Page.content page))
else
let page =
[ div
~a:[a_class ["login-signup-box"]]
- [ Os_user_view.connect_form
+ [ Os.User_view.connect_form
~a_placeholder_email:[%i18n S.your_email]
~a_placeholder_pwd:[%i18n S.your_password]
~text_keep_me_logged_in:[%i18n S.keep_logged_in]
~text_sign_in:[%i18n S.sign_in] ~email () ] ]
in
%%%MODULE_NAME%%%_base.App.send
- (%%%MODULE_NAME%%%_page.make_page (Os_page.content page))
+ (%%%MODULE_NAME%%%_page.make_page (Os.Page.content page))
else
(*VVV In that case we must do something more complex. Check
whether myid = userid and ask the user what he wants to
do. *)
- let open Eliom_registration in
+ let open Eliom.Registration in
appl_self_redirect Redirection.send
- (Redirection Eliom_service.reload_action)
+ (Redirection Eliom.Service.reload_action)
(* Set password *)
let%server set_password_handler =
- Os_session.connected_fun (fun myid () (pwd, pwd2) ->
- let%lwt () = Os_handlers.set_password_handler myid () (pwd, pwd2) in
- Lwt.return (Eliom_registration.Redirection Eliom_service.reload_action))
+ Os.Session.connected_fun (fun myid () (pwd, pwd2) ->
+ let%lwt () = Os.Handlers.set_password_handler myid () (pwd, pwd2) in
+ Lwt.return (Eliom.Registration.Redirection Eliom.Service.reload_action))
let%client set_password_handler () (pwd, pwd2) =
- let%lwt () = Os_handlers.set_password_rpc (pwd, pwd2) in
- Lwt.return (Eliom_registration.Redirection Eliom_service.reload_action)
+ let%lwt () = Os.Handlers.set_password_rpc (pwd, pwd2) in
+ Lwt.return (Eliom.Registration.Redirection Eliom.Service.reload_action)
(* Preregister *)
-let%server preregister_handler = Os_handlers.preregister_handler
+let%server preregister_handler = Os.Handlers.preregister_handler
let%rpc preregister_rpc (email : string) : unit Lwt.t =
preregister_handler () email
@@ -154,7 +154,7 @@ let%shared main_service_handler myid_o () () =
; p [%i18n welcome_text11] ]
let%shared about_handler myid_o () () =
- let open Eliom_content.Html.F in
+ let open Eliom.Content.Html.F in
%%%MODULE_NAME%%%_container.page
~a:[a_class ["os-page-about"]]
myid_o
@@ -172,9 +172,9 @@ let%shared settings_handler myid_o () () =
%%%MODULE_NAME%%%_container.page myid_o content
let%server update_language_handler () language =
- Os_session.connected_wrapper %%%MODULE_NAME%%%_language.update_language
+ Os.Session.connected_wrapper %%%MODULE_NAME%%%_language.update_language
(%%%MODULE_NAME%%%_i18n.language_of_string language)
let%client update_language_handler () language =
%%%MODULE_NAME%%%_i18n.(set_language (language_of_string language));
- Os_current_user.update_language language
+ Os.Current_user.update_language language
diff --git a/template.distillery/PROJECT_NAME_handlers.eliomi b/template.distillery/PROJECT_NAME_handlers.eliomi
index 089dbf08d..9a477a58a 100644
--- a/template.distillery/PROJECT_NAME_handlers.eliomi
+++ b/template.distillery/PROJECT_NAME_handlers.eliomi
@@ -4,14 +4,14 @@
(** This module defines handlers to upload avatar, upload personal
data, set a new password, and also main handlers (main page, about
page, and settings page). In addition to including all default
- handlers from OS (see {!Os_handlers}), it overrides some of them
+ handlers from OS (see {!Os.Handlers}), it overrides some of them
for the purposes of this template. *)
val%server upload_user_avatar_handler :
- Os_types.User.id
+ Os.Types.User.id
-> unit
-> unit
- * ((float * float * float * float) option * Ocsigen_extensions.file_info)
+ * ((float * float * float * float) option * Ocsigen.Extensions.file_info)
-> unit Lwt.t
(** Update new user avatar with cropping option. The new avatar is saved
and the old one is removed. *)
@@ -21,15 +21,15 @@ val%shared set_personal_data_handler :
-> (string * string) * (string * string)
-> unit Lwt.t
(** Update personal data. It uses the default OS handler
- {!Os_handlers.set_personal_data_handler} and gets the user information
- with {!Os_session.connected_fun}. *)
+ {!Os.Handlers.set_personal_data_handler} and gets the user information
+ with {!Os.Session.connected_fun}. *)
val%shared forgot_password_handler : unit -> string -> unit Lwt.t
(** Reset forgotten password. It uses the default OS handler
- {!Os_handlers.forgot_password_handler} with the main service. *)
+ {!Os.Handlers.forgot_password_handler} with the main service. *)
val%shared action_link_handler :
- Os_types.User.id option
+ Os.Types.User.id option
-> string
-> unit
-> %%%MODULE_NAME%%%_base.App.result Lwt.t
@@ -37,10 +37,10 @@ val%shared action_link_handler :
val%shared set_password_handler :
unit
-> string * string
- -> Eliom_service.non_ocaml Eliom_registration.redirection Lwt.t
+ -> Eliom.Service.non_ocaml Eliom.Registration.redirection Lwt.t
(** Set a new password. It uses the default OS handler
- {!Os_handlers.set_password_handler} and gets the user information
- with {!Os_session.connected_fun}. *)
+ {!Os.Handlers.set_password_handler} and gets the user information
+ with {!Os.Session.connected_fun}. *)
val%shared preregister_handler : unit -> string -> unit Lwt.t
@@ -53,24 +53,24 @@ val%shared preregister_handler : unit -> string -> unit Lwt.t
by sending the userid as first parameter. *)
val%shared main_service_handler :
- Os_types.User.id option
+ Os.Types.User.id option
-> unit
-> unit
- -> Os_page.content Lwt.t
+ -> Os.Page.content Lwt.t
(** The first page of the application *)
val%shared about_handler :
- Os_types.User.id option
+ Os.Types.User.id option
-> unit
-> unit
- -> Os_page.content Lwt.t
+ -> Os.Page.content Lwt.t
(** About page *)
val%shared settings_handler :
- Os_types.User.id option
+ Os.Types.User.id option
-> unit
-> unit
- -> Os_page.content Lwt.t
+ -> Os.Page.content Lwt.t
(** Settings page. If the user is connected (see
{!%%%MODULE_NAME%%%_container.get_user_data}), a settings
container will be created. *)
@@ -78,4 +78,4 @@ val%shared settings_handler :
val%shared update_language_handler :
unit
-> string
- -> Eliom_registration.Action.page Lwt.t
+ -> Eliom.Registration.Action.page Lwt.t
diff --git a/template.distillery/PROJECT_NAME_icons.eliom b/template.distillery/PROJECT_NAME_icons.eliom
index b5b6edc8c..e9c7bcbb7 100644
--- a/template.distillery/PROJECT_NAME_icons.eliom
+++ b/template.distillery/PROJECT_NAME_icons.eliom
@@ -7,7 +7,7 @@
http://fontawesome.io/ for more information and for the complete
list of CSS classes values. *)
-module%shared Make (A : module type of Eliom_content.Html.F) = struct
+module%shared Make (A : Eliom.Content.Html.T) = struct
(** [icon classes ~a:other_css_classes ()] create an icon HTML
attribute with "fa" and [classes] as CSS classes. The HTML tag
"i" is used because it is the de facto standard for icons. The
@@ -15,7 +15,7 @@ module%shared Make (A : module type of Eliom_content.Html.F) = struct
classes with predefined icons. *)
let icon
classes
- ?(a = ([] : Html_types.i_attrib Eliom_content.Html.attrib list))
+ ?(a = ([] : Html_types.i_attrib Eliom.Content.Html.attrib list))
()
=
A.i ~a:(A.a_class ("fa" :: classes) :: a) []
@@ -31,8 +31,8 @@ module%shared Make (A : module type of Eliom_content.Html.F) = struct
complete list of CSS classes available by default. *)
end
-module%shared F = Make (Eliom_content.Html.F)
-module%shared D = Make (Eliom_content.Html.D)
+module%shared F = Make (Eliom.Content.Html.F)
+module%shared D = Make (Eliom.Content.Html.D)
-(* Register this module for use by Os_icon. *)
-module%shared Empty = Os_icons.Register (F) (D)
+(* Register this module for use by Os.Icon. *)
+module%shared Empty = Os.Icons.Register (F) (D)
diff --git a/template.distillery/PROJECT_NAME_language.eliom b/template.distillery/PROJECT_NAME_language.eliom
index cc2834c4a..4d8e51c23 100644
--- a/template.distillery/PROJECT_NAME_language.eliom
+++ b/template.distillery/PROJECT_NAME_language.eliom
@@ -3,7 +3,7 @@
let%server best_matched_language () =
(* lang contains a list of (language_as_string, quality_value) *)
- let lang = Eliom_request_info.get_accept_language () in
+ let lang = Eliom.Request_info.get_accept_language () in
(* If no quality is given, we suppose it's 1 *)
let lang =
List.map (fun (s, q) -> s, match q with Some q -> q | None -> 1.) lang
@@ -24,31 +24,31 @@ let%server best_matched_language () =
let%server update_language lang =
let language = %%%MODULE_NAME%%%_i18n.string_of_language lang in
- let myid_o = Os_current_user.Opt.get_current_userid () in
+ let myid_o = Os.Current_user.Opt.get_current_userid () in
(* Update the server and client values *)
%%%MODULE_NAME%%%_i18n.set_language lang;
ignore [%client (%%%MODULE_NAME%%%_i18n.set_language ~%lang : unit)];
(* Update in the database if a user is connected *)
match myid_o with
| None -> Lwt.return_unit
- | Some userid -> Os_user.update_language ~userid ~language
+ | Some userid -> Os.User.update_language ~userid ~language
let%server _ =
- Os_session.on_start_process (fun _ ->
+ Os.Session.on_start_process (fun _ ->
(* Guess a default language. *)
let%lwt lang = best_matched_language () in
ignore (update_language lang);
Lwt.return_unit);
- Os_session.on_start_connected_process (fun userid ->
+ Os.Session.on_start_connected_process (fun userid ->
(* Set language according to user preferences. *)
let%lwt language =
- match%lwt Os_user.get_language userid with
+ match%lwt Os.User.get_language userid with
| Some lang ->
Lwt.return (%%%MODULE_NAME%%%_i18n.guess_language_of_string lang)
| None ->
let%lwt best_language = best_matched_language () in
ignore
- (Os_user.update_language ~userid
+ (Os.User.update_language ~userid
~language:(%%%MODULE_NAME%%%_i18n.string_of_language best_language));
Lwt.return best_language
in
diff --git a/template.distillery/PROJECT_NAME_main.eliom b/template.distillery/PROJECT_NAME_main.eliom
index 4bfec9ca6..2850a0ad9 100644
--- a/template.distillery/PROJECT_NAME_main.eliom
+++ b/template.distillery/PROJECT_NAME_main.eliom
@@ -4,6 +4,6 @@
module%shared %%%MODULE_NAME%%% = %%%MODULE_NAME%%%
let%server _ =
- Ocsigen_server.start
- [ Ocsigen_server.host
- [Staticmod.run ~dir:"local/var/www/%%%PROJECT_NAME%%%" (); Eliom.run ()] ]
+ Ocsigen.Server.start
+ [ Ocsigen.Server.host
+ [Staticmod.run ~dir:"local/var/www/%%%PROJECT_NAME%%%" (); Eliom.App.run ()] ]
diff --git a/template.distillery/PROJECT_NAME_mobile.eliom b/template.distillery/PROJECT_NAME_mobile.eliom
index e95526c06..318244563 100644
--- a/template.distillery/PROJECT_NAME_mobile.eliom
+++ b/template.distillery/PROJECT_NAME_mobile.eliom
@@ -9,11 +9,11 @@ open%client Js_of_ocaml_lwt
app) early on and subsequent requests from the client will contain
the proper cookies.
- The RPC only initializes Os_date by default, but you can add your
+ The RPC only initializes Os.Date by default, but you can add your
own actions to be performed server side on first client request, if
necessary. *)
let%rpc init_request myid_o (tz : string) : unit Lwt.t =
- ignore myid_o; Os_date.initialize tz; Lwt.return_unit
+ ignore myid_o; Os.Date.initialize tz; Lwt.return_unit
let%client to_lwt f =
let wait, wakeup = Lwt.wait () in
@@ -38,26 +38,26 @@ let%client change_page_gen action =
then initial_change_page := Some action
let%client change_page_uri uri =
- change_page_gen (fun () -> Eliom_client.change_page_uri uri)
+ change_page_gen (fun () -> Eliom.Client.change_page_uri uri)
let%client handle_initial_url () =
- let tz = Os_date.user_tz () in
+ let tz = Os.Date.user_tz () in
let%lwt () = init_request tz in
let%lwt () = ondeviceready in
app_started := true;
match !initial_change_page with
| None ->
- Eliom_client.change_page ~replace:true ~service:Os_services.main_service
+ Eliom.Client.change_page ~replace:true ~service:Os.Services.main_service
() ()
| Some action -> action ()
let%client () =
Lwt.async @@ fun () ->
- if Eliom_client.is_client_app ()
+ if Eliom.Client.is_client_app ()
then (
(* Initialize the application server-side; there should be a
single initial request for that. *)
- Os_date.disable_auto_init ();
+ Os.Date.disable_auto_init ();
let%lwt _ = Lwt_js_events.onload () in
handle_initial_url ())
else Lwt.return_unit
@@ -72,7 +72,7 @@ let%client () =
(Js_of_ocaml.Dom_html.Event.make ev)
(Js_of_ocaml.Dom_html.handler (fun _ ->
Console.console##log (Js_of_ocaml.Js.string ev);
- Eliom_comet.activate ();
+ Eliom.Comet.activate ();
Js_of_ocaml.Js._true))
Js_of_ocaml.Js._false
in
@@ -145,5 +145,5 @@ let%client _ =
If you need to display debugging messages in the client side JS
debugger console, you can do so by uncommenting the following
lines. *)
-(* let () = Eliom_config.debug_timings := true *)
+(* let () = Eliom.Config.debug_timings := true *)
(* let () = Logs.set_level (Some Logs.Debug) *)
diff --git a/template.distillery/PROJECT_NAME_page.eliom b/template.distillery/PROJECT_NAME_page.eliom
index 271d9a7b3..6e1c9fc18 100644
--- a/template.distillery/PROJECT_NAME_page.eliom
+++ b/template.distillery/PROJECT_NAME_page.eliom
@@ -1,10 +1,9 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
-open%shared Eliom_content.Html.F
+open%shared Eliom.Content.Html.F
-module%client Ocsigen_config = struct
- let get_debugmode () = false
-end
+let%server debugmode () = Ocsigen.Config.get_debugmode ()
+let%client debugmode () = false
let%server css_name = !%%%MODULE_NAME%%%_config.css_name
@@ -33,7 +32,7 @@ let%client wasm_name_script = []
let%server app_js () =
if
wasm_name <> ""
- && (Eliom_request_info.get_sitedata ()).Eliom_common.enable_wasm
+ && (Eliom.Request_info.get_sitedata ()).Eliom.Common.enable_wasm
then
(* Use WASM detection script with hashed filenames *)
let app_name = !%%%MODULE_NAME%%%_config.app_name in
@@ -47,7 +46,7 @@ let%client the_local_js = [] (* in index.html *)
let%shared the_local_css = [[css_name]]
module%shared Page_config = struct
- include Os_page.Default_config
+ include Os.Page.Default_config
let title = "%%%PROJECT_NAME%%%"
let local_js = the_local_js
@@ -67,15 +66,15 @@ module%shared Page_config = struct
let default_error_page _ _ exn =
%%%MODULE_NAME%%%_container.page None
- (if Ocsigen_config.get_debugmode ()
+ (if debugmode ()
then [p [txt (Printexc.to_string exn)]]
else [p [txt "Error"]])
let default_connected_error_page myid_o _ _ exn =
%%%MODULE_NAME%%%_container.page myid_o
- (if Ocsigen_config.get_debugmode ()
+ (if debugmode ()
then [p [txt (Printexc.to_string exn)]]
else [p [txt "Error"]])
end
-include%shared Os_page.Make (Page_config)
+include%shared Os.Page.Make (Page_config)
diff --git a/template.distillery/PROJECT_NAME_page.eliomi b/template.distillery/PROJECT_NAME_page.eliomi
index b5af4cd06..83322cd3e 100644
--- a/template.distillery/PROJECT_NAME_page.eliomi
+++ b/template.distillery/PROJECT_NAME_page.eliomi
@@ -2,13 +2,13 @@
Feel free to use it, modify it, and redistribute it as you wish. *)
val%shared css_name : string
-val%shared css_name_script : [> Html_types.script] Eliom_content.Html.F.elt list
+val%shared css_name_script : [> Html_types.script] Eliom.Content.Html.F.elt list
val%shared wasm_name : string
val%shared wasm_name_script :
- [> Html_types.script] Eliom_content.Html.F.elt list
+ [> Html_types.script] Eliom.Content.Html.F.elt list
-val%shared app_js : unit -> [> `Script] Eliom_content.Html.elt list
+val%shared app_js : unit -> [> `Script] Eliom.Content.Html.elt list
val%shared the_local_js : 'a list
val%shared the_local_css : string list list
@@ -21,52 +21,52 @@ module%shared Page_config : sig
val other_head :
unit
- -> Html_types.head_content_fun Eliom_content.Html.elt list
+ -> Html_types.head_content_fun Eliom.Content.Html.elt list
val default_predicate : 'a -> 'b -> bool Lwt.t
val default_connected_predicate : 'a -> 'b -> 'c -> bool Lwt.t
- val default_error_page : 'a -> 'b -> exn -> Os_page.content Lwt.t
+ val default_error_page : 'a -> 'b -> exn -> Os.Page.content Lwt.t
val default_connected_error_page :
- Os_types.User.id option
+ Os.Types.User.id option
-> 'a
-> 'b
-> exn
- -> Os_page.content Lwt.t
+ -> Os.Page.content Lwt.t
end
val%shared make_page :
- Os_page.content
- -> [> Html_types.html] Eliom_content.Html.elt
+ Os.Page.content
+ -> [> Html_types.html] Eliom.Content.Html.elt
val%shared page :
?predicate:('a -> 'b -> bool Lwt.t)
- -> ?fallback:('a -> 'b -> exn -> Os_page.content Lwt.t)
- -> ('a -> 'b -> Os_page.content Lwt.t)
+ -> ?fallback:('a -> 'b -> exn -> Os.Page.content Lwt.t)
+ -> ('a -> 'b -> Os.Page.content Lwt.t)
-> 'a
-> 'b
- -> Html_types.html Eliom_content.Html.elt Lwt.t
+ -> Html_types.html Eliom.Content.Html.elt Lwt.t
module%shared Opt : sig
val connected_page :
- ?allow:Os_types.Group.t list
- -> ?deny:Os_types.Group.t list
- -> ?predicate:(Os_types.User.id option -> 'a -> 'b -> bool Lwt.t)
+ ?allow:Os.Types.Group.t list
+ -> ?deny:Os.Types.Group.t list
+ -> ?predicate:(Os.Types.User.id option -> 'a -> 'b -> bool Lwt.t)
-> ?fallback:
- (Os_types.User.id option -> 'a -> 'b -> exn -> Os_page.content Lwt.t)
- -> (Os_types.User.id option -> 'a -> 'b -> Os_page.content Lwt.t)
+ (Os.Types.User.id option -> 'a -> 'b -> exn -> Os.Page.content Lwt.t)
+ -> (Os.Types.User.id option -> 'a -> 'b -> Os.Page.content Lwt.t)
-> 'a
-> 'b
- -> Html_types.html Eliom_content.Html.elt Lwt.t
+ -> Html_types.html Eliom.Content.Html.elt Lwt.t
end
val%shared connected_page :
- ?allow:Os_types.Group.t list
- -> ?deny:Os_types.Group.t list
- -> ?predicate:(Os_types.User.id option -> 'a -> 'b -> bool Lwt.t)
+ ?allow:Os.Types.Group.t list
+ -> ?deny:Os.Types.Group.t list
+ -> ?predicate:(Os.Types.User.id option -> 'a -> 'b -> bool Lwt.t)
-> ?fallback:
- (Os_types.User.id option -> 'a -> 'b -> exn -> Os_page.content Lwt.t)
- -> (Os_types.User.id -> 'a -> 'b -> Os_page.content Lwt.t)
+ (Os.Types.User.id option -> 'a -> 'b -> exn -> Os.Page.content Lwt.t)
+ -> (Os.Types.User.id -> 'a -> 'b -> Os.Page.content Lwt.t)
-> 'a
-> 'b
- -> Html_types.html Eliom_content.Html.elt Lwt.t
+ -> Html_types.html Eliom.Content.Html.elt Lwt.t
diff --git a/template.distillery/PROJECT_NAME_phone_connect.eliom b/template.distillery/PROJECT_NAME_phone_connect.eliom
index 628925e38..70b124355 100644
--- a/template.distillery/PROJECT_NAME_phone_connect.eliom
+++ b/template.distillery/PROJECT_NAME_phone_connect.eliom
@@ -5,7 +5,7 @@
[enable] has to be set to [true].
- Use [Os_connect_phone.set_send_sms_handler] to register your
+ Use [Os.Connect_phone.set_send_sms_handler] to register your
SMS-sending function, e.g., by using Amazon SNS or Twilio.
You can remove this file if you don't need this functionality. *)
@@ -15,20 +15,20 @@ let%shared enable = false
let%server () =
if enable
then
- Os_connect_phone.set_send_sms_handler (fun ~number message ->
+ Os.Connect_phone.set_send_sms_handler (fun ~number message ->
Printf.printf "Send SMS %s to %s\n%!" message number;
Lwt.return (Ok ()))
let%shared () =
if enable
then (
- Os_user_view.enable_phone ();
- Eliom_registration.Action.register
- ~service:Os_services.confirm_code_recovery_service
- Os_handlers.confirm_code_recovery_handler;
- Eliom_registration.Action.register
- ~service:Os_services.confirm_code_extra_service
- Os_handlers.confirm_code_extra_handler;
- Eliom_registration.Action.register
- ~service:Os_services.confirm_code_signup_service
- Os_handlers.confirm_code_signup_handler)
+ Os.User_view.enable_phone ();
+ Eliom.Registration.Action.register
+ ~service:Os.Services.confirm_code_recovery_service
+ Os.Handlers.confirm_code_recovery_handler;
+ Eliom.Registration.Action.register
+ ~service:Os.Services.confirm_code_extra_service
+ Os.Handlers.confirm_code_extra_handler;
+ Eliom.Registration.Action.register
+ ~service:Os.Services.confirm_code_signup_service
+ Os.Handlers.confirm_code_signup_handler)
diff --git a/template.distillery/PROJECT_NAME_services.eliom b/template.distillery/PROJECT_NAME_services.eliom
index c4c5fa2cd..a74e98bf2 100644
--- a/template.distillery/PROJECT_NAME_services.eliom
+++ b/template.distillery/PROJECT_NAME_services.eliom
@@ -2,25 +2,25 @@
Feel free to use it, modify it, and redistribute it as you wish. *)
let%server about_service =
- Eliom_service.create ~path:(Eliom_service.Path ["about"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["about"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
-let%server upload_user_avatar_service : (unit, unit) Ot_picture_uploader.service
+let%server upload_user_avatar_service : (unit, unit) Ot.Picture_uploader.service
=
- Ot_picture_uploader.mk_service "upload_user_avatar_service" [%json: unit]
+ Ot.Picture_uploader.mk_service "upload_user_avatar_service" [%json: unit]
let%server settings_service =
- Eliom_service.create ~path:(Eliom_service.Path ["settings"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["settings"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%server os_github_service =
- Eliom_service.extern ~prefix:"http://github.com"
+ Eliom.Service.extern ~prefix:"http://github.com"
~path:["ocsigen"; "ocsigen-start"]
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%server ocsigen_service =
- Eliom_service.extern ~prefix:"http://ocsigen.org" ~path:[]
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.extern ~prefix:"http://ocsigen.org" ~path:[]
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client about_service = ~%about_service
let%client upload_user_avatar_service = ~%upload_user_avatar_service
@@ -30,4 +30,4 @@ let%client os_github_service = ~%os_github_service
(* The OS lib needs access to the settings service to perform
redirections to it. We need to register it *)
-let%server () = Os_services.register_settings_service settings_service
+let%server () = Os.Services.register_settings_service settings_service
diff --git a/template.distillery/PROJECT_NAME_services.eliomi b/template.distillery/PROJECT_NAME_services.eliomi
index a6dd2c76d..9a5d090ed 100644
--- a/template.distillery/PROJECT_NAME_services.eliomi
+++ b/template.distillery/PROJECT_NAME_services.eliomi
@@ -4,57 +4,57 @@
val%shared about_service :
( unit
, unit
- , Eliom_service.get
- , Eliom_service.att
- , Eliom_service.non_co
- , Eliom_service.non_ext
- , Eliom_service.reg
+ , Eliom.Service.get
+ , Eliom.Service.att
+ , Eliom.Service.non_co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
, [`WithoutSuffix]
, unit
, unit
- , Eliom_service.non_ocaml )
- Eliom_service.t
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
-val%shared upload_user_avatar_service : (unit, unit) Ot_picture_uploader.service
+val%shared upload_user_avatar_service : (unit, unit) Ot.Picture_uploader.service
val%shared settings_service :
( unit
, unit
- , Eliom_service.get
- , Eliom_service.att
- , Eliom_service.non_co
- , Eliom_service.non_ext
- , Eliom_service.reg
+ , Eliom.Service.get
+ , Eliom.Service.att
+ , Eliom.Service.non_co
+ , Eliom.Service.non_ext
+ , Eliom.Service.reg
, [`WithoutSuffix]
, unit
, unit
- , Eliom_service.non_ocaml )
- Eliom_service.t
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
val%shared os_github_service :
( unit
, unit
- , Eliom_service.get
- , Eliom_service.att
- , Eliom_service.non_co
- , Eliom_service.ext
- , Eliom_service.non_reg
+ , Eliom.Service.get
+ , Eliom.Service.att
+ , Eliom.Service.non_co
+ , Eliom.Service.ext
+ , Eliom.Service.non_reg
, [`WithoutSuffix]
, unit
, unit
- , Eliom_service.non_ocaml )
- Eliom_service.t
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
val%shared ocsigen_service :
( unit
, unit
- , Eliom_service.get
- , Eliom_service.att
- , Eliom_service.non_co
- , Eliom_service.ext
- , Eliom_service.non_reg
+ , Eliom.Service.get
+ , Eliom.Service.att
+ , Eliom.Service.non_co
+ , Eliom.Service.ext
+ , Eliom.Service.non_reg
, [`WithoutSuffix]
, unit
, unit
- , Eliom_service.non_ocaml )
- Eliom_service.t
+ , Eliom.Service.non_ocaml )
+ Eliom.Service.t
diff --git a/template.distillery/PROJECT_NAME_settings.eliom b/template.distillery/PROJECT_NAME_settings.eliom
index 40f39283b..f9103b2d4 100644
--- a/template.distillery/PROJECT_NAME_settings.eliom
+++ b/template.distillery/PROJECT_NAME_settings.eliom
@@ -3,7 +3,7 @@
open%client Js_of_ocaml_lwt
let%shared update_main_email_button email =
- let open Eliom_content.Html in
+ let open Eliom.Content.Html in
let button =
D.button
~a:[D.a_class ["button"]]
@@ -12,17 +12,17 @@ let%shared update_main_email_button email =
ignore
[%client
(Lwt.async (fun () ->
- Lwt_js_events.clicks (Eliom_content.Html.To_dom.of_element ~%button)
+ Lwt_js_events.clicks (Eliom.Content.Html.To_dom.of_element ~%button)
(fun _ _ ->
- let%lwt () = Os_current_user.update_main_email ~%email in
- Eliom_client.change_page
+ let%lwt () = Os.Current_user.update_main_email ~%email in
+ Eliom.Client.change_page
~service:%%%MODULE_NAME%%%_services.settings_service () ()))
: unit)];
button
(* A button to remove the email from the database *)
let%shared delete_email_button email =
- let open Eliom_content.Html in
+ let open Eliom.Content.Html in
let button =
D.button
~a:[D.a_class ["button"; "os-remove-email-button"]]
@@ -31,10 +31,10 @@ let%shared delete_email_button email =
ignore
[%client
(Lwt.async (fun () ->
- Lwt_js_events.clicks (Eliom_content.Html.To_dom.of_element ~%button)
+ Lwt_js_events.clicks (Eliom.Content.Html.To_dom.of_element ~%button)
(fun _ _ ->
- let%lwt () = Os_current_user.remove_email_from_user ~%email in
- Eliom_client.change_page
+ let%lwt () = Os.Current_user.remove_email_from_user ~%email in
+ Eliom.Client.change_page
~service:%%%MODULE_NAME%%%_services.settings_service () ()))
: unit)];
button
@@ -50,7 +50,7 @@ let%shared buttons_of_email is_main_email is_validated email =
(* A list of labels describing the email properties. *)
let%shared labels_of_email is_main_email is_validated =
- let open Eliom_content.Html.F in
+ let open Eliom.Content.Html.F in
let valid_label =
span
~a:[a_class ["os-settings-label"; "os-validated-email"]]
@@ -74,7 +74,7 @@ let%shared li_of_email main_email (email, is_validated) =
| Some main_email -> main_email = email
| None -> false
in
- let open Eliom_content.Html.D in
+ let open Eliom.Content.Html.D in
let labels = labels_of_email is_main_email is_validated
and buttons = buttons_of_email is_main_email is_validated email
and email = span ~a:[a_class ["os-settings-email"]] [txt email] in
@@ -83,23 +83,23 @@ let%shared li_of_email main_email (email, is_validated) =
let%shared ul_of_emails (main_email, emails) =
let li_of_email = li_of_email main_email in
let%lwt li_list = Lwt_list.map_s li_of_email emails in
- Lwt.return Eliom_content.Html.D.(div ~a:[a_class ["os-emails"]] [ul li_list])
+ Lwt.return Eliom.Content.Html.D.(div ~a:[a_class ["os-emails"]] [ul li_list])
(* List with information about emails *)
let%rpc get_emails myid () : (string option * (string * bool) list) Lwt.t =
- let%lwt main_email = Os_db.User.email_of_userid myid in
- let%lwt emails = Os_db.User.emails_of_userid myid in
+ let%lwt main_email = Os.Db.User.email_of_userid myid in
+ let%lwt emails = Os.Db.User.emails_of_userid myid in
let%lwt emails =
Lwt_list.map_s
(fun email ->
- let%lwt v = Os_current_user.is_email_validated email in
+ let%lwt v = Os.Current_user.is_email_validated email in
Lwt.return (email, v))
emails
in
Lwt.return (main_email, emails)
let%shared select_language_form select_language_name =
- let open Eliom_content.Html in
+ let open Eliom.Content.Html in
let current_language = %%%MODULE_NAME%%%_i18n.get_language () in
let all_languages_except_current =
List.filter (fun l -> l <> current_language) %%%MODULE_NAME%%%_i18n.languages
@@ -125,31 +125,31 @@ let%shared settings_content () =
let%lwt emails = get_emails () in
let%lwt emails = ul_of_emails emails in
Lwt.return
- @@ Eliom_content.Html.D.
+ @@ Eliom.Content.Html.D.
[ div
~a:[a_class ["os-settings"]]
[ p [%i18n change_password ~capitalize:true]
- ; Os_user_view.password_form ~a_placeholder_pwd:[%i18n S.password]
+ ; Os.User_view.password_form ~a_placeholder_pwd:[%i18n S.password]
~a_placeholder_confirmation:[%i18n S.retype_password]
~text_send_button:[%i18n S.send]
- ~service:Os_services.set_password_service ()
+ ~service:Os.Services.set_password_service ()
; br ()
- ; Os_user_view.upload_pic_link
+ ; Os.User_view.upload_pic_link
~submit:([a_class ["button"]], [txt "Submit"])
~content:[%i18n change_profile_picture]
%%%MODULE_NAME%%%_services.upload_user_avatar_service
; br ()
- ; Os_user_view.reset_tips_link
+ ; Os.User_view.reset_tips_link
~text_link:[%i18n S.see_help_again_from_beginning] ()
; br ()
- ; Os_user_view.disconnect_all_link
+ ; Os.User_view.disconnect_all_link
~text_link:[%i18n S.disconnect_all] ()
; br ()
; p [%i18n link_new_email]
- ; Os_user_view.generic_email_form
+ ; Os.User_view.generic_email_form
~a_placeholder_email:[%i18n S.email_address] ~text:[%i18n S.send]
- ~service:Os_services.add_email_service ()
+ ~service:Os.Services.add_email_service ()
; p [%i18n currently_registered_emails]
; div ~a:[a_class ["os-emails"]] [emails]
- ; Form.post_form ~service:Os_services.update_language_service
+ ; Form.post_form ~service:Os.Services.update_language_service
select_language_form () ] ]
diff --git a/template.distillery/PROJECT_NAME_static_config.eliom.in b/template.distillery/PROJECT_NAME_static_config.eliom.in
index 206cc2584..809a553eb 100644
--- a/template.distillery/PROJECT_NAME_static_config.eliom.in
+++ b/template.distillery/PROJECT_NAME_static_config.eliom.in
@@ -2,17 +2,17 @@
These information are taken from the config file otherwise.
*)
let%server set_static_config () =
- if not (Ocsigen_config.has_configuration_file ())
+ if not (Ocsigen.Config.has_configuration_file ())
then begin
- Ocsigen_config.set_ports [`All, 8080];
- Ocsigen_config.set_veryverbose ();
- Ocsigen_config.set_debugmode true;
- Ocsigen_config.set_logdir "local/var/log/%%%PROJECT_NAME%%%";
- Ocsigen_config.set_datadir "local/var/data/%%%PROJECT_NAME%%%";
- Ocsigen_config.set_uploaddir (Some "/tmp");
- Ocsigen_config.set_usedefaulthostname true;
- Ocsigen_config.set_command_pipe "local/var/run/%%%PROJECT_NAME%%%-cmd";
- Ocsigen_config.set_default_charset (Some "utf-8");
+ Ocsigen.Config.set_ports [`All, 8080];
+ Ocsigen.Config.set_veryverbose ();
+ Ocsigen.Config.set_debugmode true;
+ Ocsigen.Config.set_logdir "local/var/log/%%%PROJECT_NAME%%%";
+ Ocsigen.Config.set_datadir "local/var/data/%%%PROJECT_NAME%%%";
+ Ocsigen.Config.set_uploaddir (Some "/tmp");
+ Ocsigen.Config.set_usedefaulthostname true;
+ Ocsigen.Config.set_command_pipe "local/var/run/%%%PROJECT_NAME%%%-cmd";
+ Ocsigen.Config.set_default_charset (Some "utf-8");
Ocsipersist_settings.set_host "%%PGHOST%%";
Ocsipersist_settings.set_port %%PGPORT%%;
Ocsipersist_settings.set_database "ocsipersist_%%%PROJECT_NAME%%%";
diff --git a/template.distillery/demo.eliom b/template.distillery/demo.eliom
index 6ca63ec30..f8d379a28 100644
--- a/template.distillery/demo.eliom
+++ b/template.distillery/demo.eliom
@@ -1,7 +1,7 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
-open%shared Eliom_content.Html.D
+open%shared Eliom.Content.Html.D
(* drawer / demo welcome page ***********************************************)
diff --git a/template.distillery/demo_cache.eliom b/template.distillery/demo_cache.eliom
index 50dc6abf4..e10d7d765 100644
--- a/template.distillery/demo_cache.eliom
+++ b/template.distillery/demo_cache.eliom
@@ -1,7 +1,7 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
-(* Eliom_cscache demo *)
-open%shared Eliom_content.Html.F
+(* Eliom.Cscache demo *)
+open%shared Eliom.Content.Html.F
(* Page for this demo *)
let%shared page () =
@@ -10,10 +10,10 @@ let%shared page () =
; p
[%i18n
Demo.cache_2
- ~eliom_cscache:[code [txt "Eliom_cscache"]]
- ~os_user_proxy:[code [txt "Os_user_proxy"]]]
- ; p [%i18n Demo.cache_3 ~eliom_cscache:[code [txt "Eliom_cscache"]]]
- ; p [%i18n Demo.cache_4 ~eliom_cscache:[code [txt "Eliom_cscache"]]] ]
+ ~eliom_cscache:[code [txt "Eliom.Cscache"]]
+ ~os_user_proxy:[code [txt "Os.User_proxy"]]]
+ ; p [%i18n Demo.cache_3 ~eliom_cscache:[code [txt "Eliom.Cscache"]]]
+ ; p [%i18n Demo.cache_4 ~eliom_cscache:[code [txt "Eliom.Cscache"]]] ]
(* Service registration is done on both sides (shared section),
so that pages can be generated from the server
diff --git a/template.distillery/demo_calendar.eliom b/template.distillery/demo_calendar.eliom
index 673b77db6..3f7b91cb5 100644
--- a/template.distillery/demo_calendar.eliom
+++ b/template.distillery/demo_calendar.eliom
@@ -1,7 +1,7 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
(* Calendar demo *)
-open%shared Eliom_content.Html.D
+open%shared Eliom.Content.Html.D
(* A reactive value containing the currently selected date *)
(* NOTE: in this example, we define a shared signal on the server side. Its
@@ -17,7 +17,7 @@ open%shared Eliom_content.Html.D
`%shared`: the compiler will emit an error because the type of one of those
signals can't be inferred (it remains unknown at the end of the typing pass)
since it's never used throughout the program. *)
-let%server s, f = Eliom_shared.React.S.create None
+let%server s, f = Eliom.Shared.React.S.create None
let%client action y m d =
~%f (Some (y, m, d));
@@ -30,23 +30,23 @@ let%shared string_of_date = function
~d:(string_of_int d)]
| None -> ""
-let%server date_as_string () : string Eliom_shared.React.S.t =
- Eliom_shared.React.S.map [%shared string_of_date] s
+let%server date_as_string () : string Eliom.Shared.React.S.t =
+ Eliom.Shared.React.S.map [%shared string_of_date] s
-let%rpc date_reactive () : string Eliom_shared.React.S.t Lwt.t =
+let%rpc date_reactive () : string Eliom.Shared.React.S.t Lwt.t =
Lwt.return @@ date_as_string ()
(* Page for this demo *)
let%shared page () =
let calendar =
- Ot_calendar.make ~click_non_highlighted:true ~action:[%client action] ()
+ Ot.Calendar.make ~click_non_highlighted:true ~action:[%client action] ()
in
let%lwt dr = date_reactive () in
Lwt.return
[ h1 [%i18n Demo.calendar]
; p [%i18n Demo.this_page_show_calendar]
; div ~a:[a_class ["os-calendar"]] [calendar]
- ; p [Eliom_content.Html.R.txt dr] ]
+ ; p [Eliom.Content.Html.R.txt dr] ]
(* Service registration is done on both sides (shared section),
so that pages can be generated from the server
diff --git a/template.distillery/demo_carousel1.eliom b/template.distillery/demo_carousel1.eliom
index 023a0addb..51bf5a13c 100644
--- a/template.distillery/demo_carousel1.eliom
+++ b/template.distillery/demo_carousel1.eliom
@@ -1,27 +1,27 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
(* Carousel demo *)
-open%client Eliom_content.Html
-open%shared Eliom_content.Html.F
+open%client Eliom.Content.Html
+open%shared Eliom.Content.Html.F
(* Bind arrow keys *)
let%shared
bind_keys
- (change : ([`Goto of int | `Next | `Prev] -> unit) Eliom_client_value.t)
- (carousel : [`Div] Eliom_content.Html.elt)
+ (change : ([`Goto of int | `Next | `Prev] -> unit) Eliom.Client_value.t)
+ (carousel : [`Div] Eliom.Content.Html.elt)
=
ignore
[%client
(let arrow_thread =
(* Wait for the carousel to be in the page
(in the case the page is generated client side): *)
- let%lwt () = Ot_nodeready.nodeready (To_dom.of_element ~%carousel) in
- Ot_carousel.bind_arrow_keys ~change:~%change
+ let%lwt () = Ot.Nodeready.nodeready (To_dom.of_element ~%carousel) in
+ Ot.Carousel.bind_arrow_keys ~change:~%change
Js_of_ocaml.Dom_html.document##.body
in
(* Do not forget to cancel the thread when we remove the carousel
(here, when we go to another page): *)
- Eliom_client.onunload (fun () -> Lwt.cancel arrow_thread)
+ Eliom.Client.onunload (fun () -> Lwt.cancel arrow_thread)
: unit)]
(* Page for this demo *)
@@ -46,12 +46,12 @@ let%shared page () =
let carousel_pages = ["1"; "2"; "3"; "4"] in
let length = List.length carousel_pages in
let carousel_content = List.map make_page carousel_pages in
- let {Ot_carousel.elt = carousel; pos; vis_elts} =
- Ot_carousel.make ~update carousel_content
+ let {Ot.Carousel.elt = carousel; pos; vis_elts} =
+ Ot.Carousel.make ~update carousel_content
in
- let bullets = Ot_carousel.bullets ~change ~pos ~length ~size:vis_elts () in
- let prev = Ot_carousel.previous ~change ~pos [] in
- let next = Ot_carousel.next ~change ~pos ~vis_elts ~length [] in
+ let bullets = Ot.Carousel.bullets ~change ~pos ~length ~size:vis_elts () in
+ let prev = Ot.Carousel.previous ~change ~pos [] in
+ let next = Ot.Carousel.next ~change ~pos ~vis_elts ~length [] in
bind_keys change carousel;
Lwt.return
[ h1 [%i18n Demo.carousel_1]
diff --git a/template.distillery/demo_carousel2.eliom b/template.distillery/demo_carousel2.eliom
index d8cf9bb12..9bad9f4b2 100644
--- a/template.distillery/demo_carousel2.eliom
+++ b/template.distillery/demo_carousel2.eliom
@@ -1,8 +1,8 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
(* Page with several tabs *)
-open%shared Eliom_content.Html
-open%shared Eliom_content.Html.F
+open%shared Eliom.Content.Html
+open%shared Eliom.Content.Html.F
let%shared lorem_ipsum =
[ p
@@ -43,14 +43,14 @@ let%shared page () =
[%client
fun () ->
let t = To_dom.of_element !(~%tabs_r) in
- int_of_float (Ot_size.client_top t) + t##.offsetHeight]
+ int_of_float (Ot.Size.client_top t) + t##.offsetHeight]
in
- (* We want a "full-height" carousel. See Ot_carousel documentation. *)
- let {Ot_carousel.elt = carousel; pos; swipe_pos} =
- Ot_carousel.make ~update ~full_height:(`Header get_header_height)
+ (* We want a "full-height" carousel. See Ot.Carousel documentation. *)
+ let {Ot.Carousel.elt = carousel; pos; swipe_pos} =
+ Ot.Carousel.make ~update ~full_height:(`Header get_header_height)
carousel_content
in
- let ribbon = Ot_carousel.ribbon ~change ~pos ~cursor:swipe_pos tab_content in
+ let ribbon = Ot.Carousel.ribbon ~change ~pos ~cursor:swipe_pos tab_content in
let tabs =
(* ribbon container is necessary for shadow,
because position:sticky is not interpreted as relative
@@ -67,7 +67,7 @@ let%shared page () =
[%client
(Lwt.async (fun () ->
Lwt.map ignore
- (Ot_sticky.make_sticky ~ios_html_scroll_hack:true ~dir:`Top ~%tabs))
+ (Ot.Sticky.make_sticky ~ios_html_scroll_hack:true ~dir:`Top ~%tabs))
: unit)];
Lwt.return
[ h1 [%i18n Demo.carousel_2]
diff --git a/template.distillery/demo_carousel3.eliom b/template.distillery/demo_carousel3.eliom
index 808120614..d7db9d06f 100644
--- a/template.distillery/demo_carousel3.eliom
+++ b/template.distillery/demo_carousel3.eliom
@@ -1,8 +1,8 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
(* Wheel demo *)
-open%shared Eliom_content.Html
-open%shared Eliom_content.Html.F
+open%shared Eliom.Content.Html
+open%shared Eliom.Content.Html.F
(* Page for this demo *)
let%shared page () =
@@ -54,7 +54,7 @@ let%shared page () =
let update = [%client fst ~%carousel_change_signal] in
let change = [%client fun a -> snd ~%carousel_change_signal ?step:None a] in
let carousel, pos, _swipe_pos =
- Ot_carousel.wheel
+ Ot.Carousel.wheel
~a:[a_class ["demo-carousel3"]]
~update ~vertical:true ~inertia:1. ~position:10 ~transition_duration:3.
~face_size:25 carousel_content
@@ -64,11 +64,11 @@ let%shared page () =
; p [%i18n Demo.carousel_third_example_1]
; carousel
; div
- [ Ot_carousel.previous ~a:[a_class ["demo-prev"]] ~change ~pos []
- ; Ot_carousel.next
+ [ Ot.Carousel.previous ~a:[a_class ["demo-prev"]] ~change ~pos []
+ ; Ot.Carousel.next
~a:[a_class ["demo-next"]]
~change ~pos
- ~vis_elts:(Eliom_shared.React.S.const 1)
+ ~vis_elts:(Eliom.Shared.React.S.const 1)
~length [] ] ]
(* Service registration is done on both sides (shared section),
diff --git a/template.distillery/demo_forms.eliom b/template.distillery/demo_forms.eliom
index 34f6d430a..05a47c7c7 100644
--- a/template.distillery/demo_forms.eliom
+++ b/template.distillery/demo_forms.eliom
@@ -1,7 +1,7 @@
-(* Demo page for Ot_form widgets *)
+(* Demo page for Ot.Form widgets *)
-open%shared Eliom_content.Html
-open%shared Eliom_content.Html.F
+open%shared Eliom.Content.Html
+open%shared Eliom.Content.Html.F
open%client Js_of_ocaml
open%client Js_of_ocaml_lwt
@@ -12,7 +12,7 @@ let%shared output_line label signal =
p
~a:[a_class ["demo-forms-output"]]
[ strong [txt (label ^ ": ")]
- ; R.txt (Eliom_shared.React.S.map [%shared fun v -> v] signal) ]
+ ; R.txt (Eliom.Shared.React.S.map [%shared fun v -> v] signal) ]
let%shared page () =
(* -- standard form -- *)
@@ -49,7 +49,7 @@ let%shared page () =
; a_placeholder [%i18n Demo.S.form_standard_password] ]
()
in
- let pwd_container = Ot_form.password_toggle pwd_inp in
+ let pwd_container = Ot.Form.password_toggle pwd_inp in
let msg_inp =
D.Raw.textarea
~a:[a_placeholder [%i18n Demo.S.form_standard_message]]
@@ -101,7 +101,7 @@ let%shared page () =
let terms_l = [%i18n Demo.S.form_standard_terms] in
let satisfaction_l = [%i18n Demo.S.form_standard_satisfaction] in
let color_l = [%i18n Demo.S.form_standard_color] in
- let (_ : unit Eliom_client_value.t) =
+ let (_ : unit Eliom.Client_value.t) =
[%client
let btn_el = To_dom.of_element ~%submit_btn in
let result_el = To_dom.of_element ~%result_div in
@@ -170,7 +170,7 @@ let%shared page () =
in
(* -- reactive_input -- *)
let ri_input, (ri_signal, _ri_set) =
- Ot_form.reactive_input ~value:"hello" ()
+ Ot.Form.reactive_input ~value:"hello" ()
in
let ri_section =
section [%i18n Demo.S.form_reactive_input_title]
@@ -180,7 +180,7 @@ let%shared page () =
in
(* -- reactive_textarea -- *)
let rt_elt, (rt_signal, _rt_set) =
- Ot_form.reactive_textarea ~resize:true ~a_rows:3
+ Ot.Form.reactive_textarea ~resize:true ~a_rows:3
~a_placeholder:[%i18n Demo.S.form_placeholder_type_here] ()
in
let rt_section =
@@ -191,7 +191,7 @@ let%shared page () =
in
(* -- debounced_input -- *)
let db_input, (db_raw, db_debounced, _db_set) =
- Ot_form.debounced_input ~delay:0.5 ~value:"" ()
+ Ot.Form.debounced_input ~delay:0.5 ~value:"" ()
in
let db_section =
section [%i18n Demo.S.form_debounced_title]
@@ -202,7 +202,7 @@ let%shared page () =
in
(* -- password_input -- *)
let pw_container, _pw_input, (pw_visible_s, _pw_set_visible) =
- Ot_form.password_input ~placeholder:[%i18n Demo.S.form_placeholder_password]
+ Ot.Form.password_input ~placeholder:[%i18n Demo.S.form_placeholder_password]
()
in
let true_s = [%i18n Demo.S.form_true] in
@@ -215,13 +215,13 @@ let%shared page () =
~a:[a_class ["demo-forms-output"]]
[ strong [txt ([%i18n Demo.S.form_label_visible] ^ ": ")]
; R.txt
- (Eliom_shared.React.S.map
+ (Eliom.Shared.React.S.map
[%shared fun v -> if v then ~%true_s else ~%false_s]
pw_visible_s) ] ]
in
(* -- reactive_select -- *)
let sel_elt, (sel_signal, _sel_set) =
- Ot_form.reactive_select
+ Ot.Form.reactive_select
~options:["fr", "France"; "de", "Germany"; "it", "Italy"; "es", "Spain"]
~selected:"fr" ()
in
@@ -233,7 +233,7 @@ let%shared page () =
in
(* -- reactive_toggle_button -- *)
let toggle_btn, (toggle_s, _toggle_set) =
- Ot_form.reactive_toggle_button [txt [%i18n Demo.S.form_toggle_label]]
+ Ot.Form.reactive_toggle_button [txt [%i18n Demo.S.form_toggle_label]]
in
let on_s = [%i18n Demo.S.form_on] in
let off_s = [%i18n Demo.S.form_off] in
@@ -245,19 +245,19 @@ let%shared page () =
~a:[a_class ["demo-forms-output"]]
[ strong [txt ([%i18n Demo.S.form_label_state] ^ ": ")]
; R.txt
- (Eliom_shared.React.S.map
+ (Eliom.Shared.React.S.map
[%shared fun v -> if v then ~%on_s else ~%off_s]
toggle_s) ] ]
in
(* -- checkbox -- *)
let cb_label, _cb_input =
- Ot_form.checkbox ~style:`Box [txt [%i18n Demo.S.form_checkbox_box]]
+ Ot.Form.checkbox ~style:`Box [txt [%i18n Demo.S.form_checkbox_box]]
in
let cb_label2, _cb_input2 =
- Ot_form.checkbox ~style:`Toggle [txt [%i18n Demo.S.form_checkbox_toggle]]
+ Ot.Form.checkbox ~style:`Toggle [txt [%i18n Demo.S.form_checkbox_toggle]]
in
let cb_label3, _cb_input3 =
- Ot_form.checkbox ~style:`Bullet [txt [%i18n Demo.S.form_checkbox_bullet]]
+ Ot.Form.checkbox ~style:`Bullet [txt [%i18n Demo.S.form_checkbox_bullet]]
in
let cb_section =
section [%i18n Demo.S.form_checkbox_title]
@@ -268,7 +268,7 @@ let%shared page () =
in
(* -- reactive_checkbox -- *)
let rcb =
- Ot_form.reactive_checkbox ~style:`Box [txt [%i18n Demo.S.form_check_me]]
+ Ot.Form.reactive_checkbox ~style:`Box [txt [%i18n Demo.S.form_check_me]]
in
let rcb_section =
section [%i18n Demo.S.form_reactive_checkbox_title]
@@ -278,21 +278,21 @@ let%shared page () =
~a:[a_class ["demo-forms-output"]]
[ strong [txt ([%i18n Demo.S.form_label_checked] ^ ": ")]
; R.txt
- (Eliom_shared.React.S.map
+ (Eliom.Shared.React.S.map
[%shared fun v -> if v then ~%true_s else ~%false_s]
rcb#value) ]
; p
~a:[a_class ["demo-forms-output"]]
[ strong [txt ([%i18n Demo.S.form_label_manually_changed] ^ ": ")]
; R.txt
- (Eliom_shared.React.S.map
+ (Eliom.Shared.React.S.map
[%shared fun v -> if v then ~%true_s else ~%false_s]
rcb#manually_changed) ] ]
in
(* -- radio_buttons -- *)
- let radio_react = Eliom_shared.React.S.create (Some 0) in
+ let radio_react = Eliom.Shared.React.S.create (Some 0) in
let radio_labels =
- Ot_form.radio_buttons ~selection_react:radio_react ~name:"demo-radio"
+ Ot.Form.radio_buttons ~selection_react:radio_react ~name:"demo-radio"
[ [txt [%i18n Demo.S.form_radio_red]]
; [txt [%i18n Demo.S.form_radio_green]]
; [txt [%i18n Demo.S.form_radio_blue]] ]
@@ -306,16 +306,16 @@ let%shared page () =
~a:[a_class ["demo-forms-output"]]
[ strong [txt ([%i18n Demo.S.form_label_selection] ^ ": ")]
; R.txt
- (Eliom_shared.React.S.map
+ (Eliom.Shared.React.S.map
[%shared
fun v ->
match v with None -> ~%none_s | Some i -> string_of_int i]
(fst radio_react)) ] ]
in
(* -- int_input / optional_int_input -- *)
- let int_div, int_signal = Ot_form.int_input ~min:0 ~max:100 42 in
+ let int_div, int_signal = Ot.Form.int_input ~min:0 ~max:100 42 in
let oint_div, oint_signal =
- Ot_form.optional_int_input ~min:0 ~max:50 (Some 10)
+ Ot.Form.optional_int_input ~min:0 ~max:50 (Some 10)
in
let invalid_s = [%i18n Demo.S.form_invalid] in
let int_section =
@@ -328,7 +328,7 @@ let%shared page () =
~a:[a_class ["demo-forms-output"]]
[ strong [txt ([%i18n Demo.S.form_label_value] ^ ": ")]
; R.txt
- (Eliom_shared.React.S.map
+ (Eliom.Shared.React.S.map
[%shared
fun v ->
match v with
@@ -342,7 +342,7 @@ let%shared page () =
~a:[a_class ["demo-forms-output"]]
[ strong [txt ([%i18n Demo.S.form_label_value] ^ ": ")]
; R.txt
- (Eliom_shared.React.S.map
+ (Eliom.Shared.React.S.map
[%shared
fun v ->
match v with
@@ -353,7 +353,7 @@ let%shared page () =
in
(* -- reactive_date_input -- *)
let date_input, (date_signal, _date_set) =
- Ot_form.reactive_date_input ~value:(2025, 6, 15) ()
+ Ot.Form.reactive_date_input ~value:(2025, 6, 15) ()
in
let date_section =
section [%i18n Demo.S.form_date_title]
@@ -363,7 +363,7 @@ let%shared page () =
~a:[a_class ["demo-forms-output"]]
[ strong [txt ([%i18n Demo.S.form_label_date] ^ ": ")]
; R.txt
- (Eliom_shared.React.S.map
+ (Eliom.Shared.React.S.map
[%shared
fun v ->
match v with
@@ -373,7 +373,7 @@ let%shared page () =
in
(* -- reactive_time_input -- *)
let time_input, (time_signal, _time_set) =
- Ot_form.reactive_time_input ~value:(14, 30) ()
+ Ot.Form.reactive_time_input ~value:(14, 30) ()
in
let time_section =
section [%i18n Demo.S.form_time_title]
@@ -383,7 +383,7 @@ let%shared page () =
~a:[a_class ["demo-forms-output"]]
[ strong [txt ([%i18n Demo.S.form_label_time] ^ ": ")]
; R.txt
- (Eliom_shared.React.S.map
+ (Eliom.Shared.React.S.map
[%shared
fun v ->
match v with
@@ -393,11 +393,11 @@ let%shared page () =
in
(* -- disableable_button -- *)
let dis_toggle_btn, (dis_s, _dis_set) =
- Ot_form.reactive_toggle_button ~init:false
+ Ot.Form.reactive_toggle_button ~init:false
[txt [%i18n Demo.S.form_disable_below]]
in
let dis_button =
- Ot_form.disableable_button ~disabled:dis_s
+ Ot.Form.disableable_button ~disabled:dis_s
[txt [%i18n Demo.S.form_can_be_disabled]]
in
let dis_section =
@@ -408,7 +408,7 @@ let%shared page () =
in
(* -- prevent_double_submit -- *)
let pds_button =
- Ot_form.prevent_double_submit
+ Ot.Form.prevent_double_submit
~f:[%client fun () -> Lwt_js.sleep 2.0]
[txt [%i18n Demo.S.form_click_2s]]
in
@@ -419,7 +419,7 @@ let%shared page () =
(* -- input_validation_tools -- *)
let even_error = [%i18n Demo.S.form_even_error] in
let val_attrs, val_class, val_result =
- Ot_form.input_validation_tools ~init:""
+ Ot.Form.input_validation_tools ~init:""
[%shared
fun s ->
if String.length s = 0
@@ -437,7 +437,7 @@ let%shared page () =
:: val_class :: val_attrs)
()
in
- let () = Ot_form.graceful_invalid_style val_input in
+ let () = Ot.Form.graceful_invalid_style val_input in
let ok_prefix = [%i18n Demo.S.form_ok_prefix] in
let error_prefix = [%i18n Demo.S.form_error_prefix] in
let val_section =
@@ -448,7 +448,7 @@ let%shared page () =
~a:[a_class ["demo-forms-output"]]
[ strong [txt ([%i18n Demo.S.form_label_result] ^ ": ")]
; R.txt
- (Eliom_shared.React.S.map
+ (Eliom.Shared.React.S.map
[%shared
fun v ->
match v with
@@ -458,22 +458,22 @@ let%shared page () =
in
(* -- reactive_fieldset -- *)
let fs_toggle, (fs_disabled_s, _fs_set) =
- Ot_form.reactive_toggle_button ~init:false
+ Ot.Form.reactive_toggle_button ~init:false
[txt [%i18n Demo.S.form_disable_fieldset]]
in
let fs_input1, _ =
- Ot_form.reactive_input ~value:[%i18n Demo.S.form_field_1] ()
+ Ot.Form.reactive_input ~value:[%i18n Demo.S.form_field_1] ()
in
let fs_input2, _ =
- Ot_form.reactive_input ~value:[%i18n Demo.S.form_field_2] ()
+ Ot.Form.reactive_input ~value:[%i18n Demo.S.form_field_2] ()
in
let fs =
- Ot_form.reactive_fieldset ~disabled:fs_disabled_s
+ Ot.Form.reactive_fieldset ~disabled:fs_disabled_s
[ div [strong [txt [%i18n Demo.S.form_fieldset_content]]]
; div [fs_input1]
; div [fs_input2]
- ; Ot_form.disableable_button
- ~disabled:(Eliom_shared.React.S.const false)
+ ; Ot.Form.disableable_button
+ ~disabled:(Eliom.Shared.React.S.const false)
[txt [%i18n Demo.S.form_button_inside]] ]
in
let fs_section =
@@ -481,9 +481,9 @@ let%shared page () =
[p [txt [%i18n Demo.S.form_fieldset_desc]]; div [fs_toggle]; fs]
in
(* -- lwt_bound_input_enter -- *)
- let enter_output = Eliom_shared.React.S.create "" in
+ let enter_output = Eliom.Shared.React.S.create "" in
let enter_input =
- Ot_form.lwt_bound_input_enter
+ Ot.Form.lwt_bound_input_enter
~a:[a_placeholder [%i18n Demo.S.form_placeholder_enter]]
[%client
fun v ->
diff --git a/template.distillery/demo_i18n.eliom b/template.distillery/demo_i18n.eliom
index 80d65c221..b2ff5dc85 100644
--- a/template.distillery/demo_i18n.eliom
+++ b/template.distillery/demo_i18n.eliom
@@ -1,7 +1,7 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
(* Ocsigen_i18n demo *)
-open%shared Eliom_content.Html.F
+open%shared Eliom.Content.Html.F
(* Page for this demo *)
let%shared page () =
diff --git a/template.distillery/demo_links.eliom b/template.distillery/demo_links.eliom
index c50336e69..db75d6743 100644
--- a/template.distillery/demo_links.eliom
+++ b/template.distillery/demo_links.eliom
@@ -1,12 +1,12 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
(* Static files demo *)
-open%shared Eliom_content.Html.F
+open%shared Eliom.Content.Html.F
(* An example of external service: *)
let%server ocsigen_service =
- Eliom_service.extern ~prefix:"http://ocsigen.org" ~path:[]
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.extern ~prefix:"http://ocsigen.org" ~path:[]
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
(* Make service available on the client *)
let%client ocsigen_service = ~%ocsigen_service
@@ -27,7 +27,7 @@ let%shared page () =
[%i18n
Demo.links_and_forms_1
~t1:
- [a ~service:Os_services.main_service [%i18n Demo.internal_link] ()]
+ [a ~service:Os.Services.main_service [%i18n Demo.internal_link] ()]
~t2:[a ~service:ocsigen_service [%i18n Demo.external_service] ()]]
; h2 [%i18n Demo.static_files]
; p
@@ -39,9 +39,9 @@ let%shared page () =
~a:[a_class ["demo-static-img"]]
~alt:"local_img"
~src:
- (Eliom_content.Html.F.make_uri
+ (Eliom.Content.Html.F.make_uri
~absolute:false (* We want local file on mobile app *)
- ~service:(Eliom_service.static_dir ())
+ ~service:(Eliom.Service.static_dir ())
["images"; "ocsigen.png"])
()
; p [%i18n Demo.static_files_2]
@@ -49,10 +49,10 @@ let%shared page () =
~a:[a_class ["demo-static-img"]]
~alt:"distant_img"
~src:
- (Eliom_content.Html.F.make_uri
+ (Eliom.Content.Html.F.make_uri
(* We want a distant file:
keep the default value of ~absolute *)
- ~service:(Eliom_service.static_dir ())
+ ~service:(Eliom.Service.static_dir ())
["images"; "ocsigen.png"])
() ]
diff --git a/template.distillery/demo_notif.eliom b/template.distillery/demo_notif.eliom
index 1f29c59a6..ea7472d4d 100644
--- a/template.distillery/demo_notif.eliom
+++ b/template.distillery/demo_notif.eliom
@@ -2,16 +2,16 @@
Feel free to use it, modify it, and redistribute it as you wish. *)
(* Notification demo *)
open%client Js_of_ocaml_lwt
-open%shared Eliom_content
+open%shared Eliom.Content
open%shared Html.D
-(* Instantiate function Os_notif.Simple for each kind of notification
+(* Instantiate function Os.Notif.Simple for each kind of notification
you need.
The key is the resource ID. For example, if you are implementing a
messaging application, it can be the chatroom ID
(for example type key = int64).
*)
-module Notif = Os_notif.Make_Simple (struct
+module Notif = Os.Notif.Make_Simple (struct
type key = unit
(* The resources identifiers.
@@ -28,7 +28,7 @@ let%rpc notify (v : string) : unit Lwt.t =
Notif.notify (* ~notfor:`Me *) (() : Notif.key) v;
(* Use ~notfor:`Me to avoid receiving the message in this tab,
or ~notfor:(`User myid) to avoid sending to the current user.
- (Where myid is Os_current_user.get_current_userid ())
+ (Where myid is Os.Current_user.get_current_userid ())
*)
Lwt.return_unit
@@ -37,38 +37,38 @@ let%rpc listen () : unit Lwt.t = Notif.listen (); Lwt.return_unit
(* Display a message every time the React event [e = Notif.client_ev ()]
happens. *)
let%server () =
- Os_session.on_start_process (fun _ ->
- let e : (unit * string) Eliom_react.Down.t = Notif.client_ev () in
+ Os.Session.on_start_process (fun _ ->
+ let e : (unit * string) Eliom.Eliom_react.Down.t = Notif.client_ev () in
ignore
[%client
- (Eliom_lib.Dom_reference.retain Js_of_ocaml.Dom_html.window
+ (Eliom.Lib.Dom_reference.retain Js_of_ocaml.Dom_html.window
~keep:
(React.E.map
(fun (_, msg) ->
- (* Eliom_lib.alert "%s" msg *)
- Os_msg.msg ~level:`Msg (Printf.sprintf "%s" msg))
+ (* Eliom.Lib.alert "%s" msg *)
+ Os.Msg.msg ~level:`Msg (Printf.sprintf "%s" msg))
~%e)
: unit)];
Lwt.return_unit)
(* Make a text input field that calls [f s] for each [s] submitted *)
let%shared make_form msg f =
- let inp = Eliom_content.Html.D.Raw.input ()
+ let inp = Eliom.Content.Html.D.Raw.input ()
and btn =
- Eliom_content.Html.(D.button ~a:[D.a_class ["button"]] [D.txt msg])
+ Eliom.Content.Html.(D.button ~a:[D.a_class ["button"]] [D.txt msg])
in
ignore
[%client
(Lwt.async @@ fun () ->
- let btn = Eliom_content.Html.To_dom.of_element ~%btn
- and inp = Eliom_content.Html.To_dom.of_input ~%inp in
+ let btn = Eliom.Content.Html.To_dom.of_element ~%btn
+ and inp = Eliom.Content.Html.To_dom.of_input ~%inp in
Lwt_js_events.clicks btn @@ fun _ _ ->
let v = Js_of_ocaml.Js.to_string inp##.value in
let%lwt () = ~%f v in
inp##.value := Js_of_ocaml.Js.string "";
Lwt.return_unit
: unit)];
- Eliom_content.Html.D.div [inp; btn]
+ Eliom.Content.Html.D.div [inp; btn]
let%rpc unlisten () : unit Lwt.t = Notif.unlisten (); Lwt.return_unit
@@ -77,15 +77,15 @@ let%shared page () =
(* Subscribe to notifications when entering this page: *)
let%lwt () = listen () in
(* Unsubscribe from notifications when user leaves this page *)
- let (_ : unit Eliom_client_value.t) =
- [%client Eliom_client.Page_status.ondead (fun () -> Lwt.async unlisten)]
+ let (_ : unit Eliom.Client_value.t) =
+ [%client Eliom.Client.Page_status.ondead (fun () -> Lwt.async unlisten)]
in
Lwt.return
- Eliom_content.Html.F.
+ Eliom.Content.Html.F.
[ h1 [%i18n Demo.notification]
; p
([%i18n
- Demo.exchange_msg_between_users ~os_notif:[code [txt "Os_notif"]]]
+ Demo.exchange_msg_between_users ~os_notif:[code [txt "Os.Notif"]]]
@ [ br ()
; txt [%i18n Demo.S.open_multiple_tabs_browsers]
; br ()
diff --git a/template.distillery/demo_pagetransition.eliom b/template.distillery/demo_pagetransition.eliom
index d9b4c2f93..fb43b5beb 100644
--- a/template.distillery/demo_pagetransition.eliom
+++ b/template.distillery/demo_pagetransition.eliom
@@ -1,12 +1,12 @@
(* This demo illustrates Eliom's DOM caching feature.
- By running [Eliom_client.onload Eliom_client.push_history_dom] one
+ By running [Eliom.Client.onload Eliom.Client.push_history_dom] one
can push the DOM of the current page into Eliom's cache. Every page
which is cached in this manner will be immediately served from the
cache instead of being charged from the server or regenerated by
the client. Also the scroll position is restored that the page had
at the end of the last visit. *)
-open%shared Eliom_content
+open%shared Eliom.Content
open%shared Html
open%shared Html.D
open%client Js_of_ocaml_lwt
@@ -36,10 +36,10 @@ let%shared page () =
((* It is the address of the dom that will be stored in cache, so
it doesn't matter when [push_history_dom] is called. However,
it is important that the dom is bound to the right state id.
- So it is better to call [push_history_dom] in Eliom_client.onload,
+ So it is better to call [push_history_dom] in Eliom.Client.onload,
when the state id has already been updated and the dom of
the current page is ready. *)
- Eliom_client.onload Eliom_client.push_history_dom;
+ Eliom.Client.onload Eliom.Client.push_history_dom;
let counter =
let r = ref 10 in
fun () ->
diff --git a/template.distillery/demo_pgocaml.eliom b/template.distillery/demo_pgocaml.eliom
index 8f50fa051..75b6233ec 100644
--- a/template.distillery/demo_pgocaml.eliom
+++ b/template.distillery/demo_pgocaml.eliom
@@ -1,7 +1,7 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
(* PGOcaml demo *)
-open%shared Eliom_content.Html.F
+open%shared Eliom.Content.Html.F
(* Fetch users in database *)
let%rpc get_users () : string list Lwt.t =
@@ -12,7 +12,7 @@ let%rpc get_users () : string list Lwt.t =
(* Generate page for this demo *)
let%shared page () =
let%lwt user_block =
- Ot_spinner.with_spinner
+ Ot.Spinner.with_spinner
(let%lwt users = get_users () in
let users =
List.map
diff --git a/template.distillery/demo_pgocaml_db.ml b/template.distillery/demo_pgocaml_db.ml
index 33ff265c7..e994b1efe 100644
--- a/template.distillery/demo_pgocaml_db.ml
+++ b/template.distillery/demo_pgocaml_db.ml
@@ -1,7 +1,7 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
-open Os_db
+open Os.Db
(* We are using PGOCaml to make type safe DB requests to Postgresql.
The Makefile automatically compiles
diff --git a/template.distillery/demo_popup.eliom b/template.distillery/demo_popup.eliom
index efb4a51e2..b79f011ad 100644
--- a/template.distillery/demo_popup.eliom
+++ b/template.distillery/demo_popup.eliom
@@ -1,8 +1,8 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
(* Popup button demo *)
-open%shared Eliom_content.Html
-open%shared Eliom_content.Html.F
+open%shared Eliom.Content.Html
+open%shared Eliom.Content.Html.F
open%client Js_of_ocaml_lwt
(* Name for demo menu. This value is defined both server and client-side. *)
@@ -15,9 +15,9 @@ let%shared page () =
(* As we are using ~%button (in a client section below)
to refer to this precise occurrence of the button in the page,
button must be a D node
- (from module Eliom_content.Html.D,
+ (from module Eliom.Content.Html.D,
which will add an unique identifier in its attributes),
- and not a functional node (Eliom_content.Html.F). *)
+ and not a functional node (Eliom.Content.Html.F). *)
D.Form.input
~a:[a_class ["button"]]
~input_type:`Submit ~value:[%i18n Demo.S.popup_click] Form.string
@@ -43,13 +43,13 @@ let%shared page () =
We run it asynchronously. *)
Lwt_js_events.clicks (To_dom.of_element ~%button) (fun _ _ ->
let%lwt _ =
- Ot_popup.popup
- ~close_button:[Os_icons.F.close ()]
+ Ot.Popup.popup
+ ~close_button:[Os.Icons.F.close ()]
(fun _ -> Lwt.return @@ p [%i18n Demo.popup_message])
in
Lwt.return_unit))
: unit)];
- (* Page elements, using module Eliom_content.Html.F
+ (* Page elements, using module Eliom.Content.Html.F
(as we don't want to add a unique identifier).
See internationalization demo for i18n syntax.
*)
diff --git a/template.distillery/demo_pulltorefresh.eliom b/template.distillery/demo_pulltorefresh.eliom
index 16e595b6f..ee7f22f5c 100644
--- a/template.distillery/demo_pulltorefresh.eliom
+++ b/template.distillery/demo_pulltorefresh.eliom
@@ -3,21 +3,21 @@
(** Demo for refreshable content *)
-open%shared Eliom_content.Html
-open%shared Eliom_content.Html.D
+open%shared Eliom.Content.Html
+open%shared Eliom.Content.Html.D
let%shared page () =
- let counter_sig, set_counter = Eliom_shared.React.S.create 0 in
+ let counter_sig, set_counter = Eliom.Shared.React.S.create 0 in
let reload =
[%client
fun () ->
let%lwt _ = Js_of_ocaml_lwt.Lwt_js.sleep 1. in
- let n = Eliom_shared.React.S.value ~%counter_sig in
+ let n = Eliom.Shared.React.S.value ~%counter_sig in
~%set_counter (n + 1);
Lwt.return_true]
in
let counter_node_sig =
- Eliom_shared.React.S.map
+ Eliom.Shared.React.S.map
[%shared
fun n ->
let n = [F.txt @@ string_of_int n] in
@@ -32,7 +32,7 @@ let%shared page () =
; F.p [%i18n Demo.pull_to_refresh_2]
; R.node counter_node_sig ]
in
- Lwt.return @@ [Ot_pulltorefresh.make ~dragThreshold:15. ~content reload]
+ Lwt.return @@ [Ot.Pulltorefresh.make ~dragThreshold:15. ~content reload]
(* Service registration is done on both sides (shared section),
so that pages can be generated from the server
diff --git a/template.distillery/demo_react.eliom b/template.distillery/demo_react.eliom
index dc94ae9c2..9e74d0244 100644
--- a/template.distillery/demo_react.eliom
+++ b/template.distillery/demo_react.eliom
@@ -4,42 +4,42 @@
(** Demo for shared reactive content *)
open%client Js_of_ocaml_lwt
-open%shared Eliom_content
+open%shared Eliom.Content
open%shared Html.D
(* Make a text input field that calls [f s] for each [s] submitted *)
let%shared make_form msg f =
- let inp = Eliom_content.Html.D.Raw.input ()
+ let inp = Eliom.Content.Html.D.Raw.input ()
and btn =
- Eliom_content.Html.(D.button ~a:[D.a_class ["button"]] [D.txt msg])
+ Eliom.Content.Html.(D.button ~a:[D.a_class ["button"]] [D.txt msg])
in
ignore
[%client
(Lwt.async @@ fun () ->
- let btn = Eliom_content.Html.To_dom.of_element ~%btn
- and inp = Eliom_content.Html.To_dom.of_input ~%inp in
+ let btn = Eliom.Content.Html.To_dom.of_element ~%btn
+ and inp = Eliom.Content.Html.To_dom.of_input ~%inp in
Lwt_js_events.clicks btn @@ fun _ _ ->
let v = Js_of_ocaml.Js.to_string inp##.value in
let%lwt () = ~%f v in
inp##.value := Js_of_ocaml.Js.string "";
Lwt.return_unit
: unit)];
- Eliom_content.Html.D.div [inp; btn]
+ Eliom.Content.Html.D.div [inp; btn]
(* Page for this demo *)
let%shared page () =
(* Client reactive list, initially empty.
It can be defined either from client or server side,
(depending on whether this code is executed client or server-side).
- Use Eliom_shared.ReactiveData.RList for lists or
- Eliom_shared.React.S for other data types.
+ Use Eliom.Shared.ReactiveData.RList for lists or
+ Eliom.Shared.React.S for other data types.
*)
- let l, h = Eliom_shared.ReactiveData.RList.create [] in
+ let l, h = Eliom.Shared.ReactiveData.RList.create [] in
let inp =
(* Form that performs a cons (client-side). *)
make_form [%i18n Demo.S.reactive_programming_button]
[%client
- (fun v -> Lwt.return (Eliom_shared.ReactiveData.RList.cons v ~%h)
+ (fun v -> Lwt.return (Eliom.Shared.ReactiveData.RList.cons v ~%h)
: string -> unit Lwt.t)]
and l =
(* Produce items from l contents.
@@ -47,12 +47,12 @@ let%shared page () =
to compute the initial page. It will then be called client-side
every time the reactive list changes to update the
page automatically. *)
- Eliom_shared.ReactiveData.RList.map
- [%shared (fun s -> Eliom_content.Html.(D.li [D.txt s]) : _ -> _)]
+ Eliom.Shared.ReactiveData.RList.map
+ [%shared (fun s -> Eliom.Content.Html.(D.li [D.txt s]) : _ -> _)]
l
in
Lwt.return
- Eliom_content.Html.
+ Eliom.Content.Html.
[ F.h1 [%i18n Demo.reactive_programming]
; F.p [F.txt [%i18n Demo.S.reactive_programming_1]]
; F.p [F.txt [%i18n Demo.S.reactive_programming_2]]
diff --git a/template.distillery/demo_ref.eliom b/template.distillery/demo_ref.eliom
index 8fcfb6e6d..10cf705a9 100644
--- a/template.distillery/demo_ref.eliom
+++ b/template.distillery/demo_ref.eliom
@@ -1,22 +1,23 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
-(* Demo for Eliom references and Os_date *)
-open%shared Eliom_content.Html.F
+(* Demo for Eliom references and Os.Date *)
+open%shared Eliom.Content.Html.F
(* An Eliom reference storing the last time the user visited the current
- page. It has scope Eliom_common.default_group_scope, which means that
+ page. It has scope Eliom.Common.default_group_scope, which means that
the value will be different for each user of the Web site, but the same
for all the sessions of a same user.
Ocsigen Start is creating a session group for each user.
*)
let%server last_visit =
- Eliom_reference.eref ~persistent:"demo_last_visit"
- ~scope:Eliom_common.default_group_scope None
+ Eliom.Reference.eref
+ ~persistent:("demo_last_visit", [%json: Os.Date.local_calendar option])
+ ~scope:Eliom.Common.default_group_scope None
(* Read & reset last_visit *)
-let%rpc get_reset_last_visit () : Os_date.local_calendar option Lwt.t =
- let%lwt v = Eliom_reference.get last_visit in
- let%lwt () = Eliom_reference.set last_visit (Some (Os_date.now ())) in
+let%rpc get_reset_last_visit () : Os.Date.local_calendar option Lwt.t =
+ let%lwt v = Eliom.Reference.get last_visit in
+ let%lwt () = Eliom.Reference.set last_visit (Some (Os.Date.now ())) in
Lwt.return v
(* Call get_reset_last_visit and produce pretty message *)
@@ -27,7 +28,7 @@ let%shared get_reset_last_visit_message () =
| Some last_visit ->
Lwt.return
([%i18n Demo.eliom_ref_last_visit]
- @ [txt " "; txt (Os_date.smart_time last_visit)])
+ @ [txt " "; txt (Os.Date.smart_time last_visit)])
(* Generate page for this demo *)
let%shared page () =
diff --git a/template.distillery/demo_rpc.eliom b/template.distillery/demo_rpc.eliom
index 719a5a9b3..60316fb9f 100644
--- a/template.distillery/demo_rpc.eliom
+++ b/template.distillery/demo_rpc.eliom
@@ -2,7 +2,7 @@
Feel free to use it, modify it, and redistribute it as you wish. *)
(* RPC button demo *)
open%client Js_of_ocaml_lwt
-open%shared Eliom_content
+open%shared Eliom.Content
open%shared Html.D
(* A server-side reference that stores data for the current browser
@@ -11,23 +11,23 @@ open%shared Html.D
like client-process (a tab of a browser) or session-group (a user).
*)
let%server my_ref =
- Eliom_reference.eref ~scope:Eliom_common.default_session_scope 0
+ Eliom.Reference.eref ~scope:Eliom.Common.default_session_scope 0
(* Server-side function that increments my_ref and returns new val *)
let%rpc incr_my_ref () : int Lwt.t =
- let%lwt v = Eliom_reference.get my_ref in
+ let%lwt v = Eliom.Reference.get my_ref in
let v = v + 1 in
- let%lwt () = Eliom_reference.set my_ref v in
+ let%lwt () = Eliom.Reference.set my_ref v in
Lwt.return v
let%shared button msg f =
let btn =
- Eliom_content.Html.(D.button ~a:[D.a_class ["button"]] [D.txt msg])
+ Eliom.Content.Html.(D.button ~a:[D.a_class ["button"]] [D.txt msg])
in
ignore
[%client
(Lwt.async @@ fun () ->
- Lwt_js_events.clicks (Eliom_content.Html.To_dom.of_element ~%btn)
+ Lwt_js_events.clicks (Eliom.Content.Html.To_dom.of_element ~%btn)
(fun _ _ -> ~%f ())
: unit)];
btn
@@ -39,12 +39,12 @@ let%shared page () =
[%client
(fun () ->
let%lwt v = incr_my_ref () in
- Eliom_lib.alert "Update: %d" v;
+ Eliom.Lib.alert "Update: %d" v;
Lwt.return_unit
: unit -> unit Lwt.t)]
in
Lwt.return
- Eliom_content.Html.
+ Eliom.Content.Html.
[ F.h1 [%i18n Demo.rpc_button]
; F.p [F.txt [%i18n Demo.S.rpc_button_description]]
; F.p [btn] ]
diff --git a/template.distillery/demo_services.eliom b/template.distillery/demo_services.eliom
index bf67d39ae..3da888bfc 100644
--- a/template.distillery/demo_services.eliom
+++ b/template.distillery/demo_services.eliom
@@ -11,141 +11,141 @@
*)
let%server demo =
- Eliom_service.create ~path:(Eliom_service.Path ["demo"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo = ~%demo
let%server demo_popup =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-popup"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-popup"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_popup = ~%demo_popup
let%server demo_rpc =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-rpc"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-rpc"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_rpc = ~%demo_rpc
let%server demo_ref =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-ref"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-ref"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_ref = ~%demo_ref
let%server demo_spinner =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-spinner"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-spinner"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_spinner = ~%demo_spinner
let%server demo_pgocaml =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-pgocaml"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-pgocaml"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_pgocaml = ~%demo_pgocaml
let%server demo_users =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-users"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-users"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_users = ~%demo_users
let%server demo_links =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-links"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-links"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_links = ~%demo_links
let%server demo_i18n =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-i18n"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-i18n"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_i18n = ~%demo_i18n
let%server demo_tips =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-tips"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-tips"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_tips = ~%demo_tips
let%server demo_carousel1 =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-carousel1"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-carousel1"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_carousel1 = ~%demo_carousel1
let%server demo_carousel2 =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-carousel2"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-carousel2"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_carousel2 = ~%demo_carousel2
let%server demo_carousel3 =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-carousel3"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-carousel3"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_carousel3 = ~%demo_carousel3
let%server demo_tongue =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-tongue"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-tongue"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_tongue = ~%demo_tongue
let%server demo_calendar =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-calendar"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-calendar"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_calendar = ~%demo_calendar
let%server demo_timepicker =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-timepicker"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-timepicker"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_timepicker = ~%demo_timepicker
let%server demo_notif =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-notif"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-notif"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_notif = ~%demo_notif
let%server demo_react =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-react"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-react"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_react = ~%demo_react
let%server demo_pulltorefresh =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-pulltorefresh"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-pulltorefresh"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_pulltorefresh = ~%demo_pulltorefresh
let%server demo_cache =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-cache"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-cache"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_cache = ~%demo_cache
let%server demo_pagetransition =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-pagetransition"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-pagetransition"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_pagetransition = ~%demo_pagetransition
let%server demo_forms =
- Eliom_service.create ~path:(Eliom_service.Path ["demo-forms"])
- ~meth:(Eliom_service.Get Eliom_parameter.unit) ()
+ Eliom.Service.create ~path:(Eliom.Service.Path ["demo-forms"])
+ ~meth:(Eliom.Service.Get Eliom.Parameter.unit) ()
let%client demo_forms = ~%demo_forms
let%server detail_page =
- Eliom_service.create
- ~path:(Eliom_service.Path ["demo-page-transition"; "detail"; ""])
- ~meth:(Eliom_service.Get (Eliom_parameter.int "page"))
+ Eliom.Service.create
+ ~path:(Eliom.Service.Path ["demo-page-transition"; "detail"; ""])
+ ~meth:(Eliom.Service.Get (Eliom.Parameter.int "page"))
()
let%client detail_page = ~%detail_page
diff --git a/template.distillery/demo_spinner.eliom b/template.distillery/demo_spinner.eliom
index 13e0b50f4..374028459 100644
--- a/template.distillery/demo_spinner.eliom
+++ b/template.distillery/demo_spinner.eliom
@@ -2,33 +2,33 @@
Feel free to use it, modify it, and redistribute it as you wish. *)
(* Spinner demo *)
open%client Js_of_ocaml_lwt
-open%shared Eliom_content
+open%shared Eliom.Content
open%shared Html.D
(* Build the spinner *)
let%client make_spinner () =
- (* [Ot_spinner.with_spinner_no_lwt] accepts an Lwt thread "slowly"
+ (* [Ot.Spinner.with_spinner_no_lwt] accepts an Lwt thread "slowly"
producing HTML content *)
- Ot_spinner.with_spinner_no_lwt
+ Ot.Spinner.with_spinner_no_lwt
(* sleep for 5 seconds to simulate a delay, then return content *)
(let%lwt () = Lwt_js.sleep 5. in
Lwt.return
- Eliom_content.Html.D.
+ Eliom.Content.Html.D.
[ txt [%i18n Demo.S.spinner_content_ready]
; txt " "
; txt [%i18n Demo.S.spinner_message_replace_spinner] ])
(* Page for this demo *)
-let%shared page () : Html_types.div_content Eliom_content.Html.elt list Lwt.t =
+let%shared page () : Html_types.div_content Eliom.Content.Html.elt list Lwt.t =
Lwt.return
- Eliom_content.Html.
+ Eliom.Content.Html.
[ F.h1 [%i18n Demo.spinner]
; F.p [F.txt [%i18n Demo.S.spinner_description_ot]]
; F.p [F.txt [%i18n Demo.S.spinner_description_1]]
; F.p [F.txt [%i18n Demo.S.spinner_description_2]]
; F.p [F.txt [%i18n Demo.S.spinner_description_3]]
; F.p [F.txt [%i18n Demo.S.spinner_generated_client_side]]
- ; C.node [%client (make_spinner () : [> `Div] Eliom_content.Html.elt)] ]
+ ; C.node [%client (make_spinner () : [> `Div] Eliom.Content.Html.elt)] ]
(* Service registration is done on both sides (shared section),
so that pages can be generated from the server
diff --git a/template.distillery/demo_timepicker.eliom b/template.distillery/demo_timepicker.eliom
index 485df9b6b..1b1c06477 100644
--- a/template.distillery/demo_timepicker.eliom
+++ b/template.distillery/demo_timepicker.eliom
@@ -1,11 +1,11 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
-open%shared Eliom_content.Html.D
+open%shared Eliom.Content.Html.D
open%client Js_of_ocaml_lwt
(* Timepicker demo *)
-let%server s, f = Eliom_shared.React.S.create None
+let%server s, f = Eliom.Shared.React.S.create None
let%client action (h, m) =
~%f (Some (h, m));
@@ -16,24 +16,24 @@ let%shared string_of_time = function
[%i18n Demo.S.you_click_on_time ~h:(string_of_int h) ~m:(string_of_int m)]
| None -> ""
-let%server time_as_string () : string Eliom_shared.React.S.t =
- Eliom_shared.React.S.map [%shared string_of_time] s
+let%server time_as_string () : string Eliom.Shared.React.S.t =
+ Eliom.Shared.React.S.map [%shared string_of_time] s
-let%rpc time_reactive () : string Eliom_shared.React.S.t Lwt.t =
+let%rpc time_reactive () : string Eliom.Shared.React.S.t Lwt.t =
Lwt.return @@ time_as_string ()
(* Page for this demo *)
let%shared page () =
let time_picker, _, back_f =
- Ot_time_picker.make ~h24:true ~action:[%client action] ()
+ Ot.Time_picker.make ~h24:true ~action:[%client action] ()
in
let button =
- Eliom_content.Html.D.button [%i18n Demo.timepicker_back_to_hours]
+ Eliom.Content.Html.D.button [%i18n Demo.timepicker_back_to_hours]
in
ignore
[%client
(Lwt.async (fun () ->
- Lwt_js_events.clicks (Eliom_content.Html.To_dom.of_element ~%button)
+ Lwt_js_events.clicks (Eliom.Content.Html.To_dom.of_element ~%button)
(fun _ _ -> ~%back_f (); Lwt.return_unit))
: _)];
let%lwt tr = time_reactive () in
@@ -41,7 +41,7 @@ let%shared page () =
[ h1 [%i18n Demo.timepicker]
; p [%i18n Demo.timepicker_description]
; div [time_picker]
- ; p [Eliom_content.Html.R.txt tr]
+ ; p [Eliom.Content.Html.R.txt tr]
; div [button] ]
(* Service registration is done on both sides (shared section),
diff --git a/template.distillery/demo_tips.eliom b/template.distillery/demo_tips.eliom
index c36d2ecb6..a1ac968f9 100644
--- a/template.distillery/demo_tips.eliom
+++ b/template.distillery/demo_tips.eliom
@@ -1,20 +1,20 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
-(* Os_tips demo *)
-open%shared Eliom_content.Html.F
+(* Os.Tips demo *)
+open%shared Eliom.Content.Html.F
(* Here is an example of tip. Call this function while generating the
widget concerned by the explanation it contains. *)
let%shared example_tip () =
- (* Have a look at the API documentation of module Os_tips for
+ (* Have a look at the API documentation of module Os.Tips for
more options. *)
- Os_tips.bubble () ~top:[%client 40] ~right:[%client 0] ~width:[%client 300]
+ Os.Tips.bubble () ~top:[%client 40] ~right:[%client 0] ~width:[%client 300]
~height:[%client 180] ~arrow:[%client `top 250] ~name:"example"
~content:
[%client
fun _ ->
Lwt.return
- Eliom_content.Html.F.
+ Eliom.Content.Html.F.
[p [%i18n Demo.example_tip]; p [%i18n Demo.look_module_tip]]]
(* Page for this demo *)
@@ -23,7 +23,7 @@ let%shared page () =
let%lwt () = example_tip () in
Lwt.return
[ h1 [%i18n Demo.tips1]
- ; p [%i18n Demo.tips2 ~os_tips:[code [txt "Os_tips"]]]
+ ; p [%i18n Demo.tips2 ~os_tips:[code [txt "Os.Tips"]]]
; p [%i18n Demo.tips3]
; p
[%i18n
diff --git a/template.distillery/demo_tongue.eliom b/template.distillery/demo_tongue.eliom
index 47cd7303d..41934b63a 100644
--- a/template.distillery/demo_tongue.eliom
+++ b/template.distillery/demo_tongue.eliom
@@ -1,7 +1,7 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
(* Tongue demo *)
-open%shared Eliom_content.Html.F
+open%shared Eliom.Content.Html.F
(* Page for this demo *)
let%shared page () =
@@ -14,14 +14,14 @@ let%shared page () =
; div ~a:[a_class ["demo-tongue-6"]] [] ]
in
let tongue =
- Ot_tongue.tongue ~side:`Bottom
+ Ot.Tongue.tongue ~side:`Bottom
~stops:[`Px 70; `Interval (`Percent 100, `Full_content)]
~init:(`Px 70) content
in
Lwt.return
[ h1 [%i18n Demo.tongue_1]
; p [%i18n Demo.ot_tongue_1]
- ; div ~a:[a_class ["demo-tongue"]] [tongue.Ot_tongue.elt] ]
+ ; div ~a:[a_class ["demo-tongue"]] [tongue.Ot.Tongue.elt] ]
(* Service registration is done on both sides (shared section),
so that pages can be generated from the server
diff --git a/template.distillery/demo_tools.eliom b/template.distillery/demo_tools.eliom
index cb8780a1c..ebcf07a0f 100644
--- a/template.distillery/demo_tools.eliom
+++ b/template.distillery/demo_tools.eliom
@@ -26,7 +26,7 @@ let%shared demos =
]
let%shared drawer_contents () =
- let open Eliom_content.Html.F in
+ let open Eliom.Content.Html.F in
let make_link (name, service) = li [a ~service [txt @@ name ()] ()] in
let submenu =
ul ~a:[a_class ["os-drawer-submenu"]] (List.map make_link demos)
diff --git a/template.distillery/demo_users.eliom b/template.distillery/demo_users.eliom
index 2df687b1d..50d909ad8 100644
--- a/template.distillery/demo_users.eliom
+++ b/template.distillery/demo_users.eliom
@@ -1,14 +1,14 @@
(* This file was generated by Ocsigen Start.
Feel free to use it, modify it, and redistribute it as you wish. *)
-(* Os_current_user demo *)
-open%shared Eliom_content.Html.F
+(* Os.Current_user demo *)
+open%shared Eliom.Content.Html.F
let%shared display_user_name = function
| None -> p [%i18n Demo.you_are_not_connected]
| Some user ->
p
[ txt ([%i18n Demo.S.you_are] ^ " ")
- ; em [txt (Os_user.fullname_of_user user)] ]
+ ; em [txt (Os.User.fullname_of_user user)] ]
let%shared display_user_id = function
| None -> p [%i18n Demo.log_in_to_see_demo]
@@ -25,20 +25,20 @@ let%shared page () =
of mistaking an user for another.
We use prefix "_o" for optional value.
*)
- let myid_o = Os_current_user.Opt.get_current_userid () in
- let me_o = Os_current_user.Opt.get_current_user () in
+ let myid_o = Os.Current_user.Opt.get_current_userid () in
+ let me_o = Os.Current_user.Opt.get_current_user () in
Lwt.return
[ h1 [%i18n Demo.users]
; p
[ txt [%i18n Demo.S.the_module]
- ; code [txt " Os_current_user "]
+ ; code [txt " Os.Current_user "]
; txt [%i18n Demo.S.allows_get_information_currently_connected_user] ]
; display_user_name me_o
; display_user_id myid_o
; p [txt [%i18n Demo.S.these_functions_called_server_or_client_side]]
; p
[ txt [%i18n Demo.S.always_get_current_user_using_module]
- ; code [txt " Os_current_user. "]
+ ; code [txt " Os.Current_user. "]
; txt [%i18n Demo.S.never_trust_client_pending_user_id] ] ]
(* Service registration is done on both sides (shared section),
diff --git a/template.distillery/package-lock.json b/template.distillery/package-lock.json
new file mode 100644
index 000000000..792744d20
--- /dev/null
+++ b/template.distillery/package-lock.json
@@ -0,0 +1,1272 @@
+{
+ "name": "os_template",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "os_template",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "autoprefixer": "^9.8.6",
+ "postcss-cli": "^7.1.2"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/at-least-node": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/autoprefixer": {
+ "version": "9.8.6",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz",
+ "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==",
+ "dependencies": {
+ "browserslist": "^4.12.0",
+ "caniuse-lite": "^1.0.30001109",
+ "colorette": "^1.2.1",
+ "normalize-range": "^0.1.2",
+ "num2fraction": "^1.2.2",
+ "postcss": "^7.0.32",
+ "postcss-value-parser": "^4.1.0"
+ },
+ "bin": {
+ "autoprefixer": "bin/autoprefixer"
+ },
+ "funding": {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.23.3",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz",
+ "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001646",
+ "electron-to-chromium": "^1.5.4",
+ "node-releases": "^2.0.18",
+ "update-browserslist-db": "^1.1.0"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/caller-callsite": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
+ "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==",
+ "dependencies": {
+ "callsites": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/caller-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
+ "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==",
+ "dependencies": {
+ "caller-callsite": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
+ "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001655",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz",
+ "integrity": "sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ]
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/cliui": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+ "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^6.2.0"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
+ "node_modules/colorette": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
+ "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g=="
+ },
+ "node_modules/cosmiconfig": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
+ "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
+ "dependencies": {
+ "import-fresh": "^2.0.0",
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.13.1",
+ "parse-json": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/dependency-graph": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.9.0.tgz",
+ "integrity": "sha512-9YLIBURXj4DJMFALxXw9K3Y3rwb5Fk0X5/8ipCzaN84+gKxoHK43tVKRNakCQbiEx07E8Uwhuq21BpUagFhZ8w==",
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dependencies": {
+ "path-type": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.13",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz",
+ "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q=="
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+ },
+ "node_modules/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==",
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fastq": {
+ "version": "1.17.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
+ "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fs-extra": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
+ "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
+ "dependencies": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-stdin": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz",
+ "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/globby": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+ "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+ "dependencies": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.2.9",
+ "ignore": "^5.2.0",
+ "merge2": "^1.4.1",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/import-cwd": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
+ "integrity": "sha512-Ew5AZzJQFqrOV5BTW3EIoHAnoie1LojZLXKcCQ/yTRyVZosBhK1x1ViYjHGf5pAFOq8ZyChZp6m/fSN7pJyZtg==",
+ "dependencies": {
+ "import-from": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
+ "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==",
+ "dependencies": {
+ "caller-path": "^2.0.0",
+ "resolve-from": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/import-from": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz",
+ "integrity": "sha512-0vdnLL2wSGnhlRmzHJAg5JHjt1l2vYhzJ7tNLGbeVg0fse56tpGaH0uzH+r9Slej+BSXXEHvBKDEnVSLLE9/+w==",
+ "dependencies": {
+ "resolve-from": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-directory": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
+ "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/json-parse-better-errors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
+ },
+ "node_modules/jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
+ "node_modules/log-symbols": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
+ "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
+ "dependencies": {
+ "chalk": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/log-symbols/node_modules/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==",
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/log-symbols/node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/log-symbols/node_modules/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==",
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/log-symbols/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
+ },
+ "node_modules/log-symbols/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/log-symbols/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.18",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
+ "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g=="
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/num2fraction": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
+ "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg=="
+ },
+ "node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
+ "dependencies": {
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+ "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA=="
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "7.0.39",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+ "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+ "dependencies": {
+ "picocolors": "^0.2.1",
+ "source-map": "^0.6.1"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ }
+ },
+ "node_modules/postcss-cli": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-7.1.2.tgz",
+ "integrity": "sha512-3mlEmN1v2NVuosMWZM2tP8bgZn7rO5PYxRRrXtdSyL5KipcgBDjJ9ct8/LKxImMCJJi3x5nYhCGFJOkGyEqXBQ==",
+ "dependencies": {
+ "chalk": "^4.0.0",
+ "chokidar": "^3.3.0",
+ "dependency-graph": "^0.9.0",
+ "fs-extra": "^9.0.0",
+ "get-stdin": "^8.0.0",
+ "globby": "^11.0.0",
+ "postcss": "^7.0.0",
+ "postcss-load-config": "^2.0.0",
+ "postcss-reporter": "^6.0.0",
+ "pretty-hrtime": "^1.0.3",
+ "read-cache": "^1.0.0",
+ "yargs": "^15.0.2"
+ },
+ "bin": {
+ "postcss": "bin/postcss"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/postcss-load-config": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz",
+ "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==",
+ "dependencies": {
+ "cosmiconfig": "^5.0.0",
+ "import-cwd": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ }
+ },
+ "node_modules/postcss-reporter": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-6.0.1.tgz",
+ "integrity": "sha512-LpmQjfRWyabc+fRygxZjpRxfhRf9u/fdlKf4VHG4TSPbV2XNsuISzYW1KL+1aQzx53CAppa1bKG4APIB/DOXXw==",
+ "dependencies": {
+ "chalk": "^2.4.1",
+ "lodash": "^4.17.11",
+ "log-symbols": "^2.2.0",
+ "postcss": "^7.0.7"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/postcss-reporter/node_modules/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==",
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-reporter/node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-reporter/node_modules/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==",
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/postcss-reporter/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
+ },
+ "node_modules/postcss-reporter/node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-reporter/node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
+ },
+ "node_modules/pretty-hrtime": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
+ "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/read-cache": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
+ "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+ "dependencies": {
+ "pify": "^2.3.0"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/require-main-filename": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
+ },
+ "node_modules/resolve-from": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+ "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
+ },
+ "node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/universalify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+ "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz",
+ "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "escalade": "^3.1.2",
+ "picocolors": "^1.0.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/update-browserslist-db/node_modules/picocolors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
+ "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew=="
+ },
+ "node_modules/which-module": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
+ "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="
+ },
+ "node_modules/wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/y18n": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
+ "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
+ },
+ "node_modules/yargs": {
+ "version": "15.4.1",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+ "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+ "dependencies": {
+ "cliui": "^6.0.0",
+ "decamelize": "^1.2.0",
+ "find-up": "^4.1.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^4.2.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^18.1.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+ "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+ "dependencies": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ }
+ }
+}
diff --git a/template.distillery/package.json b/template.distillery/package.json
new file mode 100644
index 000000000..25f7c6b1a
--- /dev/null
+++ b/template.distillery/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "os_template",
+ "version": "1.0.0",
+ "description": "Instructions ============",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/ocsigen/os_template.git"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "bugs": {
+ "url": "https://github.com/ocsigen/os_template/issues"
+ },
+ "homepage": "https://github.com/ocsigen/os_template#readme",
+ "dependencies": {
+ "autoprefixer": "^9.8.6",
+ "postcss-cli": "^7.1.2"
+ }
+}
diff --git a/ocsigen-dune-rules/test/rules.t/a.eliom b/template.distillery/static!css!.import-external-css
similarity index 100%
rename from ocsigen-dune-rules/test/rules.t/a.eliom
rename to template.distillery/static!css!.import-external-css
diff --git a/template.distillery/static!css!ot_buttons.css b/template.distillery/static!css!ot_buttons.css
new file mode 100644
index 000000000..321ba53f2
--- /dev/null
+++ b/template.distillery/static!css!ot_buttons.css
@@ -0,0 +1,60 @@
+.ot-dropdown:hover {
+ background-color: gray;
+}
+
+.ot-dropdown {
+ position: relative;
+ transition: background-color .3s;
+}
+
+.ot-dropdown-background {
+ position: fixed;
+ background-color: black;
+ opacity: 0;
+ left: 0; right: 0; top: 0; bottom: 0;
+ visibility: hidden;
+ transition: opacity .1s, visibility .1s;
+ z-index: 1
+}
+
+.ot-dropdown-button {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ z-index: 5;
+}
+
+.ot-dropdown-menu {
+ position: absolute ;
+ top: 100% ;
+ right: 0 ;
+ min-width: max-content ;
+ overflow: hidden ;
+ z-index: 10 ;
+ box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.15) ;
+ visibility: hidden;
+ opacity: 0;
+ transition: opacity .2s, visibility .2s;
+}
+
+.ot-dropdown:hover > .ot-dropdown-background {
+ visibility: visible;
+ opacity: 0.2;
+}
+
+.ot-dropdown > .ot-dropdown-background:hover {
+ visibility: hidden;
+ opacity: 0;
+}
+
+.ot-dropdown:hover > .ot-dropdown-menu {
+ visibility: visible;
+ opacity: 1;
+}
+
+// not strictly necessary, but without this the menu will disappear a little
+// after once the background is completely gone (even without a transition)
+.ot-dropdown-background:hover ~ .ot-dropdown-menu {
+ visibility: hidden;
+ opacity: 0;
+}
diff --git a/template.distillery/static!css!ot_carousel.css b/template.distillery/static!css!ot_carousel.css
new file mode 100644
index 000000000..05977a209
--- /dev/null
+++ b/template.distillery/static!css!ot_carousel.css
@@ -0,0 +1,172 @@
+/* Ocsigen widget: carousel */
+
+.ot-carousel {
+
+ overflow: hidden ;
+ width: 200px; /* default size. Override this in your own stylesheet */
+ height: 150px; /* default size. Override this in your own stylesheet */
+
+}
+
+.ot-carousel > .ot-car2 {
+ display: flex ;
+ flex-wrap: nowrap ;
+
+// transform: translate3d(0,0,0);
+ transition-property: transform, -webkit-transform;
+ transition-timing-function: cubic-bezier(.03,.84,.56,1);
+
+ height: 100%;
+ width: 100%;
+}
+.ot-carousel > .ot-car2.ot-swiping { will-change: transform; }
+
+.ot-carousel > .ot-car2 .ot-carpage {
+ width: 100% ;
+ height: 100% ;
+ margin-left: 0 ;
+ margin-right: 0 ;
+ flex-shrink: 0 ;
+ flex-grow: 0 ;
+}
+
+.ot-carousel.ot-horizontal {
+ touch-action: pan-y;
+}
+
+.ot-carousel.ot-horizontal > .ot-car2 {
+ flex-direction: row ;
+}
+
+.ot-carousel.ot-vertical {
+ touch-action: pan-x;
+}
+
+.ot-carousel.ot-vertical > .ot-car2 {
+ flex-direction: column ;
+}
+
+.ot-bullet-nav {
+ list-style-type: none ;
+ display: flex ;
+ flex-direction: row ;
+ justify-content: center ;
+}
+
+.ot-bullet-nav-item {
+
+ flex: 1 1 0 ;
+ cursor: pointer;
+ border: 1px solid rgba(255, 255, 255, 0.8);;
+ border-radius: 50%;
+ width: 8px;
+ height: 8px;
+ margin: 4px;
+
+}
+
+.ot-bullet-nav-item.ot-active { background-color: rgba(255, 255, 255, 0.8); }
+
+.ot-car-ribbon {
+ position: relative;
+ user-select: none;
+ cursor: pointer;
+ touch-action: pan-x;
+}
+
+.ot-car-ribbon::after {
+ z-index: 1;
+ content: '';
+ position: absolute;
+ width: 100%;
+ bottom: -6px;
+ height: 6px;
+ background-image:
+ linear-gradient(to bottom, rgba(100,100,100, .3), rgba(100,100,100,0));
+}
+
+.ot-car-ribbon-list {
+ position: relative;
+ width: 100% ;
+ display: flex ;
+ left: 0;
+ width: 100% ;
+
+ white-space: nowrap;
+ padding: 20px 0;
+ margin: 0;
+}
+
+
+.ot-car-ribbon-list:not(.ot-notransition) {
+ transition-property: left;
+ transition-timing-function: cubic-bezier(.03,.84,.56,1);
+}
+
+.ot-car-ribbon-list-item {
+
+ display: inline-block;
+ cursor: pointer;
+ padding: 0 1rem;
+ flex-grow: 1;
+ flex-shrink: 0;
+ text-align: center;
+
+}
+
+
+.ot-car-prev, .ot-car-next {
+ background-color: transparent;
+}
+.ot-car-next.ot-blurred::before,
+.ot-car-prev.ot-blurred::before {
+ visibility: hidden;
+}
+.ot-car-prev::before {
+ content: '❬';
+}
+.ot-car-next::before {
+ content: '❭';
+}
+
+.ot-car-cursor {
+ box-sizing: border-box;
+ position: absolute;
+ height: 3px;
+ bottom: 0;
+ background-color: #66aaff;
+ transition-property: transform, width;
+ will-change: transform, width;
+}
+
+.ot-carousel.ot-full-height > .ot-car2:not(.ot-swiping)
+ > .ot-carpage:not(.ot-active) {
+ max-height: 100vh; /* We limit the size of non visible columns to avoid
+ scrolling too much in small columns
+ But NOT during swipe, as swiping might change the
+ scroll position in page. */
+}
+
+.ot-carousel.ot-wheel {
+ height: 25px;
+ width: 200px;
+ overflow: visible;
+ margin: 100px auto;
+ perspective: 500px;
+}
+.ot-carousel.ot-wheel > .ot-car2 {
+ position: absolute;
+ transform-style: preserve-3d;
+}
+.ot-carousel.ot-wheel > .ot-car2 > .ot-carpage {
+ backface-visibility: hidden;
+ position: absolute;
+ height: 25px;
+ line-height: 25px;
+ vertical-align: middle;
+ transition: opacity 2s;
+ opacity: 1;
+}
+.ot-carousel.ot-wheel .ot-carpage.ot-hidden-wheel-face {
+ opacity: 0;
+}
diff --git a/template.distillery/static!css!ot_datetime.css b/template.distillery/static!css!ot_datetime.css
new file mode 100644
index 000000000..c07f4e74c
--- /dev/null
+++ b/template.distillery/static!css!ot_datetime.css
@@ -0,0 +1,250 @@
+div.ot-toggle {
+ display: inline;
+ padding: 5px 1px 5px 1px;
+ border-radius: 5px
+}
+
+div.ot-inactive {
+ color: white;
+ display: inline;
+ padding: 3px;
+ border: solid 1px transparent;
+ cursor: pointer;
+}
+
+div.ot-active.ot-up {
+ color: green;
+ display: inline;
+ padding: 3px;
+ border: solid 1px green;
+ border-radius: 5px;
+}
+
+div.ot-active.ot-down {
+ color: red;
+ display: inline;
+ padding: 3px;
+ border: solid 1px red;
+ border-radius: 5px;
+}
+
+svg.ot-tp-clock {
+ width: 120px;
+ background-color: #eee;
+ border-radius: 50%;
+ display: inline-block;
+}
+
+svg.ot-tp-clock.ot-tp-clock-24h {
+ width: 160px;
+ border-radius: 80px;
+}
+
+svg.ot-tp-clock text {
+ font-size: 11px;
+}
+
+svg.ot-tp-clock.ot-tp-clock-24h text {
+ font-size: 9px;
+}
+
+svg.ot-tp-clock path {
+ stroke: #333333;
+ stroke-width: 2px;
+}
+
+svg.ot-tp-clock path.ot-tp-hand {
+ stroke: #990000;
+ stroke-width: 1px;
+}
+
+svg.ot-tp-clock circle.ot-tp-hand-circle {
+ stroke: #ff5d55;
+ stroke-width: 1px;
+ fill: #ff5d55;
+ fill-opacity: 1;
+}
+
+svg.ot-tp-clock.ot-tp-click-anywhere {
+ cursor: pointer;
+}
+
+div.ot-tp-container {
+ padding: 16px;
+ display: block;
+ text-align: center;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -webkit-tap-highlight-color: transparent;
+}
+
+.ot-tp-text {
+ cursor: pointer;
+}
+
+div.ot-tp-container div.ot-toggle {
+ display: inline;
+ padding: 5px 1px 5px 1px;
+ margin: 4px 0px 0px 0px;
+ border: solid 1px #333333;
+ border-radius: 5px
+}
+
+div.ot-tp-container div.ot-inactive {
+ color: black;
+ display: inline;
+ padding: 3px;
+ border: solid 1px transparent;
+ cursor: pointer;
+}
+
+div.ot-tp-container div.ot-active {
+ color: black;
+ background-color: #fafafa;
+ display: inline;
+ padding: 3px;
+ border: solid 1px #333333;
+ border-radius: 5px;
+}
+
+div.ot-tp-container div.ot-toggle {
+ display: inline-block;
+ padding: 5px 1px 5px 1px;
+ background-color: white;
+ border: 1px solid #333333;
+}
+
+div.ot-tp-container div.ot-tp-display {
+ display: block;
+ margin-left: 4px;
+ padding: 6px;
+ font-size: 22px;
+}
+.ot-c-next-year-button{
+ position: absolute;
+ right: 0px;
+ top: 10px;
+}
+.ot-c-next-button {
+ position: absolute;
+ right: 50px;
+ top: 10px;
+}
+.ot-c-prev-year-button{
+ position: absolute;
+ left: 0px;
+ top: 10px;
+}
+.ot-c-prev-button {
+ position: absolute;
+ left: 50px;
+ top: 10px;
+}
+.ot-c-select-month {
+ border: 0px;
+ outline: 0px;
+ width: 60px;
+ text-align-last:center;
+ background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='-5 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
+ background-position: right 0px center;
+ background-repeat: no-repeat;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ font-weight: bold;
+ position: absolute;
+ z-index:1;
+ right: 200px;
+ top: 14px;
+}
+.ot-c-select-year {
+ border: 0px;
+ outline: 0px;
+ width: 60px;
+ text-align-last:center;
+ background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='-5 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
+ background-position: right 0px center;
+ background-repeat: no-repeat;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ font-weight: bold;
+ position: absolute;
+ z-index:1;
+ right: 140px;
+ top: 14px;
+}
+.ot-c-select-month option, .ot-c-select-year option{
+ background: white;
+}
+.ot-c-out-period {
+ background-color: #fcfcfc;
+ color: rgb(200, 200, 200);
+ pointer-events: none;
+}
+.ot-c-table {
+ font-size: 14px;
+ line-height: 22px;
+ table-layout: fixed;
+}
+.ot-c-table th:not(.ot-c-header) {
+ vertical-align: middle;
+ font-weight: bold;
+ text-align: center;
+ text-transform: uppercase;
+ padding: 0 22px;
+ height: 36px;
+}
+.ot-c-table th.ot-c-header {
+ height: 43px;
+ font-size: 19px;
+ position: relative;
+ text-transform: capitalize;
+}
+.ot-c-table td {
+ vertical-align: middle;
+ text-align: center;
+ padding: 0;
+ height: 36px;
+ cursor: pointer;
+}
+.ot-c-table td:not(:empty):hover {
+ background-color: #eee;
+ border-radius: 5px;
+}
+.ot-c-clicked {
+ background-color: #990000;
+ border-radius: 50%;
+}
+.ot-c-prev-year-button,
+.ot-c-next-year-button,
+.ot-c-prev-button,
+.ot-c-next-button {
+ padding: 0 28px;
+ cursor: pointer;
+}
+th.ot-c-header {
+ text-align:center;
+}
+
+@keyframes shake-animation {
+ 0% {transform: translateX(0)}
+ 25% {transform: translateX(-5px)}
+ 75% {transform: translateX(5px)}
+ 100% {transform: translateX(0)}
+}
+
+.ot-tp-clock-min {
+ animation-name: shake-animation;
+ animation-duration: .1s;
+}
+.ot-c-current>div {
+ color: white;
+ background-color: #ff5d55;
+ width: 27px;
+ line-height: 27px;
+ border-radius: 50%;
+ display: inline-block;
+}
\ No newline at end of file
diff --git a/template.distillery/static!css!ot_drawer.css b/template.distillery/static!css!ot_drawer.css
new file mode 100644
index 000000000..14cbbad6d
--- /dev/null
+++ b/template.distillery/static!css!ot_drawer.css
@@ -0,0 +1,172 @@
+/* Generic drawer stylesheet. */
+
+html.ot-drawer-open, html.ot-drawer-open > body {
+ overflow: hidden;
+ position: fixed ; /* To prevent scroll on mobile devices.
+ One must also set top property manually
+ to prevent scrolling page to top. */
+}
+
+/* .ot-dr-container.open .ot-dr-toggle-button { */
+/* display: none; */
+/* } */
+
+/* @include media-screen-m-l { */
+/* .ot-dr-toggle-button { */
+/* top: 1rem; */
+/* } */
+/* } */
+
+/* .ot-dr-toggle-button::before { */
+/* font-family: 'FontAwesome'; */
+/* content: '\f0c9'; */
+/* padding: 1rem; */
+/* } */
+
+/* .ot-dr-toggle-button.login::before { */
+/* font-family: 'Ubuntu'; */
+/* content: 'login'; */
+/* } */
+
+
+.ot-drawer-bckgrnd {
+ background-color: rgba(0,0,0,0);
+ transition: background-color .2s;
+}
+
+.ot-drawer-bckgrnd.ot-dr-closing,
+.ot-drawer-bckgrnd.ot-dr-opening,
+.ot-drawer-bckgrnd.ot-dr-open {
+ position: fixed;
+ width: 100vw;
+ height: 100vh;
+ top: 0;
+ left: 0;
+ z-index: 1;
+}
+
+.ot-drawer-bckgrnd.ot-dr-open {
+ background-color: rgba(0,0,0,0.5);
+}
+
+.ot-drawer {
+
+ position: fixed;
+ width: 100%;
+ height: 100%;
+ z-index: 1;
+
+ /* [ overflow: visible ; ] is needed for the button
+ * to be displayed
+ * if the drawer needs to be scrollable, you probably will want
+ * to wrap the content into a wrapper
+ * with overflow-y: auto ; touch-action: pan-y; */
+ overflow: visible ;
+
+ transition: -webkit-transform .2s ease-out;
+ transition: transform .2s ease-out;
+
+ /* We set up drawer so that the default transform is the identity
+ * Otherwise, with Firefox, a transition is performed on page
+ * change. */
+
+ background-color: white;
+}
+
+@media (min-width: 720px) {
+ .ot-drawer.ot-dr-left, .ot-drawer.ot-dr-right {
+ width: 300px;
+ }
+
+ .ot-drawer.ot-dr-top, .ot-drawer.ot-dr-bottom {
+ height: 300px;
+ }
+}
+
+@media (max-width: 720px) {
+ .ot-drawer.ot-dr-left, .ot-drawer.ot-dr-right {
+ width: calc(100% - 50px);
+ }
+
+ .ot-drawer.ot-dr-top, .ot-drawer.ot-dr-bottom {
+ height: calc(100% - 50px);
+ }
+}
+
+.ot-drawer.ot-dr-top { bottom: 100% ; }
+.ot-drawer.ot-dr-right { left: 100% ; top: 0 }
+.ot-drawer.ot-dr-bottom { top: 100% ; }
+.ot-drawer.ot-dr-left { right: 100% ; top: 0 }
+
+.ot-dr-toggle-button::before { content: "≡"; }
+
+.ot-drawer-bckgrnd.ot-dr-open .ot-dr-top .ot-dr-toggle-button::before {
+ content: "︿" ;
+}
+
+.ot-drawer-bckgrnd.ot-dr-open .ot-dr-right .ot-dr-toggle-button::before {
+ content: "⟩" ;
+}
+
+.ot-drawer-bckgrnd.ot-dr-open .ot-dr-bottom .ot-dr-toggle-button::before {
+ content: "﹀" ;
+}
+
+.ot-drawer-bckgrnd.ot-dr-open .ot-dr-left .ot-dr-toggle-button::before {
+ content: "⟨" ;
+}
+
+.ot-drawer-bckgrnd.ot-dr-open .ot-dr-toggle-button {
+ background-color: #445;
+}
+
+.ot-drawer > .ot-dr-toggle-button {
+ position: absolute ;
+ cursor: pointer ;
+ height: 50px;
+ width: 50px;
+ padding: 0;
+ background-color: transparent;
+ border: none;
+ font-size: 30px;
+ outline: none;
+}
+
+.ot-drawer.ot-dr-top > .ot-dr-toggle-button {
+ top: 100% ;
+ right: calc(50% - 25px) ;
+}
+
+.ot-drawer.ot-dr-right > .ot-dr-toggle-button,
+.ot-drawer.ot-dr-left > .ot-dr-toggle-button {
+ top: 0 ;
+}
+
+.ot-drawer.ot-dr-bottom > .ot-dr-toggle-button {
+ bottom: 100% ;
+ left: calc(50% - 25px) ;
+}
+
+.ot-drawer.ot-dr-left > .ot-dr-toggle-button { left: 100% ; }
+.ot-drawer.ot-dr-right > .ot-dr-toggle-button { right: 100% ; }
+
+
+.ot-drawer-bckgrnd.ot-dr-open .ot-drawer.ot-dr-left {
+ -webkit-transform: translateX(100%);
+ transform: translateX(100%);
+}
+
+.ot-drawer-bckgrnd.ot-dr-open .ot-drawer.ot-dr-right {
+ -webkit-transform: translateX(-100%);
+ transform: translateX(-100%);
+}
+
+.ot-drawer-bckgrnd.ot-dr-open .ot-drawer.ot-dr-top {
+ -webkit-transform: translateY(100%);
+ transform: translateY(100%);
+}
+
+.ot-drawer-bckgrnd.ot-dr-open .ot-drawer.ot-dr-bottom {
+ -webkit-transform: translateY(-100%);
+ transform: translateY(-100%);
+}
diff --git a/template.distillery/static!css!ot_form.css b/template.distillery/static!css!ot_form.css
new file mode 100644
index 000000000..cd47b7099
--- /dev/null
+++ b/template.distillery/static!css!ot_form.css
@@ -0,0 +1,227 @@
+/* ================================================================ */
+/* Toggle button */
+/* ================================================================ */
+
+.ot-toggle-button {
+ display: inline-flex;
+ align-items: center;
+ padding: 0.4em 1em;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ cursor: pointer;
+ transition: background-color 0.15s, border-color 0.15s, color 0.15s;
+}
+
+.ot-toggle-off {
+ background-color: #4a90d9;
+ border-color: #4a90d9;
+ color: white;
+}
+
+.ot-toggle-off:hover {
+ background-color: #3a7bc8;
+ border-color: #3a7bc8;
+}
+
+.ot-toggle-on {
+ background-color: #3570a8;
+ border-color: #2d6090;
+ color: white;
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3);
+}
+
+.ot-toggle-on:hover {
+ background-color: #2d6090;
+ border-color: #265580;
+}
+
+/* ================================================================ */
+/* Password input */
+/* ================================================================ */
+
+.ot-password-container {
+ display: flex;
+ align-items: center;
+}
+
+.ot-password-container > .ot-password-input,
+.ot-password-container > input {
+ flex: 1;
+}
+
+.ot-password-toggle {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0.4em 0.6em;
+ border: 1px solid #ccc;
+ border-left: none;
+ background: #f5f5f5;
+ cursor: pointer;
+ line-height: 1;
+}
+
+.ot-password-toggle:hover {
+ background: #e8e8e8;
+}
+
+/* Pressed look when password is visible (toggle shows the "hide" icon) */
+.ot-password-toggle:has(.ot-password-toggle-hide) {
+ background: #e0e0e0;
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2);
+}
+
+/* The toggle contains a span that gets class ot-password-toggle-show
+ or ot-password-toggle-hide via R.a_class. We use background-image
+ SVGs so the icon is visible even though the span has no text. */
+.ot-password-toggle-show,
+.ot-password-toggle-hide {
+ display: inline-block;
+ width: 1.4em;
+ height: 1.4em;
+ background-size: contain;
+ background-repeat: no-repeat;
+ background-position: center;
+}
+
+/* Eye open (Feather icon) */
+.ot-password-toggle-show {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23555' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E");
+}
+
+/* Eye off / barred (Feather icon) */
+.ot-password-toggle-hide {
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23555' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24'/%3E%3Cline x1='1' y1='1' x2='23' y2='23'/%3E%3C/svg%3E");
+}
+
+/* ================================================================ */
+/* Checkbox */
+/* ================================================================ */
+
+/* The label element has both a desktop and a mobile style class,
+ e.g. ot-checkbox-box-desktop + ot-checkbox-toggle-mobile.
+ We only style desktop classes here; apps should add media queries
+ to switch to mobile styles at their chosen breakpoint.
+
+ DOM structure:
+ label.ot-checkbox.ot-checkbox-{style}-desktop
+ input.ot-checkbox-input[type=checkbox] (hidden)
+ span.ot-checkbox-label
+ span.ot-checkbox-decoration
+ span.ot-checkbox-sub-decoration
+ span (text content)
+*/
+
+.ot-checkbox {
+ display: inline-flex;
+ align-items: center;
+ cursor: pointer;
+ gap: 0.5em;
+}
+
+.ot-checkbox-label {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.4em;
+}
+
+.ot-checkbox > .ot-checkbox-input {
+ position: absolute;
+ opacity: 0;
+ width: 0;
+ height: 0;
+}
+
+/* --- Box style -------------------------------------------------- */
+
+.ot-checkbox-box-desktop .ot-checkbox-decoration {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 1.2em;
+ height: 1.2em;
+ border: 2px solid #888;
+ border-radius: 3px;
+ background: white;
+ transition: background-color 0.15s, border-color 0.15s;
+}
+
+.ot-checkbox-box-desktop .ot-checkbox-sub-decoration {
+ width: 0.35em;
+ height: 0.65em;
+ border: solid transparent;
+ border-width: 0 2px 2px 0;
+ transform: rotate(45deg);
+ margin-bottom: 0.1em;
+}
+
+.ot-checkbox-box-desktop > .ot-checkbox-input:checked + .ot-checkbox-label .ot-checkbox-decoration {
+ background-color: #4a90d9;
+ border-color: #4a90d9;
+}
+
+.ot-checkbox-box-desktop > .ot-checkbox-input:checked + .ot-checkbox-label .ot-checkbox-sub-decoration {
+ border-color: white;
+}
+
+/* --- Toggle style ----------------------------------------------- */
+
+.ot-checkbox-toggle-desktop .ot-checkbox-decoration {
+ display: inline-block;
+ width: 2.4em;
+ height: 1.3em;
+ border-radius: 0.65em;
+ background-color: #ccc;
+ position: relative;
+ transition: background-color 0.2s;
+}
+
+.ot-checkbox-toggle-desktop .ot-checkbox-sub-decoration {
+ display: block;
+ position: absolute;
+ width: 1.05em;
+ height: 1.05em;
+ border-radius: 50%;
+ background: white;
+ top: 0.125em;
+ left: 0.125em;
+ transition: transform 0.2s;
+}
+
+.ot-checkbox-toggle-desktop > .ot-checkbox-input:checked + .ot-checkbox-label .ot-checkbox-decoration {
+ background-color: #4a90d9;
+}
+
+.ot-checkbox-toggle-desktop > .ot-checkbox-input:checked + .ot-checkbox-label .ot-checkbox-sub-decoration {
+ transform: translateX(1.1em);
+}
+
+/* --- Bullet style ----------------------------------------------- */
+
+.ot-checkbox-bullet-desktop .ot-checkbox-decoration {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 1.2em;
+ height: 1.2em;
+ border: 2px solid #888;
+ border-radius: 50%;
+ background: white;
+ transition: border-color 0.15s;
+}
+
+.ot-checkbox-bullet-desktop .ot-checkbox-sub-decoration {
+ width: 0.6em;
+ height: 0.6em;
+ border-radius: 50%;
+ background-color: transparent;
+ transition: background-color 0.15s;
+}
+
+.ot-checkbox-bullet-desktop > .ot-checkbox-input:checked + .ot-checkbox-label .ot-checkbox-decoration {
+ border-color: #4a90d9;
+}
+
+.ot-checkbox-bullet-desktop > .ot-checkbox-input:checked + .ot-checkbox-label .ot-checkbox-sub-decoration {
+ background-color: #4a90d9;
+}
diff --git a/template.distillery/static!css!ot_icons.css b/template.distillery/static!css!ot_icons.css
new file mode 100644
index 000000000..b1f6d93f8
--- /dev/null
+++ b/template.distillery/static!css!ot_icons.css
@@ -0,0 +1,173 @@
+@keyframes ot-icon-animation-spinning {
+ 0% { transform: rotate(0deg) ; }
+ 100% { transform: rotate(360deg) ; }
+}
+
+@keyframes ot-icon-animation-shake {
+ 10%, 90% { transform: translate3d(-.05em, 0, 0); }
+ 20%, 80% { transform: translate3d(.1em, 0, 0); }
+ 30%, 50%, 70% { transform: translate3d(-.2em, 0, 0); }
+ 40%, 60% { transform: translate3d(.2em, 0, 0); }
+}
+
+.ot-icon-animation-shaking {
+ animation: ot-icon-animation-shake 1s cubic-bezier(.36,.07,.19,.97) both ;
+}
+
+.ot-icon-animation-once { animation-iteration-count: 1 ; }
+
+.ot-icon {
+ display: inline-block ;
+ width: 1em ;
+ height: 1em ;
+ overflow: hidden ;
+ position: relative ;
+}
+
+.ot-icon,
+.ot-icon::before,
+.ot-icon::after {
+ box-sizing: border-box ;
+ display: inline-block ;
+}
+
+.ot-icon::before,
+.ot-icon::after {
+ content: '' ;
+}
+
+.ot-icon-user {
+ text-align: center ;
+}
+.ot-icon-user::before, .ot-icon-user::after {
+ display: block ;
+ margin: auto ;
+}
+.ot-icon-user::before {
+ width: .5em ;
+ height: .5em ;
+ margin-bottom: .05em ;
+ border-radius: 50% ;
+ background-color: black ;
+}
+.ot-icon-user::after {
+ box-sizing: border-box;
+ width: 1em;
+ height: 1em;
+ border-radius: 50% 50% 0% 0%;
+ background-color: black ;
+}
+
+.ot-icon-error::before,
+.ot-icon-question::before {
+ content: '?' ;
+ display: block ;
+ font-weight: bold ;
+ width: 1em ;
+ height: 1em ;
+ line-height: 1em ;
+ border-radius: 50% ;
+ background-color: rgb(0, 0, 0) ;
+ color: rgb(255, 255, 255) ;
+ text-align: center ;
+}
+
+.ot-icon-plus::before {
+ position: absolute ;
+ left: .15em ;
+ right: .15em ;
+ top: .4em ;
+ bottom: .4em ;
+ background-color: #000 ;
+}
+.ot-icon-plus::after {
+ position: absolute ;
+ top: .15em ;
+ bottom: .15em ;
+ left: .4em ;
+ right: .4em ;
+ background-color: #000 ;
+}
+
+.ot-icon-power {
+ text-align: center ;
+}
+.ot-icon-power::before {
+ display: block ;
+ position: absolute ;
+ bottom: 0 ;
+ top: .1em ;
+ left: .05em ;
+ right: .05em ;
+ border: .1em solid #000 ;
+ border-top: .1em solid transparent ;
+ border-radius: 50% ;
+}
+.ot-icon-power::after {
+ position: absolute ;
+ top: 0 ;
+ bottom: .5em ;
+ left: .45em ;
+ right: .45em ;
+ background-color: #000 ;
+}
+
+.ot-icon-sign-in::after,
+.ot-icon-sign-out::after {
+ position: absolute;
+ width: .5em;
+ height: .5em;
+ top: .25em;
+ border: .1em solid #000;
+ border-bottom: none;
+ border-left: none;
+ transform: rotate(45deg);
+ border-radius: 0 .1rem 0 0;
+}
+.ot-icon-sign-in::after { left: -.075em ; }
+.ot-icon-sign-out::after { right: .15em ; }
+
+.ot-icon-sign-in::before,
+.ot-icon-sign-out::before {
+ width: .75em;
+ margin-left: .125em ;
+ height: 1em;
+ border: .1em solid #000;
+}
+
+.ot-icon-sign-in::before { border-left: none ; }
+.ot-icon-sign-out::before { border-right: none ; }
+
+.ot-icon-gear::before {
+ width: 1em ;
+ height: 1em ;
+ border-radius: 50% ;
+ border: .2em dotted #000 ;
+}
+
+.ot-icon-gear::after {
+ position:absolute ;
+ width: .8em ;
+ height: .8em ;
+ left: .2rem ;
+ top: .2rem ;
+ border: .5rem solid #000 ;
+ border-radius: 50% ;
+}
+
+.ot-icon-close::before {
+ position: absolute ;
+ left: .4em ;
+ width: .2em ;
+ height: 1em ;
+ background: #000 ;
+ transform: rotate(-45deg);
+}
+.ot-icon-close::after {
+ position: absolute ;
+ width: .2em ;
+ height: 1em ;
+ left: .4em ;
+ background: #000 ;
+ transform: rotate(45deg) ;
+}
diff --git a/template.distillery/static!css!ot_page_transition.css b/template.distillery/static!css!ot_page_transition.css
new file mode 100644
index 000000000..3b90a5eb0
--- /dev/null
+++ b/template.distillery/static!css!ot_page_transition.css
@@ -0,0 +1,38 @@
+.ot-page-transition-wrapper {
+ position: fixed;
+ overflow: hidden;
+ z-index: 1000;
+ top: 0;
+ height: 100vh;
+ width: 100vw;
+ background-color: white;
+}
+
+.ot-page-transition-wrapper-backward {
+ left: 0;
+}
+
+.ot-page-transition-wrapper-forward {
+ right: 100vw;
+}
+
+.ot-page-transition-ss-container {
+ width: 100vw;
+ height: 100vh;
+ background-size: contain;
+ background-repeat: no-repeat;
+ background-color: lightgrey;
+}
+
+.ot-page-transition-wrapper-post-backward {
+ transform: translateX(100vw);
+}
+
+.ot-page-transition-body-pre-forward {
+ transform: translateX(100vw);
+ height: 100vh;
+}
+
+.ot-page-transition-screenshot-post-forward {
+ transform: translateX(100vw);
+}
diff --git a/template.distillery/static!css!ot_picture_uploader.css b/template.distillery/static!css!ot_picture_uploader.css
new file mode 100644
index 000000000..048940577
--- /dev/null
+++ b/template.distillery/static!css!ot_picture_uploader.css
@@ -0,0 +1,106 @@
+.ot-pup-ctrls {
+ position: absolute ;
+ overflow: visible ;
+ top: 0px ;
+ left: 0px ;
+ right: 0px ;
+ bottom: 0px ;
+ cursor: move ;
+ will-change: bottom, left, right, top ;
+ border: 1px solid black;
+}
+
+.ot-no-file .ot-pup-ctrls {
+ border: none;
+}
+
+.ot-pup-ctrl { position: absolute ; }
+
+.ot-pup-ctrl-t {
+ top: 0px ;
+ left: 10px ;
+ right: 10px ;
+ height: 10px ;
+ cursor: n-resize ;
+}
+.ot-pup-ctrl-tr {
+ right: 0px ;
+ top: 0px ;
+ width: 10px ;
+ height: 10px ;
+ cursor: ne-resize ;
+}
+.ot-pup-ctrl-r {
+ right: 0px ;
+ top: 10px ;
+ bottom: 10px ;
+ width: 10px ;
+ cursor: e-resize ;
+}
+.ot-pup-ctrl-br {
+ right: 0px ;
+ bottom: 0px ;
+ width: 10px ;
+ height: 10px ;
+ cursor: se-resize ;
+}
+.ot-pup-ctrl-b {
+ bottom: 0px ;
+ left: 10px ;
+ right: 10px ;
+ height: 10px ;
+ cursor: s-resize ;
+}
+.ot-pup-ctrl-bl {
+ left: 0px ;
+ bottom: 0px ;
+ width: 10px ;
+ height: 10px ;
+ cursor: sw-resize ;
+}
+.ot-pup-ctrl-l {
+ left: 0px ;
+ top: 10px ;
+ bottom: 10px ;
+ width: 10px ;
+ cursor: w-resize ;
+}
+.ot-pup-ctrl-tl {
+ left: 0px ;
+ top: 0px ;
+ width: 10px ;
+ height: 10px ;
+ cursor: nw-resize ;
+}
+
+.ot-pup-fltr {
+ background-color: rgba(255, 255, 255, .5) ;
+ position: absolute ;
+ will-change: top,bottom,right,left,width,height ;
+}
+.ot-pup-fltr-t { top: 0px ; cursor: n-resize ; }
+.ot-pup-fltr-tr { top: 0px ; right: 0px ; cursor: ne-resize ; }
+.ot-pup-fltr-tl { top: 0px ; left: 0px ; cursor: nw-resize ; }
+.ot-pup-fltr-b { bottom: 0px ; cursor: s-resize ; }
+.ot-pup-fltr-br { bottom: 0px ; right: 0px ; cursor: se-resize ; }
+.ot-pup-fltr-bl { bottom: 0px ; left: 0px ; cursor: sw-resize ; }
+.ot-pup-fltr-l { left: 0px ; cursor: w-resize ; }
+.ot-pup-fltr-r { right: 0px ; cursor: e-resize ; }
+
+.ot-pup-crop-container {
+ position: absolute ;
+ top:0px ;
+ left:0px ;
+ right:0px ;
+ bottom:0px ;
+}
+
+.ot-pup-preview {
+ width: 100% ;
+ display: block ;
+}
+
+.ot-pup-container {
+ position: relative ;
+ width: 100% ;
+}
diff --git a/template.distillery/static!css!ot_popup.css b/template.distillery/static!css!ot_popup.css
new file mode 100644
index 000000000..617e4262c
--- /dev/null
+++ b/template.distillery/static!css!ot_popup.css
@@ -0,0 +1,76 @@
+html.ot-with-popup,
+html.ot-with-popup>body {
+ overflow: hidden;
+ position: fixed;
+ /* To prevent scroll on mobile devices.
+ One must also set top property manually
+ to prevent scrolling page to top. */
+ width: 100%;
+}
+
+.ot-popup-background {
+ position: fixed;
+ right: 0;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ z-index: 1;
+ background-color: rgba(0, 0, 0, 0.6);
+ display: flex;
+}
+
+.ot-popup {
+ position: relative;
+ margin: auto;
+ z-index: 2;
+ display: flex;
+ max-height: 100%;
+ min-height: 2em;
+ /* .ot-popup-close button */
+ overflow: auto;
+ background-color: #FFFFFF;
+ padding: .5em;
+ border-radius: 2px;
+}
+
+.ot-popup-close {
+ position: absolute;
+ top: 0;
+ right: 0;
+ background: transparent;
+ border: none;
+ cursor: pointer;
+ z-index: 2;
+ padding: 5px;
+}
+
+.ot-popup-content {
+ width: 100%;
+ flex: 1 1 auto;
+ overflow: auto;
+ display: flex;
+}
+
+.ot-hcf {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ flex-wrap: nowrap;
+ align-items: stretch;
+ overflow: auto;
+}
+
+.ot-hcf-header,
+.ot-hcf-footer {
+ flex-shrink: 0;
+}
+
+.ot-hcf-header:empty,
+.ot-hcf-footer:empty {
+ display: none;
+}
+
+.ot-hcf-content {
+ flex-grow: 1;
+ overflow: auto;
+}
\ No newline at end of file
diff --git a/template.distillery/static!css!ot_spinner.css b/template.distillery/static!css!ot_spinner.css
new file mode 100644
index 000000000..fdc547f61
--- /dev/null
+++ b/template.distillery/static!css!ot_spinner.css
@@ -0,0 +1,24 @@
+.ot-spn-error,
+.ot-spn-spinning {
+ display: flex ;
+ justify-content: center ;
+ align-items: center ;
+}
+
+.ot-icon-animation-spinning {
+ display: flex !important;
+ align-items: center;
+ justify-content: center;
+}
+
+.ot-icon-animation-spinning::before {
+ content: "";
+ margin: 1rem;
+ padding: 10px ;
+ background-position: center ;
+ background-repeat: no-repeat ;
+ background-size:contain;
+ background-image: url("data:image/svg+xml,%3Csvg xmlns:xlink='http://www.w3.org/1999/xlink' xmlns='http://www.w3.org/2000/svg' viewBox='-256 -256 512 512'%3E%3Cg fill='%23ccc'%3E%3Crect id='r' ry='19' height='143' width='52' transform='translate(-26,108)'/%3E%3Cuse xlink:href='%23r' transform='rotate(30)'/%3E%3Cuse xlink:href='%23r' transform='rotate(-30)'/%3E%3Cuse xlink:href='%23r' transform='rotate(60)'/%3E%3Cuse xlink:href='%23r' transform='rotate(-60)'/%3E%3Cuse xlink:href='%23r' transform='rotate(-90)'/%3E%3Cuse xlink:href='%23r' transform='rotate(-120)'/%3E%3Cuse xlink:href='%23r' transform='rotate(-150)'/%3E%3C/g%3E%3Cuse xlink:href='%23r' transform='rotate(90)' fill='%23c5c5c5'/%3E%3Cuse xlink:href='%23r' transform='rotate(120)' fill='%23999'/%3E%3Cuse xlink:href='%23r' transform='rotate(150)' fill='%23878787'/%3E%3Cuse xlink:href='%23r' transform='rotate(180)' fill='%23626262'/%3E%3C/svg%3E");
+ animation: ot-icon-animation-spinning 1s steps(12) infinite;
+}
+.ot-icon-animation-spinning::after { content: normal !important; }
diff --git a/template.distillery/static!css!ot_sticky.css b/template.distillery/static!css!ot_sticky.css
new file mode 100644
index 000000000..9798611bc
--- /dev/null
+++ b/template.distillery/static!css!ot_sticky.css
@@ -0,0 +1,10 @@
+.ot-sticky-fixed {
+ position: fixed;
+}
+.ot-sticky-fixed:not(.ot-stuck) {
+ visibility: hidden;
+}
+
+.ot-sticky-inline.ot-stuck {
+ visibility: hidden;
+}
diff --git a/template.distillery/static!css!ot_tongue.css b/template.distillery/static!css!ot_tongue.css
new file mode 100644
index 000000000..04f1ccad6
--- /dev/null
+++ b/template.distillery/static!css!ot_tongue.css
@@ -0,0 +1,71 @@
+.ot-tongue {
+ position: fixed;
+ will-change: transform;
+ z-index: 1;
+ background-color: white;
+ box-shadow: 0 2px 9px 0 rgba(173, 173, 173, 0.5);
+ overflow: hidden;
+}
+.ot-tongue::after {
+ content: "";
+ position: absolute;
+ background-color: #eee;
+ border-radius: 2px;
+ z-index: 1;
+}
+.ot-tongue-left {
+ height: 100%;
+ padding-right: 70px;
+ border-radius: 0 5px 5px 0;
+ top: 0;
+ right: 100%;
+}
+.ot-tongue-left::after {
+ right: 4px;
+ width: 4px;
+ top: calc(50% - 10px);
+ height: 20px;
+}
+.ot-tongue-right {
+ height: 100%;
+ padding-left: 70px;
+ border-radius: 5px 0 0 5px;
+ top: 0;
+ left: 100%;
+}
+.ot-tongue-right::after {
+ left: 4px;
+ width: 4px;
+ top: calc(50% - 10px);
+ height: 20px;
+}
+.ot-tongue-top {
+ width: 100%;
+ padding-bottom: 70px;
+ border-radius: 0 0 5px 5px;
+ bottom: 100%;
+ left: 0;
+}
+.ot-tongue-top::after {
+ bottom: 4px;
+ height: 4px;
+ left: calc(50% - 10px);
+ width: 20px;
+}
+.ot-tongue-bottom {
+ width: 100%;
+ padding-top: 70px;
+ border-radius: 5px 5px 0 0;
+ top: 0;
+ transform: translateY(100vh);
+ left: 0;
+}
+.ot-tongue-bottom::after {
+ top: 4px;
+ height: 4px;
+ left: calc(50% - 10px);
+ width: 20px;
+}
+.ot-tongue:not(.notransition) {
+ transition: transform 0.4s cubic-bezier(0.1, 1, 0.8, 1);
+}
diff --git a/template.distillery/static!defaultcss!PROJECT_NAME.css b/template.distillery/static!defaultcss!PROJECT_NAME.css
new file mode 100644
index 000000000..7ab3d4a9c
--- /dev/null
+++ b/template.distillery/static!defaultcss!PROJECT_NAME.css
@@ -0,0 +1,3 @@
+@import url(font-awesome.min.css);@import url(ot_buttons.css);@import url(ot_carousel.css);@import url(ot_sticky.css);@import url(ot_datetime.css);@import url(ot_drawer.css);@import url(ot_icons.css);@import url(ot_picture_uploader.css);@import url(ot_popup.css);@import url(ot_spinner.css);@import url(ot_page_transition.css);@import url(ot_tongue.css);@import url(ot_form.css);@import url("https://fonts.googleapis.com/css?family=Quicksand");html{box-sizing:border-box}*,*::before,*::after{box-sizing:inherit}body{margin:0;font-size:15px;background-color:#f8fafc;color:#334155;line-height:1.6}body,input,textarea,keygen,select,button{font-family:'Quicksand', sans-serif}a,a:visited{text-decoration:none;color:#2563eb;cursor:pointer;transition:color 0.15s ease}a:hover,a:visited:hover{color:#1d4ed8}button,input{border:none}button,input[type="submit"],input[type="button"]{cursor:pointer}.button{border-radius:8px;box-shadow:0 1px 2px rgba(0,0,0,0.05);background-color:#2563eb;color:white;font-size:14px;font-weight:600;padding:8px 20px;margin:5px;border:none;transition:background-color 0.15s ease, box-shadow 0.15s ease}.button:hover{background-color:#1d4ed8;box-shadow:0 4px 12px rgba(0,0,0,0.08)}input{padding:8px 12px;border-radius:8px;border:1px solid #e2e8f0;transition:border-color 0.15s ease, box-shadow 0.15s ease}input:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px rgba(37,99,235,0.1)}.connected-user-box{display:flex;align-items:center}.connected-user-box .fa-user{height:50px;width:50px;font-size:22px}.connected-user-box .fa-user::before{line-height:50px}.os-page-header{position:fixed;top:0;z-index:1;height:56px;width:100%;background-color:#1e293b;display:flex;flex-direction:row;justify-content:space-between;align-items:center;box-shadow:0 1px 3px rgba(0,0,0,0.12);padding:0 24px 0 50px}.os-page-header .connected-user-box{color:white}a.os-page-header-app-name{text-decoration:none;color:white;font-size:24px;font-weight:700;letter-spacing:-0.3px}.ot-dr-toggle-button{color:white}.os-drawer-menu{padding:0;margin:0;overflow-y:auto;height:100%;touch-action:pan-y}.os-drawer-menu,.os-drawer-menu ul{list-style-type:none}.os-drawer-menu .os-drawer-item{display:block;padding:14px 20px;font-size:15px;transition:background-color 0.15s ease}.os-drawer-menu a:hover{background-color:rgba(0,0,0,0.04);color:#2563eb}.os-drawer-menu .connected-user-box{border-bottom:1px solid #e2e8f0;padding:16px 20px}.os-drawer-submenu{padding:0}.os-drawer-submenu>li>a{display:block;padding:8px 8px 8px 50px;font-size:14px;color:#64748b}.os-body{padding:72px 24px 40px;max-width:960px;margin:0 auto}.os-page-footer{position:fixed;bottom:0;left:0;right:0;background-color:#1e293b;color:rgba(255,255,255,0.6);padding:12px 16px;font-size:11px;text-align:center}.os-page-footer a,.os-page-footer a:visited{color:rgba(255,255,255,0.8)}.os-page-footer a:hover,.os-page-footer a:visited:hover{color:white}.os-welcome-box h2,.os-sign-in h2,.os-sign-up h2,.os-forgot-pwd h2{font-size:18px;font-weight:700;margin:0 0 16px 0;color:#1e293b}.os-welcome-box form,.os-welcome-box .form-like,.os-sign-in form,.os-sign-in .form-like,.os-sign-up form,.os-sign-up .form-like,.os-forgot-pwd form,.os-forgot-pwd .form-like{display:flex;margin:0 auto;flex-direction:column;background-color:white;padding:12px 0;width:100%;max-width:100%;border-radius:12px;gap:6px}.os-welcome-box input[type="checkbox"],.os-sign-in input[type="checkbox"],.os-sign-up input[type="checkbox"],.os-forgot-pwd input[type="checkbox"]{vertical-align:middle}.os-welcome-box input[type="submit"],.os-welcome-box button:not(.ot-password-toggle),.os-sign-in input[type="submit"],.os-sign-in button:not(.ot-password-toggle),.os-sign-up input[type="submit"],.os-sign-up button:not(.ot-password-toggle),.os-forgot-pwd input[type="submit"],.os-forgot-pwd button:not(.ot-password-toggle){margin:12px 0 4px;padding:10px 24px;background-color:#2563eb;color:white;border:none;border-radius:8px;font-weight:600;font-size:15px;transition:background-color 0.15s ease}.os-welcome-box input[type="submit"]:hover,.os-welcome-box button:not(.ot-password-toggle):hover,.os-sign-in input[type="submit"]:hover,.os-sign-in button:not(.ot-password-toggle):hover,.os-sign-up input[type="submit"]:hover,.os-sign-up button:not(.ot-password-toggle):hover,.os-forgot-pwd input[type="submit"]:hover,.os-forgot-pwd button:not(.ot-password-toggle):hover{background-color:#1d4ed8}.os-welcome-box input[type="text"],.os-welcome-box input[type="password"],.os-welcome-box input[type="email"],.os-welcome-box input[type="tel"],.os-sign-in input[type="text"],.os-sign-in input[type="password"],.os-sign-in input[type="email"],.os-sign-in input[type="tel"],.os-sign-up input[type="text"],.os-sign-up input[type="password"],.os-sign-up input[type="email"],.os-sign-up input[type="tel"],.os-forgot-pwd input[type="text"],.os-forgot-pwd input[type="password"],.os-forgot-pwd input[type="email"],.os-forgot-pwd input[type="tel"]{width:100%;display:block;margin:4px 0;padding:10px 14px;border:1px solid #e2e8f0;border-radius:8px;font-size:15px;background-color:#f8fafc;transition:border-color 0.15s ease, box-shadow 0.15s ease}.os-welcome-box input[type="text"]:focus,.os-welcome-box input[type="password"]:focus,.os-welcome-box input[type="email"]:focus,.os-welcome-box input[type="tel"]:focus,.os-sign-in input[type="text"]:focus,.os-sign-in input[type="password"]:focus,.os-sign-in input[type="email"]:focus,.os-sign-in input[type="tel"]:focus,.os-sign-up input[type="text"]:focus,.os-sign-up input[type="password"]:focus,.os-sign-up input[type="email"]:focus,.os-sign-up input[type="tel"]:focus,.os-forgot-pwd input[type="text"]:focus,.os-forgot-pwd input[type="password"]:focus,.os-forgot-pwd input[type="email"]:focus,.os-forgot-pwd input[type="tel"]:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px rgba(37,99,235,0.1);background-color:white}.os-welcome-box label,.os-sign-in label,.os-sign-up label,.os-forgot-pwd label{font-size:13px;font-weight:600;color:#64748b;margin-top:4px}.os-welcome-box .ot-password-container,.os-sign-in .ot-password-container,.os-sign-up .ot-password-container,.os-forgot-pwd .ot-password-container{width:100%;margin:4px 0;border:1px solid #e2e8f0;border-radius:8px;background-color:#f8fafc;overflow:hidden;transition:border-color 0.15s ease, box-shadow 0.15s ease}.os-welcome-box .ot-password-container:focus-within,.os-sign-in .ot-password-container:focus-within,.os-sign-up .ot-password-container:focus-within,.os-forgot-pwd .ot-password-container:focus-within{border-color:#3b82f6;box-shadow:0 0 0 3px rgba(37,99,235,0.1);background-color:white}.os-welcome-box .ot-password-container input[type="password"],.os-welcome-box .ot-password-container input[type="text"],.os-sign-in .ot-password-container input[type="password"],.os-sign-in .ot-password-container input[type="text"],.os-sign-up .ot-password-container input[type="password"],.os-sign-up .ot-password-container input[type="text"],.os-forgot-pwd .ot-password-container input[type="password"],.os-forgot-pwd .ot-password-container input[type="text"]{margin:0;border:none;border-radius:0;background:transparent;box-shadow:none}.os-welcome-box .ot-password-container input[type="password"]:focus,.os-welcome-box .ot-password-container input[type="text"]:focus,.os-sign-in .ot-password-container input[type="password"]:focus,.os-sign-in .ot-password-container input[type="text"]:focus,.os-sign-up .ot-password-container input[type="password"]:focus,.os-sign-up .ot-password-container input[type="text"]:focus,.os-forgot-pwd .ot-password-container input[type="password"]:focus,.os-forgot-pwd .ot-password-container input[type="text"]:focus{border:none;box-shadow:none}.os-welcome-box .ot-password-container .ot-password-toggle,.os-sign-in .ot-password-container .ot-password-toggle,.os-sign-up .ot-password-container .ot-password-toggle,.os-forgot-pwd .ot-password-container .ot-password-toggle{margin:0;border:none;border-left:1px solid #e2e8f0;border-radius:0;background:transparent;padding:8px 12px}.os-sign-up-btn{background-color:#2563eb;color:white;border:none;border-radius:8px;font-weight:600}.os-sign-up-btn:hover{background-color:#1d4ed8}.os-forgot-pwd-link{font-size:13px;color:#64748b;margin-top:8px}.os-forgot-pwd-link:hover{color:#2563eb}.os-settings h2{font-size:18px;font-weight:700;margin:0 0 16px 0;color:#1e293b}.os-settings>p{font-size:16px;font-weight:700;color:#1e293b;margin:24px 0 8px}.os-settings>p:first-child{margin-top:0}.os-settings form,.os-settings .form-like{display:flex;flex-direction:column;background-color:white;padding:20px 24px;border-radius:12px;border:1px solid #e2e8f0;box-shadow:0 1px 2px rgba(0,0,0,0.05);gap:6px;max-width:480px}.os-settings input[type="checkbox"]{vertical-align:middle}.os-settings input[type="submit"],.os-settings button:not(.ot-password-toggle){margin:12px 0 4px;padding:10px 24px;background-color:#2563eb;color:white;border:none;border-radius:8px;font-weight:600;font-size:15px;cursor:pointer;transition:background-color 0.15s ease}.os-settings input[type="submit"]:hover,.os-settings button:not(.ot-password-toggle):hover{background-color:#1d4ed8}.os-settings input[type="text"],.os-settings input[type="password"],.os-settings input[type="email"],.os-settings input[type="tel"]{width:100%;display:block;margin:4px 0;padding:10px 14px;border:1px solid #e2e8f0;border-radius:8px;font-size:15px;background-color:#f8fafc;transition:border-color 0.15s ease, box-shadow 0.15s ease}.os-settings input[type="text"]:focus,.os-settings input[type="password"]:focus,.os-settings input[type="email"]:focus,.os-settings input[type="tel"]:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px rgba(37,99,235,0.1);background-color:white}.os-settings select{width:100%;max-width:300px;padding:10px 14px;border:1px solid #e2e8f0;border-radius:8px;font-size:15px;background-color:#f8fafc;cursor:pointer}.os-settings select:focus{outline:none;border-color:#3b82f6}.os-settings label{font-size:13px;font-weight:600;color:#64748b;margin-top:4px}.os-settings .ot-password-container{width:100%;margin:4px 0;border:1px solid #e2e8f0;border-radius:8px;background-color:#f8fafc;overflow:hidden;transition:border-color 0.15s ease, box-shadow 0.15s ease}.os-settings .ot-password-container:focus-within{border-color:#3b82f6;box-shadow:0 0 0 3px rgba(37,99,235,0.1);background-color:white}.os-settings .ot-password-container input[type="password"],.os-settings .ot-password-container input[type="text"]{margin:0;border:none;border-radius:0;background:transparent;box-shadow:none}.os-settings .ot-password-container input[type="password"]:focus,.os-settings .ot-password-container input[type="text"]:focus{border:none;box-shadow:none}.os-settings .ot-password-container .ot-password-toggle{margin:0;border:none;border-left:1px solid #e2e8f0;border-radius:0;background:transparent;padding:8px 12px}.os-settings>a{display:inline-flex;align-items:center;gap:6px;padding:8px 0;color:#2563eb;font-size:14px}.os-settings>a:hover{color:#1d4ed8}.os-settings>br{display:none}.os-settings-section{background-color:white;border:1px solid #e2e8f0;border-radius:12px;padding:24px;margin-bottom:20px;box-shadow:0 1px 2px rgba(0,0,0,0.05)}.os-settings-section>p:first-child{font-size:16px;font-weight:700;color:#1e293b;margin:0 0 16px}.os-settings-section form{border:none;box-shadow:none;padding:0}#os-msg{position:fixed;top:72px;left:50%;transform:translateX(-50%);z-index:100;width:100%;max-width:600px;padding:0 16px}#os-msg p{padding:16px 24px;text-align:center;background-color:rgba(37,99,235,0.95);color:white;border-radius:8px;box-shadow:0 10px 25px rgba(0,0,0,0.12);font-weight:500}#os-msg p.os-err{background-color:rgba(220,38,38,0.95);color:white}.os-page-main .os-page-header .os-connection-box{position:absolute;top:15px;right:15px}.os-page-main:not(.os-connected) .os-page-header{display:block;height:40vh;background:linear-gradient(135deg, #1e293b 0%, #334564 100%)}.os-page-main:not(.os-connected) .os-page-header .os-page-header-app-name{display:block;position:absolute;top:28vh;font-size:32px}.os-page-main:not(.os-connected) .os-body{margin-top:40vh}@media (max-width: 720px){.os-page-footer{display:none}.os-page-header .os-connection-box,.os-page-header .os-page-header-app-name,.os-page-header .connected-user-box{display:none}.os-page-main .os-page-header .os-connection-box{display:flex;flex-direction:column;position:absolute;top:45vh;left:0;width:100%}.os-page-main .os-page-header .os-connection-box .button{width:150px;margin:16px auto}.os-page-main.os-not-connected .os-body{display:none}.os-page-header{display:block}}.os-emails{text-align:left}.os-emails ul{list-style:none;padding:0;margin:0;background-color:white;border:1px solid #e2e8f0;border-radius:12px;overflow:hidden;box-shadow:0 1px 2px rgba(0,0,0,0.05)}.os-emails ul li{padding:12px 16px;border-bottom:1px solid #e2e8f0;display:flex;justify-content:space-between;align-items:center;gap:8px}.os-emails ul li:last-child{border-bottom:none}.os-emails ul li .os-settings-label{font-weight:600;padding:3px 10px;margin-left:4px;border-radius:20px;font-size:12px;letter-spacing:0.02em}.os-emails ul li .os-settings-email{flex-grow:2;padding-right:12px;font-size:14px}.os-emails ul li .os-main-email{color:#fff;background-color:#16a34a}.os-emails ul li .os-validated-email{color:#fff;background-color:#2563eb}.os-emails ul li .os-remove-email-button{box-shadow:none;font-size:16px;margin:0;padding:6px 8px;color:#dc2626;background:none;border-radius:8px;transition:background-color 0.15s ease}.os-emails ul li .os-remove-email-button:hover{background-color:rgba(220,38,38,0.08)}.os-emails ul li .button{font-size:12px;padding:5px 12px;margin:0 2px}.os-avatar{margin-right:15px;width:35px}.ot-drawer{display:flex;flex-direction:column}.ot-drawer .connected-user-box{flex-shrink:0}.ot-dr-left .os-avatar{margin-left:16px}.ot-popup{border-radius:12px;box-shadow:0 10px 25px rgba(0,0,0,0.12);padding:16px;overflow:visible;min-width:340px;max-width:440px}.ot-popup-close{top:8px;right:8px;padding:8px;color:#64748b;background:white;border-radius:50%;transition:color 0.15s ease, background-color 0.15s ease;z-index:3}.ot-popup-close:hover{color:#1e293b;background-color:#f8fafc}.ot-popup-content{padding:0}.ot-popup-background{background-color:rgba(15,23,42,0.5);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}div.os-tip{position:absolute;margin:20px;box-shadow:0px 0px 2px 2px rgba(0,0,0,0.2);z-index:1111;transition:opacity 0.5s}div.os-tip div.os-tip-bec{background-color:white;width:20px;height:20px;position:absolute;transform:rotate(45deg);box-shadow:0px 0px 2px 2px rgba(0,0,0,0.2);z-index:-1}div.os-tip div.os-tip-content{padding:30px 20px 30px 20px;background-color:white;height:100%;width:100%}div.os-tip .os-tip-close{position:absolute;top:5px;right:5px}div.os-tip li,div.os-tip p{padding-bottom:10px}.demo-carousel1{display:flex;justify-content:center}.demo-carousel1 .demo-carousel1-box{position:relative;margin:auto}.demo-carousel1 .ot-carousel{width:300px;height:200px}.demo-carousel1 .demo-carousel1-page{width:100%;height:100%;padding:16px;color:white}.demo-carousel1 .demo-carousel1-page-1{background-color:#49b2cc}.demo-carousel1 .demo-carousel1-page-2{background-color:#dddd55}.demo-carousel1 .demo-carousel1-page-3{background-color:#c14768}.demo-carousel1 .demo-carousel1-page-4{background-color:#45bf7d}.demo-carousel1 .ot-bullet-nav{position:absolute;bottom:16px;right:16px;margin:0}.demo-carousel1 .ot-car-prev,.demo-carousel1 .ot-car-next{position:absolute;top:75px;width:50px;height:50px;color:white;outline:none}.demo-carousel1 .ot-car-prev{left:0}.demo-carousel1 .ot-car-next{right:0}.os-page-demo-carousel2 .demo-carousel2{margin:0 -16px}.os-page-demo-carousel2 .ot-carousel{width:100%;height:auto}.os-page-demo-carousel2 .demo-carousel2-page{padding:16px}.os-page-demo-carousel2 .demo-carousel2-page p{text-align:justify}.os-page-demo-carousel2 .demo-carousel2-page-1{background-color:white}.os-page-demo-carousel2 .demo-carousel2-page-2{background-color:#ffffee}.os-page-demo-carousel2 .demo-carousel2-page-3{background-color:#ffddee}.os-page-demo-carousel2 .demo-carousel2-page-4{background-color:#ddffee}.os-page-demo-carousel2 .demo-carousel2-tabs{position:sticky;background-color:white;z-index:1;top:50px}.os-page-demo-carousel3 .demo-prev,.os-page-demo-carousel3 .demo-next{width:20px;height:20px;background-color:#6ae;color:white}.os-page-demo-notif input:not([type]),.os-page-demo-react input:not([type]){background-color:#eee}.os-page-demo-links .demo-static-img{width:300px}.os-page-demo-transition .demo-list{padding-left:0;list-style-type:none}.os-page-demo-transition .demo-list-item{width:100%;height:150px;font-size:20px;padding-top:65px;text-align:center}.os-page-demo-transition .demo-list-item>a:visited,.os-page-demo-transition .demo-list-item>a{color:white}.os-page-demo-transition .demo-list-item.demo-list-item-0{background-color:#b1eb00}.os-page-demo-transition .demo-list-item.demo-list-item-1{background-color:#53baf3}.os-page-demo-transition .demo-list-item.demo-list-item-2{background-color:#ff85cb}.os-page-demo-transition .demo-list-item.demo-list-item-3{background-color:#f4402c}.os-page-demo-transition .demo-list-item.demo-list-item-4{background-color:#ffac00}.os-page-demo-transition .demo-button{margin:0 auto;padding:20px;width:200px;font-size:20px;text-align:center;background-color:#ffffee}.demo-tongue{display:flex;flex-direction:column}.demo-tongue .demo-tongue-1{background-color:#ffffee;height:100px}.demo-tongue .demo-tongue-2{background-color:#ffddee;height:150px}.demo-tongue .demo-tongue-3{background-color:#ddffee;height:80px}.demo-tongue .demo-tongue-4{background-color:#ddeeff;height:200px}.demo-tongue .demo-tongue-5{background-color:#eeccff;height:130px}.demo-tongue .demo-tongue-6{background-color:#ffeeaa;height:300px}.os-page-demo-forms>.os-body .demo-forms-section{margin-bottom:2em;padding:1em 1.2em;border:1px solid #e0e0e0;border-radius:6px;background-color:#fafafa}.os-page-demo-forms>.os-body .demo-forms-section h3{margin-top:0;padding-bottom:0.4em;border-bottom:1px solid #e0e0e0;font-size:1.1em}.os-page-demo-forms>.os-body .demo-forms-output{margin:0.4em 0;padding:0.5em 0.8em;background-color:#f0f4f8;border-radius:4px;font-family:monospace;font-size:0.9em}.os-page-demo-forms>.os-body input[type="text"],.os-page-demo-forms>.os-body input[type="email"],.os-page-demo-forms>.os-body input[type="number"],.os-page-demo-forms>.os-body input[type="date"],.os-page-demo-forms>.os-body input[type="time"],.os-page-demo-forms>.os-body input[type="password"],.os-page-demo-forms>.os-body textarea,.os-page-demo-forms>.os-body select{display:block;width:100%;max-width:400px;padding:0.5em;margin:0.4em 0;border:1px solid #ccc;border-radius:4px;font-size:1em;box-sizing:border-box}.os-page-demo-forms>.os-body textarea{min-height:80px;resize:vertical}.os-page-demo-forms>.os-body .button,.os-page-demo-forms>.os-body button:not(.ot-password-toggle):not(.ot-toggle-button):not(.ot-form-step-button){padding:0.5em 1.2em;margin:0.5em 0;border:none;border-radius:4px;background-color:#4a90d9;color:white;font-size:1em;cursor:pointer}.os-page-demo-forms>.os-body .button:hover,.os-page-demo-forms>.os-body button:not(.ot-password-toggle):not(.ot-toggle-button):not(.ot-form-step-button):hover{background-color:#3a7bc8}.os-page-demo-forms>.os-body .button:disabled,.os-page-demo-forms>.os-body button:not(.ot-password-toggle):not(.ot-toggle-button):not(.ot-form-step-button):disabled{background-color:#aaa;cursor:not-allowed}.os-page-demo-forms>.os-body .ot-password-container{max-width:400px}.os-page-demo-forms>.os-body .ot-password-container input{border-top-right-radius:0;border-bottom-right-radius:0}.os-page-demo-forms>.os-body .ot-password-toggle{margin:0.4em 0;border-radius:0 4px 4px 0}
+
+/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInByb2plY3RfbmFtZS5jc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsaUNBQWlDLENBQUMsMkJBQTJCLENBQUMsNEJBQTRCLENBQUMsMEJBQTBCLENBQUMsNEJBQTRCLENBQUMsMEJBQTBCLENBQUMseUJBQXlCLENBQUMsb0NBQW9DLENBQUMseUJBQXlCLENBQUMsMkJBQTJCLENBQUMsbUNBQW1DLENBQUMsMEJBQTBCLENBQUMsd0JBQXdCLENBQUMsZ0VBQWdFLENBQUMsS0FBSyxxQkFBcUIsQ0FBQyxxQkFBcUIsa0JBQWtCLENBQUMsS0FBSyxRQUFRLENBQUMsY0FBYyxDQUFDLHdCQUF3QixDQUFDLGFBQWEsQ0FBQyxlQUFlLENBQUMseUNBQXlDLG1DQUFtQyxDQUFDLFlBQVksb0JBQW9CLENBQUMsYUFBYSxDQUFDLGNBQWMsQ0FBQywyQkFBMkIsQ0FBQyx3QkFBd0IsYUFBYSxDQUFDLGFBQWEsV0FBVyxDQUFDLGlEQUFpRCxjQUFjLENBQUMsUUFBUSxpQkFBaUIsQ0FBQyxxQ0FBcUMsQ0FBQyx3QkFBd0IsQ0FBQyxXQUFXLENBQUMsY0FBYyxDQUFDLGVBQWUsQ0FBQyxnQkFBZ0IsQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLDZEQUE2RCxDQUFDLGNBQWMsd0JBQXdCLENBQUMsc0NBQXNDLENBQUMsTUFBTSxnQkFBZ0IsQ0FBQyxpQkFBaUIsQ0FBQyx3QkFBd0IsQ0FBQyx5REFBeUQsQ0FBQyxZQUFZLFlBQVksQ0FBQyxvQkFBb0IsQ0FBQyx3Q0FBd0MsQ0FBQyxvQkFBb0IsWUFBWSxDQUFDLGtCQUFrQixDQUFDLDZCQUE2QixXQUFXLENBQUMsVUFBVSxDQUFDLGNBQWMsQ0FBQyxxQ0FBcUMsZ0JBQWdCLENBQUMsZ0JBQWdCLGNBQWMsQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUMsd0JBQXdCLENBQUMsWUFBWSxDQUFDLGtCQUFrQixDQUFDLDZCQUE2QixDQUFDLGtCQUFrQixDQUFDLHFDQUFxQyxDQUFDLHFCQUFxQixDQUFDLG9DQUFvQyxXQUFXLENBQUMsMEJBQTBCLG9CQUFvQixDQUFDLFdBQVcsQ0FBQyxjQUFjLENBQUMsZUFBZSxDQUFDLHFCQUFxQixDQUFDLHFCQUFxQixXQUFXLENBQUMsZ0JBQWdCLFNBQVMsQ0FBQyxRQUFRLENBQUMsZUFBZSxDQUFDLFdBQVcsQ0FBQyxrQkFBa0IsQ0FBQyxtQ0FBbUMsb0JBQW9CLENBQUMsZ0NBQWdDLGFBQWEsQ0FBQyxpQkFBaUIsQ0FBQyxjQUFjLENBQUMsc0NBQXNDLENBQUMsd0JBQXdCLGlDQUFpQyxDQUFDLGFBQWEsQ0FBQyxvQ0FBb0MsK0JBQStCLENBQUMsaUJBQWlCLENBQUMsbUJBQW1CLFNBQVMsQ0FBQyx3QkFBd0IsYUFBYSxDQUFDLHdCQUF3QixDQUFDLGNBQWMsQ0FBQyxhQUFhLENBQUMsU0FBUyxzQkFBc0IsQ0FBQyxlQUFlLENBQUMsYUFBYSxDQUFDLGdCQUFnQixjQUFjLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsd0JBQXdCLENBQUMsMkJBQTJCLENBQUMsaUJBQWlCLENBQUMsY0FBYyxDQUFDLGlCQUFpQixDQUFDLDRDQUE0QywyQkFBMkIsQ0FBQyx3REFBd0QsV0FBVyxDQUFDLG1FQUFtRSxjQUFjLENBQUMsZUFBZSxDQUFDLGlCQUFpQixDQUFDLGFBQWEsQ0FBQyw4S0FBOEssWUFBWSxDQUFDLGFBQWEsQ0FBQyxxQkFBcUIsQ0FBQyxzQkFBc0IsQ0FBQyxjQUFjLENBQUMsVUFBVSxDQUFDLGNBQWMsQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsbUpBQW1KLHFCQUFxQixDQUFDLGtVQUFrVSxpQkFBaUIsQ0FBQyxpQkFBaUIsQ0FBQyx3QkFBd0IsQ0FBQyxXQUFXLENBQUMsV0FBVyxDQUFDLGlCQUFpQixDQUFDLGVBQWUsQ0FBQyxjQUFjLENBQUMsc0NBQXNDLENBQUMsa1hBQWtYLHdCQUF3QixDQUFDLDRoQkFBNGhCLFVBQVUsQ0FBQyxhQUFhLENBQUMsWUFBWSxDQUFDLGlCQUFpQixDQUFDLHdCQUF3QixDQUFDLGlCQUFpQixDQUFDLGNBQWMsQ0FBQyx3QkFBd0IsQ0FBQyx5REFBeUQsQ0FBQyw0bkJBQTRuQixZQUFZLENBQUMsb0JBQW9CLENBQUMsd0NBQXdDLENBQUMsc0JBQXNCLENBQUMsK0VBQStFLGNBQWMsQ0FBQyxlQUFlLENBQUMsYUFBYSxDQUFDLGNBQWMsQ0FBQyxtSkFBbUosVUFBVSxDQUFDLFlBQVksQ0FBQyx3QkFBd0IsQ0FBQyxpQkFBaUIsQ0FBQyx3QkFBd0IsQ0FBQyxlQUFlLENBQUMseURBQXlELENBQUMsdU1BQXVNLG9CQUFvQixDQUFDLHdDQUF3QyxDQUFDLHNCQUFzQixDQUFDLDhjQUE4YyxRQUFRLENBQUMsV0FBVyxDQUFDLGVBQWUsQ0FBQyxzQkFBc0IsQ0FBQyxlQUFlLENBQUMsOGZBQThmLFdBQVcsQ0FBQyxlQUFlLENBQUMsbU9BQW1PLFFBQVEsQ0FBQyxXQUFXLENBQUMsNkJBQTZCLENBQUMsZUFBZSxDQUFDLHNCQUFzQixDQUFDLGdCQUFnQixDQUFDLGdCQUFnQix3QkFBd0IsQ0FBQyxXQUFXLENBQUMsV0FBVyxDQUFDLGlCQUFpQixDQUFDLGVBQWUsQ0FBQyxzQkFBc0Isd0JBQXdCLENBQUMsb0JBQW9CLGNBQWMsQ0FBQyxhQUFhLENBQUMsY0FBYyxDQUFDLDBCQUEwQixhQUFhLENBQUMsZ0JBQWdCLGNBQWMsQ0FBQyxlQUFlLENBQUMsaUJBQWlCLENBQUMsYUFBYSxDQUFDLGVBQWUsY0FBYyxDQUFDLGVBQWUsQ0FBQyxhQUFhLENBQUMsaUJBQWlCLENBQUMsMkJBQTJCLFlBQVksQ0FBQywwQ0FBMEMsWUFBWSxDQUFDLHFCQUFxQixDQUFDLHNCQUFzQixDQUFDLGlCQUFpQixDQUFDLGtCQUFrQixDQUFDLHdCQUF3QixDQUFDLHFDQUFxQyxDQUFDLE9BQU8sQ0FBQyxlQUFlLENBQUMsb0NBQW9DLHFCQUFxQixDQUFDLCtFQUErRSxpQkFBaUIsQ0FBQyxpQkFBaUIsQ0FBQyx3QkFBd0IsQ0FBQyxXQUFXLENBQUMsV0FBVyxDQUFDLGlCQUFpQixDQUFDLGVBQWUsQ0FBQyxjQUFjLENBQUMsY0FBYyxDQUFDLHNDQUFzQyxDQUFDLDJGQUEyRix3QkFBd0IsQ0FBQyxvSUFBb0ksVUFBVSxDQUFDLGFBQWEsQ0FBQyxZQUFZLENBQUMsaUJBQWlCLENBQUMsd0JBQXdCLENBQUMsaUJBQWlCLENBQUMsY0FBYyxDQUFDLHdCQUF3QixDQUFDLHlEQUF5RCxDQUFDLDRKQUE0SixZQUFZLENBQUMsb0JBQW9CLENBQUMsd0NBQXdDLENBQUMsc0JBQXNCLENBQUMsb0JBQW9CLFVBQVUsQ0FBQyxlQUFlLENBQUMsaUJBQWlCLENBQUMsd0JBQXdCLENBQUMsaUJBQWlCLENBQUMsY0FBYyxDQUFDLHdCQUF3QixDQUFDLGNBQWMsQ0FBQywwQkFBMEIsWUFBWSxDQUFDLG9CQUFvQixDQUFDLG1CQUFtQixjQUFjLENBQUMsZUFBZSxDQUFDLGFBQWEsQ0FBQyxjQUFjLENBQUMsb0NBQW9DLFVBQVUsQ0FBQyxZQUFZLENBQUMsd0JBQXdCLENBQUMsaUJBQWlCLENBQUMsd0JBQXdCLENBQUMsZUFBZSxDQUFDLHlEQUF5RCxDQUFDLGlEQUFpRCxvQkFBb0IsQ0FBQyx3Q0FBd0MsQ0FBQyxzQkFBc0IsQ0FBQyxrSEFBa0gsUUFBUSxDQUFDLFdBQVcsQ0FBQyxlQUFlLENBQUMsc0JBQXNCLENBQUMsZUFBZSxDQUFDLDhIQUE4SCxXQUFXLENBQUMsZUFBZSxDQUFDLHdEQUF3RCxRQUFRLENBQUMsV0FBVyxDQUFDLDZCQUE2QixDQUFDLGVBQWUsQ0FBQyxzQkFBc0IsQ0FBQyxnQkFBZ0IsQ0FBQyxlQUFlLG1CQUFtQixDQUFDLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsYUFBYSxDQUFDLGNBQWMsQ0FBQyxxQkFBcUIsYUFBYSxDQUFDLGdCQUFnQixZQUFZLENBQUMscUJBQXFCLHNCQUFzQixDQUFDLHdCQUF3QixDQUFDLGtCQUFrQixDQUFDLFlBQVksQ0FBQyxrQkFBa0IsQ0FBQyxxQ0FBcUMsQ0FBQyxtQ0FBbUMsY0FBYyxDQUFDLGVBQWUsQ0FBQyxhQUFhLENBQUMsZUFBZSxDQUFDLDBCQUEwQixXQUFXLENBQUMsZUFBZSxDQUFDLFNBQVMsQ0FBQyxRQUFRLGNBQWMsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLDBCQUEwQixDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUMsZUFBZSxDQUFDLGNBQWMsQ0FBQyxVQUFVLGlCQUFpQixDQUFDLGlCQUFpQixDQUFDLHFDQUFxQyxDQUFDLFdBQVcsQ0FBQyxpQkFBaUIsQ0FBQyx1Q0FBdUMsQ0FBQyxlQUFlLENBQUMsaUJBQWlCLHFDQUFxQyxDQUFDLFdBQVcsQ0FBQyxpREFBaUQsaUJBQWlCLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxpREFBaUQsYUFBYSxDQUFDLFdBQVcsQ0FBQyw0REFBNEQsQ0FBQywwRUFBMEUsYUFBYSxDQUFDLGlCQUFpQixDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsMENBQTBDLGVBQWUsQ0FBQywwQkFBMEIsZ0JBQWdCLFlBQVksQ0FBQyxnSEFBZ0gsWUFBWSxDQUFDLGlEQUFpRCxZQUFZLENBQUMscUJBQXFCLENBQUMsaUJBQWlCLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMseURBQXlELFdBQVcsQ0FBQyxnQkFBZ0IsQ0FBQyx3Q0FBd0MsWUFBWSxDQUFDLGdCQUFnQixhQUFhLENBQUMsQ0FBQyxXQUFXLGVBQWUsQ0FBQyxjQUFjLGVBQWUsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLHNCQUFzQixDQUFDLHdCQUF3QixDQUFDLGtCQUFrQixDQUFDLGVBQWUsQ0FBQyxxQ0FBcUMsQ0FBQyxpQkFBaUIsaUJBQWlCLENBQUMsK0JBQStCLENBQUMsWUFBWSxDQUFDLDZCQUE2QixDQUFDLGtCQUFrQixDQUFDLE9BQU8sQ0FBQyw0QkFBNEIsa0JBQWtCLENBQUMsb0NBQW9DLGVBQWUsQ0FBQyxnQkFBZ0IsQ0FBQyxlQUFlLENBQUMsa0JBQWtCLENBQUMsY0FBYyxDQUFDLHFCQUFxQixDQUFDLG9DQUFvQyxXQUFXLENBQUMsa0JBQWtCLENBQUMsY0FBYyxDQUFDLGdDQUFnQyxVQUFVLENBQUMsd0JBQXdCLENBQUMscUNBQXFDLFVBQVUsQ0FBQyx3QkFBd0IsQ0FBQyx5Q0FBeUMsZUFBZSxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsZUFBZSxDQUFDLGFBQWEsQ0FBQyxlQUFlLENBQUMsaUJBQWlCLENBQUMsc0NBQXNDLENBQUMsK0NBQStDLHFDQUFxQyxDQUFDLHlCQUF5QixjQUFjLENBQUMsZ0JBQWdCLENBQUMsWUFBWSxDQUFDLFdBQVcsaUJBQWlCLENBQUMsVUFBVSxDQUFDLFdBQVcsWUFBWSxDQUFDLHFCQUFxQixDQUFDLCtCQUErQixhQUFhLENBQUMsdUJBQXVCLGdCQUFnQixDQUFDLFVBQVUsa0JBQWtCLENBQUMsdUNBQXVDLENBQUMsWUFBWSxDQUFDLGdCQUFnQixDQUFDLGVBQWUsQ0FBQyxlQUFlLENBQUMsZ0JBQWdCLE9BQU8sQ0FBQyxTQUFTLENBQUMsV0FBVyxDQUFDLGFBQWEsQ0FBQyxnQkFBZ0IsQ0FBQyxpQkFBaUIsQ0FBQyx3REFBd0QsQ0FBQyxTQUFTLENBQUMsc0JBQXNCLGFBQWEsQ0FBQyx3QkFBd0IsQ0FBQyxrQkFBa0IsU0FBUyxDQUFDLHFCQUFxQixtQ0FBbUMsQ0FBQyxpQ0FBd0IsQ0FBeEIseUJBQXlCLENBQUMsV0FBVyxpQkFBaUIsQ0FBQyxXQUFXLENBQUMsMENBQTBDLENBQUMsWUFBWSxDQUFDLHVCQUF1QixDQUFDLDBCQUEwQixzQkFBc0IsQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLGlCQUFpQixDQUFDLHVCQUF1QixDQUFDLDBDQUEwQyxDQUFDLFVBQVUsQ0FBQyw4QkFBOEIsMkJBQTJCLENBQUMsc0JBQXNCLENBQUMsV0FBVyxDQUFDLFVBQVUsQ0FBQyx5QkFBeUIsaUJBQWlCLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQywyQkFBMkIsbUJBQW1CLENBQUMsZ0JBQWdCLFlBQVksQ0FBQyxzQkFBc0IsQ0FBQyxvQ0FBb0MsaUJBQWlCLENBQUMsV0FBVyxDQUFDLDZCQUE2QixXQUFXLENBQUMsWUFBWSxDQUFDLHFDQUFxQyxVQUFVLENBQUMsV0FBVyxDQUFDLFlBQVksQ0FBQyxXQUFXLENBQUMsdUNBQXVDLHdCQUF3QixDQUFDLHVDQUF1Qyx3QkFBd0IsQ0FBQyx1Q0FBdUMsd0JBQXdCLENBQUMsdUNBQXVDLHdCQUF3QixDQUFDLCtCQUErQixpQkFBaUIsQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQywwREFBMEQsaUJBQWlCLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsV0FBVyxDQUFDLFlBQVksQ0FBQyw2QkFBNkIsTUFBTSxDQUFDLDZCQUE2QixPQUFPLENBQUMsd0NBQXdDLGNBQWMsQ0FBQyxxQ0FBcUMsVUFBVSxDQUFDLFdBQVcsQ0FBQyw2Q0FBNkMsWUFBWSxDQUFDLCtDQUErQyxrQkFBa0IsQ0FBQywrQ0FBK0Msc0JBQXNCLENBQUMsK0NBQStDLHdCQUF3QixDQUFDLCtDQUErQyx3QkFBd0IsQ0FBQywrQ0FBK0Msd0JBQXdCLENBQUMsNkNBQTZDLGVBQWUsQ0FBQyxzQkFBc0IsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLHNFQUFzRSxVQUFVLENBQUMsV0FBVyxDQUFDLHFCQUFxQixDQUFDLFdBQVcsQ0FBQyw0RUFBNEUscUJBQXFCLENBQUMscUNBQXFDLFdBQVcsQ0FBQyxvQ0FBb0MsY0FBYyxDQUFDLG9CQUFvQixDQUFDLHlDQUF5QyxVQUFVLENBQUMsWUFBWSxDQUFDLGNBQWMsQ0FBQyxnQkFBZ0IsQ0FBQyxpQkFBaUIsQ0FBQyw4RkFBOEYsV0FBVyxDQUFDLDBEQUEwRCx3QkFBd0IsQ0FBQywwREFBMEQsd0JBQXdCLENBQUMsMERBQTBELHdCQUF3QixDQUFDLDBEQUEwRCx3QkFBd0IsQ0FBQywwREFBMEQsd0JBQXdCLENBQUMsc0NBQXNDLGFBQWEsQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLGNBQWMsQ0FBQyxpQkFBaUIsQ0FBQyx3QkFBd0IsQ0FBQyxhQUFhLFlBQVksQ0FBQyxxQkFBcUIsQ0FBQyw0QkFBNEIsd0JBQXdCLENBQUMsWUFBWSxDQUFDLDRCQUE0Qix3QkFBd0IsQ0FBQyxZQUFZLENBQUMsNEJBQTRCLHdCQUF3QixDQUFDLFdBQVcsQ0FBQyw0QkFBNEIsd0JBQXdCLENBQUMsWUFBWSxDQUFDLDRCQUE0Qix3QkFBd0IsQ0FBQyxZQUFZLENBQUMsNEJBQTRCLHdCQUF3QixDQUFDLFlBQVksQ0FBQyxpREFBaUQsaUJBQWlCLENBQUMsaUJBQWlCLENBQUMsd0JBQXdCLENBQUMsaUJBQWlCLENBQUMsd0JBQXdCLENBQUMsb0RBQW9ELFlBQVksQ0FBQyxvQkFBb0IsQ0FBQywrQkFBK0IsQ0FBQyxlQUFlLENBQUMsZ0RBQWdELGNBQWMsQ0FBQyxtQkFBbUIsQ0FBQyx3QkFBd0IsQ0FBQyxpQkFBaUIsQ0FBQyxxQkFBcUIsQ0FBQyxlQUFlLENBQUMsaVhBQWlYLGFBQWEsQ0FBQyxVQUFVLENBQUMsZUFBZSxDQUFDLGFBQWEsQ0FBQyxjQUFjLENBQUMscUJBQXFCLENBQUMsaUJBQWlCLENBQUMsYUFBYSxDQUFDLHFCQUFxQixDQUFDLHNDQUFzQyxlQUFlLENBQUMsZUFBZSxDQUFDLG1KQUFtSixtQkFBbUIsQ0FBQyxjQUFjLENBQUMsV0FBVyxDQUFDLGlCQUFpQixDQUFDLHdCQUF3QixDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUMsY0FBYyxDQUFDLCtKQUErSix3QkFBd0IsQ0FBQyxxS0FBcUsscUJBQXFCLENBQUMsa0JBQWtCLENBQUMsb0RBQW9ELGVBQWUsQ0FBQywwREFBMEQseUJBQXlCLENBQUMsNEJBQTRCLENBQUMsaURBQWlELGNBQWMsQ0FBQyx5QkFBeUIiLCJmaWxlIjoicHJvamVjdF9uYW1lLmNzcyIsInNvdXJjZXNDb250ZW50IjpbIkBpbXBvcnQgdXJsKGZvbnQtYXdlc29tZS5taW4uY3NzKTtAaW1wb3J0IHVybChvdF9idXR0b25zLmNzcyk7QGltcG9ydCB1cmwob3RfY2Fyb3VzZWwuY3NzKTtAaW1wb3J0IHVybChvdF9zdGlja3kuY3NzKTtAaW1wb3J0IHVybChvdF9kYXRldGltZS5jc3MpO0BpbXBvcnQgdXJsKG90X2RyYXdlci5jc3MpO0BpbXBvcnQgdXJsKG90X2ljb25zLmNzcyk7QGltcG9ydCB1cmwob3RfcGljdHVyZV91cGxvYWRlci5jc3MpO0BpbXBvcnQgdXJsKG90X3BvcHVwLmNzcyk7QGltcG9ydCB1cmwob3Rfc3Bpbm5lci5jc3MpO0BpbXBvcnQgdXJsKG90X3BhZ2VfdHJhbnNpdGlvbi5jc3MpO0BpbXBvcnQgdXJsKG90X3Rvbmd1ZS5jc3MpO0BpbXBvcnQgdXJsKG90X2Zvcm0uY3NzKTtAaW1wb3J0IHVybChcImh0dHBzOi8vZm9udHMuZ29vZ2xlYXBpcy5jb20vY3NzP2ZhbWlseT1RdWlja3NhbmRcIik7aHRtbHtib3gtc2l6aW5nOmJvcmRlci1ib3h9KiwqOjpiZWZvcmUsKjo6YWZ0ZXJ7Ym94LXNpemluZzppbmhlcml0fWJvZHl7bWFyZ2luOjA7Zm9udC1zaXplOjE1cHg7YmFja2dyb3VuZC1jb2xvcjojZjhmYWZjO2NvbG9yOiMzMzQxNTU7bGluZS1oZWlnaHQ6MS42fWJvZHksaW5wdXQsdGV4dGFyZWEsa2V5Z2VuLHNlbGVjdCxidXR0b257Zm9udC1mYW1pbHk6J1F1aWNrc2FuZCcsIHNhbnMtc2VyaWZ9YSxhOnZpc2l0ZWR7dGV4dC1kZWNvcmF0aW9uOm5vbmU7Y29sb3I6IzI1NjNlYjtjdXJzb3I6cG9pbnRlcjt0cmFuc2l0aW9uOmNvbG9yIDAuMTVzIGVhc2V9YTpob3ZlcixhOnZpc2l0ZWQ6aG92ZXJ7Y29sb3I6IzFkNGVkOH1idXR0b24saW5wdXR7Ym9yZGVyOm5vbmV9YnV0dG9uLGlucHV0W3R5cGU9XCJzdWJtaXRcIl0saW5wdXRbdHlwZT1cImJ1dHRvblwiXXtjdXJzb3I6cG9pbnRlcn0uYnV0dG9ue2JvcmRlci1yYWRpdXM6OHB4O2JveC1zaGFkb3c6MCAxcHggMnB4IHJnYmEoMCwwLDAsMC4wNSk7YmFja2dyb3VuZC1jb2xvcjojMjU2M2ViO2NvbG9yOndoaXRlO2ZvbnQtc2l6ZToxNHB4O2ZvbnQtd2VpZ2h0OjYwMDtwYWRkaW5nOjhweCAyMHB4O21hcmdpbjo1cHg7Ym9yZGVyOm5vbmU7dHJhbnNpdGlvbjpiYWNrZ3JvdW5kLWNvbG9yIDAuMTVzIGVhc2UsIGJveC1zaGFkb3cgMC4xNXMgZWFzZX0uYnV0dG9uOmhvdmVye2JhY2tncm91bmQtY29sb3I6IzFkNGVkODtib3gtc2hhZG93OjAgNHB4IDEycHggcmdiYSgwLDAsMCwwLjA4KX1pbnB1dHtwYWRkaW5nOjhweCAxMnB4O2JvcmRlci1yYWRpdXM6OHB4O2JvcmRlcjoxcHggc29saWQgI2UyZThmMDt0cmFuc2l0aW9uOmJvcmRlci1jb2xvciAwLjE1cyBlYXNlLCBib3gtc2hhZG93IDAuMTVzIGVhc2V9aW5wdXQ6Zm9jdXN7b3V0bGluZTpub25lO2JvcmRlci1jb2xvcjojM2I4MmY2O2JveC1zaGFkb3c6MCAwIDAgM3B4IHJnYmEoMzcsOTksMjM1LDAuMSl9LmNvbm5lY3RlZC11c2VyLWJveHtkaXNwbGF5OmZsZXg7YWxpZ24taXRlbXM6Y2VudGVyfS5jb25uZWN0ZWQtdXNlci1ib3ggLmZhLXVzZXJ7aGVpZ2h0OjUwcHg7d2lkdGg6NTBweDtmb250LXNpemU6MjJweH0uY29ubmVjdGVkLXVzZXItYm94IC5mYS11c2VyOjpiZWZvcmV7bGluZS1oZWlnaHQ6NTBweH0ub3MtcGFnZS1oZWFkZXJ7cG9zaXRpb246Zml4ZWQ7dG9wOjA7ei1pbmRleDoxO2hlaWdodDo1NnB4O3dpZHRoOjEwMCU7YmFja2dyb3VuZC1jb2xvcjojMWUyOTNiO2Rpc3BsYXk6ZmxleDtmbGV4LWRpcmVjdGlvbjpyb3c7anVzdGlmeS1jb250ZW50OnNwYWNlLWJldHdlZW47YWxpZ24taXRlbXM6Y2VudGVyO2JveC1zaGFkb3c6MCAxcHggM3B4IHJnYmEoMCwwLDAsMC4xMik7cGFkZGluZzowIDI0cHggMCA1MHB4fS5vcy1wYWdlLWhlYWRlciAuY29ubmVjdGVkLXVzZXItYm94e2NvbG9yOndoaXRlfWEub3MtcGFnZS1oZWFkZXItYXBwLW5hbWV7dGV4dC1kZWNvcmF0aW9uOm5vbmU7Y29sb3I6d2hpdGU7Zm9udC1zaXplOjI0cHg7Zm9udC13ZWlnaHQ6NzAwO2xldHRlci1zcGFjaW5nOi0wLjNweH0ub3QtZHItdG9nZ2xlLWJ1dHRvbntjb2xvcjp3aGl0ZX0ub3MtZHJhd2VyLW1lbnV7cGFkZGluZzowO21hcmdpbjowO292ZXJmbG93LXk6YXV0bztoZWlnaHQ6MTAwJTt0b3VjaC1hY3Rpb246cGFuLXl9Lm9zLWRyYXdlci1tZW51LC5vcy1kcmF3ZXItbWVudSB1bHtsaXN0LXN0eWxlLXR5cGU6bm9uZX0ub3MtZHJhd2VyLW1lbnUgLm9zLWRyYXdlci1pdGVte2Rpc3BsYXk6YmxvY2s7cGFkZGluZzoxNHB4IDIwcHg7Zm9udC1zaXplOjE1cHg7dHJhbnNpdGlvbjpiYWNrZ3JvdW5kLWNvbG9yIDAuMTVzIGVhc2V9Lm9zLWRyYXdlci1tZW51IGE6aG92ZXJ7YmFja2dyb3VuZC1jb2xvcjpyZ2JhKDAsMCwwLDAuMDQpO2NvbG9yOiMyNTYzZWJ9Lm9zLWRyYXdlci1tZW51IC5jb25uZWN0ZWQtdXNlci1ib3h7Ym9yZGVyLWJvdHRvbToxcHggc29saWQgI2UyZThmMDtwYWRkaW5nOjE2cHggMjBweH0ub3MtZHJhd2VyLXN1Ym1lbnV7cGFkZGluZzowfS5vcy1kcmF3ZXItc3VibWVudT5saT5he2Rpc3BsYXk6YmxvY2s7cGFkZGluZzo4cHggOHB4IDhweCA1MHB4O2ZvbnQtc2l6ZToxNHB4O2NvbG9yOiM2NDc0OGJ9Lm9zLWJvZHl7cGFkZGluZzo3MnB4IDI0cHggNDBweDttYXgtd2lkdGg6OTYwcHg7bWFyZ2luOjAgYXV0b30ub3MtcGFnZS1mb290ZXJ7cG9zaXRpb246Zml4ZWQ7Ym90dG9tOjA7bGVmdDowO3JpZ2h0OjA7YmFja2dyb3VuZC1jb2xvcjojMWUyOTNiO2NvbG9yOnJnYmEoMjU1LDI1NSwyNTUsMC42KTtwYWRkaW5nOjEycHggMTZweDtmb250LXNpemU6MTFweDt0ZXh0LWFsaWduOmNlbnRlcn0ub3MtcGFnZS1mb290ZXIgYSwub3MtcGFnZS1mb290ZXIgYTp2aXNpdGVke2NvbG9yOnJnYmEoMjU1LDI1NSwyNTUsMC44KX0ub3MtcGFnZS1mb290ZXIgYTpob3Zlciwub3MtcGFnZS1mb290ZXIgYTp2aXNpdGVkOmhvdmVye2NvbG9yOndoaXRlfS5vcy13ZWxjb21lLWJveCBoMiwub3Mtc2lnbi1pbiBoMiwub3Mtc2lnbi11cCBoMiwub3MtZm9yZ290LXB3ZCBoMntmb250LXNpemU6MThweDtmb250LXdlaWdodDo3MDA7bWFyZ2luOjAgMCAxNnB4IDA7Y29sb3I6IzFlMjkzYn0ub3Mtd2VsY29tZS1ib3ggZm9ybSwub3Mtd2VsY29tZS1ib3ggLmZvcm0tbGlrZSwub3Mtc2lnbi1pbiBmb3JtLC5vcy1zaWduLWluIC5mb3JtLWxpa2UsLm9zLXNpZ24tdXAgZm9ybSwub3Mtc2lnbi11cCAuZm9ybS1saWtlLC5vcy1mb3Jnb3QtcHdkIGZvcm0sLm9zLWZvcmdvdC1wd2QgLmZvcm0tbGlrZXtkaXNwbGF5OmZsZXg7bWFyZ2luOjAgYXV0bztmbGV4LWRpcmVjdGlvbjpjb2x1bW47YmFja2dyb3VuZC1jb2xvcjp3aGl0ZTtwYWRkaW5nOjEycHggMDt3aWR0aDoxMDAlO21heC13aWR0aDoxMDAlO2JvcmRlci1yYWRpdXM6MTJweDtnYXA6NnB4fS5vcy13ZWxjb21lLWJveCBpbnB1dFt0eXBlPVwiY2hlY2tib3hcIl0sLm9zLXNpZ24taW4gaW5wdXRbdHlwZT1cImNoZWNrYm94XCJdLC5vcy1zaWduLXVwIGlucHV0W3R5cGU9XCJjaGVja2JveFwiXSwub3MtZm9yZ290LXB3ZCBpbnB1dFt0eXBlPVwiY2hlY2tib3hcIl17dmVydGljYWwtYWxpZ246bWlkZGxlfS5vcy13ZWxjb21lLWJveCBpbnB1dFt0eXBlPVwic3VibWl0XCJdLC5vcy13ZWxjb21lLWJveCBidXR0b246bm90KC5vdC1wYXNzd29yZC10b2dnbGUpLC5vcy1zaWduLWluIGlucHV0W3R5cGU9XCJzdWJtaXRcIl0sLm9zLXNpZ24taW4gYnV0dG9uOm5vdCgub3QtcGFzc3dvcmQtdG9nZ2xlKSwub3Mtc2lnbi11cCBpbnB1dFt0eXBlPVwic3VibWl0XCJdLC5vcy1zaWduLXVwIGJ1dHRvbjpub3QoLm90LXBhc3N3b3JkLXRvZ2dsZSksLm9zLWZvcmdvdC1wd2QgaW5wdXRbdHlwZT1cInN1Ym1pdFwiXSwub3MtZm9yZ290LXB3ZCBidXR0b246bm90KC5vdC1wYXNzd29yZC10b2dnbGUpe21hcmdpbjoxMnB4IDAgNHB4O3BhZGRpbmc6MTBweCAyNHB4O2JhY2tncm91bmQtY29sb3I6IzI1NjNlYjtjb2xvcjp3aGl0ZTtib3JkZXI6bm9uZTtib3JkZXItcmFkaXVzOjhweDtmb250LXdlaWdodDo2MDA7Zm9udC1zaXplOjE1cHg7dHJhbnNpdGlvbjpiYWNrZ3JvdW5kLWNvbG9yIDAuMTVzIGVhc2V9Lm9zLXdlbGNvbWUtYm94IGlucHV0W3R5cGU9XCJzdWJtaXRcIl06aG92ZXIsLm9zLXdlbGNvbWUtYm94IGJ1dHRvbjpub3QoLm90LXBhc3N3b3JkLXRvZ2dsZSk6aG92ZXIsLm9zLXNpZ24taW4gaW5wdXRbdHlwZT1cInN1Ym1pdFwiXTpob3Zlciwub3Mtc2lnbi1pbiBidXR0b246bm90KC5vdC1wYXNzd29yZC10b2dnbGUpOmhvdmVyLC5vcy1zaWduLXVwIGlucHV0W3R5cGU9XCJzdWJtaXRcIl06aG92ZXIsLm9zLXNpZ24tdXAgYnV0dG9uOm5vdCgub3QtcGFzc3dvcmQtdG9nZ2xlKTpob3Zlciwub3MtZm9yZ290LXB3ZCBpbnB1dFt0eXBlPVwic3VibWl0XCJdOmhvdmVyLC5vcy1mb3Jnb3QtcHdkIGJ1dHRvbjpub3QoLm90LXBhc3N3b3JkLXRvZ2dsZSk6aG92ZXJ7YmFja2dyb3VuZC1jb2xvcjojMWQ0ZWQ4fS5vcy13ZWxjb21lLWJveCBpbnB1dFt0eXBlPVwidGV4dFwiXSwub3Mtd2VsY29tZS1ib3ggaW5wdXRbdHlwZT1cInBhc3N3b3JkXCJdLC5vcy13ZWxjb21lLWJveCBpbnB1dFt0eXBlPVwiZW1haWxcIl0sLm9zLXdlbGNvbWUtYm94IGlucHV0W3R5cGU9XCJ0ZWxcIl0sLm9zLXNpZ24taW4gaW5wdXRbdHlwZT1cInRleHRcIl0sLm9zLXNpZ24taW4gaW5wdXRbdHlwZT1cInBhc3N3b3JkXCJdLC5vcy1zaWduLWluIGlucHV0W3R5cGU9XCJlbWFpbFwiXSwub3Mtc2lnbi1pbiBpbnB1dFt0eXBlPVwidGVsXCJdLC5vcy1zaWduLXVwIGlucHV0W3R5cGU9XCJ0ZXh0XCJdLC5vcy1zaWduLXVwIGlucHV0W3R5cGU9XCJwYXNzd29yZFwiXSwub3Mtc2lnbi11cCBpbnB1dFt0eXBlPVwiZW1haWxcIl0sLm9zLXNpZ24tdXAgaW5wdXRbdHlwZT1cInRlbFwiXSwub3MtZm9yZ290LXB3ZCBpbnB1dFt0eXBlPVwidGV4dFwiXSwub3MtZm9yZ290LXB3ZCBpbnB1dFt0eXBlPVwicGFzc3dvcmRcIl0sLm9zLWZvcmdvdC1wd2QgaW5wdXRbdHlwZT1cImVtYWlsXCJdLC5vcy1mb3Jnb3QtcHdkIGlucHV0W3R5cGU9XCJ0ZWxcIl17d2lkdGg6MTAwJTtkaXNwbGF5OmJsb2NrO21hcmdpbjo0cHggMDtwYWRkaW5nOjEwcHggMTRweDtib3JkZXI6MXB4IHNvbGlkICNlMmU4ZjA7Ym9yZGVyLXJhZGl1czo4cHg7Zm9udC1zaXplOjE1cHg7YmFja2dyb3VuZC1jb2xvcjojZjhmYWZjO3RyYW5zaXRpb246Ym9yZGVyLWNvbG9yIDAuMTVzIGVhc2UsIGJveC1zaGFkb3cgMC4xNXMgZWFzZX0ub3Mtd2VsY29tZS1ib3ggaW5wdXRbdHlwZT1cInRleHRcIl06Zm9jdXMsLm9zLXdlbGNvbWUtYm94IGlucHV0W3R5cGU9XCJwYXNzd29yZFwiXTpmb2N1cywub3Mtd2VsY29tZS1ib3ggaW5wdXRbdHlwZT1cImVtYWlsXCJdOmZvY3VzLC5vcy13ZWxjb21lLWJveCBpbnB1dFt0eXBlPVwidGVsXCJdOmZvY3VzLC5vcy1zaWduLWluIGlucHV0W3R5cGU9XCJ0ZXh0XCJdOmZvY3VzLC5vcy1zaWduLWluIGlucHV0W3R5cGU9XCJwYXNzd29yZFwiXTpmb2N1cywub3Mtc2lnbi1pbiBpbnB1dFt0eXBlPVwiZW1haWxcIl06Zm9jdXMsLm9zLXNpZ24taW4gaW5wdXRbdHlwZT1cInRlbFwiXTpmb2N1cywub3Mtc2lnbi11cCBpbnB1dFt0eXBlPVwidGV4dFwiXTpmb2N1cywub3Mtc2lnbi11cCBpbnB1dFt0eXBlPVwicGFzc3dvcmRcIl06Zm9jdXMsLm9zLXNpZ24tdXAgaW5wdXRbdHlwZT1cImVtYWlsXCJdOmZvY3VzLC5vcy1zaWduLXVwIGlucHV0W3R5cGU9XCJ0ZWxcIl06Zm9jdXMsLm9zLWZvcmdvdC1wd2QgaW5wdXRbdHlwZT1cInRleHRcIl06Zm9jdXMsLm9zLWZvcmdvdC1wd2QgaW5wdXRbdHlwZT1cInBhc3N3b3JkXCJdOmZvY3VzLC5vcy1mb3Jnb3QtcHdkIGlucHV0W3R5cGU9XCJlbWFpbFwiXTpmb2N1cywub3MtZm9yZ290LXB3ZCBpbnB1dFt0eXBlPVwidGVsXCJdOmZvY3Vze291dGxpbmU6bm9uZTtib3JkZXItY29sb3I6IzNiODJmNjtib3gtc2hhZG93OjAgMCAwIDNweCByZ2JhKDM3LDk5LDIzNSwwLjEpO2JhY2tncm91bmQtY29sb3I6d2hpdGV9Lm9zLXdlbGNvbWUtYm94IGxhYmVsLC5vcy1zaWduLWluIGxhYmVsLC5vcy1zaWduLXVwIGxhYmVsLC5vcy1mb3Jnb3QtcHdkIGxhYmVse2ZvbnQtc2l6ZToxM3B4O2ZvbnQtd2VpZ2h0OjYwMDtjb2xvcjojNjQ3NDhiO21hcmdpbi10b3A6NHB4fS5vcy13ZWxjb21lLWJveCAub3QtcGFzc3dvcmQtY29udGFpbmVyLC5vcy1zaWduLWluIC5vdC1wYXNzd29yZC1jb250YWluZXIsLm9zLXNpZ24tdXAgLm90LXBhc3N3b3JkLWNvbnRhaW5lciwub3MtZm9yZ290LXB3ZCAub3QtcGFzc3dvcmQtY29udGFpbmVye3dpZHRoOjEwMCU7bWFyZ2luOjRweCAwO2JvcmRlcjoxcHggc29saWQgI2UyZThmMDtib3JkZXItcmFkaXVzOjhweDtiYWNrZ3JvdW5kLWNvbG9yOiNmOGZhZmM7b3ZlcmZsb3c6aGlkZGVuO3RyYW5zaXRpb246Ym9yZGVyLWNvbG9yIDAuMTVzIGVhc2UsIGJveC1zaGFkb3cgMC4xNXMgZWFzZX0ub3Mtd2VsY29tZS1ib3ggLm90LXBhc3N3b3JkLWNvbnRhaW5lcjpmb2N1cy13aXRoaW4sLm9zLXNpZ24taW4gLm90LXBhc3N3b3JkLWNvbnRhaW5lcjpmb2N1cy13aXRoaW4sLm9zLXNpZ24tdXAgLm90LXBhc3N3b3JkLWNvbnRhaW5lcjpmb2N1cy13aXRoaW4sLm9zLWZvcmdvdC1wd2QgLm90LXBhc3N3b3JkLWNvbnRhaW5lcjpmb2N1cy13aXRoaW57Ym9yZGVyLWNvbG9yOiMzYjgyZjY7Ym94LXNoYWRvdzowIDAgMCAzcHggcmdiYSgzNyw5OSwyMzUsMC4xKTtiYWNrZ3JvdW5kLWNvbG9yOndoaXRlfS5vcy13ZWxjb21lLWJveCAub3QtcGFzc3dvcmQtY29udGFpbmVyIGlucHV0W3R5cGU9XCJwYXNzd29yZFwiXSwub3Mtd2VsY29tZS1ib3ggLm90LXBhc3N3b3JkLWNvbnRhaW5lciBpbnB1dFt0eXBlPVwidGV4dFwiXSwub3Mtc2lnbi1pbiAub3QtcGFzc3dvcmQtY29udGFpbmVyIGlucHV0W3R5cGU9XCJwYXNzd29yZFwiXSwub3Mtc2lnbi1pbiAub3QtcGFzc3dvcmQtY29udGFpbmVyIGlucHV0W3R5cGU9XCJ0ZXh0XCJdLC5vcy1zaWduLXVwIC5vdC1wYXNzd29yZC1jb250YWluZXIgaW5wdXRbdHlwZT1cInBhc3N3b3JkXCJdLC5vcy1zaWduLXVwIC5vdC1wYXNzd29yZC1jb250YWluZXIgaW5wdXRbdHlwZT1cInRleHRcIl0sLm9zLWZvcmdvdC1wd2QgLm90LXBhc3N3b3JkLWNvbnRhaW5lciBpbnB1dFt0eXBlPVwicGFzc3dvcmRcIl0sLm9zLWZvcmdvdC1wd2QgLm90LXBhc3N3b3JkLWNvbnRhaW5lciBpbnB1dFt0eXBlPVwidGV4dFwiXXttYXJnaW46MDtib3JkZXI6bm9uZTtib3JkZXItcmFkaXVzOjA7YmFja2dyb3VuZDp0cmFuc3BhcmVudDtib3gtc2hhZG93Om5vbmV9Lm9zLXdlbGNvbWUtYm94IC5vdC1wYXNzd29yZC1jb250YWluZXIgaW5wdXRbdHlwZT1cInBhc3N3b3JkXCJdOmZvY3VzLC5vcy13ZWxjb21lLWJveCAub3QtcGFzc3dvcmQtY29udGFpbmVyIGlucHV0W3R5cGU9XCJ0ZXh0XCJdOmZvY3VzLC5vcy1zaWduLWluIC5vdC1wYXNzd29yZC1jb250YWluZXIgaW5wdXRbdHlwZT1cInBhc3N3b3JkXCJdOmZvY3VzLC5vcy1zaWduLWluIC5vdC1wYXNzd29yZC1jb250YWluZXIgaW5wdXRbdHlwZT1cInRleHRcIl06Zm9jdXMsLm9zLXNpZ24tdXAgLm90LXBhc3N3b3JkLWNvbnRhaW5lciBpbnB1dFt0eXBlPVwicGFzc3dvcmRcIl06Zm9jdXMsLm9zLXNpZ24tdXAgLm90LXBhc3N3b3JkLWNvbnRhaW5lciBpbnB1dFt0eXBlPVwidGV4dFwiXTpmb2N1cywub3MtZm9yZ290LXB3ZCAub3QtcGFzc3dvcmQtY29udGFpbmVyIGlucHV0W3R5cGU9XCJwYXNzd29yZFwiXTpmb2N1cywub3MtZm9yZ290LXB3ZCAub3QtcGFzc3dvcmQtY29udGFpbmVyIGlucHV0W3R5cGU9XCJ0ZXh0XCJdOmZvY3Vze2JvcmRlcjpub25lO2JveC1zaGFkb3c6bm9uZX0ub3Mtd2VsY29tZS1ib3ggLm90LXBhc3N3b3JkLWNvbnRhaW5lciAub3QtcGFzc3dvcmQtdG9nZ2xlLC5vcy1zaWduLWluIC5vdC1wYXNzd29yZC1jb250YWluZXIgLm90LXBhc3N3b3JkLXRvZ2dsZSwub3Mtc2lnbi11cCAub3QtcGFzc3dvcmQtY29udGFpbmVyIC5vdC1wYXNzd29yZC10b2dnbGUsLm9zLWZvcmdvdC1wd2QgLm90LXBhc3N3b3JkLWNvbnRhaW5lciAub3QtcGFzc3dvcmQtdG9nZ2xle21hcmdpbjowO2JvcmRlcjpub25lO2JvcmRlci1sZWZ0OjFweCBzb2xpZCAjZTJlOGYwO2JvcmRlci1yYWRpdXM6MDtiYWNrZ3JvdW5kOnRyYW5zcGFyZW50O3BhZGRpbmc6OHB4IDEycHh9Lm9zLXNpZ24tdXAtYnRue2JhY2tncm91bmQtY29sb3I6IzI1NjNlYjtjb2xvcjp3aGl0ZTtib3JkZXI6bm9uZTtib3JkZXItcmFkaXVzOjhweDtmb250LXdlaWdodDo2MDB9Lm9zLXNpZ24tdXAtYnRuOmhvdmVye2JhY2tncm91bmQtY29sb3I6IzFkNGVkOH0ub3MtZm9yZ290LXB3ZC1saW5re2ZvbnQtc2l6ZToxM3B4O2NvbG9yOiM2NDc0OGI7bWFyZ2luLXRvcDo4cHh9Lm9zLWZvcmdvdC1wd2QtbGluazpob3Zlcntjb2xvcjojMjU2M2VifS5vcy1zZXR0aW5ncyBoMntmb250LXNpemU6MThweDtmb250LXdlaWdodDo3MDA7bWFyZ2luOjAgMCAxNnB4IDA7Y29sb3I6IzFlMjkzYn0ub3Mtc2V0dGluZ3M+cHtmb250LXNpemU6MTZweDtmb250LXdlaWdodDo3MDA7Y29sb3I6IzFlMjkzYjttYXJnaW46MjRweCAwIDhweH0ub3Mtc2V0dGluZ3M+cDpmaXJzdC1jaGlsZHttYXJnaW4tdG9wOjB9Lm9zLXNldHRpbmdzIGZvcm0sLm9zLXNldHRpbmdzIC5mb3JtLWxpa2V7ZGlzcGxheTpmbGV4O2ZsZXgtZGlyZWN0aW9uOmNvbHVtbjtiYWNrZ3JvdW5kLWNvbG9yOndoaXRlO3BhZGRpbmc6MjBweCAyNHB4O2JvcmRlci1yYWRpdXM6MTJweDtib3JkZXI6MXB4IHNvbGlkICNlMmU4ZjA7Ym94LXNoYWRvdzowIDFweCAycHggcmdiYSgwLDAsMCwwLjA1KTtnYXA6NnB4O21heC13aWR0aDo0ODBweH0ub3Mtc2V0dGluZ3MgaW5wdXRbdHlwZT1cImNoZWNrYm94XCJde3ZlcnRpY2FsLWFsaWduOm1pZGRsZX0ub3Mtc2V0dGluZ3MgaW5wdXRbdHlwZT1cInN1Ym1pdFwiXSwub3Mtc2V0dGluZ3MgYnV0dG9uOm5vdCgub3QtcGFzc3dvcmQtdG9nZ2xlKXttYXJnaW46MTJweCAwIDRweDtwYWRkaW5nOjEwcHggMjRweDtiYWNrZ3JvdW5kLWNvbG9yOiMyNTYzZWI7Y29sb3I6d2hpdGU7Ym9yZGVyOm5vbmU7Ym9yZGVyLXJhZGl1czo4cHg7Zm9udC13ZWlnaHQ6NjAwO2ZvbnQtc2l6ZToxNXB4O2N1cnNvcjpwb2ludGVyO3RyYW5zaXRpb246YmFja2dyb3VuZC1jb2xvciAwLjE1cyBlYXNlfS5vcy1zZXR0aW5ncyBpbnB1dFt0eXBlPVwic3VibWl0XCJdOmhvdmVyLC5vcy1zZXR0aW5ncyBidXR0b246bm90KC5vdC1wYXNzd29yZC10b2dnbGUpOmhvdmVye2JhY2tncm91bmQtY29sb3I6IzFkNGVkOH0ub3Mtc2V0dGluZ3MgaW5wdXRbdHlwZT1cInRleHRcIl0sLm9zLXNldHRpbmdzIGlucHV0W3R5cGU9XCJwYXNzd29yZFwiXSwub3Mtc2V0dGluZ3MgaW5wdXRbdHlwZT1cImVtYWlsXCJdLC5vcy1zZXR0aW5ncyBpbnB1dFt0eXBlPVwidGVsXCJde3dpZHRoOjEwMCU7ZGlzcGxheTpibG9jazttYXJnaW46NHB4IDA7cGFkZGluZzoxMHB4IDE0cHg7Ym9yZGVyOjFweCBzb2xpZCAjZTJlOGYwO2JvcmRlci1yYWRpdXM6OHB4O2ZvbnQtc2l6ZToxNXB4O2JhY2tncm91bmQtY29sb3I6I2Y4ZmFmYzt0cmFuc2l0aW9uOmJvcmRlci1jb2xvciAwLjE1cyBlYXNlLCBib3gtc2hhZG93IDAuMTVzIGVhc2V9Lm9zLXNldHRpbmdzIGlucHV0W3R5cGU9XCJ0ZXh0XCJdOmZvY3VzLC5vcy1zZXR0aW5ncyBpbnB1dFt0eXBlPVwicGFzc3dvcmRcIl06Zm9jdXMsLm9zLXNldHRpbmdzIGlucHV0W3R5cGU9XCJlbWFpbFwiXTpmb2N1cywub3Mtc2V0dGluZ3MgaW5wdXRbdHlwZT1cInRlbFwiXTpmb2N1c3tvdXRsaW5lOm5vbmU7Ym9yZGVyLWNvbG9yOiMzYjgyZjY7Ym94LXNoYWRvdzowIDAgMCAzcHggcmdiYSgzNyw5OSwyMzUsMC4xKTtiYWNrZ3JvdW5kLWNvbG9yOndoaXRlfS5vcy1zZXR0aW5ncyBzZWxlY3R7d2lkdGg6MTAwJTttYXgtd2lkdGg6MzAwcHg7cGFkZGluZzoxMHB4IDE0cHg7Ym9yZGVyOjFweCBzb2xpZCAjZTJlOGYwO2JvcmRlci1yYWRpdXM6OHB4O2ZvbnQtc2l6ZToxNXB4O2JhY2tncm91bmQtY29sb3I6I2Y4ZmFmYztjdXJzb3I6cG9pbnRlcn0ub3Mtc2V0dGluZ3Mgc2VsZWN0OmZvY3Vze291dGxpbmU6bm9uZTtib3JkZXItY29sb3I6IzNiODJmNn0ub3Mtc2V0dGluZ3MgbGFiZWx7Zm9udC1zaXplOjEzcHg7Zm9udC13ZWlnaHQ6NjAwO2NvbG9yOiM2NDc0OGI7bWFyZ2luLXRvcDo0cHh9Lm9zLXNldHRpbmdzIC5vdC1wYXNzd29yZC1jb250YWluZXJ7d2lkdGg6MTAwJTttYXJnaW46NHB4IDA7Ym9yZGVyOjFweCBzb2xpZCAjZTJlOGYwO2JvcmRlci1yYWRpdXM6OHB4O2JhY2tncm91bmQtY29sb3I6I2Y4ZmFmYztvdmVyZmxvdzpoaWRkZW47dHJhbnNpdGlvbjpib3JkZXItY29sb3IgMC4xNXMgZWFzZSwgYm94LXNoYWRvdyAwLjE1cyBlYXNlfS5vcy1zZXR0aW5ncyAub3QtcGFzc3dvcmQtY29udGFpbmVyOmZvY3VzLXdpdGhpbntib3JkZXItY29sb3I6IzNiODJmNjtib3gtc2hhZG93OjAgMCAwIDNweCByZ2JhKDM3LDk5LDIzNSwwLjEpO2JhY2tncm91bmQtY29sb3I6d2hpdGV9Lm9zLXNldHRpbmdzIC5vdC1wYXNzd29yZC1jb250YWluZXIgaW5wdXRbdHlwZT1cInBhc3N3b3JkXCJdLC5vcy1zZXR0aW5ncyAub3QtcGFzc3dvcmQtY29udGFpbmVyIGlucHV0W3R5cGU9XCJ0ZXh0XCJde21hcmdpbjowO2JvcmRlcjpub25lO2JvcmRlci1yYWRpdXM6MDtiYWNrZ3JvdW5kOnRyYW5zcGFyZW50O2JveC1zaGFkb3c6bm9uZX0ub3Mtc2V0dGluZ3MgLm90LXBhc3N3b3JkLWNvbnRhaW5lciBpbnB1dFt0eXBlPVwicGFzc3dvcmRcIl06Zm9jdXMsLm9zLXNldHRpbmdzIC5vdC1wYXNzd29yZC1jb250YWluZXIgaW5wdXRbdHlwZT1cInRleHRcIl06Zm9jdXN7Ym9yZGVyOm5vbmU7Ym94LXNoYWRvdzpub25lfS5vcy1zZXR0aW5ncyAub3QtcGFzc3dvcmQtY29udGFpbmVyIC5vdC1wYXNzd29yZC10b2dnbGV7bWFyZ2luOjA7Ym9yZGVyOm5vbmU7Ym9yZGVyLWxlZnQ6MXB4IHNvbGlkICNlMmU4ZjA7Ym9yZGVyLXJhZGl1czowO2JhY2tncm91bmQ6dHJhbnNwYXJlbnQ7cGFkZGluZzo4cHggMTJweH0ub3Mtc2V0dGluZ3M+YXtkaXNwbGF5OmlubGluZS1mbGV4O2FsaWduLWl0ZW1zOmNlbnRlcjtnYXA6NnB4O3BhZGRpbmc6OHB4IDA7Y29sb3I6IzI1NjNlYjtmb250LXNpemU6MTRweH0ub3Mtc2V0dGluZ3M+YTpob3Zlcntjb2xvcjojMWQ0ZWQ4fS5vcy1zZXR0aW5ncz5icntkaXNwbGF5Om5vbmV9Lm9zLXNldHRpbmdzLXNlY3Rpb257YmFja2dyb3VuZC1jb2xvcjp3aGl0ZTtib3JkZXI6MXB4IHNvbGlkICNlMmU4ZjA7Ym9yZGVyLXJhZGl1czoxMnB4O3BhZGRpbmc6MjRweDttYXJnaW4tYm90dG9tOjIwcHg7Ym94LXNoYWRvdzowIDFweCAycHggcmdiYSgwLDAsMCwwLjA1KX0ub3Mtc2V0dGluZ3Mtc2VjdGlvbj5wOmZpcnN0LWNoaWxke2ZvbnQtc2l6ZToxNnB4O2ZvbnQtd2VpZ2h0OjcwMDtjb2xvcjojMWUyOTNiO21hcmdpbjowIDAgMTZweH0ub3Mtc2V0dGluZ3Mtc2VjdGlvbiBmb3Jte2JvcmRlcjpub25lO2JveC1zaGFkb3c6bm9uZTtwYWRkaW5nOjB9I29zLW1zZ3twb3NpdGlvbjpmaXhlZDt0b3A6NzJweDtsZWZ0OjUwJTt0cmFuc2Zvcm06dHJhbnNsYXRlWCgtNTAlKTt6LWluZGV4OjEwMDt3aWR0aDoxMDAlO21heC13aWR0aDo2MDBweDtwYWRkaW5nOjAgMTZweH0jb3MtbXNnIHB7cGFkZGluZzoxNnB4IDI0cHg7dGV4dC1hbGlnbjpjZW50ZXI7YmFja2dyb3VuZC1jb2xvcjpyZ2JhKDM3LDk5LDIzNSwwLjk1KTtjb2xvcjp3aGl0ZTtib3JkZXItcmFkaXVzOjhweDtib3gtc2hhZG93OjAgMTBweCAyNXB4IHJnYmEoMCwwLDAsMC4xMik7Zm9udC13ZWlnaHQ6NTAwfSNvcy1tc2cgcC5vcy1lcnJ7YmFja2dyb3VuZC1jb2xvcjpyZ2JhKDIyMCwzOCwzOCwwLjk1KTtjb2xvcjp3aGl0ZX0ub3MtcGFnZS1tYWluIC5vcy1wYWdlLWhlYWRlciAub3MtY29ubmVjdGlvbi1ib3h7cG9zaXRpb246YWJzb2x1dGU7dG9wOjE1cHg7cmlnaHQ6MTVweH0ub3MtcGFnZS1tYWluOm5vdCgub3MtY29ubmVjdGVkKSAub3MtcGFnZS1oZWFkZXJ7ZGlzcGxheTpibG9jaztoZWlnaHQ6NDB2aDtiYWNrZ3JvdW5kOmxpbmVhci1ncmFkaWVudCgxMzVkZWcsICMxZTI5M2IgMCUsICMzMzQ1NjQgMTAwJSl9Lm9zLXBhZ2UtbWFpbjpub3QoLm9zLWNvbm5lY3RlZCkgLm9zLXBhZ2UtaGVhZGVyIC5vcy1wYWdlLWhlYWRlci1hcHAtbmFtZXtkaXNwbGF5OmJsb2NrO3Bvc2l0aW9uOmFic29sdXRlO3RvcDoyOHZoO2ZvbnQtc2l6ZTozMnB4fS5vcy1wYWdlLW1haW46bm90KC5vcy1jb25uZWN0ZWQpIC5vcy1ib2R5e21hcmdpbi10b3A6NDB2aH1AbWVkaWEgKG1heC13aWR0aDogNzIwcHgpey5vcy1wYWdlLWZvb3RlcntkaXNwbGF5Om5vbmV9Lm9zLXBhZ2UtaGVhZGVyIC5vcy1jb25uZWN0aW9uLWJveCwub3MtcGFnZS1oZWFkZXIgLm9zLXBhZ2UtaGVhZGVyLWFwcC1uYW1lLC5vcy1wYWdlLWhlYWRlciAuY29ubmVjdGVkLXVzZXItYm94e2Rpc3BsYXk6bm9uZX0ub3MtcGFnZS1tYWluIC5vcy1wYWdlLWhlYWRlciAub3MtY29ubmVjdGlvbi1ib3h7ZGlzcGxheTpmbGV4O2ZsZXgtZGlyZWN0aW9uOmNvbHVtbjtwb3NpdGlvbjphYnNvbHV0ZTt0b3A6NDV2aDtsZWZ0OjA7d2lkdGg6MTAwJX0ub3MtcGFnZS1tYWluIC5vcy1wYWdlLWhlYWRlciAub3MtY29ubmVjdGlvbi1ib3ggLmJ1dHRvbnt3aWR0aDoxNTBweDttYXJnaW46MTZweCBhdXRvfS5vcy1wYWdlLW1haW4ub3Mtbm90LWNvbm5lY3RlZCAub3MtYm9keXtkaXNwbGF5Om5vbmV9Lm9zLXBhZ2UtaGVhZGVye2Rpc3BsYXk6YmxvY2t9fS5vcy1lbWFpbHN7dGV4dC1hbGlnbjpsZWZ0fS5vcy1lbWFpbHMgdWx7bGlzdC1zdHlsZTpub25lO3BhZGRpbmc6MDttYXJnaW46MDtiYWNrZ3JvdW5kLWNvbG9yOndoaXRlO2JvcmRlcjoxcHggc29saWQgI2UyZThmMDtib3JkZXItcmFkaXVzOjEycHg7b3ZlcmZsb3c6aGlkZGVuO2JveC1zaGFkb3c6MCAxcHggMnB4IHJnYmEoMCwwLDAsMC4wNSl9Lm9zLWVtYWlscyB1bCBsaXtwYWRkaW5nOjEycHggMTZweDtib3JkZXItYm90dG9tOjFweCBzb2xpZCAjZTJlOGYwO2Rpc3BsYXk6ZmxleDtqdXN0aWZ5LWNvbnRlbnQ6c3BhY2UtYmV0d2VlbjthbGlnbi1pdGVtczpjZW50ZXI7Z2FwOjhweH0ub3MtZW1haWxzIHVsIGxpOmxhc3QtY2hpbGR7Ym9yZGVyLWJvdHRvbTpub25lfS5vcy1lbWFpbHMgdWwgbGkgLm9zLXNldHRpbmdzLWxhYmVse2ZvbnQtd2VpZ2h0OjYwMDtwYWRkaW5nOjNweCAxMHB4O21hcmdpbi1sZWZ0OjRweDtib3JkZXItcmFkaXVzOjIwcHg7Zm9udC1zaXplOjEycHg7bGV0dGVyLXNwYWNpbmc6MC4wMmVtfS5vcy1lbWFpbHMgdWwgbGkgLm9zLXNldHRpbmdzLWVtYWlse2ZsZXgtZ3JvdzoyO3BhZGRpbmctcmlnaHQ6MTJweDtmb250LXNpemU6MTRweH0ub3MtZW1haWxzIHVsIGxpIC5vcy1tYWluLWVtYWlse2NvbG9yOiNmZmY7YmFja2dyb3VuZC1jb2xvcjojMTZhMzRhfS5vcy1lbWFpbHMgdWwgbGkgLm9zLXZhbGlkYXRlZC1lbWFpbHtjb2xvcjojZmZmO2JhY2tncm91bmQtY29sb3I6IzI1NjNlYn0ub3MtZW1haWxzIHVsIGxpIC5vcy1yZW1vdmUtZW1haWwtYnV0dG9ue2JveC1zaGFkb3c6bm9uZTtmb250LXNpemU6MTZweDttYXJnaW46MDtwYWRkaW5nOjZweCA4cHg7Y29sb3I6I2RjMjYyNjtiYWNrZ3JvdW5kOm5vbmU7Ym9yZGVyLXJhZGl1czo4cHg7dHJhbnNpdGlvbjpiYWNrZ3JvdW5kLWNvbG9yIDAuMTVzIGVhc2V9Lm9zLWVtYWlscyB1bCBsaSAub3MtcmVtb3ZlLWVtYWlsLWJ1dHRvbjpob3ZlcntiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMjIwLDM4LDM4LDAuMDgpfS5vcy1lbWFpbHMgdWwgbGkgLmJ1dHRvbntmb250LXNpemU6MTJweDtwYWRkaW5nOjVweCAxMnB4O21hcmdpbjowIDJweH0ub3MtYXZhdGFye21hcmdpbi1yaWdodDoxNXB4O3dpZHRoOjM1cHh9Lm90LWRyYXdlcntkaXNwbGF5OmZsZXg7ZmxleC1kaXJlY3Rpb246Y29sdW1ufS5vdC1kcmF3ZXIgLmNvbm5lY3RlZC11c2VyLWJveHtmbGV4LXNocmluazowfS5vdC1kci1sZWZ0IC5vcy1hdmF0YXJ7bWFyZ2luLWxlZnQ6MTZweH0ub3QtcG9wdXB7Ym9yZGVyLXJhZGl1czoxMnB4O2JveC1zaGFkb3c6MCAxMHB4IDI1cHggcmdiYSgwLDAsMCwwLjEyKTtwYWRkaW5nOjE2cHg7b3ZlcmZsb3c6dmlzaWJsZTttaW4td2lkdGg6MzQwcHg7bWF4LXdpZHRoOjQ0MHB4fS5vdC1wb3B1cC1jbG9zZXt0b3A6OHB4O3JpZ2h0OjhweDtwYWRkaW5nOjhweDtjb2xvcjojNjQ3NDhiO2JhY2tncm91bmQ6d2hpdGU7Ym9yZGVyLXJhZGl1czo1MCU7dHJhbnNpdGlvbjpjb2xvciAwLjE1cyBlYXNlLCBiYWNrZ3JvdW5kLWNvbG9yIDAuMTVzIGVhc2U7ei1pbmRleDozfS5vdC1wb3B1cC1jbG9zZTpob3Zlcntjb2xvcjojMWUyOTNiO2JhY2tncm91bmQtY29sb3I6I2Y4ZmFmY30ub3QtcG9wdXAtY29udGVudHtwYWRkaW5nOjB9Lm90LXBvcHVwLWJhY2tncm91bmR7YmFja2dyb3VuZC1jb2xvcjpyZ2JhKDE1LDIzLDQyLDAuNSk7YmFja2Ryb3AtZmlsdGVyOmJsdXIoNHB4KX1kaXYub3MtdGlwe3Bvc2l0aW9uOmFic29sdXRlO21hcmdpbjoyMHB4O2JveC1zaGFkb3c6MHB4IDBweCAycHggMnB4IHJnYmEoMCwwLDAsMC4yKTt6LWluZGV4OjExMTE7dHJhbnNpdGlvbjpvcGFjaXR5IDAuNXN9ZGl2Lm9zLXRpcCBkaXYub3MtdGlwLWJlY3tiYWNrZ3JvdW5kLWNvbG9yOndoaXRlO3dpZHRoOjIwcHg7aGVpZ2h0OjIwcHg7cG9zaXRpb246YWJzb2x1dGU7dHJhbnNmb3JtOnJvdGF0ZSg0NWRlZyk7Ym94LXNoYWRvdzowcHggMHB4IDJweCAycHggcmdiYSgwLDAsMCwwLjIpO3otaW5kZXg6LTF9ZGl2Lm9zLXRpcCBkaXYub3MtdGlwLWNvbnRlbnR7cGFkZGluZzozMHB4IDIwcHggMzBweCAyMHB4O2JhY2tncm91bmQtY29sb3I6d2hpdGU7aGVpZ2h0OjEwMCU7d2lkdGg6MTAwJX1kaXYub3MtdGlwIC5vcy10aXAtY2xvc2V7cG9zaXRpb246YWJzb2x1dGU7dG9wOjVweDtyaWdodDo1cHh9ZGl2Lm9zLXRpcCBsaSxkaXYub3MtdGlwIHB7cGFkZGluZy1ib3R0b206MTBweH0uZGVtby1jYXJvdXNlbDF7ZGlzcGxheTpmbGV4O2p1c3RpZnktY29udGVudDpjZW50ZXJ9LmRlbW8tY2Fyb3VzZWwxIC5kZW1vLWNhcm91c2VsMS1ib3h7cG9zaXRpb246cmVsYXRpdmU7bWFyZ2luOmF1dG99LmRlbW8tY2Fyb3VzZWwxIC5vdC1jYXJvdXNlbHt3aWR0aDozMDBweDtoZWlnaHQ6MjAwcHh9LmRlbW8tY2Fyb3VzZWwxIC5kZW1vLWNhcm91c2VsMS1wYWdle3dpZHRoOjEwMCU7aGVpZ2h0OjEwMCU7cGFkZGluZzoxNnB4O2NvbG9yOndoaXRlfS5kZW1vLWNhcm91c2VsMSAuZGVtby1jYXJvdXNlbDEtcGFnZS0xe2JhY2tncm91bmQtY29sb3I6IzQ5YjJjY30uZGVtby1jYXJvdXNlbDEgLmRlbW8tY2Fyb3VzZWwxLXBhZ2UtMntiYWNrZ3JvdW5kLWNvbG9yOiNkZGRkNTV9LmRlbW8tY2Fyb3VzZWwxIC5kZW1vLWNhcm91c2VsMS1wYWdlLTN7YmFja2dyb3VuZC1jb2xvcjojYzE0NzY4fS5kZW1vLWNhcm91c2VsMSAuZGVtby1jYXJvdXNlbDEtcGFnZS00e2JhY2tncm91bmQtY29sb3I6IzQ1YmY3ZH0uZGVtby1jYXJvdXNlbDEgLm90LWJ1bGxldC1uYXZ7cG9zaXRpb246YWJzb2x1dGU7Ym90dG9tOjE2cHg7cmlnaHQ6MTZweDttYXJnaW46MH0uZGVtby1jYXJvdXNlbDEgLm90LWNhci1wcmV2LC5kZW1vLWNhcm91c2VsMSAub3QtY2FyLW5leHR7cG9zaXRpb246YWJzb2x1dGU7dG9wOjc1cHg7d2lkdGg6NTBweDtoZWlnaHQ6NTBweDtjb2xvcjp3aGl0ZTtvdXRsaW5lOm5vbmV9LmRlbW8tY2Fyb3VzZWwxIC5vdC1jYXItcHJldntsZWZ0OjB9LmRlbW8tY2Fyb3VzZWwxIC5vdC1jYXItbmV4dHtyaWdodDowfS5vcy1wYWdlLWRlbW8tY2Fyb3VzZWwyIC5kZW1vLWNhcm91c2VsMnttYXJnaW46MCAtMTZweH0ub3MtcGFnZS1kZW1vLWNhcm91c2VsMiAub3QtY2Fyb3VzZWx7d2lkdGg6MTAwJTtoZWlnaHQ6YXV0b30ub3MtcGFnZS1kZW1vLWNhcm91c2VsMiAuZGVtby1jYXJvdXNlbDItcGFnZXtwYWRkaW5nOjE2cHh9Lm9zLXBhZ2UtZGVtby1jYXJvdXNlbDIgLmRlbW8tY2Fyb3VzZWwyLXBhZ2UgcHt0ZXh0LWFsaWduOmp1c3RpZnl9Lm9zLXBhZ2UtZGVtby1jYXJvdXNlbDIgLmRlbW8tY2Fyb3VzZWwyLXBhZ2UtMXtiYWNrZ3JvdW5kLWNvbG9yOndoaXRlfS5vcy1wYWdlLWRlbW8tY2Fyb3VzZWwyIC5kZW1vLWNhcm91c2VsMi1wYWdlLTJ7YmFja2dyb3VuZC1jb2xvcjojZmZmZmVlfS5vcy1wYWdlLWRlbW8tY2Fyb3VzZWwyIC5kZW1vLWNhcm91c2VsMi1wYWdlLTN7YmFja2dyb3VuZC1jb2xvcjojZmZkZGVlfS5vcy1wYWdlLWRlbW8tY2Fyb3VzZWwyIC5kZW1vLWNhcm91c2VsMi1wYWdlLTR7YmFja2dyb3VuZC1jb2xvcjojZGRmZmVlfS5vcy1wYWdlLWRlbW8tY2Fyb3VzZWwyIC5kZW1vLWNhcm91c2VsMi10YWJze3Bvc2l0aW9uOnN0aWNreTtiYWNrZ3JvdW5kLWNvbG9yOndoaXRlO3otaW5kZXg6MTt0b3A6NTBweH0ub3MtcGFnZS1kZW1vLWNhcm91c2VsMyAuZGVtby1wcmV2LC5vcy1wYWdlLWRlbW8tY2Fyb3VzZWwzIC5kZW1vLW5leHR7d2lkdGg6MjBweDtoZWlnaHQ6MjBweDtiYWNrZ3JvdW5kLWNvbG9yOiM2YWU7Y29sb3I6d2hpdGV9Lm9zLXBhZ2UtZGVtby1ub3RpZiBpbnB1dDpub3QoW3R5cGVdKSwub3MtcGFnZS1kZW1vLXJlYWN0IGlucHV0Om5vdChbdHlwZV0pe2JhY2tncm91bmQtY29sb3I6I2VlZX0ub3MtcGFnZS1kZW1vLWxpbmtzIC5kZW1vLXN0YXRpYy1pbWd7d2lkdGg6MzAwcHh9Lm9zLXBhZ2UtZGVtby10cmFuc2l0aW9uIC5kZW1vLWxpc3R7cGFkZGluZy1sZWZ0OjA7bGlzdC1zdHlsZS10eXBlOm5vbmV9Lm9zLXBhZ2UtZGVtby10cmFuc2l0aW9uIC5kZW1vLWxpc3QtaXRlbXt3aWR0aDoxMDAlO2hlaWdodDoxNTBweDtmb250LXNpemU6MjBweDtwYWRkaW5nLXRvcDo2NXB4O3RleHQtYWxpZ246Y2VudGVyfS5vcy1wYWdlLWRlbW8tdHJhbnNpdGlvbiAuZGVtby1saXN0LWl0ZW0+YTp2aXNpdGVkLC5vcy1wYWdlLWRlbW8tdHJhbnNpdGlvbiAuZGVtby1saXN0LWl0ZW0+YXtjb2xvcjp3aGl0ZX0ub3MtcGFnZS1kZW1vLXRyYW5zaXRpb24gLmRlbW8tbGlzdC1pdGVtLmRlbW8tbGlzdC1pdGVtLTB7YmFja2dyb3VuZC1jb2xvcjojYjFlYjAwfS5vcy1wYWdlLWRlbW8tdHJhbnNpdGlvbiAuZGVtby1saXN0LWl0ZW0uZGVtby1saXN0LWl0ZW0tMXtiYWNrZ3JvdW5kLWNvbG9yOiM1M2JhZjN9Lm9zLXBhZ2UtZGVtby10cmFuc2l0aW9uIC5kZW1vLWxpc3QtaXRlbS5kZW1vLWxpc3QtaXRlbS0ye2JhY2tncm91bmQtY29sb3I6I2ZmODVjYn0ub3MtcGFnZS1kZW1vLXRyYW5zaXRpb24gLmRlbW8tbGlzdC1pdGVtLmRlbW8tbGlzdC1pdGVtLTN7YmFja2dyb3VuZC1jb2xvcjojZjQ0MDJjfS5vcy1wYWdlLWRlbW8tdHJhbnNpdGlvbiAuZGVtby1saXN0LWl0ZW0uZGVtby1saXN0LWl0ZW0tNHtiYWNrZ3JvdW5kLWNvbG9yOiNmZmFjMDB9Lm9zLXBhZ2UtZGVtby10cmFuc2l0aW9uIC5kZW1vLWJ1dHRvbnttYXJnaW46MCBhdXRvO3BhZGRpbmc6MjBweDt3aWR0aDoyMDBweDtmb250LXNpemU6MjBweDt0ZXh0LWFsaWduOmNlbnRlcjtiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZWV9LmRlbW8tdG9uZ3Vle2Rpc3BsYXk6ZmxleDtmbGV4LWRpcmVjdGlvbjpjb2x1bW59LmRlbW8tdG9uZ3VlIC5kZW1vLXRvbmd1ZS0xe2JhY2tncm91bmQtY29sb3I6I2ZmZmZlZTtoZWlnaHQ6MTAwcHh9LmRlbW8tdG9uZ3VlIC5kZW1vLXRvbmd1ZS0ye2JhY2tncm91bmQtY29sb3I6I2ZmZGRlZTtoZWlnaHQ6MTUwcHh9LmRlbW8tdG9uZ3VlIC5kZW1vLXRvbmd1ZS0ze2JhY2tncm91bmQtY29sb3I6I2RkZmZlZTtoZWlnaHQ6ODBweH0uZGVtby10b25ndWUgLmRlbW8tdG9uZ3VlLTR7YmFja2dyb3VuZC1jb2xvcjojZGRlZWZmO2hlaWdodDoyMDBweH0uZGVtby10b25ndWUgLmRlbW8tdG9uZ3VlLTV7YmFja2dyb3VuZC1jb2xvcjojZWVjY2ZmO2hlaWdodDoxMzBweH0uZGVtby10b25ndWUgLmRlbW8tdG9uZ3VlLTZ7YmFja2dyb3VuZC1jb2xvcjojZmZlZWFhO2hlaWdodDozMDBweH0ub3MtcGFnZS1kZW1vLWZvcm1zPi5vcy1ib2R5IC5kZW1vLWZvcm1zLXNlY3Rpb257bWFyZ2luLWJvdHRvbToyZW07cGFkZGluZzoxZW0gMS4yZW07Ym9yZGVyOjFweCBzb2xpZCAjZTBlMGUwO2JvcmRlci1yYWRpdXM6NnB4O2JhY2tncm91bmQtY29sb3I6I2ZhZmFmYX0ub3MtcGFnZS1kZW1vLWZvcm1zPi5vcy1ib2R5IC5kZW1vLWZvcm1zLXNlY3Rpb24gaDN7bWFyZ2luLXRvcDowO3BhZGRpbmctYm90dG9tOjAuNGVtO2JvcmRlci1ib3R0b206MXB4IHNvbGlkICNlMGUwZTA7Zm9udC1zaXplOjEuMWVtfS5vcy1wYWdlLWRlbW8tZm9ybXM+Lm9zLWJvZHkgLmRlbW8tZm9ybXMtb3V0cHV0e21hcmdpbjowLjRlbSAwO3BhZGRpbmc6MC41ZW0gMC44ZW07YmFja2dyb3VuZC1jb2xvcjojZjBmNGY4O2JvcmRlci1yYWRpdXM6NHB4O2ZvbnQtZmFtaWx5Om1vbm9zcGFjZTtmb250LXNpemU6MC45ZW19Lm9zLXBhZ2UtZGVtby1mb3Jtcz4ub3MtYm9keSBpbnB1dFt0eXBlPVwidGV4dFwiXSwub3MtcGFnZS1kZW1vLWZvcm1zPi5vcy1ib2R5IGlucHV0W3R5cGU9XCJlbWFpbFwiXSwub3MtcGFnZS1kZW1vLWZvcm1zPi5vcy1ib2R5IGlucHV0W3R5cGU9XCJudW1iZXJcIl0sLm9zLXBhZ2UtZGVtby1mb3Jtcz4ub3MtYm9keSBpbnB1dFt0eXBlPVwiZGF0ZVwiXSwub3MtcGFnZS1kZW1vLWZvcm1zPi5vcy1ib2R5IGlucHV0W3R5cGU9XCJ0aW1lXCJdLC5vcy1wYWdlLWRlbW8tZm9ybXM+Lm9zLWJvZHkgaW5wdXRbdHlwZT1cInBhc3N3b3JkXCJdLC5vcy1wYWdlLWRlbW8tZm9ybXM+Lm9zLWJvZHkgdGV4dGFyZWEsLm9zLXBhZ2UtZGVtby1mb3Jtcz4ub3MtYm9keSBzZWxlY3R7ZGlzcGxheTpibG9jazt3aWR0aDoxMDAlO21heC13aWR0aDo0MDBweDtwYWRkaW5nOjAuNWVtO21hcmdpbjowLjRlbSAwO2JvcmRlcjoxcHggc29saWQgI2NjYztib3JkZXItcmFkaXVzOjRweDtmb250LXNpemU6MWVtO2JveC1zaXppbmc6Ym9yZGVyLWJveH0ub3MtcGFnZS1kZW1vLWZvcm1zPi5vcy1ib2R5IHRleHRhcmVhe21pbi1oZWlnaHQ6ODBweDtyZXNpemU6dmVydGljYWx9Lm9zLXBhZ2UtZGVtby1mb3Jtcz4ub3MtYm9keSAuYnV0dG9uLC5vcy1wYWdlLWRlbW8tZm9ybXM+Lm9zLWJvZHkgYnV0dG9uOm5vdCgub3QtcGFzc3dvcmQtdG9nZ2xlKTpub3QoLm90LXRvZ2dsZS1idXR0b24pOm5vdCgub3QtZm9ybS1zdGVwLWJ1dHRvbil7cGFkZGluZzowLjVlbSAxLjJlbTttYXJnaW46MC41ZW0gMDtib3JkZXI6bm9uZTtib3JkZXItcmFkaXVzOjRweDtiYWNrZ3JvdW5kLWNvbG9yOiM0YTkwZDk7Y29sb3I6d2hpdGU7Zm9udC1zaXplOjFlbTtjdXJzb3I6cG9pbnRlcn0ub3MtcGFnZS1kZW1vLWZvcm1zPi5vcy1ib2R5IC5idXR0b246aG92ZXIsLm9zLXBhZ2UtZGVtby1mb3Jtcz4ub3MtYm9keSBidXR0b246bm90KC5vdC1wYXNzd29yZC10b2dnbGUpOm5vdCgub3QtdG9nZ2xlLWJ1dHRvbik6bm90KC5vdC1mb3JtLXN0ZXAtYnV0dG9uKTpob3ZlcntiYWNrZ3JvdW5kLWNvbG9yOiMzYTdiYzh9Lm9zLXBhZ2UtZGVtby1mb3Jtcz4ub3MtYm9keSAuYnV0dG9uOmRpc2FibGVkLC5vcy1wYWdlLWRlbW8tZm9ybXM+Lm9zLWJvZHkgYnV0dG9uOm5vdCgub3QtcGFzc3dvcmQtdG9nZ2xlKTpub3QoLm90LXRvZ2dsZS1idXR0b24pOm5vdCgub3QtZm9ybS1zdGVwLWJ1dHRvbik6ZGlzYWJsZWR7YmFja2dyb3VuZC1jb2xvcjojYWFhO2N1cnNvcjpub3QtYWxsb3dlZH0ub3MtcGFnZS1kZW1vLWZvcm1zPi5vcy1ib2R5IC5vdC1wYXNzd29yZC1jb250YWluZXJ7bWF4LXdpZHRoOjQwMHB4fS5vcy1wYWdlLWRlbW8tZm9ybXM+Lm9zLWJvZHkgLm90LXBhc3N3b3JkLWNvbnRhaW5lciBpbnB1dHtib3JkZXItdG9wLXJpZ2h0LXJhZGl1czowO2JvcmRlci1ib3R0b20tcmlnaHQtcmFkaXVzOjB9Lm9zLXBhZ2UtZGVtby1mb3Jtcz4ub3MtYm9keSAub3QtcGFzc3dvcmQtdG9nZ2xle21hcmdpbjowLjRlbSAwO2JvcmRlci1yYWRpdXM6MCA0cHggNHB4IDB9XG4iXX0= */
\ No newline at end of file
diff --git a/template.distillery/static!defaultcss!PROJECT_NAME.css.map b/template.distillery/static!defaultcss!PROJECT_NAME.css.map
new file mode 100644
index 000000000..8f1809639
--- /dev/null
+++ b/template.distillery/static!defaultcss!PROJECT_NAME.css.map
@@ -0,0 +1,7 @@
+{
+"version": 3,
+"mappings": "AAAQ,iCAAsB,CACtB,2BAAgB,CAChB,4BAAiB,CACjB,0BAAe,CACf,4BAAiB,CACjB,0BAAe,CACf,yBAAc,CACd,oCAAyB,CACzB,yBAAc,CACd,2BAAgB,CAChB,mCAAwB,CACxB,0BAAe,CCLf,gEAAwD,CAMhE,IAAK,CAAE,UAAU,CAAE,UAAU,CAC7B,oBAAuB,CAAE,UAAU,CAAE,OAAO,CAE5C,IAAK,CACD,MAAM,CAAE,CAAC,CACT,SAAS,CAAE,IAAI,CACf,gBAAgB,CAAE,KAAK,CAG3B,wCAA8C,CAC1C,WAAW,CAAE,uBAAuB,CAGxC,WAAa,CACT,eAAe,CAAE,IAAI,CACrB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,OAAO,CAGnB,YAAc,CACV,MAAM,CAAE,IAAI,CAGhB,gDAAmD,CAC/C,MAAM,CAAE,OAAO,CAGnB,OAAQ,CACJ,aAAa,CAAE,GAAG,CAClB,UAAU,CAAE,0BAAyB,CACrC,gBAAgB,CAAE,KAAK,CACvB,KAAK,CAAE,IAAI,CACX,cAAc,CAAE,SAAS,CACzB,SAAS,CAAE,IAAI,CACf,OAAO,CAAE,QAAQ,CACjB,MAAM,CAAE,GAAG,CAGf,KAAM,CACF,OAAO,CAAE,GAAG,CACZ,aAAa,CAAE,GAAG,CAGtB,mBAAoB,CAChB,OAAO,CAAE,IAAI,CACb,WAAW,CAAE,MAAM,CACnB,4BAAS,CACL,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,CACX,SAAS,CAAE,IAAI,CACf,oCAAU,CACN,WAAW,CAAE,IAAI,CAK7B,eAAgB,CACZ,QAAQ,CAAE,KAAK,CACf,GAAG,CAAE,CAAC,CACN,OAAO,CAAE,CAAC,CACV,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,CACX,gBAAgB,CAlEP,IAAI,CAmEb,OAAO,CAAE,IAAI,CACb,cAAc,CAAE,GAAG,CACnB,eAAe,CAAE,aAAa,CAC9B,WAAW,CAAE,MAAM,CACnB,UAAU,CAAE,0BAAyB,CACrC,OAAO,CAAE,aAAa,CACtB,mCAAoB,CAChB,KAAK,CAAE,KAAK,CAIpB,yBAA0B,CACtB,eAAe,CAAE,IAAI,CACrB,KAAK,CAAE,KAAK,CACZ,SAAS,CAAE,IAAI,CAGnB,oBAAqB,CACjB,KAAK,CAAE,KAAK,CAGhB,eAAgB,CACZ,OAAO,CAAE,CAAC,CACV,MAAM,CAAE,CAAC,CACT,UAAU,CAAE,IAAI,CAChB,MAAM,CAAE,IAAI,CACZ,YAAY,CAAE,KAAK,CACnB,kCAAM,CACF,eAAe,CAAE,IAAI,CAEzB,+BAAgB,CACZ,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,IAAI,CAEjB,uBAAQ,CACA,gBAAgB,CArGf,IAAI,CAsGL,KAAK,CAAE,KAAK,CAEpB,mCAAoB,CAChB,aAAa,CAAE,cAAc,CAIrC,kBAAmB,CACf,OAAO,CAAE,CAAC,CACV,uBAAS,CACL,OAAO,CAAE,KAAK,CACd,OAAO,CAAE,gBAAgB,CAIjC,QAAS,CACL,OAAO,CAAE,SAAS,CAGtB,eAAgB,CACZ,QAAQ,CAAE,KAAK,CACf,MAAM,CAAE,CAAC,CACT,IAAI,CAAE,CAAC,CACP,KAAK,CAAE,CAAC,CACR,gBAAgB,CAAE,IAAI,CACtB,OAAO,CAAE,IAAI,CACb,SAAS,CAAE,IAAI,CACf,UAAU,CAAE,MAAM,CAIlB,kFAAG,CACC,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,YAAY,CAExB,uNAAiB,CACb,OAAO,CAAE,IAAI,CACb,MAAM,CAAE,MAAM,CACd,cAAc,CAAE,MAAM,CACtB,gBAAgB,CAAE,IAAI,CACtB,OAAO,CAAE,IAAI,CACb,KAAK,CAAE,KAAK,CAEhB,sLAAuB,CACnB,cAAc,CAAE,MAAM,CAE1B,mRAA6B,CACzB,MAAM,CAAE,QAAQ,CAEpB,+pBACuC,CACnC,KAAK,CAAE,KAAK,CACZ,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,QAAQ,CAEpB,iGAAM,CACF,SAAS,CAAE,IAAI,CAGvB,eAAgB,CACZ,gBAAgB,CAAE,OAAO,CACzB,KAAK,CAAE,KAAK,CAEhB,mBAAoB,CAChB,SAAS,CAAE,IAAI,CAGnB,OAAQ,CACJ,QAAQ,CAAE,KAAK,CACf,GAAG,CAAE,KAAK,CACV,IAAI,CAAE,CAAC,CACP,KAAK,CAAE,CAAC,CACR,OAAO,CAAE,GAAG,CACZ,SAAE,CACE,OAAO,CAAE,MAAM,CACf,UAAU,CAAE,MAAM,CAClB,gBAAgB,CAAE,qBAAqB,CACvC,gBAAS,CACL,gBAAgB,CAAE,iBAAiB,CACnC,KAAK,CAAE,KAAK,CAKxB,gDAAiD,CAC7C,QAAQ,CAAE,QAAQ,CAClB,GAAG,CAAE,IAAI,CACT,KAAK,CAAE,IAAI,CAIX,gDAAgB,CACZ,OAAO,CAAE,KAAK,CACd,MAAM,CAAE,IAAI,CACZ,yEAAyB,CACrB,OAAO,CAAE,KAAK,CACd,QAAQ,CAAE,QAAQ,CAClB,GAAG,CAAE,IAAI,CAGjB,yCAAS,CACL,UAAU,CAAE,IAAI,CAIxB,yBAAiC,CAC7B,eAAgB,CAAE,OAAO,CAAE,IAAI,CAE3B,+GAAkE,CAC9D,OAAO,CAAE,IAAI,CAIjB,gDAAmC,CAC/B,OAAO,CAAE,IAAI,CACb,cAAc,CAAE,MAAM,CACtB,QAAQ,CAAE,QAAQ,CAClB,GAAG,CAAE,IAAI,CACT,IAAI,CAAE,CAAC,CACP,KAAK,CAAE,IAAI,CACX,wDAAQ,CACJ,KAAK,CAAE,KAAK,CACZ,MAAM,CAAE,SAAS,CAGzB,uCAA4B,CACxB,OAAO,CAAE,IAAI,CAGrB,eAAgB,CAAE,OAAO,CAAE,KAAK,EAGpC,cAAe,CACX,UAAU,CAAE,MAAM,CAGtB,UAAW,CACP,UAAU,CAAE,IAAI,CAChB,OAAO,CAAE,IAAI,CACb,eAAe,CAAE,MAAM,CACvB,aAAG,CACC,UAAU,CAAE,IAAI,CAChB,gBAAG,CACC,OAAO,CAAE,QAAQ,CACjB,aAAa,CAAE,iBAAiB,CAChC,OAAO,CAAE,IAAI,CACb,eAAe,CAAE,aAAa,CAC9B,WAAW,CAAE,MAAM,CACnB,mCAAmB,CACf,WAAW,CAAE,IAAI,CACjB,OAAO,CAAE,QAAQ,CACjB,WAAW,CAAE,GAAG,CAChB,aAAa,CAAE,GAAG,CAEtB,mCAAmB,CACf,SAAS,CAAE,CAAC,CACZ,aAAa,CAAE,IAAI,CAEvB,+BAAe,CACX,KAAK,CAAE,IAAI,CACX,gBAAgB,CAAE,OAAO,CAE7B,oCAAoB,CAChB,KAAK,CAAE,IAAI,CACX,gBAAgB,CAAE,IAAI,CAE1B,wCAAwB,CACpB,UAAU,CAAE,IAAI,CAChB,SAAS,CAAE,IAAI,CACf,MAAM,CAAE,GAAG,CACX,KAAK,CAAE,OAAO,CAM9B,UAAW,CACP,YAAY,CAAE,IAAI,CAClB,KAAK,CAAE,IAAI,CAGf,UAAW,CACP,OAAO,CAAE,IAAI,CACb,cAAc,CAAE,MAAM,CACtB,8BAAoB,CAChB,WAAW,CAAE,CAAC,CAGtB,sBAAuB,CACnB,WAAW,CAAE,IAAI,CAIrB,UAAW,CACT,QAAQ,CAAE,QAAQ,CAClB,MAAM,CAAE,IAAI,CACZ,UAAU,CAAE,+BAAkC,CAC9C,OAAO,CAAE,IAAI,CACb,UAAU,CAAE,YAAY,CACxB,yBAAe,CACX,gBAAgB,CAAE,KAAK,CACvB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,QAAQ,CAAE,QAAQ,CAClB,SAAS,CAAE,aAAa,CACxB,UAAU,CAAE,+BAAkC,CAC9C,OAAO,CAAE,EAAE,CAEf,6BAAmB,CACf,OAAO,CAAE,mBAAmB,CAC5B,gBAAgB,CAAE,KAAK,CACvB,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,CAEf,wBAAc,CACV,QAAQ,CAAE,QAAQ,CAClB,GAAG,CAAE,GAAG,CACR,KAAK,CAAE,GAAG,CAEd,0BACE,CACE,cAAc,CAAE,IAAI,CCzU1B,eAAgB,CACd,OAAO,CAAE,IAAI,CACb,eAAe,CAAE,MAAM,CACvB,mCAAoB,CAClB,QAAQ,CAAE,QAAQ,CAClB,MAAM,CAAE,IAAI,CAEd,4BAAa,CACX,KAAK,CAAE,KAAK,CACZ,MAAM,CAAE,KAAK,CAEf,oCAAqB,CACnB,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,OAAO,CAAE,IAAI,CACb,KAAK,CAAE,KAAK,CAEd,sCAAuB,CACrB,gBAAgB,CAAE,OAAO,CAE3B,sCAAuB,CACrB,gBAAgB,CAAE,OAAO,CAE3B,sCAAuB,CACrB,gBAAgB,CAAE,OAAO,CAE3B,sCAAuB,CACrB,gBAAgB,CAAE,OAAO,CAE3B,8BAAe,CACb,QAAQ,CAAE,QAAQ,CAClB,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,CAAC,CAEX,yDACa,CACX,QAAQ,CAAE,QAAQ,CAClB,GAAG,CAAE,IAAI,CACT,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,KAAK,CAAE,KAAK,CACZ,OAAO,CAAE,IAAI,CAEf,4BAAa,CACX,IAAI,CAAE,CAAC,CAET,4BAAa,CACX,KAAK,CAAE,CAAC,CAIV,uCAAgB,CACd,MAAM,CAAE,OAAO,CAEjB,oCAAa,CACX,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CAEd,4CAAqB,CACnB,OAAO,CAAE,IAAI,CACb,8CAAE,CACA,UAAU,CAAE,OAAO,CAGvB,8CAAuB,CACrB,gBAAgB,CAAE,KAAK,CAEzB,8CAAuB,CACrB,gBAAgB,CAAE,OAAO,CAE3B,8CAAuB,CACrB,gBAAgB,CAAE,OAAO,CAE3B,8CAAuB,CACrB,gBAAgB,CAAE,OAAO,CAE3B,4CAAqB,CACnB,QAAQ,CAAE,MAAM,CAChB,gBAAgB,CAAE,KAAK,CACvB,OAAO,CAAE,CAAC,CACV,GAAG,CAAE,IAAI,CAIX,qEACW,CACT,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,gBAAgB,CAAE,IAAI,CACtB,KAAK,CAAE,KAAK,CAKd,2EAAkB,CAChB,gBAAgB,CAAE,IAAI,CAG1B,oCAAqC,CACnC,KAAK,CAAE,KAAK,CAIZ,mCAAW,CACT,YAAY,CAAE,CAAC,CACf,eAAe,CAAE,IAAI,CAGvB,wCAAgB,CACd,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,KAAK,CACb,SAAS,CAAE,IAAI,CACf,WAAW,CAAE,IAAI,CACjB,UAAU,CAAE,MAAM,CAGpB,6FACoB,CAClB,KAAK,CAAE,KAAK,CAGd,yDAAiC,CAC/B,gBAAgB,CAAE,OAAO,CAE3B,yDAAiC,CAC/B,gBAAgB,CAAE,OAAO,CAE3B,yDAAiC,CAC/B,gBAAgB,CAAE,OAAO,CAE3B,yDAAiC,CAC/B,gBAAgB,CAAE,OAAO,CAE3B,yDAAiC,CAC/B,gBAAgB,CAAE,OAAO,CAG3B,qCAAa,CACX,MAAM,CAAE,MAAM,CACd,OAAO,CAAE,IAAI,CACb,KAAK,CAAE,KAAK,CACZ,SAAS,CAAE,IAAI,CACf,UAAU,CAAE,MAAM,CAClB,gBAAgB,CAAE,OAAO,CAG7B,YAAa,CACX,OAAO,CAAE,IAAI,CACb,cAAc,CAAE,MAAM,CACtB,2BAAe,CACb,gBAAgB,CAAE,OAAO,CACzB,MAAM,CAAE,KAAK,CAEf,2BAAe,CACb,gBAAgB,CAAE,OAAO,CACzB,MAAM,CAAE,KAAK,CAEf,2BAAe,CACb,gBAAgB,CAAE,OAAO,CACzB,MAAM,CAAE,IAAI,CAEd,2BAAe,CACb,gBAAgB,CAAE,OAAO,CACzB,MAAM,CAAE,KAAK,CAEf,2BAAe,CACb,gBAAgB,CAAE,OAAO,CACzB,MAAM,CAAE,KAAK,CAEf,2BAAe,CACb,gBAAgB,CAAE,OAAO,CACzB,MAAM,CAAE,KAAK",
+"sources": ["../../sass/%%%PROJECT_NAME%%%.scss","../../sass/os.scss","../../sass/demo.scss"],
+"names": [],
+"file": "%%%PROJECT_NAME%%%.css"
+}
diff --git a/template.distillery/static!wasm_loader.js b/template.distillery/static!wasm_loader.js
new file mode 100644
index 000000000..347c155d8
--- /dev/null
+++ b/template.distillery/static!wasm_loader.js
@@ -0,0 +1,64 @@
+// WebAssembly loader for Ocsigen applications
+// Detects WASM support and loads the appropriate version
+
+(function() {
+ 'use strict';
+
+ // Disable the automatic Eliom script if WASM loader is active
+ // This runs immediately to prevent script execution
+ if (window.__ELIOM_USE_WASM__) {
+ // Override document.write to intercept any automatic script injection
+ var original_write = document.write;
+ document.write = function(content) {
+ // Block caml_p scripts
+ if (content.indexOf('caml_p') === -1 || content.indexOf('class="caml_p"') === -1) {
+ original_write.call(document, content);
+ }
+ };
+
+ // Also disable any existing caml_p scripts (for scripts already in DOM)
+ setTimeout(function() {
+ var scripts = document.getElementsByTagName('script');
+ for (var i = 0; i < scripts.length; i++) {
+ if (scripts[i].className && scripts[i].className.indexOf('caml_p') !== -1 &&
+ scripts[i] !== document.currentScript) {
+ scripts[i].type = 'text/plain';
+ if (scripts[i].parentNode) {
+ scripts[i].parentNode.removeChild(scripts[i]);
+ }
+ }
+ }
+ }, 0);
+ }
+
+ // Check WebAssembly support
+ function supportsWasm() {
+ try {
+ if (typeof WebAssembly === "object" && typeof WebAssembly.instantiate === "function") {
+ var module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
+ if (module instanceof WebAssembly.Module) {
+ return new WebAssembly.Instance(module) instanceof WebAssembly.Instance;
+ }
+ }
+ } catch (e) {}
+ return false;
+ }
+
+ // Get data attributes
+ var currentScript = document.currentScript;
+ if (!currentScript) return;
+
+ var jsPath = currentScript.getAttribute('data-js');
+ var wasmPath = currentScript.getAttribute('data-wasm');
+
+ // Load the appropriate script
+ var scriptToLoad = (supportsWasm() && wasmPath) ? wasmPath : jsPath;
+
+ if (scriptToLoad) {
+ console.log('Loading:', supportsWasm() ? 'WebAssembly' : 'JavaScript', 'version');
+ var script = document.createElement('script');
+ script.src = scriptToLoad;
+ script.async = false;
+ document.head.appendChild(script);
+ }
+})();
diff --git a/template.distillery/tools!gen_dune.ml b/template.distillery/tools!gen_dune.ml
index 9a2d8f1b2..c1fb39935 100644
--- a/template.distillery/tools!gen_dune.ml
+++ b/template.distillery/tools!gen_dune.ml
@@ -23,7 +23,33 @@ let handle_file_client nm =
nm nm
let () =
- Array.concat (List.map Sys.readdir [".."; "../assets"])
+ let root = Sys.readdir ".." in
+ let assets = Sys.readdir "../assets" in
+ (* The build directory mirrors the sources but also holds generated files,
+ which must not be enumerated or their client rule would be emitted twice:
+ - .pp.eliom/.pp.eliomi: preprocessing artifacts;
+ - the i18n modules produced from assets/*.tsv (the .tsv already emits the
+ rule) and the static config produced from *.eliom.in. *)
+ let generated_eliom = Hashtbl.create 16 in
+ Array.iter
+ (fun nm ->
+ if Filename.check_suffix nm ".tsv"
+ then Hashtbl.replace generated_eliom (Filename.chop_suffix nm ".tsv") ())
+ assets;
+ Array.iter
+ (fun nm ->
+ if Filename.check_suffix nm ".eliom.in"
+ then
+ Hashtbl.replace generated_eliom (Filename.chop_suffix nm ".eliom.in") ())
+ root;
+ let is_generated nm =
+ Filename.check_suffix nm ".pp.eliom"
+ || Filename.check_suffix nm ".pp.eliomi"
+ || (Filename.check_suffix nm ".eliom"
+ && Hashtbl.mem generated_eliom (Filename.chop_suffix nm ".eliom"))
+ in
+ Array.concat [root; assets]
|> Array.to_list |> List.sort compare
|> List.filter (fun nm -> nm.[0] <> '.')
+ |> List.filter (fun nm -> not (is_generated nm))
|> List.iter handle_file_client