Tizen 2.0 Release tizen_2.0 submit/tizen_2.0/20130215.192323
authorHyungKyu Song <hk76.song@samsung.com>
Fri, 15 Feb 2013 15:57:34 +0000 (00:57 +0900)
committerHyungKyu Song <hk76.song@samsung.com>
Fri, 15 Feb 2013 15:57:34 +0000 (00:57 +0900)
28 files changed:
AUTHORS [new file with mode: 0644]
LICENSE.Flora [new file with mode: 0644]
NOTICE.Flora [new file with mode: 0644]
config.xml [new file with mode: 0644]
css/GraphSchedule.css [new file with mode: 0644]
css/jquery.ui.layout.css [new file with mode: 0644]
css/style.css [new file with mode: 0644]
icon.png [new file with mode: 0755]
images/background.png [new file with mode: 0644]
images/longBothHorizonGradient.png [new file with mode: 0644]
images/longBothHorizonGradient2.png [new file with mode: 0644]
images/markers.png [new file with mode: 0644]
images/state_lazy.png [new file with mode: 0644]
images/state_run.png [new file with mode: 0644]
index.html [new file with mode: 0644]
js/GraphSchedule.js [new file with mode: 0644]
js/UI.js [new file with mode: 0644]
js/UI.simpleTemplate.js [new file with mode: 0644]
js/app.alarms.js [new file with mode: 0644]
js/app.alarmsGenerating.js [new file with mode: 0644]
js/app.js [new file with mode: 0644]
js/app.onAlarm.js [new file with mode: 0644]
js/app.timeRange.js [new file with mode: 0644]
js/ext.jqMobile.js [new file with mode: 0644]
js/main.js [new file with mode: 0644]
music/Runner.mp3 [new file with mode: 0644]
signature1.xml [new file with mode: 0644]
templates/GraphSchedule.tmpl [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..3d165e3
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,5 @@
+Tomasz Lukawski <t.lukawski at samsung dot com>
+Artur Kobylinski <a.kobylinski at samsung dot com>
+Piotr Wronski <p.wronski at samsung dot com>
+Pawel Sierszen <p.sierszen at samsung dot com>
+Tomasz Paciorek <t.paciorek at samsung dot com>
diff --git a/LICENSE.Flora b/LICENSE.Flora
new file mode 100644 (file)
index 0000000..9c95663
--- /dev/null
@@ -0,0 +1,206 @@
+Flora License
+
+Version 1.0, May, 2012
+
+http://floralicense.org/license/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction,
+and distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by
+the copyright owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and
+all other entities that control, are controlled by, or are
+under common control with that entity. For the purposes of
+this definition, "control" means (i) the power, direct or indirect,
+to cause the direction or management of such entity,
+whether by contract or otherwise, or (ii) ownership of fifty percent (50%)
+or more of the outstanding shares, or (iii) beneficial ownership of
+such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity
+exercising permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications,
+including but not limited to software source code, documentation source,
+and configuration files.
+
+"Object" form shall mean any form resulting from mechanical
+transformation or translation of a Source form, including but
+not limited to compiled object code, generated documentation,
+and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form,
+made available under the License, as indicated by a copyright notice
+that is included in or attached to the work (an example is provided
+in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form,
+that is based on (or derived from) the Work and for which the editorial
+revisions, annotations, elaborations, or other modifications represent,
+as a whole, an original work of authorship. For the purposes of this License,
+Derivative Works shall not include works that remain separable from,
+or merely link (or bind by name) to the interfaces of, the Work and
+Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original
+version of the Work and any modifications or additions to that Work or
+Derivative Works thereof, that is intentionally submitted to Licensor
+for inclusion in the Work by the copyright owner or by an individual or
+Legal Entity authorized to submit on behalf of the copyright owner.
+For the purposes of this definition, "submitted" means any form of
+electronic, verbal, or written communication sent to the Licensor or
+its representatives, including but not limited to communication on
+electronic mailing lists, source code control systems, and issue
+tracking systems that are managed by, or on behalf of, the Licensor
+for the purpose of discussing and improving the Work, but excluding
+communication that is conspicuously marked or otherwise designated
+in writing by the copyright owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity
+on behalf of whom a Contribution has been received by Licensor and
+subsequently incorporated within the Work.
+
+"Tizen Certified Platform" shall mean a software platform that complies
+with the standards set forth in the Compatibility Definition Document
+and passes the Compatibility Test Suite as defined from time to time
+by the Tizen Technical Steering Group and certified by the Tizen
+Association or its designated agent.
+
+2. Grant of Copyright License.  Subject to the terms and conditions of
+this License, each Contributor hereby grants to You a perpetual,
+worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the
+Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License.  Subject to the terms and conditions of
+this License, each Contributor hereby grants to You a perpetual,
+worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+(except as stated in this section) patent license to make, have made,
+use, offer to sell, sell, import, and otherwise transfer the Work
+solely as incorporated into a Tizen Certified Platform, where such
+license applies only to those patent claims licensable by such
+Contributor that are necessarily infringed by their Contribution(s)
+alone or by combination of their Contribution(s) with the Work solely
+as incorporated into a Tizen Certified Platform to which such
+Contribution(s) was submitted. If You institute patent litigation
+against any entity (including a cross-claim or counterclaim
+in a lawsuit) alleging that the Work or a Contribution incorporated
+within the Work constitutes direct or contributory patent infringement,
+then any patent licenses granted to You under this License for that
+Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution.  You may reproduce and distribute copies of the
+Work or Derivative Works thereof pursuant to the copyright license
+above, in any medium, with or without modifications, and in Source or
+Object form, provided that You meet the following conditions:
+
+  1. You must give any other recipients of the Work or Derivative Works
+     a copy of this License; and
+  2. You must cause any modified files to carry prominent notices stating
+     that You changed the files; and
+  3. You must retain, in the Source form of any Derivative Works that
+     You distribute, all copyright, patent, trademark, and attribution
+     notices from the Source form of the Work, excluding those notices
+     that do not pertain to any part of the Derivative Works; and
+  4. If the Work includes a "NOTICE" text file as part of its distribution,
+     then any Derivative Works that You distribute must include a readable
+     copy of the attribution notices contained within such NOTICE file,
+     excluding those notices that do not pertain to any part of
+     the Derivative Works, in at least one of the following places:
+     within a NOTICE text file distributed as part of the Derivative Works;
+     within the Source form or documentation, if provided along with the
+     Derivative Works; or, within a display generated by the Derivative Works,
+     if and wherever such third-party notices normally appear.
+     The contents of the NOTICE file are for informational purposes only
+     and do not modify the License.
+
+You may add Your own attribution notices within Derivative Works
+that You distribute, alongside or as an addendum to the NOTICE text
+from the Work, provided that such additional attribution notices
+cannot be construed as modifying the License. You may add Your own
+copyright statement to Your modifications and may provide additional or
+different license terms and conditions for use, reproduction, or
+distribution of Your modifications, or for any such Derivative Works
+as a whole, provided Your use, reproduction, and distribution of
+the Work otherwise complies with the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+any Contribution intentionally submitted for inclusion in the Work
+by You to the Licensor shall be under the terms and conditions of
+this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify
+the terms of any separate license agreement you may have executed
+with Licensor regarding such Contributions.
+
+6. Trademarks.  This License does not grant permission to use the trade
+names, trademarks, service marks, or product names of the Licensor,
+except as required for reasonable and customary use in describing the
+origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+agreed to in writing, Licensor provides the Work (and each
+Contributor provides its Contributions) on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+implied, including, without limitation, any warranties or conditions
+of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+PARTICULAR PURPOSE. You are solely responsible for determining the
+appropriateness of using or redistributing the Work and assume any
+risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+whether in tort (including negligence), contract, or otherwise,
+unless required by applicable law (such as deliberate and grossly
+negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special,
+incidental, or consequential damages of any character arising as a
+result of this License or out of the use or inability to use the
+Work (including but not limited to damages for loss of goodwill,
+work stoppage, computer failure or malfunction, or any and all
+other commercial damages or losses), even if such Contributor
+has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+the Work or Derivative Works thereof, You may choose to offer,
+and charge a fee for, acceptance of support, warranty, indemnity,
+or other liability obligations and/or rights consistent with this
+License. However, in accepting such obligations, You may act only
+on Your own behalf and on Your sole responsibility, not on behalf
+of any other Contributor, and only if You agree to indemnify,
+defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason
+of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Flora License to your work
+
+To apply the Flora License to your work, attach the following
+boilerplate notice, with the fields enclosed by brackets "[]"
+replaced with your own identifying information. (Don't include
+the brackets!) The text should be enclosed in the appropriate
+comment syntax for the file format. We also recommend that a
+file or class name and description of purpose be included on the
+same "printed page" as the copyright notice for easier
+identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Flora License, Version 1.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://floralicense.org/license/
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
diff --git a/NOTICE.Flora b/NOTICE.Flora
new file mode 100644 (file)
index 0000000..fdb699a
--- /dev/null
@@ -0,0 +1,4 @@
+Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
+Except as noted, this software is licensed under Flora License, Version 1.
+Please, see the LICENSE file for Flora License terms and conditions.
+
diff --git a/config.xml b/config.xml
new file mode 100644 (file)
index 0000000..a4cf761
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<widget xmlns="http://www.w3.org/ns/widgets" xmlns:tizen="http://tizen.org/ns/widgets" id="http://sample-web-application.tizen.org/ExercisePlanner" version="2.0.0" viewmodes="maximized">
+    <tizen:application id="3YbLJNtYMR" required_version="1.0"/>
+    <content src="index.html"/>
+    <tizen:privilege name="http://tizen.org/privilege/alarm"/>
+    <tizen:privilege name="http://tizen.org/privilege/application.launch"/>
+    <tizen:privilege name="http://tizen.org/privilege/application.read"/>
+    <tizen:privilege name="http://tizen.org/privilege/time"/>
+    <tizen:privilege name="http://tizen.org/privilege/tizen"/>
+    <icon src="icon.png"/>
+    <name>ExercisePlanner</name>
+    <tizen:setting screen-orientation="portrait" context-menu="enable"/>
+</widget>
+
diff --git a/css/GraphSchedule.css b/css/GraphSchedule.css
new file mode 100644 (file)
index 0000000..61da77d
--- /dev/null
@@ -0,0 +1,122 @@
+.GraphSchedule {
+       position: relative;
+       overflow-x: scroll;
+       width: 100%;
+       height: 100px;
+       background-color: transparent;
+       z-index: 1000;
+}
+
+.GraphSchedule .container {
+       width: 600px;
+       bottom: 5px;
+       position: absolute;
+}
+
+.GraphSchedule table {
+       pointer-events: none;
+}
+
+.GraphSchedule td {
+       width: 70px;
+       text-align: left;
+       color: gray;
+       height: 10px;
+}
+
+.GraphSchedule table .grid td {
+       border-width: 1px 0 0px 1px;
+       border-style: solid;
+       border-color: white;
+       font-size: 13px;
+       font-family: Helvetica;
+       position: relative;
+}
+
+.GraphSchedule table .ranges td {
+       border-width: 1px 0 0 1px;
+       border-style: solid;
+       border-color: gray;
+       position: relative;
+}
+
+.GraphSchedule table .ranges .th {
+       border-width: 0px;
+       background-color: rgba(50, 50, 50, 0.2);
+       position: relative;
+       padding: 0;
+}
+
+.GraphSchedule table .rangesWeekend td {
+       border-width: 1px 0 0 1px;
+       border-style: solid;
+       border-color: gray;
+       position: relative;
+}
+
+.GraphSchedule table .rangesWeekend .th {
+       border-width: 0px;
+       background-color: rgba(50, 50, 250, 0.2);
+       position: relative;
+       padding: 0;
+}
+
+.GraphSchedule .flag {
+       position: absolute;
+       width: 10px;
+       height: 60px;
+       background-color: transparent;
+       bottom: 19px;
+}
+
+.GraphSchedule .flag .container {
+       position: relative;
+       width: 10px;
+       bottom: -1px;
+       height: 60px;
+}
+
+.GraphSchedule .flag .rod {
+       position: absolute;
+       width: 2px;
+       height: 55px;
+       left: 0;
+       background-color: brown;
+       bottom: 0;
+       border-width: 0 1px 0 0;
+       border-style: solid;
+       border-color: #aaa;
+}
+
+.GraphSchedule .flag p {
+       position: absolute;
+       width: 15px;
+       left: 3px;
+       background-color: #f88;
+       height: 15px;
+       top: -10px;
+       background-image: -webkit-linear-gradient(left, #F88 18%, #E31448 59%);
+}
+
+.GraphSchedule .flag .hint {
+       display: none;
+       position: absolute;
+       width: 42px;
+       height: 18px;
+       top: 8px;
+       left: 2px;
+       background-color: #FF9;
+       -webkit-border-radius: 5px 5px 5px;
+       position: absolute;
+}
+
+.currentTimeBar {
+       position: absolute;
+       height: 100px;
+       background-color: yellow;
+       width: 2px;
+       bottom: -20px;
+       border-width: 0 1px 0 0;
+       border-style: solid;
+       border-color: #FC0;
+}
\ No newline at end of file
diff --git a/css/jquery.ui.layout.css b/css/jquery.ui.layout.css
new file mode 100644 (file)
index 0000000..bcecced
--- /dev/null
@@ -0,0 +1,33 @@
+.ui-myHeader {\r
+       background-color: #293d5e;\r
+       height: 70px;\r
+}\r
+\r
+.ui-myContent {\r
+       overflow: auto;\r
+       -webkit-box-flex: 1;\r
+       height: 0px;\r
+}\r
+\r
+.ui-myFooter {\r
+       background-color: #192333;\r
+       height: 70px;\r
+}\r
+\r
+.ui-myExit {\r
+       float: right;\r
+       background-color: #555;\r
+       width: 70px;\r
+       height: 50px;\r
+       margin-top: 10px;\r
+       margin-right: 10px;\r
+       border-radius: 5px;\r
+       background-image: url('../images/00_winset_Back.png');\r
+       background-repeat: no-repeat;\r
+       background-position: center center;\r
+       background-size: 50%;\r
+}\r
+\r
+.ui-myHeader {\r
+       text-align: center;\r
+}
\ No newline at end of file
diff --git a/css/style.css b/css/style.css
new file mode 100644 (file)
index 0000000..e1eff8f
--- /dev/null
@@ -0,0 +1,279 @@
+#one {
+       background-image: url('../images/background.png');
+}
+
+.screen {
+       font-family: serif;
+       color: white;
+       font-size: 17pt;
+}
+
+#sentence {
+       margin: 10px 30px 0 30px;
+       position: relative;
+       float: right;
+       text-indent: 30px;
+}
+
+#signature {
+       margin: 0px 30px 0 auto;
+       position: relative;
+       float: right;
+}
+
+#logo {
+       font-family: courier;
+       font-size: 36px;
+       width: 100%;
+       background-repeat: no-repeat;
+       margin: 0px 40px 0 auto;
+       color: white;
+       border-bottom: 1px solid white;
+       font-weight: bolder;
+       text-align: right;
+       line-height: 43px;
+}
+
+#status {
+       width: 400px;
+       height: 350px;
+       margin: 0 auto;
+       background-repeat: no-repeat;
+}
+
+#status.lazy {
+       background-image: url('../images/state_lazy.png');
+}
+
+#status.run {
+       background-image: url('../images/state_run.png');
+}
+
+#communicate {
+       font-size: 17pt;
+       text-align: center;
+       min-height: 70px;
+}
+
+#communicate.onAlert {
+       font-size: 60px;
+       text-align: center;
+       text-shadow: 5px 5px 5px black;
+}
+
+#communicate b {
+       font-size: 25px;
+}
+
+#communicate div {
+       font-size: 32px;
+       font-weight: bold;
+}
+
+.schedule {
+       height: 100px;
+}
+
+.scheduleOptions {
+       height: 100px;
+}
+
+.increasingStrength {
+       display: none;
+}
+
+.strength {
+       margin: 0 0 20px 0;
+}
+
+.timeRangeLabel {
+       height: 50px;
+}
+
+.activeStatus {
+       display: inline;
+       float: right;
+       color: blue;
+}
+
+.activeStatusDisable {
+       color: red;
+}
+
+.times li {
+       float: left;
+       width: 200px;
+}
+
+.times {
+       width: 100%;
+       float: left;
+       margin: 0;
+       padding: 10px;
+}
+
+.times .ui-datefield {
+       font-size: 60px;
+}
+
+/**
+
+old styles;
+
+*/
+.exerciseView {
+       width: 80%;
+       height: 200px;
+       border-width: 1px;
+       border-color: #888 #DDD #DDD #888;
+       border-style: solid;
+       background-color: #578;
+       -webkit-border-radius: 0.6em;
+       -webkit-box-align: center;
+       margin: 0 auto;
+       box-shadow: 0px 0px 20px #000;
+       position: relative;
+}
+
+.optionsExercises label {
+       line-height: 44px;
+}
+
+#exercises {
+       margin-bottom: 10px;
+}
+
+.myHeader {
+
+}
+
+.ui-controlgroup .ui-radio {
+       width: 20%;
+}
+
+.myContent {
+       margin: auto 10px 10px 10px;
+}
+
+.footerContent {
+       margin: 0 auto;
+       text-align: center;
+       padding-top: 20px;
+}
+
+.newExerciseName label {
+       width: 100%;
+}
+
+.newExerciseName input { /*background-color:white;*/
+
+}
+
+.ui-footer {
+       z-index: 1000;
+}
+
+#availableTime {
+       margin-top: 12px;
+       overflow: hidden;
+       margin-left: 0;
+       margin-right: 0;
+}
+
+#availableTime li {
+       margin-left: 0;
+       margin-right: 0;
+}
+
+.ui-swipelist-item .ui-btn {
+       padding: 4px;
+       margin-right: 12px;
+}
+
+.ui-li-text-sub-right {
+       font-size: 18px;
+       margin-right: 17px;
+       float: right;
+       margin-top: 2px;
+       color: #08f;
+}
+
+.disabled {
+       color: #f00;
+}
+
+ul {
+       list-style-type: none;
+}
+
+.goToOptionsPack {
+       width: 100%;
+}
+
+.goToOptions {
+       width: 80%;
+       margin-left: 10%;
+       margin-right: 10%;
+}
+
+.buttonOptions {
+       float: right;
+       box-shadow: 0px 0px 10px #000;
+}
+
+.buttonStop {
+       background-color: #F40;
+       box-shadow: 0px 0px 10px #000;
+}
+
+.selectPeriodType .ui-radio {
+       width: 100%;
+}
+
+#formEnablePeriod {
+       margin-bottom: 20px;
+}
+
+#ok_wait {
+       position: absolute;
+       bottom: 0;
+       width: 100%;
+}
+
+#ok_wait .ok {
+       left: 50px;
+}
+
+#ok_wait .wait {
+       right: 50px;
+       position: absolute;
+}
+
+span.meterDesc {
+       position: absolute;
+       z-index: 100;
+       display: block;
+       text-align: center;
+       width: inherit;
+       padding-top: 8px;
+       color: #333;
+}
+
+.enableOption {
+       padding-bottom: 20px;
+}
+
+.enableOption>div {
+       display: table-cell;
+}
+
+.enableOption>label {
+       float: left;
+       padding-right: 20px;
+       padding-top: 8px;
+       vertical-align: middle;
+}
+
+div.period {
+       padding-left: 10px;
+}
diff --git a/icon.png b/icon.png
new file mode 100755 (executable)
index 0000000..983c883
Binary files /dev/null and b/icon.png differ
diff --git a/images/background.png b/images/background.png
new file mode 100644 (file)
index 0000000..532ca02
Binary files /dev/null and b/images/background.png differ
diff --git a/images/longBothHorizonGradient.png b/images/longBothHorizonGradient.png
new file mode 100644 (file)
index 0000000..946d3cd
Binary files /dev/null and b/images/longBothHorizonGradient.png differ
diff --git a/images/longBothHorizonGradient2.png b/images/longBothHorizonGradient2.png
new file mode 100644 (file)
index 0000000..5ff092a
Binary files /dev/null and b/images/longBothHorizonGradient2.png differ
diff --git a/images/markers.png b/images/markers.png
new file mode 100644 (file)
index 0000000..23feef7
Binary files /dev/null and b/images/markers.png differ
diff --git a/images/state_lazy.png b/images/state_lazy.png
new file mode 100644 (file)
index 0000000..c2e67dd
Binary files /dev/null and b/images/state_lazy.png differ
diff --git a/images/state_run.png b/images/state_run.png
new file mode 100644 (file)
index 0000000..a72d60e
Binary files /dev/null and b/images/state_run.png differ
diff --git a/index.html b/index.html
new file mode 100644 (file)
index 0000000..96d82bf
--- /dev/null
@@ -0,0 +1,237 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+<meta charset="utf-8" />
+<meta name="description" content="Alerts" />
+<meta name="viewport" content="width=480, user-scalable=no" />
+
+<title>ExercisePlanner</title>
+
+<script src="/usr/share/tizen-web-ui-fw/latest/js/jquery.js"></script>
+<script src="/usr/share/tizen-web-ui-fw/latest/js/tizen-web-ui-fw-libs.js"></script>
+<script src="/usr/share/tizen-web-ui-fw/latest/js/tizen-web-ui-fw.js"
+       data-framework-theme="tizen-white"></script>
+
+<script src="./js/UI.js"></script>
+<script src="./js/UI.simpleTemplate.js"></script>
+<script src="./js/ext.jqMobile.js"></script>
+<script src="./js/GraphSchedule.js"></script>
+
+<script src="./js/app.js"></script>
+<script src="./js/app.alarms.js"></script>
+<script src="./js/app.timeRange.js"></script>
+<script src="./js/app.alarmsGenerating.js"></script>
+<script src="./js/app.onAlarm.js"></script>
+<script type="text/javascript" src="./js/main.js"></script>
+
+<link rel="stylesheet" type="text/css" href="./css/style.css" />
+<link rel="stylesheet" type="text/css" href="./css/GraphSchedule.css" />
+</head>
+
+<body>
+       <div data-role="page" id="one" data-add-back-btn="footer" data-footer-exist="true">
+               <div data-role="content">
+                       <div class="screen">
+                               <div id="logo">Exercise Planner</div>
+                               <div id="status"></div>
+                               <div class="schedule"></div>
+                               <div id="communicate"></div>
+                               <div id="sentence"></div>
+                               <div id="signature"></div>
+                       </div>
+               </div>
+
+               <div data-role="footer" data-position="fixed">
+                       <div data-role="tabbar" id="mainControl" data-style="tabbar">
+                               <ul>
+                                       <li><a href="#" id="startStop">stop training</a></li>
+                                       <li><a href="#two" id="options">options</a></li>
+                               </ul>
+                       </div>
+
+                       <div id="onAlertControl" data-style="tabbar"
+                               style="display: none;">
+                               <ul>
+                                       <li><a href="#" id="ok">OK</a></li>
+                                       <li><a href="#" id="wait">Wait</a></li>
+                                       <li><a href="#" id="todayOffAll">Today off all</a></li>
+                               </ul>
+                       </div>
+               </div>
+       </div>
+
+       <div data-role="page" id="two" data-add-back-btn="footer" data-footer-exist="true">
+               <div data-role="header" data-position="fixed">
+                       <h1>ExercisePlanner &gt; options</h1>
+               </div>
+
+               <div data-role="content">
+                       <div class="myContent">
+
+                               <div data-role="fieldcontain" class="frequency">
+                                       <div>Frequency</div>
+                                       <fieldset data-role="controlgroup" data-type="horizontal" id="frequency">
+                                               <input type="radio" name="radioFrequency"
+                                                       data-icon="segment-titlestyle-segonly" id="freq1" value="1" />
+                                               <label for="freq1">1</label>
+                                               <input type="radio" name="radioFrequency"
+                                                       data-icon="segment-titlestyle-segonly" id="freq2" value="2" />
+                                               <label for="freq2">2</label>
+                                               <input type="radio" name="radioFrequency"
+                                                       data-icon="segment-titlestyle-segonly" id="freq3" value="3" />
+                                               <label for="freq3">3</label>
+                                               <input type="radio" name="radioFrequency"
+                                                       data-icon="segment-titlestyle-segonly" id="freq4" value="4" />
+                                               <label for="freq4">4</label>
+                                               <input type="radio" name="radioFrequency"
+                                                       data-icon="segment-titlestyle-segonly" id="freq5" value="5" />
+                                               <label for="freq5">5</label>
+                                       </fieldset>
+                               </div>
+
+                               <div class="scheduleOptions"></div>
+
+                               <div data-role="tabbar" data-style="tabbar" class="typeOfPeriods">
+                                       <ul>
+                                               <li id="workdaysType"><a>workday</a></li>
+                                               <li id="weekendType"><a>weekend</a></li>
+                                       </ul>
+                               </div>
+
+                               <div data-role="fieldcontain" class="strength">
+                                       <div>Strength</div>
+                                       <fieldset data-role="controlgroup" data-type="horizontal"
+                                               id="strength">
+                                               <input type="radio" name="radioStrength"
+                                                       data-icon="segment-titlestyle-segonly" id="stre1" value="1" />
+                                               <label for="stre1">1</label>
+                                               <input type="radio" name="radioStrength"
+                                                       data-icon="segment-titlestyle-segonly" id="stre2" value="2" />
+                                               <label for="stre2">2</label>
+                                               <input type="radio" name="radioStrength"
+                                                       data-icon="segment-titlestyle-segonly" id="stre3" value="3" />
+                                               <label for="stre3">3</label>
+                                               <input type="radio" name="radioStrength"
+                                                       data-icon="segment-titlestyle-segonly" id="stre4" value="4" />
+                                               <label for="stre4">4</label>
+                                               <input type="radio" name="radioStrength"
+                                                       data-icon="segment-titlestyle-segonly" id="stre5" value="5" />
+                                               <label for="stre5">5</label>
+                                       </fieldset>
+                               </div>
+
+                               <div class="increasingStrength">
+                                       <input type="checkbox" name="tizen-check1-1"
+                                               id="increasingStrength" />
+                                       <label for="increasingStrength">progressive effort</label>
+                               </div>
+
+                               <a data-role="button" data-icon="plus" id="addTimeRange" data-inline="false">add time</a>
+                               <ul data-role="swipelist" id="availableTime"></ul>
+
+                       </div>
+               </div>
+
+               <div data-role="footer" data-position="fixed">
+                       <div data-role="tabbar" data-style="toolbar">
+                               <ul>
+                                       <li><a href="#selectExercises">select workouts</a></li>
+                               </ul>
+                       </div>
+               </div>
+       </div>
+
+       <div data-role="page" id="selectExercises" data-add-back-btn="footer" data-footer-exist="true">
+               <div data-role="header" data-position="fixed">
+                       <h2>ExercisePlanner &gt; select workouts</h2>
+               </div>
+
+               <div data-role="content">
+                       <div class="optionsExercises">
+                               <div>Select workouts</div>
+                               <ul data-role="listview" id="exercises">
+                                       <li class="ui-li-1line-toggle"><span class="ui-li-text-main">bends</span>
+                                               <div data-role="toggleswitch"></div></li>
+
+                                       <li class="ui-li-1line-btn2"><span class="ui-li-text-main">custom</span>
+                                               <div data-role="button" data-inline="true" data-icon="plus"
+                                                       data-style="circle"></div></li>
+                               </ul>
+                               <a data-role="button" data-icon="plus" href="#customExercises">add
+                                       custom workout</a>
+                       </div>
+               </div>
+
+               <div data-role="footer" data-position="fixed"></div>
+       </div>
+
+       <div data-role="page" id="customExercises" data-add-back-btn="footer" data-footer-exist="true">
+               <div data-role="header" data-position="fixed">
+                       <h1>ExercisePlanner &gt; add custom workout</h1>
+               </div>
+
+               <div data-role="content">
+                       <div class="newExerciseName">
+                               <div>Enter workout name:</div>
+                               <input data-role="input" type="text" name="newExercise"
+                                       id="newExerciseName" />
+                               <input data-role="button" id="btnNewExercise" data-inline="true" type="button"
+                                       value="add"/>
+                       </div>
+               </div>
+
+               <div data-role="footer" data-position="fixed"></div>
+       </div>
+
+       <div data-role="page" id="rangesOfTimes" data-add-back-btn="footer" data-footer-exist="true">
+               <div data-role="header">
+                       <h1>add time</h1>
+               </div>
+
+               <div data-role="content">
+                       <div>
+                               <ul class="times">
+                                       <li class="ui-li-3-2-2">Start: <span class="ui-li-text-main">
+                                                       <input type="time" name="dateStart" id="startTime"
+                                                               data-format="H" />
+                                       </span>hour
+                                       </li>
+                                       <li class="ui-li-3-2-2">Duration: <span class="ui-li-text-main">
+                                                       <input type="time" name="duration" id="duration" data-format="H" />
+                                       </span> hours
+                                       </li>
+                               </ul>
+
+                               <fieldset data-role="controlgroup" class="selectPeriodType">
+                                       <legend>Choose a type of period:</legend>
+                                       <input type="radio" name="periodType" id="periodType1"
+                                               value="everyday" checked="checked" />
+                                       <label for="periodType1">everyday</label>
+
+                                       <input type="radio" name="periodType" id="periodType2"
+                                               value="weekend" />
+                                       <label for="periodType2">weekend</label>
+
+                                       <input type="radio" name="periodType" id="periodType3"
+                                               value="workday" />
+                                       <label for="periodType3">workday</label>
+                               </fieldset>
+                               <div class="enableOption">
+                                       <span>Enabled</span>
+                                       <select id="formEnablePeriod" data-role="slider">
+                                               <option value="off"></option>
+                                               <option value="on"></option>
+                                       </select>
+                               </div>
+                       </div>
+
+                       <input data-role="button" data-inline="true" type="button"
+                               id="updateTime" value="add" />
+               </div>
+
+               <div data-role="footer"></div>
+       </div>
+
+</body>
+</html>
diff --git a/js/GraphSchedule.js b/js/GraphSchedule.js
new file mode 100644 (file)
index 0000000..b19ed7c
--- /dev/null
@@ -0,0 +1,191 @@
+/*jslint devel: true*/
+/*global $ */
+/**
+ * Constructor
+ *
+ * @param {object} params
+ * @returns
+ */
+function GraphSchedule(params) {
+       "use strict";
+       this.init(params);
+}
+
+(function () {
+       "use strict";
+       GraphSchedule.prototype = {
+               template: '',
+               ui: null,
+               $flag: null,
+               $graph: null,
+               timeRanges: {
+                       workday: [],
+                       weekend: []
+               },
+               flags: []
+       };
+
+       GraphSchedule.prototype.createUI = function createUI() {
+               console.log('GraphSchedule..createUI');
+               var $tmp = $('<div></div>');
+
+               $tmp.html(this.template);
+               this.$flag = $tmp.find('.flag');
+               this.$graph = $tmp.find('.GraphSchedule');
+               this.ui = this.$graph;
+
+               this.addCurrentTimeBar();
+               this.showFlags();
+
+               this.center();
+       };
+
+       GraphSchedule.prototype.center = function center() {
+               // set scroll position;
+               this.$graph[0].scrollLeft = 1000 * ((new Date().getHours() - 4) / 24);
+       };
+
+       GraphSchedule.prototype.refresh = function refresh() {
+               this.updateTimeRanges();
+               this.showFlags();
+               this.center();
+       };
+
+       GraphSchedule.prototype.onTemplateLoad = function onTemplateLoad() {
+               console.log('GraphSchedule..onTemplateLoad');
+       };
+
+       GraphSchedule.prototype.init = function init(params) {
+               var $loader = $('<div></div>');
+
+               if (params && params.onSuccess) {
+                       this.onTemplateLoad = params.onSuccess;
+               }
+
+               this.flags = [];
+               $loader.load('templates/GraphSchedule.tmpl', null, function (data) {
+                       console.log('$loader.onLoad');
+                       this.template = data;
+                       this.createUI();
+                       this.onTemplateLoad();
+               }.bind(this));
+       };
+
+       /**
+        *
+        * @param {Array} times
+        * @returns
+        */
+       GraphSchedule.prototype.pushTimeOfFlags = function pushTimeOfFlags(times) {
+               var i, count;
+
+               // clear previous times;
+               this.flags = [];
+
+               if (times instanceof Array) {
+                       count = times.length;
+                       for (i = 0; i < count; i += 1) {
+                               if (times[i] instanceof Date) {
+                                       this.flags.push({ time: times[i] });
+                               } else {
+                                       throw {message: 'Bag argument at [' + i + '] element of Array. Expected {Date}'};
+                               }
+                       }
+               } else {
+                       throw {message: 'Bad argument. Expected {Array} of {Date}'};
+               }
+       };
+
+       GraphSchedule.prototype.addCurrentTimeBar = function addCurrentTimeBar() {
+               console.log('addCurrentTimeBar()');
+               // remove old time bar;
+               var $currentTimeBar = this.$graph.find('.currentTimeBar'),
+                       currentTime = new Date(),
+                       hours = currentTime.getHours();
+
+               if ($currentTimeBar.length === 0) {
+                       // add new;
+                       $currentTimeBar = $('<div class="currentTimeBar"></div>');
+               }
+
+               if (hours < 10) {
+                       hours = '0' + hours;
+               }
+
+               this.$graph.find('.ranges .h' + hours).append($currentTimeBar);
+               $currentTimeBar.css('left', 100 * currentTime.getMinutes() / 60 + '%');
+
+               setTimeout(this.addCurrentTimeBar.bind(this), 5 * 60 * 1000);
+       };
+
+       GraphSchedule.prototype.addFlag = function addFlag(newFlag) {
+               console.log('addFlag()');
+               var $flagClone, hours = newFlag.time.getHours();
+               if (hours < 10) {
+                       hours = '0' + hours;
+               }
+               $flagClone = this.$flag.clone();
+               this.$graph.find('.grid td:contains(' + hours + ')').append($flagClone);
+               $flagClone.css('left', 100 * newFlag.time.getMinutes() / 60 + '%');
+       };
+
+       GraphSchedule.prototype.showFlags = function showFlags() {
+               var i, len = this.flags.length;
+               // remove old flags;
+               this.removeFlags();
+
+               // add all flags to view;
+               for (i = 0; i < len; i += 1) {
+                       this.addFlag(this.flags[i]);
+               }
+
+               this.center();
+       };
+
+       GraphSchedule.prototype.removeFlags = function removeFlags() {
+               this.$graph.find('.flag').remove();
+       };
+
+       GraphSchedule.prototype.setTimeRanges = function setTimeRanges(ranges) {
+               this.timeRanges = ranges;
+       };
+
+       GraphSchedule.prototype.setVisibleWeekend = function (bool) {
+               var row = this.ui.find('.rangesWeekend');
+               return bool ? row.show() : row.hide();
+       };
+
+       GraphSchedule.prototype.setVisibleWorkdays = function (bool) {
+               var row = this.ui.find('.ranges');
+               return bool ? row.show() : row.hide();
+       };
+
+       /**
+        * Update time ranges on graph
+        * @param ranges {array} array of boolen, keys are hours, example: [false, false, false, true, true]
+        */
+       GraphSchedule.prototype.updateTimeRanges = function updateTimeRanges() {
+               var i, len, hours;
+
+               this.$graph.find('.th').removeClass('th');
+
+               // workdays;
+               hours = this.timeRanges.workday;
+               len = hours.length;
+               for (i = 0; i < len; i += 1) {
+                       if (hours[i]) {
+                               this.$graph.find('.ranges .h' + ((i < 10) ? '0' + i : i)).addClass('th');
+                       }
+               }
+
+               //weekends;
+               hours = this.timeRanges.weekend;
+               len = hours.length;
+               for (i = 0; i < len; i += 1) {
+                       if (hours[i]) {
+                               this.$graph.find('.rangesWeekend .h' + ((i < 10) ? '0' + i : i)).addClass('th');
+                       }
+               }
+       };
+
+}());
diff --git a/js/UI.js b/js/UI.js
new file mode 100644 (file)
index 0000000..cc8bff7
--- /dev/null
+++ b/js/UI.js
@@ -0,0 +1,415 @@
+/*jslint devel: true, nomen: true*/
+/*global $, GraphSchedule, confirm, range, history */
+function UI() {
+       "use strict";
+}
+
+(function () {
+       "use strict";
+       UI.prototype = {
+               sentence : {
+                       'lazy' : {
+                               text : 'He does not seem to me to be a free man who does not sometimes do nothing.',
+                               signature : 'Marcus T. Cicero'
+                       },
+                       'run' : {
+                               text : 'A journey of a thousand miles begins with a  single step.',
+                               signature : 'Lao-tzu'
+                       }
+               },
+               graphSchedule : null,
+               app : null
+       };
+
+       UI.prototype.fillExercises = function (exercisesData) {
+               console.log('UI_fillExercises', exercisesData);
+               var i, len, self = this;
+
+               $('#exercises').replaceWith(
+                       $('<div id="exercises"></div>')
+               );
+               for (i = 0, len = exercisesData.length; i < len; i += 1) {
+                       $('#exercises').append(
+                               $(this.getExercisesTemplate(exercisesData[i], i))
+                       );
+               }
+               $('#exercises :jqmData(role="slider")').slider();
+
+               $('#exercises :jqmData(role="slider")').on('change', function (e) {
+                       console.log('slider:change');
+                       self.app.saveExercises(self.getExercisesList());
+               });
+       };
+
+       UI.prototype.fillTimesRanges = function (timesData) {
+               console.log('UI_fillTimesRanges', timesData);
+               var self = this, len, i;
+
+               $('#availableTime').replaceWith(
+                       $('<ul data-role="listview" id="availableTime"></ul>')
+               );
+               for (i = 0, len = timesData.length; i < len; i += 1) {
+                       $('#availableTime')
+                               .append($(this.getAvailableTimeTemplate(timesData[i])));
+               }
+               $('#availableTime').trigger('create');
+               $('#availableTime').listview();
+               $('#availableTime :jqmData(name=edit)').on('tap', function (e) {
+                       e.preventDefault();
+                       e.stopPropagation();
+                       self.editTimeRange($(this).data('val'));
+               });
+               $('#availableTime :jqmData(name=disable)').on('tap', function (e) {
+                       e.stopPropagation();
+                       self.app.disableTimeRange($(this).data('val'));
+               });
+               $('#availableTime :jqmData(name=delete)').on('tap', function (e) {
+                       e.stopPropagation();
+                       if (confirm('Are you sure?')) {
+                               self.app.deleteTimeRange($(this).data('val'));
+                       }
+               });
+       };
+
+       UI.prototype.fillTimeRangeForm = function fillTimeRangeForm(timeRange) {
+               console.log('UI.fillTimeRangeForm', timeRange);
+               var tmpData = new Date();
+               // Filling form;
+               $('#startTime').attr('data-val',
+                               new Date(tmpData.setHours(timeRange.start)));
+               $('#duration').attr('data-val', timeRange.duration);
+
+               if ($('#startTime').data('datetimepicker')) {
+                       $('#startTime').data('datetimepicker').options.date
+                               .setHours(timeRange.start);
+                       $('#startTime').data('datetimepicker').ui
+                               .find('.ui-datefield-hour').html(
+                                       (timeRange.start < 10) ? '0' + timeRange.start : timeRange.start
+                               );
+               }
+               if ($('#duration').data('datetimepicker')) {
+                       $('#duration').data('datetimepicker').options.date
+                               .setHours(timeRange.duration);
+                       $('#duration').data('datetimepicker').ui.find('.ui-datefield-hour')
+                               .html(
+                                       (timeRange.duration < 10) ? '0'
+                                               + timeRange.duration : timeRange.duration
+                               );
+                       $('#duration').data('datetimepicker')._populateDataSelector = function (field, pat) {
+                               var result = $.tizen.datetimepicker.prototype._populateDataSelector
+                                               .call(this, field, pat);
+                               result.values = range(1, 20);
+                               result.data = range(1, 20);
+                               return result;
+                       };
+               }
+
+               $('#formEnablePeriod')[0].value = timeRange.enabled ? 'on' : 'off';
+               $('#formEnablePeriod').slider('refresh');
+       };
+
+       UI.prototype.editTimeRange = function (nr, event) {
+               console.log('UI_editTimerange', nr, this);
+               if (event && typeof event.stopPropagation === 'function') {
+                       event.preventDefault();
+                       event.stopPropagation();
+               }
+
+               if (this.app.editTimeRange(nr) >= 0) {
+                       $('#updateTime').val('modify');
+               } else {
+                       $('#updateTime').val('add');
+               }
+
+               // change page to form;
+               $.mobile.changePage("#rangesOfTimes");
+       };
+
+       UI.prototype.getExercisesList = function () {
+               console.log('UI_getExercisesList');
+               return $('#exercises :jqmData(role=slider)').map(function (o, v) {
+                       return ({
+                               index : $(v).attr('data-index'),
+                               checked : ($(v).val() === 'on') ? true : false
+                       });
+               });
+       };
+
+       UI.prototype.addExercise = function () {
+               console.log('UI_addExercise');
+               if ($("#newExerciseName").val()) {
+                       if (this.app.addExercise($("#newExerciseName").val())) {
+                               history.back();
+                       }
+               } else {
+                       this.showErrors([ {
+                               name : 'Name of exercise is not correct.',
+                               code : 100
+                       } ]);
+               }
+       };
+
+       UI.prototype.configToUI = function () {
+               console.log('UI_configToUI');
+       };
+
+       UI.prototype.updateMainUI = function () {
+               console.log('updateMainUI');
+               this.setStatusRun(this.app.config.trainingEnabled);
+               console.log('updateMainUI: graphSchedule: ', this.graphSchedule);
+               this.graphSchedule.setTimeRanges(this.app.periodsWeekToBoolArray());
+       };
+
+       UI.prototype.getTimeRangeFromForm = function () {
+               return {
+                       start : $('#startTime').data('datetimepicker').options.date
+                                       .getHours(),
+                       duration : $('#duration').data('datetimepicker').options.date
+                                       .getHours(),
+                       stop : $('#startTime').data('datetimepicker').options.date
+                                       .getHours()
+                                       + $('#duration').data('datetimepicker').options.date
+                                                       .getHours(),
+                       style : $('.selectPeriodType :radio:checked').val(),
+                       enabled : ($('#formEnablePeriod')[0].value === 'on' ? true : false)
+               };
+       };
+
+       UI.prototype.editTimeRangeAction = function (nr) {
+               console.log('UI_editTimeRangeAction', nr);
+               if (this.app.saveTimeRange(nr, this.getTimeRangeFromForm())) {
+                       history.back();
+               } else {
+                       throw ({
+                               message : 'Time start and stop is not present.',
+                               code : 1
+                       });
+               }
+       };
+
+       UI.prototype.showNoticeInMonitor = function (notice, alarm) {
+               console.log('UI_showNoticeInMonitor', notice, alarm);
+               $('#communicate').html(notice);
+               $('#communicate').toggleClass('onAlert', alarm);
+       };
+
+       UI.prototype.changeButtonAddTime = function (text) {
+               console.log('UI_changeButtonAddTime', text);
+               $('#addTime').html(text);
+       };
+
+       UI.prototype.showErrors = function (errors) {
+               console.log('UI_showErrors', errors);
+               var i; // count;
+               for (i = 0; i < errors.length; i += 1) {
+                       alert(errors[i].name);
+               }
+       };
+
+       UI.prototype.showAlarmInMonitor = function (data) {
+               console.log('UI_showAlarmInMonitor', data);
+               var notice = '';
+               function formatNN(val) {
+                       return (val < 10) ? ('0' + val) : val;
+               }
+
+               if (data && data.alarm && this.app.config.trainingEnabled) {
+                       this.app.currentAlarm = this.app.findCurrentAlarm();
+                       if (this.app.currentAlarm.length > 0) {
+                               notice += 'Go... go... go...!<br>' + data.exerciseName + ' x '
+                                       + data.numberOfTimes;
+                       } else {
+                               notice += 'Next exercises set at: '
+                                       + formatNN(data.alarm.getHours()) + ':'
+                                       + formatNN(data.alarm.getMinutes()) + '<br>'
+                                       + data.exerciseName + ' x ' + data.numberOfTimes;
+                       }
+               } else {
+                       notice += '<br/>You have no workouts scheduled for now.<br/>';
+               }
+               this.showNoticeInMonitor(notice, false);
+       };
+
+       UI.prototype.getSentence = function (type) {
+               console.log('UIgetSentence', type);
+               return (this.sentence[type] || {
+                       text : 'No sentence',
+                       signature : 'anonymous'
+               });
+       };
+
+       UI.prototype.setSentence = function (type) {
+               console.log('UI_setSentence');
+               var sentence = this.getSentence(type);
+               $('#sentence').html('"' + sentence.text + '"');
+               $('#signature').html('- ' + sentence.signature);
+       };
+
+       UI.prototype.showWaitOk = function () {
+               console.log('UI_showWaitOk');
+               $('#mainControl').hide();
+               $('#one .ui-btn-back').hide();
+
+               $('#onAlertControl').tabbar();
+               $('#onAlertControl').show();
+               $('#onAlertControl').css('width', '');
+       };
+
+       UI.prototype.setStatusRun = function (bool) {
+               console.log('UI_setStatusRun', bool);
+               if (bool) {
+                       // icon;
+                       $('#status').removeClass('lazy').addClass('run');
+                       // sentence;
+                       this.setSentence('run');
+                       // button in control bar;
+                       $('#startStop .ui-btn-text').html('stop training');
+               } else {
+                       $('#status').removeClass('run').addClass('lazy');
+                       this.setSentence('lazy');
+                       $('#communicate').html('');
+                       $('#startStop .ui-btn-text').html('start training');
+               }
+       };
+
+       UI.prototype.bindEvents = function bindEvents() {
+               var self = this;
+
+               // bind events;
+               $('#one .ui-btn-back').on('tap', this.app.exit.bind(this.app));
+
+               $('#ok').on('tap', self.app.ok.bind(self.app));
+               $('#wait').on('tap', self.app.wait.bind(self.app));
+               $('#todayOffAll').on('tap', self.app.todayOffAll.bind(self.app));
+
+               $('#startStop').on('tap', function () {
+                       self.app.appStartStop();
+               });
+
+               $('#one').on(
+                       'pageshow',
+                       function (page, options) {
+                               console.log('#one pageshow');
+                               if (self.graphSchedule.ui) {
+                                       $('#one .schedule').append(self.graphSchedule.ui);
+                                       self.app.updateGraph();
+                                       self.graphSchedule.refresh();
+                                       self.graphSchedule.setVisibleWeekend(!self.app
+                                               .todayIsWorkday());
+                                       self.graphSchedule.setVisibleWorkdays(self.app
+                                               .todayIsWorkday());
+                               }
+                               $('#one .schedule').on('touchstart', function (ev) {
+                                       ev.stopPropagation();
+                               });
+                       }
+               );
+
+               $('#two').on('pageshow', function (page, options) {
+                       console.log('#two pageshow');
+                       if (self.graphSchedule.ui) {
+                               $('#two .scheduleOptions').append(self.graphSchedule.ui);
+                               self.graphSchedule.refresh();
+                               self.graphSchedule.setVisibleWeekend(true);
+                               self.graphSchedule.setVisibleWorkdays(true);
+                       }
+               });
+
+               $('#two').on('pageinit', function (page, options) {
+                       console.log('#two pageinit');
+                       $('.ui-radio input', $('#frequency')).change(function (ev) {
+                               self.app.setFrequency(this.value);
+                               self.updateMainUI();
+                       });
+
+                       $('.ui-radio input', $('#strength')).change(function (ev) {
+                               self.app.setStrength(this.value);
+                               self.updateMainUI();
+                       });
+
+                       $('#frequency')[0].select(self.app.config.frequency);
+                       $('#strength')[0].select(self.app.config.strength);
+
+                       $('#two .scheduleOptions').append(self.graphSchedule.ui);
+                       $('#two .scheduleOptions').on('touchstart', function (ev) {
+                               ev.stopPropagation();
+                       });
+
+                       $('#workdaysType').on('tap', function (ev) {
+                               self.app.changeTypeOfPeriods('workday');
+                       });
+
+                       $('#weekendType').on('tap', function (ev) {
+                               self.app.changeTypeOfPeriods('weekend');
+                       });
+
+                       $('#addTimeRange').on('tap', self.editTimeRange.bind(self, -1));
+
+                       self.app.updateTimesRanges();
+                       self.configToUI();
+               });
+
+               $('#selectExercises').on('pageinit', function (page, options) {
+                       self.app.updateExercises();
+                       self.configToUI();
+
+                       $('#btnNewExercise').on('tap', self.addExercise.bind(self));
+               });
+
+               $('#customExercises').on('pageshow', function (page, options) {
+                       $('#newExerciseName').val('');
+                       $('#newExerciseName').trigger('focus');
+               });
+
+               $('#rangesOfTimes').on('pageinit', function (page, options) {
+                       console.log('#rangesOfTimes init');
+                       $("#updateTime").on("tap", function (e) {
+                               e.preventDefault();
+                               e.stopPropagation();
+                               self.editTimeRangeAction(self.app.currentEditingTimePeriodId);
+                       });
+               });
+
+               $('#rangesOfTimes').on('pageshow', function (page, options) {
+                       console.log('#rangesOfTimes pageshow');
+                       $('#updateTime').data('button').refresh();
+                       self.fillTimeRangeForm(self.app.currentEditingTimePeriod);
+               });
+
+               $('#increasingStrength').on('change', function () {
+                       self.app.config.increasingStrength = this.checked;
+                       self.app.saveConfig();
+
+                       self.configToUI();
+               });
+       };
+
+       UI.prototype.onGraphSchedule = function onGraphSchedule(onInitEnd) {
+               console.log('(UI..initialize).onGraphSchedule');
+               this.updateMainUI();
+
+               $('#one .schedule').append(this.graphSchedule.ui);
+               this.app.updateGraph();
+               this.graphSchedule.refresh();
+               this.graphSchedule.setVisibleWeekend(!this.app.todayIsWorkday());
+               this.graphSchedule.setVisibleWorkdays(this.app.todayIsWorkday());
+
+               if (typeof onInitEnd === 'function') {
+                       onInitEnd();
+               }
+       };
+
+       UI.prototype.initialize = function (onInitEnd) {
+               console.log('UI..initialize');
+
+               this.bindEvents();
+
+               $('html').css('font-size', '');
+               $('body').css('font-size', '');
+
+               this.graphSchedule = new GraphSchedule({
+                       onSuccess : this.onGraphSchedule.bind(this, onInitEnd)
+               });
+       };
+
+}());
diff --git a/js/UI.simpleTemplate.js b/js/UI.simpleTemplate.js
new file mode 100644 (file)
index 0000000..3f32b5d
--- /dev/null
@@ -0,0 +1,25 @@
+/*global UI */
+(function () {
+       "use strict";
+       UI.prototype.getAvailableTimeTemplate = function getAvailableTimeTemplate(obj) {
+               return '<li>' + '<div class="timeRangeLabel">start: ' + obj.start
+                       + ' (duration: ' + obj.duration + 'h) ' + obj.style + '</div>'
+                       + '<div class="timeRangeButtons">'
+                       + '<div data-role="button" data-inline="true" data-name="edit" data-val="' + obj.nr + '">Edit</div>'
+                       + '<div data-role="button" data-inline="true" data-name="disable" data-val="' + obj.nr + '">'
+                       + ((obj.enabled) ? 'Dis' : 'En') + 'able</div>'
+                       + '<div data-role="button" data-inline="true" data-name="delete" data-val="' + obj.nr + '">Delete</div>'
+                       + '<div class="activeStatus' + ((obj.enabled) ? '' : ' activeStatusDisable') + '" data-inline="true">' + ((obj.enabled) ? 'En' : 'Dis') + 'able</div>'
+                       + '</div>' + '</li>';
+       };
+
+       UI.prototype.getExercisesTemplate = function (obj, i) {
+               return '<div>'
+                       + '<span>' + obj.name + '</span>'
+                       + '<select data-role="slider" data-index="' + i + '">'
+                       + '<option value="off" ' + (obj.enabled ? '' : 'selected="selected"') + '></option>'
+                       + '<option value="on" ' + (obj.enabled ? 'selected="selected"' : '') + '></option>'
+                       + '</select>' + '</div>';
+       };
+}());
+
diff --git a/js/app.alarms.js b/js/app.alarms.js
new file mode 100644 (file)
index 0000000..e9a82e6
--- /dev/null
@@ -0,0 +1,58 @@
+/*jslint devel: true*/
+/*global ExercisePlanner:false, tizen:false*/
+/**
+ * Methods for add / remove alarms by API;
+ */
+(function () {
+       "use strict";
+       /**
+        * Wrapper on remove all alarms joined with app
+        */
+       ExercisePlanner.prototype.removeAllAlarms = function () {
+               console.log('ExercisePlanner_removeAllAlarms');
+               tizen.alarm.removeAll();
+       };
+
+       ExercisePlanner.prototype.WORKDAYS = ["MO", "TU", "WE", "TH", "FR"];
+       ExercisePlanner.prototype.WEEKEND = ["SA", "SU"];
+
+       /**
+        * Add alarms from Array
+        *
+        * @param tabOfAlarm
+        * @param defOfPeriod
+        */
+       ExercisePlanner.prototype.addAlarmFromArray = function addAlarmFromArray(tabOfAlarm, defOfPeriod) {
+               var i, len = tabOfAlarm.length, alarm;
+
+               console.log('tabOfAlarm:', tabOfAlarm);
+               console.log('definition of period:', defOfPeriod);
+               for (i = 0; i < len; i += 1) {
+                       alarm = new tizen.AlarmAbsolute(tabOfAlarm[i], defOfPeriod);
+                       try {
+                               tizen.alarm.add(alarm, this.selfId);
+                       } catch (e) {
+                               console.error(e.message);
+                       }
+               }
+       };
+
+       /**
+        * Add alarms to API DataBase
+        *
+        * @param {object} alarms
+        */
+       ExercisePlanner.prototype.addAlarmsAllWeek = function addAlarmsAllWeek(alarms) {
+               if (alarms.everyday.length > 0) {
+                       this.addAlarmFromArray(alarms.everyday, tizen.alarm.PERIOD_DAY);
+               }
+               if (alarms.workday.length > 0) {
+                       this.addAlarmFromArray(alarms.workday, this.WORKDAYS);
+               }
+               if (alarms.weekend.length > 0) {
+                       this.addAlarmFromArray(alarms.weekend, this.WEEKEND);
+               }
+       };
+
+}());
+
diff --git a/js/app.alarmsGenerating.js b/js/app.alarmsGenerating.js
new file mode 100644 (file)
index 0000000..b868dad
--- /dev/null
@@ -0,0 +1,158 @@
+/*jslint devel: true*/
+/*global ExercisePlanner: true, ONE_DAY:false, TIME_OF_SLEEP:false */
+/**
+ *
+ */
+(function () {
+       "use strict";
+       /**
+        *
+        *
+        * @param availableTime
+        * @param typeOfPeriod
+        * @returns {object}
+        */
+       ExercisePlanner.prototype.calculateFactor = function calculateFactors(availableTime, typeOfPeriod) {
+               var factor,
+                       result = {
+                               count: 0,
+                               period: 0
+                       };
+
+               if (availableTime === 0) {
+                       return result;
+               }
+
+               factor = availableTime / (this.ONE_DAY - this.TIME_OF_SLEEP);
+               result.proportionalFrequency = this.getNumberOfWorkoutsByFrequency(this.config.frequency[typeOfPeriod]) * factor;
+
+               if ((Math.round(result.proportionalFrequency) - 1) > 0) {
+                       result.count = (Math.round(result.proportionalFrequency));
+                       result.period = availableTime / (result.count - 1);
+               } else {
+                       result.count = 1;
+                       result.period = 0;
+               }
+
+               return result;
+       };
+
+       /**
+        *
+        *
+        * @param availableTime
+        * @returns {object}
+        */
+       ExercisePlanner.prototype.calculateFactors = function calculateFactors(availableTime) {
+               return {
+                       weekend: this.calculateFactor(availableTime.weekend, 'weekend'),
+                       workday: this.calculateFactor(availableTime.workday, 'workday'),
+                       everyday: this.calculateFactor(availableTime.everyday, 'workday')
+               };
+       };
+
+       /**
+        *
+        *
+        * @param factor
+        * @param tmpPeriods
+        * @returns {Array}
+        */
+       ExercisePlanner.prototype.generateAlarmsByFactor = function (factor, tmpPeriods) {
+               console.log('ExercisePlanner_generateAlarmsByFactor', factor, tmpPeriods);
+               var i, numberOfPeriods = tmpPeriods.length,
+                       period,
+                       begin,
+                       end = 0,
+                       tableOfAlarms = [],
+                       optimalTime,
+                       deltaTime = 0,
+                       dayTime = this.beginDate || new Date();
+
+               if (numberOfPeriods === 0) {
+                       return [];
+               }
+
+               begin = tmpPeriods[0].start;
+
+               for (i = 0; i < numberOfPeriods; i += 1) {
+                       if (tmpPeriods[i].stop > end) {
+                               end = tmpPeriods[i].stop;
+                       }
+               }
+
+               dayTime.setSeconds(0);
+               console.log('generateAlarmsByFactor: end | begin ', end, begin);
+
+               if (factor.count === 1) {
+                       // One alarm per day, default placed in middle of available time;
+                       optimalTime = this.findNearestTimeRange((end + begin) / 2, tmpPeriods);
+                       console.log('optimale Hour', optimalTime);
+
+                       dayTime.setHours(parseInt(optimalTime.optimalHour, 10));
+                       dayTime.setMinutes(60 * (optimalTime.optimalHour - parseInt(optimalTime.optimalHour, 10)));
+                       tableOfAlarms.push(new Date(dayTime.getTime()));
+               } else {
+                       // set time for begin;
+                       dayTime.setHours(tmpPeriods[0].start);
+                       dayTime.setMinutes(0);
+                       tableOfAlarms.push(new Date(dayTime.getTime()));
+
+                       // set time for next hop;
+                       for (i = 0; i < numberOfPeriods; i += 1) {
+                               period = tmpPeriods[i];
+                               deltaTime += period.duration;
+                               // if available period is too small, then accumulate time
+                               // and continue to next period;
+                               console.log('delta & factor: ', deltaTime, factor.period);
+                               while (deltaTime >= factor.period * 0.999) {
+                                       deltaTime -= factor.period;
+
+                                       dayTime.setHours(parseInt(period.stop - deltaTime, 10));
+                                       dayTime.setMinutes(60 * (period.stop - deltaTime - parseInt(period.stop - deltaTime, 10)));
+
+                                       tableOfAlarms.push(new Date(dayTime.getTime()));
+                               }
+                       }
+               }
+
+               return tableOfAlarms;
+       };
+
+       /**
+        * Generate table of alarms => this.alarms
+        * @param {Date} customDate;
+        */
+       ExercisePlanner.prototype.generateAlarms = function () {
+               console.log('ExercisePlanner_generateAlarms');
+               var factors,
+                       alarms = this.alarms,
+                       periodsWeek = {
+                               everyday: [],
+                               workday: [],
+                               weekend: []
+                       };
+
+               // some periods may overlap, must be merged
+               periodsWeek = this.mergePeriods();
+               // store in cache for later reuse
+               this.cache.periodsWeek = periodsWeek;
+
+               // factors to correct how often may workouts per day
+               factors = this.calculateFactors(this.getSummaryAvailableTime());
+
+               // Set new alarms;
+               if (periodsWeek.everyday.length > 0) {
+                       alarms.everyday = this.generateAlarmsByFactor(factors.everyday, periodsWeek.everyday);
+               } else {
+                       alarms.workday = this.generateAlarmsByFactor(factors.workday, periodsWeek.workday);
+                       alarms.weekend = this.generateAlarmsByFactor(factors.weekend, periodsWeek.weekend);
+               }
+
+               // if trainig is in run then resinstall alarm imediately
+               if (this.config.trainingEnabled) {
+                       this.startAlarms();
+               }
+       };
+}());
+
diff --git a/js/app.js b/js/app.js
new file mode 100644 (file)
index 0000000..46f0697
--- /dev/null
+++ b/js/app.js
@@ -0,0 +1,471 @@
+/*jslint browser: true, devel: true */
+/*global tizen, $, app, localStorage, Audio, document, unlockScreen, UI */
+var ExercisePlanner = function () {
+       "use strict";
+};
+
+(function () {
+       "use strict";
+
+       ExercisePlanner.prototype = {
+               /**
+                * Definition of time for sleep
+                */
+               TIME_OF_SLEEP: 8,
+
+               /**
+                * Definition one day in hours
+                */
+               ONE_DAY: 24,
+
+               /**
+                * Stored time of application start
+                */
+               applicationStartTime: new Date(),
+
+               /**
+                * Cofiguration data will saved for next launch;
+                * There are default values after install;
+                */
+               config: {
+
+                       frequency: {
+                               workday: 3, // 6 for test
+                               weekend: 3
+                       },
+
+                       strength: {
+                               workday: 1,
+                               weekend: 1
+                       },
+
+                       /**
+                        * List of workouts;
+                        * - timeRanges:style [ everyday, weekend, workday ]; ( workday : mon-fri )
+                        */
+                       exercises: [{
+                               name: 'bends',
+                               enabled: true
+                       }, {
+                               name: 'squats',
+                               enabled: true
+                       }, {
+                               name: 'push-ups',
+                               enabled: false
+                       }],
+
+                       // deprecated for this version;
+                       increasingStrength: true,
+
+                       /**
+                        * Default time ranges
+                        */
+                       timesRanges: [{
+                               nr: 0,
+                               start: 8,
+                               stop: 16,
+                               duration: 8,
+                               enabled: true,
+                               style: 'everyday'
+                       }, {
+                               nr: 1,
+                               start: 18,
+                               stop: 22,
+                               duration: 4,
+                               enabled: true,
+                               style: 'weekend'
+                       }],
+
+                       nearestExercise: -1,
+
+                       count: 0,
+
+                       trainingEnabled: false
+               },
+               alarms: {
+                       everyday: [],
+                       workday: [],
+                       weekend: []
+               },
+
+               /**
+                * Used for update GraphSchedule;
+                * [ workday / weekend ]
+                */
+               currentTypeOfPeriods: 'workday',
+               /**
+                * Use on form to edit time period;
+                */
+               currentEditingTimePeriod: null,
+               currentEditingTimePeriodId: -1,
+
+               /**
+                * Date when alarm will start generating
+                */
+               beginDate: null,
+
+               /**
+                * use store temporary data for alarms;
+                */
+               cache: {},
+
+               /**
+                * HTML5 audio element for play audio when alarm is called
+                */
+               audioOfAlert: null,
+
+               /**
+                * Instance of User Interface
+                */
+               ui: null
+       };
+
+       /**
+        * Load configuration of application
+        * (use localStorage)
+        */
+       ExercisePlanner.prototype.loadConfig = function () {
+               console.log('ExercisePlanner_loadConfig');
+               var configStr = localStorage.getItem('config');
+               if (configStr) {
+                       this.config = JSON.parse(configStr);
+               } else {
+                       this.removeAllAlarms();
+                       this.sortTimeRanges();
+               }
+       };
+
+       /**
+        * Save configuration of application
+        * (use localStorage)
+        */
+       ExercisePlanner.prototype.saveConfig = function () {
+               console.log('ExercisePlanner_saveConfig');
+               localStorage.setItem('config', JSON.stringify(this.config));
+       };
+
+       ExercisePlanner.prototype.stopTraining = function () {
+               console.log('ExercisePlanner_stopTraining');
+               this.removeAllAlarms();
+               this.ui.setStatusRun(this.config.trainingEnabled);
+       };
+
+       ExercisePlanner.prototype.startTraining = function () {
+               console.log('ExercisePlanner_startTraining');
+               this.ui.setStatusRun(this.config.trainingEnabled);
+               this.startAlarms();
+       };
+
+       /**
+        * Toggle start/stop alarms for workouts
+        */
+       ExercisePlanner.prototype.appStartStop = function () {
+               console.log('ExercisePlanner_appStartStop');
+               this.config.trainingEnabled = !this.config.trainingEnabled;
+               if (this.config.trainingEnabled) {
+                       this.startTraining();
+               } else {
+                       this.stopTraining();
+               }
+               this.saveConfig();
+       };
+
+       /**
+        * Closing application with the configuration data saving
+        */
+       ExercisePlanner.prototype.exit = function () {
+               console.log('ExercisePlanner_exit');
+               this.saveConfig();
+               this.stopMusic();
+               tizen.application.getCurrentApplication().exit();
+       };
+
+       /**
+        * Sets frequency value and calculates new alarms
+        * @param value
+        */
+       ExercisePlanner.prototype.setFrequency = function (value) {
+               console.log('ExercisePlanner_setFrequency', value);
+               this.config.frequency[this.config.currentTypeOfPeriods] = parseInt(value, 10);
+
+               this.saveConfig();
+               this.generateAlarms();
+               this.updateGraph(this.config.currentTypeOfPeriods);
+               this.showNextAlarm();
+       };
+
+       /**
+        * Set Strength value
+        * @param value
+        */
+       ExercisePlanner.prototype.setStrength = function (value) {
+               console.log('ExercisePlanner_setStrength', value);
+               this.config.strength[this.config.currentTypeOfPeriods] = parseInt(value, 10);
+               this.saveConfig();
+       };
+
+       /**
+        * Sending array of exercises to UI for update
+        */
+       ExercisePlanner.prototype.updateExercises = function () {
+               console.log('ExercisePlanner_updateExercises');
+               this.ui.fillExercises(this.config.exercises);
+       };
+
+       /**
+        * Sending array of time ranges to UI for update
+        * & update graph schedule
+        */
+       ExercisePlanner.prototype.updateTimesRanges = function () {
+               console.log('ExercisePlanner_updateTimesRanges');
+
+               this.ui.fillTimesRanges(this.config.timesRanges);
+               this.ui.graphSchedule.updateTimeRanges();
+       };
+
+       /**
+        * Store exercises in config (and save)
+        * @param newData
+        */
+       ExercisePlanner.prototype.saveExercises = function (newData) {
+               console.log('ExercisePlanner_saveExercises', newData);
+               var i, l;
+
+               if (newData) {
+                       for (i = 0, l = newData.length; i < l; i += 1) {
+                               this.config.exercises[i].enabled = newData[i].checked;
+                       }
+                       this.generateNearestExercise();
+                       this.saveConfig();
+               }
+       };
+
+       /**
+        * When will earliest workout
+        * and show in UI
+        */
+       ExercisePlanner.prototype.showNextAlarm = function showNextAlarm() {
+               console.log('ExercisePlanner_showNextAlarm');
+               var alarms,
+                       currentDate = new Date();
+
+               if (this.alarms.everyday.length > 0) {
+                       alarms = this.alarms.everyday;
+               } else {
+                       alarms = (this.todayIsWorkday()) ? this.alarms.workday : this.alarms.weekend;
+               }
+
+               alarms = alarms.filter(function (item) {
+                       return (item.getTime() > currentDate.getTime());
+               }).sort(function (a, b) {
+                       return a.date - b.date;
+               });
+               console.log(alarms);
+
+               if (this.config.nearestExercise > -1) {
+                       this.ui.showAlarmInMonitor({
+                               alarm: alarms[0],
+                               exerciseName: this.config.exercises[this.config.nearestExercise].name,
+                               numberOfTimes: this.getStrength(this.config.strength.workday, this.config.count)
+                       });
+
+                       this.config.count += 1;
+               }
+               this.saveConfig();
+       };
+
+       /**
+        * Change type of periods [workday/weekend] and update graph
+        * @param type
+        */
+       ExercisePlanner.prototype.changeTypeOfPeriods = function changeTypeOfPeriods(type) {
+               if (this.config.currentTypeOfPeriods !== type) {
+                       this.config.currentTypeOfPeriods = type;
+                       this.updateGraph(this.config.currentTypeOfPeriods);
+               }
+       };
+
+       /**
+        * Check new exercise name for duplication in existings;
+        * @param name
+        * @returns
+        */
+       ExercisePlanner.prototype.checkExerciseName = function (name) {
+               console.log('ExercisePlanner_checkExerciseName', name);
+               var i, l;
+
+               if (name) {
+                       for (i = 0, l = this.config.exercises.length; i < l; i += 1) {
+                               if (this.config.exercises[i].name === name) {
+                                       return i;
+                               }
+                       }
+                       return -1;
+               }
+       };
+
+       /**
+        * Add new exercise sent from UI
+        * @param name
+        * @returns {Boolean}
+        */
+       ExercisePlanner.prototype.addExercise = function (name) {
+               console.log('ExercisePlanner_addExercise', name);
+               if (this.checkExerciseName(name) < 0) {
+                       this.config.exercises.push({
+                               name: name,
+                               enabled: false
+                       });
+                       this.saveConfig();
+                       this.ui.fillExercises(this.config.exercises);
+                       return true;
+               }
+               this.ui.showErrors({name: 'Element exists!'});
+               return false;
+       };
+
+       /**
+        * Get number of workouts by frequency
+        * @param value
+        * @returns {number}
+        */
+       ExercisePlanner.prototype.getNumberOfWorkoutsByFrequency = function getNumberOfWorkoutsByFrequency(value) {
+               console.log('ExercisePlanner_frequencyMap', value);
+               var iMap = [1, 2, 4, 8, 16, 24, 150],
+                       // -- times per 24h; proportion to set periods of available time;
+                       numberOfWorkouts = iMap[value];
+
+               return numberOfWorkouts || 2;
+       };
+
+       /**
+        * Get number of exercises in workout by strength value and optional ;
+        * @param value
+        * @param count
+        * @returns {number}
+        */
+       ExercisePlanner.prototype.getStrength = function strengthMap(value, count) {
+               console.log('ExercisePlanner_strengthMap', value, count);
+               var sMap = [1, 1, 2, 4, 10, 20],
+                       base = sMap[value] || 2;
+
+               count = count || 1;
+               return Math.round(base * (count / 10 + 1));
+       };
+
+       /**
+        * Generate name of exercise for nearest workout
+        */
+       ExercisePlanner.prototype.generateNearestExercise = function () {
+               console.log('ExercisePlanner_generateNearestExercise');
+               var tmp = this.config.exercises.filter(function (item) {
+                       return item.enabled;
+               });
+               this.config.nearestExercise = parseInt(Math.random() * tmp.length, 10);
+       };
+
+
+       /**
+        * If user want change work days this method will changing;
+        * @returns {Boolean}
+        */
+       ExercisePlanner.prototype.todayIsWorkday = function todayIsWorkday() {
+               var day = (new Date()).getDay();
+               return (day >= 1 && day <= 5);
+       };
+
+       /**
+        * Activate alarms in API.
+        */
+       ExercisePlanner.prototype.startAlarms = function startAlarms() {
+               // clear old alarms;
+               this.removeAllAlarms();
+
+               // add new alarms
+               this.addAlarmsAllWeek(this.alarms);
+
+               this.generateNearestExercise();
+               this.showNextAlarm();
+       };
+
+       /**
+        * Update Graph object
+        * @param {String} typeOfPeriods ['workday'|'weekend']
+        */
+       ExercisePlanner.prototype.updateGraph = function updateGraph(typeOfPeriods) {
+               console.log('updateGraph');
+               var alarms;
+               if (!this.ui.graphSchedule) {
+                       throw {
+                               message: 'graph schedule not exists.'
+                       };
+               }
+
+               typeOfPeriods = typeOfPeriods || ((this.todayIsWorkday()) ? 'workday' : 'weekend');
+               console.log('typeOfPeriods: ', typeOfPeriods);
+
+               if (typeOfPeriods === 'workday') {
+                       alarms = this.alarms.workday;
+               } else {
+                       alarms = this.alarms.weekend;
+               }
+               if (alarms.length === 0) {
+                       alarms = this.alarms.everyday;
+               }
+               this.ui.graphSchedule.setTimeRanges(this.periodsWeekToBoolArray());
+               this.ui.graphSchedule.pushTimeOfFlags(alarms);
+               this.ui.graphSchedule.showFlags();
+       };
+
+       /**
+        * Callback function on visibility change;
+        */
+       ExercisePlanner.prototype.onVisibilityChange = function () {
+
+               switch (document.webkitVisibilityState) {
+               case 'visible':
+                       this.applicationStartTime = new Date();
+                       this.currentAlarm = this.findCurrentAlarm();
+                       if (this.currentAlarm.length > 0) {
+                               this.ui.showWaitOk();
+                               this.startMusic();
+                       }
+                       break;
+               }
+       };
+
+       /**
+        * Turn off all alarms today
+        */
+       ExercisePlanner.prototype.todayOffAll = function todayOffAll() {
+               // set begin date to tomorrow;
+               this.beginDate = new Date();
+               this.beginDate.setDate(this.beginDate.getDate() + 1);
+               // recreate alarms;
+               this.generateAlarms();
+               this.exit();
+       };
+
+       // Initialize function
+       ExercisePlanner.prototype.init = function init() {
+               var onUiInitialize = function onUiInitialize() {
+                       console.log('onUiInitialize');
+                       // register watcher on visibility change;
+                       document.addEventListener('webkitvisibilitychange', this.onVisibilityChange.bind(this));
+                       this.showNextAlarm();
+                       this.onVisibilityChange();
+               }.bind(this);
+
+               console.log('ExercisePlanner..init');
+               this.selfId = tizen.application.getAppContext().appId;
+               this.ui = new UI();
+               this.ui.app = this;
+
+               this.loadConfig();
+               this.config.currentTypeOfPeriods = (this.todayIsWorkday()) ? 'workday' : 'weekend';
+
+               this.generateAlarms();
+
+               this.ui.initialize(onUiInitialize);
+       };
+}());
diff --git a/js/app.onAlarm.js b/js/app.onAlarm.js
new file mode 100644 (file)
index 0000000..a619b83
--- /dev/null
@@ -0,0 +1,70 @@
+/*global ExercisePlanner:false, tizen:false, Audio:false*/
+/**
+ * These method are using when alarm is call.
+ */
+(function () {
+       "use strict";
+       ExercisePlanner.prototype.findCurrentAlarm = function () {
+               console.log('ExercisePlanner_findCurrentAlarm');
+               var currentTimeInMinutes = parseInt(this.applicationStartTime.getTime() / 1000, 10),
+                       listOfAlarms = tizen.alarm.getAll();
+
+               return listOfAlarms.filter(function (item) {
+                       // alarm relative has not date property;
+                       if (!item.date) {
+                               return false;
+                       }
+
+                       // +40/-10 seconds tolerance;
+                       console.log(item.date);
+                       if (parseInt(item.date.getTime() / 1000, 10) < (currentTimeInMinutes + 40)
+                                       && parseInt(item.date.getTime() / 1000, 10) > (currentTimeInMinutes - 10)) {
+                               return true;
+                       }
+               });
+       };
+
+       ExercisePlanner.prototype.wait = function () {
+               console.log('ExercisePlanner_wait');
+               // lastAlert -> change +1min
+               var snozeTime = 1, currentAlarm = this.currentAlarm, newDate = new Date(), alarm;
+
+               if (currentAlarm) {
+                       newDate.setMinutes(newDate.getMinutes() + snozeTime);
+                       // period value must be set so application started by alert will know current alert;
+                       alarm = new tizen.AlarmAbsolute(newDate, tizen.alarm.PERIOD_WEEK * 10);
+                       tizen.alarm.add(alarm, this.selfId);
+                       // -- remove old snooze alarm
+                       if (currentAlarm.period === tizen.alarm.PERIOD_WEEK * 10) {
+                               tizen.alarm.remove(currentAlarm.id);
+                       }
+                       this.stopMusic();
+               }
+
+               this.exit();
+               // or tizen.application.hide();
+       };
+
+       ExercisePlanner.prototype.ok = function () {
+               this.exit();
+       };
+
+       ExercisePlanner.prototype.startMusic = function () {
+               console.log('ExercisePlanner_startMusic');
+
+               if (!this.audioOfAlert) {
+                       this.audioOfAlert = new Audio();
+               }
+               this.audioOfAlert.src = 'WebContent/Runner.mp3';
+               this.audioOfAlert.load();
+               this.audioOfAlert.play();
+       };
+
+       ExercisePlanner.prototype.stopMusic = function () {
+               console.log('ExercisePlanner_stopMusic');
+               if (this.audioOfAlert) {
+                       this.audioOfAlert.pause();
+               }
+       };
+}());
+
diff --git a/js/app.timeRange.js b/js/app.timeRange.js
new file mode 100644 (file)
index 0000000..8ccf962
--- /dev/null
@@ -0,0 +1,415 @@
+/*jslint devel: true*/
+/*global $, ExercisePlanner: true*/
+/**
+ *
+ */
+(function () {
+       "use strict";
+       ExercisePlanner.prototype.checkNewTimeRange = function (start, duration, style) {
+               console.log('ExercisePlanner_checkNewTimeRange', start, duration, style);
+               var result = [];
+               // check start / stop
+               /*
+                * deprecated if (start >= stop) { result.push({ name: 'Start time is greater or equal than
+                * stop time.', code: 1 }); }
+                */
+
+               if (!start) {
+                       result.push({
+                               name: 'Start time is not set.',
+                               code: 2
+                       });
+               }
+
+               if (duration < 1 || duration > 24) {
+                       result.push({
+                               name: 'Duration is not set properly.',
+                               code: 2
+                       });
+               }
+
+               /*
+                * deprecated if (!stop) { result.push({ name: 'Stop time is not set.', code: 3 }); }
+                */
+               return result;
+       };
+
+       /**
+        * Sort method for time ranges;
+        */
+       ExercisePlanner.prototype.sortTimeRanges = function () {
+               console.log('ExercisePlanner_sortTimeRanges');
+               this.config.timesRanges.sort(function (a, b) {
+                       return a.start - b.start;
+               });
+       };
+
+       /**
+        * Find and return max value of nr in time ranges array;
+        * @returns {Number}
+        */
+       ExercisePlanner.prototype.getMaxNrOfTimeRange = function getMaxNrOfTimeRange() {
+               var maxNr = -1, i, len = this.config.timesRanges.length;
+               for (i = 0; i < len; i += 1) {
+                       if (maxNr < this.config.timesRanges[i].nr) {
+                               maxNr = this.config.timesRanges[i].nr;
+                       }
+               }
+               return maxNr;
+       };
+
+       /**
+        *
+        * @param nr
+        * @returns {Boolean}
+        */
+       ExercisePlanner.prototype.getTimeRangeByNr = function getTimeRangeByNr(nr) {
+               var result = this.config.timesRanges.filter(function (item) {
+                               return (item.nr === nr);
+                       });
+               return result[0];
+       };
+
+       /**
+        * Save time range
+        *
+        * @param nr
+        * @param start
+        * @param duration
+        * @param style
+        * @param enabled
+        * @returns {Boolean}
+        */
+       ExercisePlanner.prototype.saveTimeRange = function (nr, timeRange) {
+               console.log('ExercisePlanner_saveTimeRange', nr, timeRange);
+               var index = -1,
+                       errors = this.checkNewTimeRange(timeRange.start, timeRange.duration, timeRange.style);
+               console.log(errors);
+
+               // new timeRanges has nr === -1; this mean we must get max number from config
+               if (nr === -1) {
+                       nr = this.getMaxNrOfTimeRange() + 1;
+               } else {
+                       index = this.config.timesRanges.indexOf(this.getTimeRangeByNr(nr));
+               }
+
+               timeRange.nr = nr;
+
+               if (errors.length > 0) {
+                       this.ui.showErrors(errors);
+                       return false;
+               }
+
+               if (index !== -1) {
+                       this.config.timesRanges[index] = timeRange;
+               } else {
+                       this.config.timesRanges.push(timeRange);
+               }
+
+               this.sortTimeRanges();
+               this.saveConfig();
+               this.ui.fillTimesRanges(this.config.timesRanges);
+               this.generateAlarms();
+               this.updateGraph();
+
+               return true;
+       };
+
+       /**
+        *
+        * @param {nymber}
+        * @returns {number}
+        */
+       ExercisePlanner.prototype.editTimeRange = function editTimeRange(nr) {
+               var timeRange = this.getTimeRangeByNr(nr);
+
+               if (timeRange !== undefined) {
+                       this.currentEditingTimePeriod = timeRange;
+                       this.currentEditingTimePeriodId = timeRange.nr;
+               } else {
+                       this.currentEditingTimePeriod = {
+                               nr: -1,
+                               start: 10,
+                               duration: 1,
+                               stop: 11,
+                               enabled: true,
+                               style: 'everyday'
+                       };
+                       this.currentEditingTimePeriodId = -1;
+               }
+               return this.currentEditingTimePeriodId;
+       };
+
+       /**
+        * Delete time range by number on list
+        *
+        * @param nr
+        * @returns {Boolean}
+        */
+       ExercisePlanner.prototype.deleteTimeRange = function (nr) {
+               console.log('ExercisePlanner_deleteTimeRange', nr);
+
+               var index,
+                       timeRange = this.getTimeRangeByNr(nr);
+
+               if (timeRange === undefined) {
+                       return false;
+               }
+
+               index = this.config.timesRanges.indexOf(timeRange);
+               if (index === -1) {
+                       return false;
+               }
+
+               // delete time range from array;
+               this.config.timesRanges.splice(index, 1);
+
+               this.saveConfig();
+               this.ui.fillTimesRanges(this.config.timesRanges);
+               this.generateAlarms();
+               // update time periods on graph;
+               this.ui.graphSchedule.setTimeRanges(this.periodsWeekToBoolArray());
+               this.ui.graphSchedule.refresh();
+
+               this.updateGraph();
+               this.showNextAlarm();
+               return true;
+       };
+
+       /**
+        * Disable time range by number on list
+        *
+        * @param nr
+        * @returns {Boolean}
+        */
+       ExercisePlanner.prototype.disableTimeRange = function (nr) {
+               console.log('ExercisePlanner_disableTimeRange', nr);
+               var timeRange = this.getTimeRangeByNr(nr);
+
+               if (timeRange === undefined) {
+                       return false;
+               }
+
+               timeRange.enabled = !timeRange.enabled;
+
+               this.saveConfig();
+               this.ui.fillTimesRanges(this.config.timesRanges);
+               this.generateAlarms();
+               // update time periods on graph;
+               this.ui.graphSchedule.setTimeRanges(this.periodsWeekToBoolArray());
+               this.ui.graphSchedule.refresh();
+
+               this.updateGraph(this.config.currentTypeOfPeriods);
+               this.showNextAlarm();
+               return true;
+       };
+
+       /**
+        * Combines a overlapped time periods & delete not necesary
+        * This method modifies exisiting array in cache.
+        *
+        * @param periods
+        * @returns
+        */
+       ExercisePlanner.prototype.mergeOverlapPeriods = function mergeOverlapPeriods(periods) {
+               var i, len = periods.length, wasOverlap = true, mergePeriod;
+
+               periods.sort(function (a, b) {
+                       return a - b;
+               });
+
+               if (len < 2) {
+                       return periods;
+               }
+
+               while (wasOverlap) {
+                       wasOverlap = false;
+                       len = periods.length;
+                       for (i = 0; i < len - 1; i += 1) {
+                               if (periods[i].stop > periods[i + 1].start) {
+                                       mergePeriod = $.extend({}, periods[i]);
+                                       if (mergePeriod.stop < periods[i + 1].stop) {
+                                               mergePeriod.stop = periods[i + 1].stop;
+                                               mergePeriod.duration = mergePeriod.stop - mergePeriod.start;
+                                       }
+                                       mergePeriod.nr = -1;
+                                       periods.splice(i, 2, mergePeriod);
+                                       wasOverlap = true;
+                                       break;
+                               }
+                       }
+               }
+
+               return periods;
+       };
+
+       ExercisePlanner.prototype.mergePeriods = function mergePeriods() {
+               console.log('ExercisePlanner_mergePeriods');
+               var i, len, onlyEveryDay = true,
+                       ranges = this.config.timesRanges,
+                       result = {
+                               everyday : [],
+                               weekend: [],
+                               workday: []
+                       };
+
+               // checking time ranges for different to the "everyday"
+               for (i = 0, len = ranges.length; i < len; i += 1) {
+                       if (ranges[i].style !== 'everyday') {
+                               onlyEveryDay = false;
+                               break;
+                       }
+               }
+
+               if (onlyEveryDay) {
+                       for (i = 0, len = this.config.timesRanges.length; i < len; i += 1) {
+                               if (this.config.timesRanges[i].enabled) {
+                                       result.everyday.push(this.config.timesRanges[i]);
+                               }
+                       }
+               } else {
+                       // divide 'everyday' periods at workday/weekend
+                       for (i = 0, len = this.config.timesRanges.length; i < len; i += 1) {
+                               // if time range is disabled do not append to cache;
+                               if (this.config.timesRanges[i].enabled) {
+                                       switch (this.config.timesRanges[i].style) {
+                                       case 'everyday':
+                                               result.workday.push(this.config.timesRanges[i]);
+                                               result.weekend.push(this.config.timesRanges[i]);
+                                               break;
+                                       case 'workday':
+                                               result.workday.push(this.config.timesRanges[i]);
+                                               break;
+                                       case 'weekend':
+                                               result.weekend.push(this.config.timesRanges[i]);
+                                               break;
+                                       }
+                               }
+                       }
+               }
+
+               // check and correct overlaped time periods
+               this.mergeOverlapPeriods(result.everyday);
+               this.mergeOverlapPeriods(result.workday);
+               this.mergeOverlapPeriods(result.weekend);
+
+               return result;
+       };
+
+       ExercisePlanner.prototype.getSummaryAvailableTime = function getSummaryAvailableTime() {
+               console.log('ExercisePlanner_getSummaryAvailableTime');
+               var i, len,
+                       periods = this.cache.periodsWeek,
+                       sum = {
+                               weekend: 0,
+                               workday: 0,
+                               everyday: 0
+                       };
+
+               for (i = 0, len = periods.everyday.length; i < len; i += 1) {
+                       if (periods.everyday[i].enabled) {
+                               sum.everyday += periods.everyday[i].duration;
+                       }
+               }
+               for (i = 0, len = periods.workday.length; i < len; i += 1) {
+                       if (periods.workday[i].enabled) {
+                               sum.workday += periods.workday[i].duration;
+                       }
+               }
+               for (i = 0, len = periods.weekend.length; i < len; i += 1) {
+                       if (periods.weekend[i].enabled) {
+                               sum.weekend += periods.weekend[i].duration;
+                       }
+               }
+
+               return sum;
+       };
+
+       ExercisePlanner.prototype.findNearestTimeRange = function (hour, ranges) {
+               console.log('ExercisePlanner_findNearestTimeRange', hour, ranges);
+               var nearResult,
+                       result = {
+                               requestedHour: hour,
+                               optimalHour: -1
+                       };
+
+               if (!ranges.length) {
+                       return result;
+               }
+
+               /**
+                * Function search ranges of time for nearest to a hour
+                */
+               nearResult = ranges.reduce(function (previous, element, index) {
+                       var delta = 0;
+
+                       if (element.start < hour && element.stop < hour) {
+                               delta = hour - element.stop;
+                       }
+
+                       if (element.start > hour && element.stop > hour) {
+                               delta = element.start - hour;
+                       }
+
+                       return (delta < previous.delta) ? { index: index, delta: delta } : previous;
+               }, { index: -1, delta: 100 });
+
+               if (ranges[nearResult.index].start <= hour && ranges[nearResult.index].stop >= hour) {
+                       result.optimalHour = Math.round((ranges[nearResult.index].start + ranges[nearResult.index].stop) / 2);
+               } else {
+                       result.optimalHour = (ranges[nearResult.index].start > hour) ? ranges[nearResult.index].start : ranges[nearResult.index].stop;
+               }
+
+               return result;
+       };
+
+       /**
+        * Export time period to array of boolen [boolean x 24]
+        * @returns {object}
+        */
+       ExercisePlanner.prototype.periodsWeekToBoolArray = function periodsWeekToBoolArray() {
+               var i, j, len, periods,
+                       result = {
+                               workday: [],
+                               weekend: []
+                       };
+
+               // fill default result;
+               for (i = 0; i < 24; i += 1) {
+                       result.workday[i] = false;
+                       result.weekend[i] = false;
+               }
+
+               // set values;
+               periods = this.cache.periodsWeek.everyday;
+               len = periods.length;
+               for (i = 0; i < len; i += 1) {
+                       for (j = periods[i].start; j < periods[i].start + periods[i].duration; j += 1) {
+                               result.workday[j] = true;
+                               result.weekend[j] = true;
+                       }
+               }
+
+               // set values;
+               periods = this.cache.periodsWeek.workday;
+               len = periods.length;
+               for (i = 0; i < len; i += 1) {
+                       for (j = periods[i].start; j < periods[i].start + periods[i].duration; j += 1) {
+                               result.workday[j] = true;
+                       }
+               }
+
+               // set values;
+               periods = this.cache.periodsWeek.weekend;
+               len = periods.length;
+               for (i = 0; i < len; i += 1) {
+                       for (j = periods[i].start; j < periods[i].start + periods[i].duration; j += 1) {
+                               result.weekend[j] = true;
+                       }
+               }
+               return result;
+       };
+
+
+}());
+
diff --git a/js/ext.jqMobile.js b/js/ext.jqMobile.js
new file mode 100644 (file)
index 0000000..9de50b5
--- /dev/null
@@ -0,0 +1,17 @@
+/*global $*/
+// customize JQueryMobile controlgroup
+$.fn.oldControlgroup = $.fn.controlgroup;
+$.fn.controlgroup = function (options) {
+       "use strict";
+       return this.oldControlgroup(options).each(function () {
+               this.deselectAll = function () {
+                       return $('input', this).attr('checked', false).checkboxradio('refresh');
+               };
+
+               this.select = function (value) {
+                       this.deselectAll();
+                       return $('input[value$="' + value + '"]', this).attr('checked', true).checkboxradio('refresh');
+               };
+       });
+};
+
diff --git a/js/main.js b/js/main.js
new file mode 100644 (file)
index 0000000..c3d8a85
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ *      Copyright 2012  Samsung Electronics Co., Ltd
+ *
+ *      Licensed under the Flora License, Version 1.0 (the "License");
+ *      you may not use this file except in compliance with the License.
+ *      You may obtain a copy of the License at
+ *
+ *              http://floralicense.org/license/
+ *
+ *      Unless required by applicable law or agreed to in writing, software
+ *      distributed under the License is distributed on an "AS IS" BASIS,
+ *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *      See the License for the specific language governing permissions and
+ *      limitations under the License.
+ */
+/*global ExercisePlanner, tizen, $, document*/
+var c = null, exercisePlanner = null, appService = null, ui = null;
+
+exercisePlanner = new ExercisePlanner();
+$(document).ready(exercisePlanner.init.bind(exercisePlanner));
+
diff --git a/music/Runner.mp3 b/music/Runner.mp3
new file mode 100644 (file)
index 0000000..620aba5
Binary files /dev/null and b/music/Runner.mp3 differ
diff --git a/signature1.xml b/signature1.xml
new file mode 100644 (file)
index 0000000..d56c28b
--- /dev/null
@@ -0,0 +1,160 @@
+<Signature xmlns="http://www.w3.org/2000/09/xmldsig#" Id="DistributorSignature">
+<SignedInfo>
+<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod>
+<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"></SignatureMethod>
+<Reference URI="templates/GraphSchedule.tmpl">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>deYSqUgxc88hVjk5a7xUn3Oy2THk0VIYt5J51C/luIY=</DigestValue>
+</Reference>
+<Reference URI="music/Runner.mp3">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>sN0gBCSppwupIISCWk9SKbhuih2BlUxwcFgys6SIzHE=</DigestValue>
+</Reference>
+<Reference URI="AUTHORS">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>FANWRSdDi4T/f2CqQe56fL8NMZfewK2azWEBAfnjbQg=</DigestValue>
+</Reference>
+<Reference URI="images/background.png">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>Y4XligVqi8vVA74GUDSAUawxYuomV/h4ozXffrH+hhU=</DigestValue>
+</Reference>
+<Reference URI="images/longBothHorizonGradient2.png">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>Dq5u5V1W1FL9N+KMTKfBJTEiW0aTVHUWx0utuciKSIo=</DigestValue>
+</Reference>
+<Reference URI="images/markers.png">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>FX2aaCklIguMzPy9rZPS0vY7qWsZ2idyx6ZPUUzQzrU=</DigestValue>
+</Reference>
+<Reference URI="images/state_run.png">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>Z7lFDN5i8vTxs/CnSisNoLvcKDtQEqd6K0E5KUjNgHg=</DigestValue>
+</Reference>
+<Reference URI="images/state_lazy.png">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>s8Dc9i4P69eEp8ULwUL36ZpcSLzjQ02DDL8ozuB6HJw=</DigestValue>
+</Reference>
+<Reference URI="images/longBothHorizonGradient.png">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>1WwlyV7JaL1IyVaPS14yN3wxOngbmuvC2OgVMM9RvpQ=</DigestValue>
+</Reference>
+<Reference URI="LICENSE.Flora">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>fskt8W7B8EMb3DQsvwT98x4fPKKIjY9sS5E0eSGenFA=</DigestValue>
+</Reference>
+<Reference URI="js/app.alarms.js">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>7t0Zyyn9Cu0/HXEXaxEinFCFYpmDDgP7vdyN5UVWkQk=</DigestValue>
+</Reference>
+<Reference URI="js/app.js">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>MtoxmfFtOOUWSBu/kfMTnCeClw9RLIjMS77IWrMG7wg=</DigestValue>
+</Reference>
+<Reference URI="js/ext.jqMobile.js">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>7iRwb6yZgM18/ZU4M8pBpsYb0xXylyPJhsqzbV1eLyY=</DigestValue>
+</Reference>
+<Reference URI="js/main.js">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>lwMHcPXzvcu+hIVItWfT7RIQgrJvRi9mCrq/i38fRGc=</DigestValue>
+</Reference>
+<Reference URI="js/app.onAlarm.js">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>A52TbnmMcr8G0QDY86BmznRMEAVLMrBShC2E51RITb4=</DigestValue>
+</Reference>
+<Reference URI="js/app.timeRange.js">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>4cLd4pP/oi83KOcF8LVUJB6gxUWBsE8ZiDBCoJzjE/o=</DigestValue>
+</Reference>
+<Reference URI="js/UI.simpleTemplate.js">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>xcxpAXCb5SX9K2yPYnYXSg/lFPbD5exPgfKQcvSSqr4=</DigestValue>
+</Reference>
+<Reference URI="js/UI.js">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>o9r/AN5tPtlHjYYiVoB5AfJgQsH+Aj2cUZYdzSUgyr8=</DigestValue>
+</Reference>
+<Reference URI="js/GraphSchedule.js">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>ZpmuwAVONsdanK1S4KQPaHj1EYC8Ezs1QDZQbaFWm4M=</DigestValue>
+</Reference>
+<Reference URI="js/app.alarmsGenerating.js">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>1i4kpyIdtiDzToEKnuhiGitX2hVtPRVto9KixvY1B+s=</DigestValue>
+</Reference>
+<Reference URI="config.xml">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>XTYWoMBP0dm54DvvQmpdv0uG7UuU8wt06y9PfLGVI8E=</DigestValue>
+</Reference>
+<Reference URI="icon.png">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>Nz+SecsjmNuidhKNvmQ5+3nasrw8vI4q/bjPgbfx5fI=</DigestValue>
+</Reference>
+<Reference URI="index.html">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>PrB+bVW3O2ESYgM0lAXMNEnGAXpB8AtcD2xvSegCIvU=</DigestValue>
+</Reference>
+<Reference URI="css/jquery.ui.layout.css">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>4v30rSrxvLzjKEHb3fjwwzJHfYs4SuPd2opc+CDv77g=</DigestValue>
+</Reference>
+<Reference URI="css/style.css">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>WvY/5k6O0wSwUO7d7S4qaedAyzxw4zdmPOOv6ZuFz+c=</DigestValue>
+</Reference>
+<Reference URI="css/GraphSchedule.css">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>FMRxMozySMCFzVvfumNqZOHA+/qDtj84zddroztYWME=</DigestValue>
+</Reference>
+<Reference URI="NOTICE.Flora">
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>M7oEsiEdLNeaSAYdtR7uR5WGeAELG/V70u7Huzl42Xs=</DigestValue>
+</Reference>
+<Reference URI="#prop">
+<Transforms>
+<Transform Algorithm="http://www.w3.org/2006/12/xml-c14n11"></Transform>
+</Transforms>
+<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
+<DigestValue>u/jU3U4Zm5ihTMSjKGlGYbWzDfRkGphPPHx3gJIYEJ4=</DigestValue>
+</Reference>
+</SignedInfo>
+<SignatureValue>
+q9jMxR0PK+VpYO8PfFvcJyjnNizJ3NNjovCkzI27U9+Z9hEPCLtLfOOuPEhYfJyjQJiU0h1L+3O0
+iidyZpM3PrTfyPQHuuUQ/6VlBazd/dvd/aHEZDe7+B7sr4lLfXVlOriiwPtlR7YA7YQxYJwAgGq1
+etkYVBAMO9+wW45rrAs=
+</SignatureValue>
+<KeyInfo>
+<X509Data>
+<X509Certificate>
+MIICnTCCAgYCCQDE9MbMmJ/yCzANBgkqhkiG9w0BAQUFADCBkDELMAkGA1UEBhMCS1IxDjAMBgNV
+BAgMBVN1d29uMQ4wDAYDVQQHDAVTdXdvbjEWMBQGA1UECgwNVGl6ZW4gVGVzdCBDQTEiMCAGA1UE
+CwwZVGl6ZW4gRGlzdHJpYnV0b3IgVGVzdCBDQTElMCMGA1UEAwwcVGl6ZW4gUGFydG5lciBEaXN0
+cmlidXRvciBDQTAeFw0xMjEwMjcwNzQ4MzNaFw0yMjEwMjUwNzQ4MzNaMIGUMQswCQYDVQQGEwJL
+UjEOMAwGA1UECAwFU3V3b24xDjAMBgNVBAcMBVN1d29uMRYwFAYDVQQKDA1UaXplbiBUZXN0IENB
+MSIwIAYDVQQLDBlUaXplbiBEaXN0cmlidXRvciBUZXN0IENBMSkwJwYDVQQDDCBUaXplbiBQYXJ0
+bmVyIERpc3RyaWJ1dG9yIFNpZ25lcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAy9mg2x4B
+zxlK3LJL81GsLq/pJfK1evdCKG/IOBpdoRO0rLhYnsL5+KvToPFa5g9GTZo32LikpW1NZ7++3EHE
+fnO2IGLUau4kquvhmz1LNg5xBTx7IbucmwLMRGo1BPGdsAQQLyXeQKJ5PCERmVg4MIoiL2zT/JsL
+sZ9UPT6GEB8CAwEAATANBgkqhkiG9w0BAQUFAAOBgQAw5xPBFR1XKuZ8QpsCtSE0zXVHvwIa+Ha4
+YBdRtGwEoZmiKGZV/wAhPRdmR0kISkTz20kIGz/ZwRZCVGhsr5hkkpFknYlKeKkEJ/tJfZl4D7ec
+GFAnynOzlWZqSIPz+yxX8ah9E6lTv4Vs9DhNb08nxVvxLqlpyVdk9RUsCx/yIA==
+</X509Certificate>
+<X509Certificate>
+MIICtTCCAh6gAwIBAgIJAKORBcIiXygIMA0GCSqGSIb3DQEBBQUAMIGVMQswCQYDVQQGEwJLUjEO
+MAwGA1UECAwFU3V3b24xDjAMBgNVBAcMBVN1d29uMRYwFAYDVQQKDA1UaXplbiBUZXN0IENBMSIw
+IAYDVQQLDBlUaXplbiBEaXN0cmlidXRvciBUZXN0IENBMSowKAYDVQQDDCFUaXplbiBQYXJ0bmVy
+IERpc3RyaWJ1dG9yIFJvb3QgQ0EwHhcNMTIxMDI3MDc0NTIwWhcNMjIxMDI1MDc0NTIwWjCBkDEL
+MAkGA1UEBhMCS1IxDjAMBgNVBAgMBVN1d29uMQ4wDAYDVQQHDAVTdXdvbjEWMBQGA1UECgwNVGl6
+ZW4gVGVzdCBDQTEiMCAGA1UECwwZVGl6ZW4gRGlzdHJpYnV0b3IgVGVzdCBDQTElMCMGA1UEAwwc
+VGl6ZW4gUGFydG5lciBEaXN0cmlidXRvciBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
+2ZQrdEowjqxUmB8FX8ej19VKY6jGHKNIRE5wrhBkuZ1b0FLRPiN3/Cl9wMkCnyJui4QhC28g1aBg
+w/JnaObcDqW1NgFVH3006+gZvCTDlw1nIEjvZa6P+uWOOi05xPPAE0feKPkO1POnOjnapfkkEVNU
+8TXsLbLYBylWT8rxZC8CAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBJ
+yJ7p6qs0JI+1iKOk/sYWVP6dMueY72qOc/wVj5c3ejOlgJNNXDMAQ14QcRRexffc68ipTwybU/3m
+tcNwydzKJe+GFa4b2zyKOvOgrfs4MKSR0T9XEPmTKeR+NDT2CbA6/kQoRYm0fSORzD2UXJzNZWe/
+WjwSA66hv4q+0QZQFQ==
+</X509Certificate>
+</X509Data>
+</KeyInfo>
+<Object Id="prop"><SignatureProperties xmlns:dsp="http://www.w3.org/2009/xmldsig-properties"><SignatureProperty Id="profile" Target="#DistributorSignature"><dsp:Profile URI="http://www.w3.org/ns/widgets-digsig#profile"></dsp:Profile></SignatureProperty><SignatureProperty Id="role" Target="#DistributorSignature"><dsp:Role URI="http://www.w3.org/ns/widgets-digsig#role-distributor"></dsp:Role></SignatureProperty><SignatureProperty Id="identifier" Target="#DistributorSignature"><dsp:Identifier></dsp:Identifier></SignatureProperty></SignatureProperties></Object>
+</Signature>
\ No newline at end of file
diff --git a/templates/GraphSchedule.tmpl b/templates/GraphSchedule.tmpl
new file mode 100644 (file)
index 0000000..0dc59d7
--- /dev/null
@@ -0,0 +1,91 @@
+<div class="GraphSchedule">
+       <div class="container">
+               <table>
+                       <tr class="rangesWeekend">
+                               <td class="h00"></td>
+                               <td class="h01"></td>
+                               <td class="h02"></td>
+                               <td class="h03"></td>
+                               <td class="h04"></td>
+                               <td class="h05 th"></td>
+                               <td class="h06 th"></td>
+                               <td class="h07"></td>
+                               <td class="h08"></td>
+                               <td class="h09"></td>
+                               <td class="h10"></td>
+                               <td class="h11"></td>
+                               <td class="h12"></td>
+                               <td class="h13"></td>
+                               <td class="h14"></td>
+                               <td class="h15"></td>
+                               <td class="h16"></td>
+                               <td class="h17"></td>
+                               <td class="h18"></td>
+                               <td class="h19"></td>
+                               <td class="h20"></td>
+                               <td class="h21"></td>
+                               <td class="h22"></td>
+                               <td class="h23"></td>
+                       </tr>
+                       <tr class="ranges">
+                               <td class="h00"></td>
+                               <td class="h01"></td>
+                               <td class="h02"></td>
+                               <td class="h03"></td>
+                               <td class="h04"></td>
+                               <td class="h05"></td>
+                               <td class="h06"></td>
+                               <td class="h07"></td>
+                               <td class="h08"></td>
+                               <td class="h09"></td>
+                               <td class="h10"></td>
+                               <td class="h11"></td>
+                               <td class="h12"></td>
+                               <td class="h13"></td>
+                               <td class="h14"></td>
+                               <td class="h15"></td>
+                               <td class="h16"></td>
+                               <td class="h17"></td>
+                               <td class="h18"></td>
+                               <td class="h19"></td>
+                               <td class="h20"></td>
+                               <td class="h21"></td>
+                               <td class="h22"></td>
+                               <td class="h23"></td>
+                       </tr>
+                       <tr class="grid">
+                               <td>00</td>
+                               <td>01</td>
+                               <td>02</td>
+                               <td>03</td>
+                               <td>04</td>
+                               <td>05</td>
+                               <td>06</td>
+                               <td>07</td>
+                               <td>08</td>
+                               <td>09</td>
+                               <td>10</td>
+                               <td>11</td>
+                               <td>12</td>
+                               <td>13</td>
+                               <td>14</td>
+                               <td>15</td>
+                               <td>16</td>
+                               <td>17</td>
+                               <td>18</td>
+                               <td>19</td>
+                               <td>20</td>
+                               <td>21</td>
+                               <td>22</td>
+                               <td>23</td>
+                       </tr>
+               </table>
+       </div>
+</div>
+<div class="flag">
+       <div class="container">
+               <div class="rod"></div>
+               <p></p>
+               <div class="hint"></div>
+       </div>
+</div>