commit e58bd8628a43f36782f71e7442a5bdef7741e33e
Author: Coding with Peter
Date: Mon Dec 18 11:02:11 2023 -0800
Initial commit
diff --git a/.htaccess b/.htaccess
new file mode 100644
index 0000000..ff0cd5a
--- /dev/null
+++ b/.htaccess
@@ -0,0 +1,7 @@
+LimitRequestBody 20971520
+
+RewriteEngine On
+RewriteEngine on
+RewriteRule ^calendar([0-9]+).ics$ calendar4.php?u=$1 [QSA]
+
+RewriteRule ^api/(.*)$ api2.php?query=$1 [L,QSA]
\ No newline at end of file
diff --git a/act.php b/act.php
new file mode 100644
index 0000000..fd99cd3
--- /dev/null
+++ b/act.php
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+
+ Alert message
+
+
+
+
diff --git a/admin.php b/admin.php
new file mode 100644
index 0000000..b4d7526
--- /dev/null
+++ b/admin.php
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Public
+
+
+
Admin
+
+
+
Unused
+
+
+
+
+
+
+
+
+
+
+
+ Alert message
+
+
+
+
diff --git a/api2.php b/api2.php
new file mode 100644
index 0000000..eb7b669
--- /dev/null
+++ b/api2.php
@@ -0,0 +1,407 @@
+connect_error) { die('Database connection failed: ' . $c->connect_error ); }
+if (!mysqli_select_db($c, $DBName)) { die("Uh oh, couldn't select database $DBName"); }
+mysqli_set_charset($c, 'utf8');
+
+$server = $_SERVER['SERVER_NAME'];
+$DEBUG = 0;
+function p($s) { echo "{$s}
\n"; }
+function p2($val){ echo ''; print_r($val); echo " \n"; }
+function d_err($s) { global $DEBUG; if ($DEBUG) { p($s); } }
+function ok($str) { global $c; return mysqli_real_escape_string($c, strip_tags($str, '
')); }
+function okh($str) { global $c; return mysqli_real_escape_string($c, $str); }
+function sanitizeAndValidate($s) { return okh($s); }
+function unescape_commas($s) { return preg_replace('/\[CMA\]/', ',', $s); }
+
+function single_row_select($qry, $j=1) {
+ global $c;
+ $r = mysqli_query($c, $qry); d_err($qry);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ if (!$r) { return $r; }
+ $a = mysqli_fetch_assoc($r);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ if (! $j) { return $a; } return json_encode($a); }
+
+function single_row_insert($qry) { global $c;
+ $r = mysqli_query($c, $qry);
+ return mysqli_insert_id($c); }
+
+function single_row_update($qry, $j=1) { global $c;
+ $r = mysqli_query($c, $qry);
+ return 1; }
+
+function multi_row_select($qry, $j=1) { global $c; $rows = array();
+ $result = mysqli_query($c, $qry);
+ while($r = mysqli_fetch_assoc($result)) { $rows[] = $r; }
+ if (! $j) { return $rows; } return json_encode( $rows); }
+
+function multi_row_1d($qry) { global $c;
+ $savedQuery = mysqli_query($c, $qry);
+ while($savedResult = mysqli_fetch_array($savedQuery)) {
+ $savedArray[] = $savedResult[0]; }
+ return $savedArray; }
+
+
+// _____ _____ _ _ _____ _ ______ _ ____ _ _
+// / ____|_ _| \ | |/ ____| | | ____| (_) / __ \| \ | |
+// | (___ | | | \| | | __| | | |__ ___ _ __ _ _ __ | | | | \| |
+// \___ \ | | | . ` | | |_ | | | __| / __| |/ _` | '_ \ | | | | . ` |
+// ____) |_| |_| |\ | |__| | |____| |____ \__ \ | (_| | | | | | |__| | |\ |
+// |_____/|_____|_| \_|\_____|______|______| |___/_|\__, |_| |_| \____/|_| \_|
+// __/ |
+// |___/
+// SSO
+//
+// Set GLOBAL VARS corresponding to current logged in user.
+// They may only edit their own dir info.
+//
+
+
+
+
+if ( $server == 'intranet1.gavilan.edu' ) { // The SSO check should have happened on the actual page. If it gets
+// // stuck on an api call the app will break.
+ if ( session_id() == '' ) { // session_status() == PHP_SESSION_ACTIVE // newer php uses this
+ require 'mAuth.php';
+ $USER_TYPE = $attributes['http://wso2.org/claims/Roles'][0];
+ $USER_GOO = $attributes['http://wso2.org/claims/uid'][0];
+ $USER_EMAIL = $attributes['http://wso2.org/claims/emailaddress'][0];
+ ?>
+
+ 'SELECT * FROM users WHERE id = :id',
+ '/users' => 'SELECT * FROM users',
+ '/products' => 'SELECT * FROM products',
+ '/sessions' => 'SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.location_irl,c.mode,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,c.cal_uid,sst.type AS typeStr, sst.id AS type, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c LEFT JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag GROUP BY c.id ORDER BY c.track, c.starttime;',
+ '/ses/{day}' => 'SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.location_irl,c.mode,c.gets_survey,c.category,c.parent,c.recording,c.image_url,c.is_flex_approved,c.cal_uid,sst.type AS typeStr, sst.id AS type, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c LEFT JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE c.starttime LIKE \'%:day%\' GROUP BY c.id ORDER BY c.track, c.starttime;',
+ '/settings' => 'SELECT * FROM conf_uinforecord;'
+];
+
+$functions = [
+ '/app' => 'appdata',
+ '/start' => 'startup',
+ '/update/activity' => 'set_sessioninfo',
+];
+
+
+if (1) { //// ($_SERVER['REQUEST_METHOD'] === 'GET') {
+
+ if (isset($_REQUEST['query'])) {
+ $requestUrl = '/' . $_REQUEST['query']; /// $_SERVER['REQUEST_URI'];
+
+ // Check if a matching URL template exists
+ // Execute corresponding SQL query based on the request URL
+ foreach ($queries as $urlTemplate => $sqlTemplate) {
+ $pattern = preg_replace('/{([\-_\w]+)}/', '([\-_\w]+)', $urlTemplate);
+
+ if (preg_match("#^$pattern$#", $requestUrl, $matches)) {
+ // Extract parameter values
+ $params = [];
+ preg_match_all('/{([\-_\w]+)}/', $urlTemplate, $paramNames);
+ foreach ($paramNames[1] as $index => $paramName) {
+ $paramValue = $matches[$index + 1];
+ //echo ". . index:" . $index . ". . paramName:" . $paramName . ". . paramValue:" . $paramValue . " ";
+
+ // Sanitize and validate the parameter value
+ // Store the sanitized value in the $params array
+ $params[':' . $paramName] = sanitizeAndValidate($paramValue);
+ }
+
+ // Prepare the SQL query with the parameter values
+ $sql = strtr($sqlTemplate, $params);
+ // Execute the SQL query and retrieve data
+ //echo "query:" . $sql . " ";
+
+ $result = mysqli_query($c, $sql);
+ $rows = array();
+ while($r = mysqli_fetch_assoc($result)) { $rows[] = $r; }
+ $jsonString = json_encode($rows);
+ $sizeInBytes = strlen($jsonString);
+
+ echo json_encode(array(
+ "size" => $sizeInBytes,
+ "result" => "success",
+ //"query" => $sql,
+ "data" => $rows,
+ "err" => mysqli_error($c)
+ ));
+
+
+ }
+ }
+
+ foreach ($functions as $urlTemplate => $functionCall) {
+ $pattern = preg_replace('/{([\-_\w]+)}/', '([\-_\w]+)', $urlTemplate);
+
+ if (preg_match("#^$pattern$#", $requestUrl, $matches)) {
+ // Extract parameter values
+ $params = [];
+ preg_match_all('/{([\-_\w]+)}/', $urlTemplate, $paramNames);
+ foreach ($paramNames[1] as $index => $paramName) {
+ $paramValue = $matches[$index + 1];
+ // Sanitize and validate the parameter value
+ // Store the sanitized value in the $params array
+ $params[':' . $paramName] = sanitizeAndValidate($paramValue);
+ }
+
+ $rows = call_user_func($functionCall);
+ $jsonString = json_encode($rows);
+ $sizeInBytes = strlen($jsonString);
+
+ echo json_encode(array(
+ "size" => $sizeInBytes,
+ "result" => "success",
+ "data" => $rows,
+ "err" => mysqli_error($c)
+ ));
+
+
+ }
+ }
+ }
+} /*elseif ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ // Handle updates / inserts
+ $tableName = $_GET['table'];
+ $postData = $_POST;
+ $recordId = isset($postData['id']) ? $postData['id'] : null;
+
+ $date = date('Y-m-d H:i:s');
+ $columns = explode(',', $_REQUEST['cols']);
+ $values = explode(',', $_REQUEST['vals']);
+ $values = array_map('unescape_commas', $values);
+ $columnValuePairs = array_combine($columns, $values);
+
+ // Build the update/insert query
+ if ($recordId) {
+ $query = "UPDATE $tableName SET ";
+ $query .= join(", ", array_map(function ($column, $value) {
+ return okh($column) . " = '" . okh($value) . "'";
+ }, array_keys($columnValuePairs), $columnValuePairs));
+ $query .= ", changed = '$date'";
+ $query .= " WHERE id = $recordId";
+ } else {
+ $query = "INSERT INTO $tableName (";
+ $query .= join(", ", array_map('okh', $columns));
+ $query .= ", changed) VALUES ('";
+ $query .= join("', '", array_map('okh', $values));
+ $query .= "', '$date')";
+ }
+
+ // Execute the query
+ echo "Query: " . $query . " ";
+ exit();
+ $r = mysqli_query($c, $query);
+ echo json_encode(array(
+ "rawvalstr" => $_REQUEST['vals'],
+ "result" => "success",
+ "action" => ($recordId ? "updated" : "inserted"),
+ "logaction" => $logaction,
+ "query" => $query,
+ "err" => mysqli_error($c)
+ ));
+ exit();
+
+
+} */
+
+function startup() {
+ global $USER;
+ $ddd = multi_row_select('SELECT * FROM gavi_departments ORDER BY name',0);
+ $ttt = multi_row_select('SELECT * FROM gavi_titles ORDER BY name',0);
+ $rrr = multi_row_select("SELECT * FROM gavi_roles ORDER BY 'descr'",0);
+ $ccc = multi_row_select('SELECT * FROM gavi_committees ORDER BY name',0);
+ $sss = multi_row_select('SELECT * FROM conf_sessiontypes ORDER BY id',0);
+ $aya = multi_row_select('SELECT * FROM conf_academicyears ORDER BY id',0);
+ $set = multi_row_select('SELECT id,label,value FROM conf_uinforecord',0);
+ $ppp = multi_row_select("SELECT * FROM `conf_sessions` WHERE `type` = '20' OR `type` = '21' ORDER BY starttime",0);
+
+ $SET = array();
+ foreach ($set as $setting) {
+ $SET[$setting['label']] = $setting['value'];
+ }
+ echo json_encode( array( 'user'=>$USER, 'departments'=>$ddd, 'titles'=>$ttt, 'roles'=>$rrr, 'committees'=>$ccc,
+ 'sessiontypes'=>$sss, 'settings'=>$SET, 'ay'=>$aya, 'parents'=>$ppp ) );
+ exit();
+}
+
+function appdata() {
+ global $USER;
+
+ // mysessions
+ $m = multi_row_select("SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.location_irl,c.mode,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,sst.type,sst.id AS typeId, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c LEFT JOIN conf_signups as sup on c.id=sup.session LEFT JOIN conf_hosts as h ON h.session=c.id JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE (h.host='{$USER['conf_id']}' OR sup.user='{$USER['conf_id']}') GROUP BY c.id ORDER BY c.track, c.starttime;",0);
+
+ // sessions
+ $s = multi_row_select('SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.location_irl,c.mode,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,c.cal_uid,sst.type AS typeStr, sst.id AS type, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c LEFT JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag GROUP BY c.id ORDER BY c.track, c.starttime;',0);
+
+ // hosts
+ $hh = multi_row_1d("select session FROM conf_hosts WHERE host='{$USER['conf_id']}';");
+
+ // conferences
+ $c = multi_row_select('SELECT * FROM conf_conferences;',0);
+
+ $y = multi_row_select('SELECT * FROM conf_academicyears',0);
+
+ // options
+ $o = multi_row_select('SELECT * FROM conf_uinforecord',0);
+
+ echo json_encode(array(
+ "mysessions" => $m,
+ "sessions" => $s,
+ "host" => $hh,
+ "user" => $USER,
+ "conference" => $c,
+ "ay" => $y,
+ "options" => $o,
+ ));
+ exit();
+}
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Editing of session info
+//
+function reducer ($memo, $a) { return $memo . "`" . ok($a[0]) . "` = '" . okh($a[1]) . "', "; }
+
+function set_sessioninfo() {
+ global $c, $USER;
+ $table = 'conf_sessions';
+
+ if (isset($_POST['id'])) {
+ $ID = ok($_REQUEST['id']);
+ $WHERECLAUSE = " WHERE id={$ID}";
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = array_map('unescape_commas', $vals);
+ $cv = array_map(null,$cols,$vals);
+ $q = array_reduce($cv, 'reducer', "UPDATE `{$table}` SET ");
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+ single_row_update($q,0,$c2);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated", "query"=>$q,"err"=>mysqli_error($c2)));
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"no activity id specified") ); }
+ exit();
+}
+
+
+
+
+
+
+
+
+
+
+// Return an appropriate response indicating success or failure
+// ...
+
+
+
+
+// Close the database connection
+// ...
+
+
+
+// later... permission check
+
+ // Check if the user has permission to update the record
+ /*if (isset($_POST['id'])) { // Editing another person's data
+ if (!check_permission($USER->id, $_POST['id'], 'personnel')) {
+ echo json_encode(array("result" => "fail", "err" => "You don't have permission to edit this"));
+ exit();
+ } else {
+ $logaction = log_it("Updating $tableName record with id {$_POST['id']}");
+ $recordId = $_POST['id'];
+ }
+ } else {
+ $logaction = log_it("Updating $tableName record");
+ $recordId = $USER->id;
+ }*/
+
+
diff --git a/bio.php b/bio.php
new file mode 100644
index 0000000..63faf54
--- /dev/null
+++ b/bio.php
@@ -0,0 +1,82 @@
+
+
+
+
+ Personnel Directory > Staff Bio Page";
+ $MY_PATH = $_SERVER['PHP_SELF'];
+ $MOD_DATE = '(?)';
+ if (file_exists(__FILE__)) { $MOD_DATE = date ("F d Y H:i:s.", filemtime(__FILE__)); }
+ ?>
+
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+ Alert message
+
+
+
+
+
diff --git a/cal.php b/cal.php
new file mode 100644
index 0000000..8a47e48
--- /dev/null
+++ b/cal.php
@@ -0,0 +1,65 @@
+
+
+
+
+ Personnel Directory > Activity Signups";
+ $MY_PATH = $_SERVER['PHP_SELF'];
+ $MOD_DATE = '(?)';
+ if (file_exists(__FILE__)) { $MOD_DATE = date ("F d Y H:i:s.", filemtime(__FILE__)); }
+ ?>
+
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Calendar View
+
+
Sign up for events here
+
+
+
+
+
+
+
+
+
+
+
+
+ Alert message
+
+
+
+
diff --git a/chart.php b/chart.php
new file mode 100644
index 0000000..30d4244
--- /dev/null
+++ b/chart.php
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+
+
+ Alert message
+
+
+
+
diff --git a/css/chart.css b/css/chart.css
new file mode 100644
index 0000000..2dff293
--- /dev/null
+++ b/css/chart.css
@@ -0,0 +1,187 @@
+/*************************
+ * GRID SCHEDULE LAYOUT
+ *************************/
+@media screen and (min-width:700px) {
+ .schedule {
+ display: grid;
+ column-gap: 0.5em;
+ row-gap:0.7em;
+ grid-template-rows:
+ [tracks] auto
+ /*[time-0800] 0.005fr
+ [time-0805] 0.005fr
+ [time-0810] 0.005fr
+ [time-0815] 0.005fr
+ [time-0820] 0.005fr
+ [time-0825] 0.005fr
+ [time-0830] 0.005fr
+ [time-0835] 0.005fr
+ [time-0840] 0.005fr
+ [time-0845] 0.005fr
+ [time-0850] 0.005fr
+ [time-0855] 0.005fr */
+ [time-0900] 0.005fr
+ [time-0905] 0.005fr
+ [time-0910] 0.005fr
+ [time-0915] 0.005fr
+ [time-0920] 0.005fr
+ [time-0925] 0.005fr
+ [time-0930] 0.005fr
+ [time-0935] 0.005fr
+ [time-0940] 0.005fr
+ [time-0945] 0.005fr
+ [time-0950] 0.005fr
+ [time-0955] 0.005fr
+ [time-1000] 0.005fr
+ [time-1005] 0.005fr
+ [time-1010] 0.005fr
+ [time-1015] 0.005fr
+ [time-1020] 0.005fr
+ [time-1025] 0.005fr
+ [time-1030] 0.005fr
+ [time-1035] 0.005fr
+ [time-1040] 0.005fr
+ [time-1045] 0.005fr
+ [time-1050] 0.005fr
+ [time-1055] 0.005fr
+ [time-1100] 0.005fr
+ [time-1105] 0.005fr
+ [time-1110] 0.005fr
+ [time-1115] 0.005fr
+ [time-1120] 0.005fr
+ [time-1125] 0.005fr
+ [time-1130] 0.005fr
+ [time-1135] 0.005fr
+ [time-1140] 0.005fr
+ [time-1145] 0.005fr
+ [time-1150] 0.005fr
+ [time-1155] 0.005fr
+ [time-1200] 0.005fr
+ [time-1205] 0.005fr
+ [time-1210] 0.005fr
+ [time-1215] 0.005fr
+ [time-1220] 0.005fr
+ [time-1225] 0.005fr
+ [time-1230] 0.005fr
+ [time-1235] 0.005fr
+ [time-1240] 0.005fr
+ [time-1245] 0.005fr
+ [time-1250] 0.005fr
+ [time-1255] 0.005fr
+ [time-1300] 0.005fr
+ [time-1305] 0.005fr
+ [time-1310] 0.005fr
+ [time-1315] 0.005fr
+ [time-1320] 0.005fr
+ [time-1325] 0.005fr
+ [time-1330] 0.005fr
+ [time-1335] 0.005fr
+ [time-1340] 0.005fr
+ [time-1345] 0.005fr
+ [time-1350] 0.005fr
+ [time-1355] 0.005fr
+ [time-1400] 0.005fr
+ [time-1405] 0.005fr
+ [time-1410] 0.005fr
+ [time-1415] 0.005fr
+ [time-1420] 0.005fr
+ [time-1425] 0.005fr
+ [time-1430] 0.005fr
+ [time-1435] 0.005fr
+ [time-1440] 0.005fr
+ [time-1445] 0.005fr
+ [time-1450] 0.005fr
+ [time-1455] 0.005fr
+ [time-1500] 0.005fr
+ [time-1505] 0.005fr
+ [time-1510] 0.005fr
+ [time-1515] 0.005fr
+ [time-1520] 0.005fr
+ [time-1525] 0.005fr
+ [time-1530] 0.005fr
+ [time-1535] 0.005fr
+ [time-1540] 0.005fr
+ [time-1545] 0.005fr
+ [time-1550] 0.005fr
+ [time-1555] 0.005fr
+ [time-1600] 0.005fr
+ [time-1605] 0.005fr
+ [time-1610] 0.005fr
+ [time-1615] 0.005fr
+ [time-1620] 0.005fr
+ [time-1625] 0.005fr
+ [time-1630] 0.005fr
+ [time-1635] 0.005fr
+ [time-1640] 0.005fr
+ [time-1645] 0.005fr
+ [time-1650] 0.005fr
+ [time-1655] 0.005fr
+ [time-1700] 0.005fr
+ [time-1705] 0.005fr
+ [time-1710] 0.005fr
+ [time-1715] 0.005fr
+ [time-1720] 0.005fr
+ [time-1725] 0.005fr
+ [time-1730] 0.005fr
+ [time-1735] 0.005fr
+ [time-1740] 0.005fr
+ [time-1745] 0.005fr
+ [time-1750] 0.005fr
+ [time-1755] 0.005fr;
+ /* Note 1:
+ Use 24hr time for gridline names for simplicity
+
+ Note 2: Use "auto" instead of "1fr" for a more compact schedule where height of a slot is not proportional to the session length.
+ Implementing a "compact" shortcode attribute might make sense for this!
+ Try 0.5fr for more compact equal rows. I don't quite understand how that works :)
+ */
+
+ grid-template-columns:
+ [times] 4em
+ [track-1-start] 1fr
+ [track-1-end track-2-start] 1fr
+ [track-2-end track-3-start] 1fr
+ [track-3-end track-4-start] 1fr
+ [track-4-end track-5-start] 1fr
+ [track-5-end track-6-start] 1fr
+ [track-6-end];
+ }
+}
+.time-slot { grid-column: times; }
+.track-slot { display: none; }
+ /* hidden on small screens and browsers without grid support */
+
+@supports(display:grid ) { @media screen and(min-width:700px) {
+ .track-slot { display: block; padding: 10px 5px 5px; position: sticky; top: 0; z-index: 1000; background-color: rgba(255,255,255,.9); } } }
+/* Small-screen & fallback styles */
+@supports(display:grid ) { @media screen and(min-width: 700px) { .session { margin: 0; } } }
+
+/* VISUAL STYLES * Design-y stuff ot particularly important to the demo */
+
+body { padding: 50px; /*max-width: 1100px;*/ margin: 0 auto; line-height: 1.5; }
+.session { padding: .5em; border-radius: 2px; font-size: 14px; }
+
+ /* box-shadow: rgba(255,255,255,.6) 1px 1px 0, rgba(0,0,0,.3) 4px 4px 0; */
+
+.session-title, .session-time, .session-track, .session-presenter { display: block; }
+.session-title, .time-slot { margin: 0; font-size: 1em; }
+.session-title a { color: #fff; text-decoration-style: dotted; &:hover { font-style: italic; }
+ &:focus { outline: 2px dotted rgba(255,255,255,.8); }
+ }
+.track-slot, .time-slot { font-weight: bold; font-size:.75em; }
+.track-123 { background-color: #ffa8ca; color: #000; }
+.track-0 { background-color: #ffa8ca; color: #000; }
+.track-1 { background-color: #f3ba59; color: #fff; }
+.track-2 { background-color: #e96b8f; color: #fff; }
+.track-3 { background-color: #ff9ffc; color: #fff; }
+.track-4 { background-color: #b4d3c0; color: #fff; }
+.track-5 { background-color: #dad9ff; color: #fff; }
+.track-6 { background-color: #9ccae1; color: #fff; }
+.track-all { display: flex; justify-content: center; align-items: center; background: #ccc; color: #000; box-shadow: none; }
+.text { max-width: 750px; font-size: 18px; margin: 0 auto 50px; }
+.session h3, .session { color: #272727; }
+.meta { color: #555; font-style: italic; }
+.meta a { color: #555; }
+.chart_timebox { color:lightgrey; border:1px solid lightgrey; padding:5px; }
+.chart_time { color:#5c5b5b; font-size: 80%; }
+hr { margin: 40px 0; }
\ No newline at end of file
diff --git a/css/intranet2021.css b/css/intranet2021.css
new file mode 100644
index 0000000..f557be0
--- /dev/null
+++ b/css/intranet2021.css
@@ -0,0 +1,200 @@
+
+
+
+/* GAV INTRANET CUSTOMIZATIONS BELOW....
+
+ ph 10 / 2021
+
+
+ */
+
+
+
+/*!
+Pure v2.0.6
+https://github.com/pure-css/pure/blob/master/LICENSE
+*/
+html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{-webkit-box-sizing:border-box;box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none}html{font-family:sans-serif}.hidden,[hidden]{display:none!important}.pure-img{max-width:100%;height:auto;display:block}.pure-g{letter-spacing:-.31em;text-rendering:optimizespeed;font-family:FreeSans,Arimo,"Droid Sans",Helvetica,Arial,sans-serif;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-line-pack:start;align-content:flex-start}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){table .pure-g{display:block}}.opera-only :-o-prefocus,.pure-g{word-spacing:-0.43em}.pure-u{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-g [class*=pure-u]{font-family:sans-serif}.pure-u-1,.pure-u-1-1,.pure-u-1-12,.pure-u-1-2,.pure-u-1-24,.pure-u-1-3,.pure-u-1-4,.pure-u-1-5,.pure-u-1-6,.pure-u-1-8,.pure-u-10-24,.pure-u-11-12,.pure-u-11-24,.pure-u-12-24,.pure-u-13-24,.pure-u-14-24,.pure-u-15-24,.pure-u-16-24,.pure-u-17-24,.pure-u-18-24,.pure-u-19-24,.pure-u-2-24,.pure-u-2-3,.pure-u-2-5,.pure-u-20-24,.pure-u-21-24,.pure-u-22-24,.pure-u-23-24,.pure-u-24-24,.pure-u-3-24,.pure-u-3-4,.pure-u-3-5,.pure-u-3-8,.pure-u-4-24,.pure-u-4-5,.pure-u-5-12,.pure-u-5-24,.pure-u-5-5,.pure-u-5-6,.pure-u-5-8,.pure-u-6-24,.pure-u-7-12,.pure-u-7-24,.pure-u-7-8,.pure-u-8-24,.pure-u-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-1-24{width:4.1667%}.pure-u-1-12,.pure-u-2-24{width:8.3333%}.pure-u-1-8,.pure-u-3-24{width:12.5%}.pure-u-1-6,.pure-u-4-24{width:16.6667%}.pure-u-1-5{width:20%}.pure-u-5-24{width:20.8333%}.pure-u-1-4,.pure-u-6-24{width:25%}.pure-u-7-24{width:29.1667%}.pure-u-1-3,.pure-u-8-24{width:33.3333%}.pure-u-3-8,.pure-u-9-24{width:37.5%}.pure-u-2-5{width:40%}.pure-u-10-24,.pure-u-5-12{width:41.6667%}.pure-u-11-24{width:45.8333%}.pure-u-1-2,.pure-u-12-24{width:50%}.pure-u-13-24{width:54.1667%}.pure-u-14-24,.pure-u-7-12{width:58.3333%}.pure-u-3-5{width:60%}.pure-u-15-24,.pure-u-5-8{width:62.5%}.pure-u-16-24,.pure-u-2-3{width:66.6667%}.pure-u-17-24{width:70.8333%}.pure-u-18-24,.pure-u-3-4{width:75%}.pure-u-19-24{width:79.1667%}.pure-u-4-5{width:80%}.pure-u-20-24,.pure-u-5-6{width:83.3333%}.pure-u-21-24,.pure-u-7-8{width:87.5%}.pure-u-11-12,.pure-u-22-24{width:91.6667%}.pure-u-23-24{width:95.8333%}.pure-u-1,.pure-u-1-1,.pure-u-24-24,.pure-u-5-5{width:100%}.pure-button{display:inline-block;line-height:normal;white-space:nowrap;vertical-align:middle;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:border-box;box-sizing:border-box}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-group{letter-spacing:-.31em;text-rendering:optimizespeed}.opera-only :-o-prefocus,.pure-button-group{word-spacing:-0.43em}.pure-button-group .pure-button{letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-button{font-family:inherit;font-size:100%;padding:.5em 1em;color:rgba(0,0,0,.8);border:none transparent;background-color:#e6e6e6;text-decoration:none;border-radius:2px}.pure-button-hover,.pure-button:focus,.pure-button:hover{background-image:-webkit-gradient(linear,left top,left bottom,from(transparent),color-stop(40%,rgba(0,0,0,.05)),to(rgba(0,0,0,.1)));background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{-webkit-box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset;box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset;border-color:#000}.pure-button-disabled,.pure-button-disabled:active,.pure-button-disabled:focus,.pure-button-disabled:hover,.pure-button[disabled]{border:none;background-image:none;opacity:.4;cursor:not-allowed;-webkit-box-shadow:none;box-shadow:none;pointer-events:none}.pure-button-hidden{display:none}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-button-group .pure-button{margin:0;border-radius:0;border-right:1px solid rgba(0,0,0,.2)}.pure-button-group .pure-button:first-child{border-top-left-radius:2px;border-bottom-left-radius:2px}.pure-button-group .pure-button:last-child{border-top-right-radius:2px;border-bottom-right-radius:2px;border-right:none}.pure-form input[type=color],.pure-form input[type=date],.pure-form input[type=datetime-local],.pure-form input[type=datetime],.pure-form input[type=email],.pure-form input[type=month],.pure-form input[type=number],.pure-form input[type=password],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=text],.pure-form input[type=time],.pure-form input[type=url],.pure-form input[type=week],.pure-form select,.pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 3px #ddd;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;vertical-align:middle;-webkit-box-sizing:border-box;box-sizing:border-box}.pure-form input:not([type]){padding:.5em .6em;display:inline-block;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 3px #ddd;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-box-sizing:border-box;box-sizing:border-box}.pure-form input[type=color]{padding:.2em .5em}.pure-form input[type=color]:focus,.pure-form input[type=date]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=email]:focus,.pure-form input[type=month]:focus,.pure-form input[type=number]:focus,.pure-form input[type=password]:focus,.pure-form input[type=search]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=text]:focus,.pure-form input[type=time]:focus,.pure-form input[type=url]:focus,.pure-form input[type=week]:focus,.pure-form select:focus,.pure-form textarea:focus{outline:0;border-color:#129fea}.pure-form input:not([type]):focus{outline:0;border-color:#129fea}.pure-form input[type=checkbox]:focus,.pure-form input[type=file]:focus,.pure-form input[type=radio]:focus{outline:thin solid #129FEA;outline:1px auto #129FEA}.pure-form .pure-checkbox,.pure-form .pure-radio{margin:.5em 0;display:block}.pure-form input[type=color][disabled],.pure-form input[type=date][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=email][disabled],.pure-form input[type=month][disabled],.pure-form input[type=number][disabled],.pure-form input[type=password][disabled],.pure-form input[type=search][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=text][disabled],.pure-form input[type=time][disabled],.pure-form input[type=url][disabled],.pure-form input[type=week][disabled],.pure-form select[disabled],.pure-form textarea[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input:not([type])[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly]{background-color:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form select:focus:invalid,.pure-form textarea:focus:invalid{color:#b94a48;border-color:#e9322d}.pure-form input[type=checkbox]:focus:invalid:focus,.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{height:2.25em;border:1px solid #ccc;background-color:#fff}.pure-form select[multiple]{height:auto}.pure-form label{margin:.5em 0 .2em}.pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0}.pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;color:#333;border-bottom:1px solid #e5e5e5}.pure-form-stacked input[type=color],.pure-form-stacked input[type=date],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=email],.pure-form-stacked input[type=file],.pure-form-stacked input[type=month],.pure-form-stacked input[type=number],.pure-form-stacked input[type=password],.pure-form-stacked input[type=search],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=text],.pure-form-stacked input[type=time],.pure-form-stacked input[type=url],.pure-form-stacked input[type=week],.pure-form-stacked label,.pure-form-stacked select,.pure-form-stacked textarea{display:block;margin:.25em 0}.pure-form-stacked input:not([type]){display:block;margin:.25em 0}.pure-form-aligned input,.pure-form-aligned select,.pure-form-aligned textarea,.pure-form-message-inline{display:inline-block;vertical-align:middle}.pure-form-aligned textarea{vertical-align:top}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 11em}.pure-form .pure-input-rounded,.pure-form input.pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input,.pure-form .pure-group textarea{display:block;padding:10px;margin:0 0 -1px;border-radius:0;position:relative;top:-1px}.pure-form .pure-group input:focus,.pure-form .pure-group textarea:focus{z-index:3}.pure-form .pure-group input:first-child,.pure-form .pure-group textarea:first-child{top:1px;border-radius:4px 4px 0 0;margin:0}.pure-form .pure-group input:first-child:last-child,.pure-form .pure-group textarea:first-child:last-child{top:1px;border-radius:4px;margin:0}.pure-form .pure-group input:last-child,.pure-form .pure-group textarea:last-child{top:-2px;border-radius:0 0 4px 4px;margin:0}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-1{width:100%}.pure-form .pure-input-3-4{width:75%}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-2{width:50%}.pure-form .pure-input-1-3{width:33%}.pure-form .pure-input-1-4{width:25%}.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:.875em}.pure-form-message{display:block;color:#666;font-size:.875em}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input:not([type]),.pure-form input[type=color],.pure-form input[type=date],.pure-form input[type=datetime-local],.pure-form input[type=datetime],.pure-form input[type=email],.pure-form input[type=month],.pure-form input[type=number],.pure-form input[type=password],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=text],.pure-form input[type=time],.pure-form input[type=url],.pure-form input[type=week],.pure-form label{margin-bottom:.3em;display:block}.pure-group input:not([type]),.pure-group input[type=color],.pure-group input[type=date],.pure-group input[type=datetime-local],.pure-group input[type=datetime],.pure-group input[type=email],.pure-group input[type=month],.pure-group input[type=number],.pure-group input[type=password],.pure-group input[type=search],.pure-group input[type=tel],.pure-group input[type=text],.pure-group input[type=time],.pure-group input[type=url],.pure-group input[type=week]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0 0}.pure-form-message,.pure-form-message-inline{display:block;font-size:.75em;padding:.2em 0 .8em}}.pure-menu{-webkit-box-sizing:border-box;box-sizing:border-box}.pure-menu-fixed{position:fixed;left:0;top:0;z-index:3}.pure-menu-item,.pure-menu-list{position:relative}.pure-menu-list{list-style:none;margin:0;padding:0}.pure-menu-item{padding:0;margin:0;height:100%}.pure-menu-heading,.pure-menu-link{display:block;text-decoration:none;white-space:nowrap}.pure-menu-horizontal{width:100%;white-space:nowrap}.pure-menu-horizontal .pure-menu-list{display:inline-block}.pure-menu-horizontal .pure-menu-heading,.pure-menu-horizontal .pure-menu-item,.pure-menu-horizontal .pure-menu-separator{display:inline-block;vertical-align:middle}.pure-menu-item .pure-menu-item{display:block}.pure-menu-children{display:none;position:absolute;left:100%;top:0;margin:0;padding:0;z-index:3}.pure-menu-horizontal .pure-menu-children{left:0;top:auto;width:inherit}.pure-menu-active>.pure-menu-children,.pure-menu-allow-hover:hover>.pure-menu-children{display:block;position:absolute}.pure-menu-has-children>.pure-menu-link:after{padding-left:.5em;content:"\25B8";font-size:small}.pure-menu-horizontal .pure-menu-has-children>.pure-menu-link:after{content:"\25BE"}.pure-menu-scrollable{overflow-y:scroll;overflow-x:hidden}.pure-menu-scrollable .pure-menu-list{display:block}.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list{display:inline-block}.pure-menu-horizontal.pure-menu-scrollable{white-space:nowrap;overflow-y:hidden;overflow-x:auto;padding:.5em 0}.pure-menu-horizontal .pure-menu-children .pure-menu-separator,.pure-menu-separator{background-color:#ccc;height:1px;margin:.3em 0}.pure-menu-horizontal .pure-menu-separator{width:1px;height:1.3em;margin:0 .3em}.pure-menu-horizontal .pure-menu-children .pure-menu-separator{display:block;width:auto}.pure-menu-heading{text-transform:uppercase;color:#565d64}.pure-menu-link{color:#777}.pure-menu-children{background-color:#fff}.pure-menu-heading,.pure-menu-link{padding:.5em 1em}.pure-menu-disabled{opacity:.5}.pure-menu-disabled .pure-menu-link:hover{background-color:transparent;cursor:default}.pure-menu-active>.pure-menu-link,.pure-menu-link:focus,.pure-menu-link:hover{background-color:#eee}.pure-menu-selected>.pure-menu-link,.pure-menu-selected>.pure-menu-link:visited{color:#000}.pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:.5em 1em}.pure-table thead{background-color:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child>td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child>td{border-bottom-width:0}
+
+/*! Pure v2.0.6 */
+@media screen and (min-width:35.5em){.pure-u-sm-1,.pure-u-sm-1-1,.pure-u-sm-1-12,.pure-u-sm-1-2,.pure-u-sm-1-24,.pure-u-sm-1-3,.pure-u-sm-1-4,.pure-u-sm-1-5,.pure-u-sm-1-6,.pure-u-sm-1-8,.pure-u-sm-10-24,.pure-u-sm-11-12,.pure-u-sm-11-24,.pure-u-sm-12-24,.pure-u-sm-13-24,.pure-u-sm-14-24,.pure-u-sm-15-24,.pure-u-sm-16-24,.pure-u-sm-17-24,.pure-u-sm-18-24,.pure-u-sm-19-24,.pure-u-sm-2-24,.pure-u-sm-2-3,.pure-u-sm-2-5,.pure-u-sm-20-24,.pure-u-sm-21-24,.pure-u-sm-22-24,.pure-u-sm-23-24,.pure-u-sm-24-24,.pure-u-sm-3-24,.pure-u-sm-3-4,.pure-u-sm-3-5,.pure-u-sm-3-8,.pure-u-sm-4-24,.pure-u-sm-4-5,.pure-u-sm-5-12,.pure-u-sm-5-24,.pure-u-sm-5-5,.pure-u-sm-5-6,.pure-u-sm-5-8,.pure-u-sm-6-24,.pure-u-sm-7-12,.pure-u-sm-7-24,.pure-u-sm-7-8,.pure-u-sm-8-24,.pure-u-sm-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-sm-1-24{width:4.1667%}.pure-u-sm-1-12,.pure-u-sm-2-24{width:8.3333%}.pure-u-sm-1-8,.pure-u-sm-3-24{width:12.5%}.pure-u-sm-1-6,.pure-u-sm-4-24{width:16.6667%}.pure-u-sm-1-5{width:20%}.pure-u-sm-5-24{width:20.8333%}.pure-u-sm-1-4,.pure-u-sm-6-24{width:25%}.pure-u-sm-7-24{width:29.1667%}.pure-u-sm-1-3,.pure-u-sm-8-24{width:33.3333%}.pure-u-sm-3-8,.pure-u-sm-9-24{width:37.5%}.pure-u-sm-2-5{width:40%}.pure-u-sm-10-24,.pure-u-sm-5-12{width:41.6667%}.pure-u-sm-11-24{width:45.8333%}.pure-u-sm-1-2,.pure-u-sm-12-24{width:50%}.pure-u-sm-13-24{width:54.1667%}.pure-u-sm-14-24,.pure-u-sm-7-12{width:58.3333%}.pure-u-sm-3-5{width:60%}.pure-u-sm-15-24,.pure-u-sm-5-8{width:62.5%}.pure-u-sm-16-24,.pure-u-sm-2-3{width:66.6667%}.pure-u-sm-17-24{width:70.8333%}.pure-u-sm-18-24,.pure-u-sm-3-4{width:75%}.pure-u-sm-19-24{width:79.1667%}.pure-u-sm-4-5{width:80%}.pure-u-sm-20-24,.pure-u-sm-5-6{width:83.3333%}.pure-u-sm-21-24,.pure-u-sm-7-8{width:87.5%}.pure-u-sm-11-12,.pure-u-sm-22-24{width:91.6667%}.pure-u-sm-23-24{width:95.8333%}.pure-u-sm-1,.pure-u-sm-1-1,.pure-u-sm-24-24,.pure-u-sm-5-5{width:100%}}@media screen and (min-width:48em){.pure-u-md-1,.pure-u-md-1-1,.pure-u-md-1-12,.pure-u-md-1-2,.pure-u-md-1-24,.pure-u-md-1-3,.pure-u-md-1-4,.pure-u-md-1-5,.pure-u-md-1-6,.pure-u-md-1-8,.pure-u-md-10-24,.pure-u-md-11-12,.pure-u-md-11-24,.pure-u-md-12-24,.pure-u-md-13-24,.pure-u-md-14-24,.pure-u-md-15-24,.pure-u-md-16-24,.pure-u-md-17-24,.pure-u-md-18-24,.pure-u-md-19-24,.pure-u-md-2-24,.pure-u-md-2-3,.pure-u-md-2-5,.pure-u-md-20-24,.pure-u-md-21-24,.pure-u-md-22-24,.pure-u-md-23-24,.pure-u-md-24-24,.pure-u-md-3-24,.pure-u-md-3-4,.pure-u-md-3-5,.pure-u-md-3-8,.pure-u-md-4-24,.pure-u-md-4-5,.pure-u-md-5-12,.pure-u-md-5-24,.pure-u-md-5-5,.pure-u-md-5-6,.pure-u-md-5-8,.pure-u-md-6-24,.pure-u-md-7-12,.pure-u-md-7-24,.pure-u-md-7-8,.pure-u-md-8-24,.pure-u-md-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-md-1-24{width:4.1667%}.pure-u-md-1-12,.pure-u-md-2-24{width:8.3333%}.pure-u-md-1-8,.pure-u-md-3-24{width:12.5%}.pure-u-md-1-6,.pure-u-md-4-24{width:16.6667%}.pure-u-md-1-5{width:20%}.pure-u-md-5-24{width:20.8333%}.pure-u-md-1-4,.pure-u-md-6-24{width:25%}.pure-u-md-7-24{width:29.1667%}.pure-u-md-1-3,.pure-u-md-8-24{width:33.3333%}.pure-u-md-3-8,.pure-u-md-9-24{width:37.5%}.pure-u-md-2-5{width:40%}.pure-u-md-10-24,.pure-u-md-5-12{width:41.6667%}.pure-u-md-11-24{width:45.8333%}.pure-u-md-1-2,.pure-u-md-12-24{width:50%}.pure-u-md-13-24{width:54.1667%}.pure-u-md-14-24,.pure-u-md-7-12{width:58.3333%}.pure-u-md-3-5{width:60%}.pure-u-md-15-24,.pure-u-md-5-8{width:62.5%}.pure-u-md-16-24,.pure-u-md-2-3{width:66.6667%}.pure-u-md-17-24{width:70.8333%}.pure-u-md-18-24,.pure-u-md-3-4{width:75%}.pure-u-md-19-24{width:79.1667%}.pure-u-md-4-5{width:80%}.pure-u-md-20-24,.pure-u-md-5-6{width:83.3333%}.pure-u-md-21-24,.pure-u-md-7-8{width:87.5%}.pure-u-md-11-12,.pure-u-md-22-24{width:91.6667%}.pure-u-md-23-24{width:95.8333%}.pure-u-md-1,.pure-u-md-1-1,.pure-u-md-24-24,.pure-u-md-5-5{width:100%}}@media screen and (min-width:64em){.pure-u-lg-1,.pure-u-lg-1-1,.pure-u-lg-1-12,.pure-u-lg-1-2,.pure-u-lg-1-24,.pure-u-lg-1-3,.pure-u-lg-1-4,.pure-u-lg-1-5,.pure-u-lg-1-6,.pure-u-lg-1-8,.pure-u-lg-10-24,.pure-u-lg-11-12,.pure-u-lg-11-24,.pure-u-lg-12-24,.pure-u-lg-13-24,.pure-u-lg-14-24,.pure-u-lg-15-24,.pure-u-lg-16-24,.pure-u-lg-17-24,.pure-u-lg-18-24,.pure-u-lg-19-24,.pure-u-lg-2-24,.pure-u-lg-2-3,.pure-u-lg-2-5,.pure-u-lg-20-24,.pure-u-lg-21-24,.pure-u-lg-22-24,.pure-u-lg-23-24,.pure-u-lg-24-24,.pure-u-lg-3-24,.pure-u-lg-3-4,.pure-u-lg-3-5,.pure-u-lg-3-8,.pure-u-lg-4-24,.pure-u-lg-4-5,.pure-u-lg-5-12,.pure-u-lg-5-24,.pure-u-lg-5-5,.pure-u-lg-5-6,.pure-u-lg-5-8,.pure-u-lg-6-24,.pure-u-lg-7-12,.pure-u-lg-7-24,.pure-u-lg-7-8,.pure-u-lg-8-24,.pure-u-lg-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-lg-1-24{width:4.1667%}.pure-u-lg-1-12,.pure-u-lg-2-24{width:8.3333%}.pure-u-lg-1-8,.pure-u-lg-3-24{width:12.5%}.pure-u-lg-1-6,.pure-u-lg-4-24{width:16.6667%}.pure-u-lg-1-5{width:20%}.pure-u-lg-5-24{width:20.8333%}.pure-u-lg-1-4,.pure-u-lg-6-24{width:25%}.pure-u-lg-7-24{width:29.1667%}.pure-u-lg-1-3,.pure-u-lg-8-24{width:33.3333%}.pure-u-lg-3-8,.pure-u-lg-9-24{width:37.5%}.pure-u-lg-2-5{width:40%}.pure-u-lg-10-24,.pure-u-lg-5-12{width:41.6667%}.pure-u-lg-11-24{width:45.8333%}.pure-u-lg-1-2,.pure-u-lg-12-24{width:50%}.pure-u-lg-13-24{width:54.1667%}.pure-u-lg-14-24,.pure-u-lg-7-12{width:58.3333%}.pure-u-lg-3-5{width:60%}.pure-u-lg-15-24,.pure-u-lg-5-8{width:62.5%}.pure-u-lg-16-24,.pure-u-lg-2-3{width:66.6667%}.pure-u-lg-17-24{width:70.8333%}.pure-u-lg-18-24,.pure-u-lg-3-4{width:75%}.pure-u-lg-19-24{width:79.1667%}.pure-u-lg-4-5{width:80%}.pure-u-lg-20-24,.pure-u-lg-5-6{width:83.3333%}.pure-u-lg-21-24,.pure-u-lg-7-8{width:87.5%}.pure-u-lg-11-12,.pure-u-lg-22-24{width:91.6667%}.pure-u-lg-23-24{width:95.8333%}.pure-u-lg-1,.pure-u-lg-1-1,.pure-u-lg-24-24,.pure-u-lg-5-5{width:100%}}@media screen and (min-width:80em){.pure-u-xl-1,.pure-u-xl-1-1,.pure-u-xl-1-12,.pure-u-xl-1-2,.pure-u-xl-1-24,.pure-u-xl-1-3,.pure-u-xl-1-4,.pure-u-xl-1-5,.pure-u-xl-1-6,.pure-u-xl-1-8,.pure-u-xl-10-24,.pure-u-xl-11-12,.pure-u-xl-11-24,.pure-u-xl-12-24,.pure-u-xl-13-24,.pure-u-xl-14-24,.pure-u-xl-15-24,.pure-u-xl-16-24,.pure-u-xl-17-24,.pure-u-xl-18-24,.pure-u-xl-19-24,.pure-u-xl-2-24,.pure-u-xl-2-3,.pure-u-xl-2-5,.pure-u-xl-20-24,.pure-u-xl-21-24,.pure-u-xl-22-24,.pure-u-xl-23-24,.pure-u-xl-24-24,.pure-u-xl-3-24,.pure-u-xl-3-4,.pure-u-xl-3-5,.pure-u-xl-3-8,.pure-u-xl-4-24,.pure-u-xl-4-5,.pure-u-xl-5-12,.pure-u-xl-5-24,.pure-u-xl-5-5,.pure-u-xl-5-6,.pure-u-xl-5-8,.pure-u-xl-6-24,.pure-u-xl-7-12,.pure-u-xl-7-24,.pure-u-xl-7-8,.pure-u-xl-8-24,.pure-u-xl-9-24{display:inline-block;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-xl-1-24{width:4.1667%}.pure-u-xl-1-12,.pure-u-xl-2-24{width:8.3333%}.pure-u-xl-1-8,.pure-u-xl-3-24{width:12.5%}.pure-u-xl-1-6,.pure-u-xl-4-24{width:16.6667%}.pure-u-xl-1-5{width:20%}.pure-u-xl-5-24{width:20.8333%}.pure-u-xl-1-4,.pure-u-xl-6-24{width:25%}.pure-u-xl-7-24{width:29.1667%}.pure-u-xl-1-3,.pure-u-xl-8-24{width:33.3333%}.pure-u-xl-3-8,.pure-u-xl-9-24{width:37.5%}.pure-u-xl-2-5{width:40%}.pure-u-xl-10-24,.pure-u-xl-5-12{width:41.6667%}.pure-u-xl-11-24{width:45.8333%}.pure-u-xl-1-2,.pure-u-xl-12-24{width:50%}.pure-u-xl-13-24{width:54.1667%}.pure-u-xl-14-24,.pure-u-xl-7-12{width:58.3333%}.pure-u-xl-3-5{width:60%}.pure-u-xl-15-24,.pure-u-xl-5-8{width:62.5%}.pure-u-xl-16-24,.pure-u-xl-2-3{width:66.6667%}.pure-u-xl-17-24{width:70.8333%}.pure-u-xl-18-24,.pure-u-xl-3-4{width:75%}.pure-u-xl-19-24{width:79.1667%}.pure-u-xl-4-5{width:80%}.pure-u-xl-20-24,.pure-u-xl-5-6{width:83.3333%}.pure-u-xl-21-24,.pure-u-xl-7-8{width:87.5%}.pure-u-xl-11-12,.pure-u-xl-22-24{width:91.6667%}.pure-u-xl-23-24{width:95.8333%}.pure-u-xl-1,.pure-u-xl-1-1,.pure-u-xl-24-24,.pure-u-xl-5-5{width:100%}}
+
+.pell{border:1px solid hsla(0,0%,4%,.1)}.pell,.pell-content{box-sizing:border-box}.pell-content{height:300px;outline:0;overflow-y:auto;padding:10px}.pell-actionbar{background-color:#fff;border-bottom:1px solid hsla(0,0%,4%,.1)}.pell-button{background-color:transparent;border:none;cursor:pointer;height:30px;outline:0;width:30px;vertical-align:bottom}.pell-button-selected{background-color:#f0f0f0}
+
+/* DropZone */
+@-webkit-keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%,70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@-moz-keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%,70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@keyframes passing-through{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%,70%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}100%{opacity:0;-webkit-transform:translateY(-40px);-moz-transform:translateY(-40px);-ms-transform:translateY(-40px);-o-transform:translateY(-40px);transform:translateY(-40px)}}@-webkit-keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@-moz-keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@keyframes slide-in{0%{opacity:0;-webkit-transform:translateY(40px);-moz-transform:translateY(40px);-ms-transform:translateY(40px);-o-transform:translateY(40px);transform:translateY(40px)}30%{opacity:1;-webkit-transform:translateY(0px);-moz-transform:translateY(0px);-ms-transform:translateY(0px);-o-transform:translateY(0px);transform:translateY(0px)}}@-webkit-keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}@-moz-keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}@keyframes pulse{0%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}10%{-webkit-transform:scale(1.1);-moz-transform:scale(1.1);-ms-transform:scale(1.1);-o-transform:scale(1.1);transform:scale(1.1)}20%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1)}}.dropzone,.dropzone *{box-sizing:border-box}.dropzone{min-height:150px;border:2px solid rgba(0,0,0,.3);background:#fff;padding:20px 20px}.dropzone.dz-clickable{cursor:pointer}.dropzone.dz-clickable *{cursor:default}.dropzone.dz-clickable .dz-message,.dropzone.dz-clickable .dz-message *{cursor:pointer}.dropzone.dz-started .dz-message{display:none}.dropzone.dz-drag-hover{border-style:solid}.dropzone.dz-drag-hover .dz-message{opacity:.5}.dropzone .dz-message{text-align:center;margin:2em 0}.dropzone .dz-message .dz-button{background:none;color:inherit;border:none;padding:0;font:inherit;cursor:pointer;outline:inherit}.dropzone .dz-preview{position:relative;display:inline-block;vertical-align:top;margin:16px;min-height:100px}.dropzone .dz-preview:hover{z-index:1000}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview.dz-file-preview .dz-image{border-radius:20px;background:#999;background:linear-gradient(to bottom, #eee, #ddd)}.dropzone .dz-preview.dz-file-preview .dz-details{opacity:1}.dropzone .dz-preview.dz-image-preview{background:#fff}.dropzone .dz-preview.dz-image-preview .dz-details{-webkit-transition:opacity 0.2s linear;-moz-transition:opacity 0.2s linear;-ms-transition:opacity 0.2s linear;-o-transition:opacity 0.2s linear;transition:opacity 0.2s linear}.dropzone .dz-preview .dz-remove{font-size:14px;text-align:center;display:block;cursor:pointer;border:none}.dropzone .dz-preview .dz-remove:hover{text-decoration:underline}.dropzone .dz-preview:hover .dz-details{opacity:1}.dropzone .dz-preview .dz-details{z-index:20;position:absolute;top:0;left:0;opacity:0;font-size:13px;min-width:100%;max-width:100%;padding:2em 1em;text-align:center;color:rgba(0,0,0,.9);line-height:150%}.dropzone .dz-preview .dz-details .dz-size{margin-bottom:1em;font-size:16px}.dropzone .dz-preview .dz-details .dz-filename{white-space:nowrap}.dropzone .dz-preview .dz-details .dz-filename:hover span{border:1px solid rgba(200,200,200,.8);background-color:rgba(255,255,255,.8)}.dropzone .dz-preview .dz-details .dz-filename:not(:hover){overflow:hidden;text-overflow:ellipsis}.dropzone .dz-preview .dz-details .dz-filename:not(:hover) span{border:1px solid transparent}.dropzone .dz-preview .dz-details .dz-filename span,.dropzone .dz-preview .dz-details .dz-size span{background-color:rgba(255,255,255,.4);padding:0 .4em;border-radius:3px}.dropzone .dz-preview:hover .dz-image img{-webkit-transform:scale(1.05, 1.05);-moz-transform:scale(1.05, 1.05);-ms-transform:scale(1.05, 1.05);-o-transform:scale(1.05, 1.05);transform:scale(1.05, 1.05);-webkit-filter:blur(8px);filter:blur(8px)}.dropzone .dz-preview .dz-image{border-radius:20px;overflow:hidden;width:120px;height:120px;position:relative;display:block;z-index:10}.dropzone .dz-preview .dz-image img{display:block}.dropzone .dz-preview.dz-success .dz-success-mark{-webkit-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);-moz-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);-ms-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);-o-animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);animation:passing-through 3s cubic-bezier(0.77, 0, 0.175, 1)}.dropzone .dz-preview.dz-error .dz-error-mark{opacity:1;-webkit-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);-moz-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);-ms-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);-o-animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);animation:slide-in 3s cubic-bezier(0.77, 0, 0.175, 1)}.dropzone .dz-preview .dz-success-mark,.dropzone .dz-preview .dz-error-mark{pointer-events:none;opacity:0;z-index:500;position:absolute;display:block;top:50%;left:50%;margin-left:-27px;margin-top:-27px}.dropzone .dz-preview .dz-success-mark svg,.dropzone .dz-preview .dz-error-mark svg{display:block;width:54px;height:54px}.dropzone .dz-preview.dz-processing .dz-progress{opacity:1;-webkit-transition:all 0.2s linear;-moz-transition:all 0.2s linear;-ms-transition:all 0.2s linear;-o-transition:all 0.2s linear;transition:all 0.2s linear}.dropzone .dz-preview.dz-complete .dz-progress{opacity:0;-webkit-transition:opacity 0.4s ease-in;-moz-transition:opacity 0.4s ease-in;-ms-transition:opacity 0.4s ease-in;-o-transition:opacity 0.4s ease-in;transition:opacity 0.4s ease-in}.dropzone .dz-preview:not(.dz-processing) .dz-progress{-webkit-animation:pulse 6s ease infinite;-moz-animation:pulse 6s ease infinite;-ms-animation:pulse 6s ease infinite;-o-animation:pulse 6s ease infinite;animation:pulse 6s ease infinite}.dropzone .dz-preview .dz-progress{opacity:1;z-index:1000;pointer-events:none;position:absolute;height:16px;left:50%;top:50%;margin-top:-8px;width:80px;margin-left:-40px;background:rgba(255,255,255,.9);-webkit-transform:scale(1);border-radius:8px;overflow:hidden}.dropzone .dz-preview .dz-progress .dz-upload{background:#333;background:linear-gradient(to bottom, #666, #444);position:absolute;top:0;left:0;bottom:0;width:0;-webkit-transition:width 300ms ease-in-out;-moz-transition:width 300ms ease-in-out;-ms-transition:width 300ms ease-in-out;-o-transition:width 300ms ease-in-out;transition:width 300ms ease-in-out}.dropzone .dz-preview.dz-error .dz-error-message{display:block}.dropzone .dz-preview.dz-error:hover .dz-error-message{opacity:1;pointer-events:auto}.dropzone .dz-preview .dz-error-message{pointer-events:none;z-index:1000;position:absolute;display:block;display:none;opacity:0;-webkit-transition:opacity 0.3s ease;-moz-transition:opacity 0.3s ease;-ms-transition:opacity 0.3s ease;-o-transition:opacity 0.3s ease;transition:opacity 0.3s ease;border-radius:8px;font-size:13px;top:130px;left:-10px;width:140px;background:#be2626;background:linear-gradient(to bottom, #be2626, #a92222);padding:.5em 1.2em;color:#fff}.dropzone .dz-preview .dz-error-message:after{content:"";position:absolute;top:-6px;left:64px;width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #be2626}
+
+
+
+
+
+
+html {background: #ddd;}
+body { margin-top: 0em; }
+a {color: #0000ff;text-decoration: none;}
+a:hover {color: #ff0000;text-decoration: underline;}
+h1 {font-size: 182%;}
+h2 {font-size: 153.9%;}
+h3 {font-size: 123.1%;}
+.content { color: #000;background: #fff; border:1px solid black; border-radius: 0.5em; padding:1em; margin:1em; }
+.main-content { margin-top: -1.2em; padding-left:1.5em; }
+.headerimg { max-width:100%; margin: 2em auto 2em auto; display: block; }
+.staffpic { max-width:175px; height:auto; }
+.breadcrumb { font-size:85%; }
+.navigation { color: #3C7BCF;}
+.navigation ul { padding-inline-start: 0em; }
+.navigation li {list-style: none;margin-bottom: 0.5em;}
+.navigation li a {display: block;padding: 0.5em 0.5em;border-top: 1px solid #eee;border-left: 1px solid #eee;border-bottom: 1px solid #999;border-right: 1px solid #999;background-color: #E3E3E3;}
+.navigation li a:hover {background-color: #ffffff;}
+.footer {margin-top: 2.5em; margin-bottom:2.5em; text-align: center;font-size: 75%;}
+.footer a {text-decoration: none;color: #3C7BCF;}
+.spacer { display:none; }
+.report { margin-bottom:2em; }
+.day_title { margin: 0.5em 0 0.2em 0; font-weight:bold; font-size:110%; background:#ddd; padding:0.3em; }
+.exp_header { margin:0.3em 0em 0em 0em; }
+ a, .exp_header a:hover { color:#000; text-decoration:none; }
+.decorate { width:0.85em; display:inline-block; }
+.highlight { font-weight:bold; }
+
+h1.main_header {color: #A32638;margin-top: 0.9em;margin-bottom: 0.75em;padding-top: 0;text-align: left;
+ font-family: Verdana, Arial, Helvetica, sans-serif; font-size:140%;}
+div#gav_main_content li {margin-bottom: 1em;}
+.formpush { margin-left:11em; }
+.pure-form-aligned textarea { width: 90%; max-width: 33em; height: 10em; }
+.pure-form-aligned input[type=text] { width: 90%; max-width: 33em; }
+.pure-form-aligned select { width: 90%; max-width: 33em; }
+
+.form-control.pell { width:90%; max-width:33em; display:inline-block; }
+.pure-form-aligned .pure-control-group label { vertical-align: top; margin-top: 0.65em; }
+.pell { border: 1px solid #ccc; }
+.fake_pcg { margin-top:0px!important; display: inline-block; width: 100%; max-width: 33em; }
+
+.activitylist { margin-bottom:2em; }
+.activitylist a { text-decoration: underline; }
+.rhs_grey { display:inline-block; float:right; color:#aaa; font-size:0.8rem; }
+.controls { }
+.controls input[type=checkbox] { margin-left:1em; }
+.controls input[type=text] { border:1px solid grey; width:100%; }
+.controls h3 { font-size:100%; margin-bottom:6px; padding-top: 0.75em; padding-right: 1em; }
+.linky { font-weight:bold; color:blue; text-decoration:underline; }
+
+.itn_day {}
+.itn_item { background-color: #eeeeee42; margin: 0.2em 0 1em 0; padding: 0.75em 0 0.75em 0; }
+.itn_icon {}
+.itn_info {}
+.itn_title { display: block; margin-bottom:0.3em; }
+.itn_body { display: block; margin-bottom:0.3em; }
+.itn_foot { display: block; }
+.itn_controls {}
+.itn_now { color:#999; font-size:90%; font-weight:bold; padding: 0 0 1em 0; margin-top: -1em; }
+.actionicon { width: auto; height: 0.9rem; }
+
+
+.session-survey { margin-bottom:1.5em; }
+.question { display:block; margin-bottom:0.3em; }
+
+.even.pure-g { background-color: #ffdfff; }
+.even, .odd { min-height: 2.5em; padding: 2px; }
+.listing input, .listing select { width: 99%; }
+.listing input.double { width: 48%; }
+.listing input[type=checkbox] { width: initial; }
+.clicky { cursor:pointer; }
+.subtle { font-size:90%; line-height: 100%; color:grey; }
+.lighter { color:#676; }
+
+.list-editor input, .list-editor select { width:initial; margin-bottom:0.25em; }
+
+
+.pure-button-primary { }
+.btn_float { display: inline-block; }
+.btn_rhs { display: inline-block; float:right; }
+.btn_container { text-align: right; margin-top: -2em; margin-right: 7em; }
+.calendar td { width: 14%; vertical-align: top; height: 5.6rem; border: 1px solid #ffcdcd; padding:0.25em; }
+.calendar table { width: 100%; border-collapse: collapse; }
+.calendar thead { font-weight:bold; }
+.do_month { text-align: center; }
+.cal_evt { font-size: 80%; margin-top:0.4em; color:#333; }
+
+#alert { width:10em; max-width:50%; position:fixed; top:10px; left:50%; transform: translateX(-50%); padding:10px;
+ background-color: yellow; color: black; font-size: 16px; text-align:center; font-weight:bold; opacity:0.0; /* visibility:hidden; */ }
+.success { background-color: pink; padding: 0.5em; margin: 0.5em; /*visibility:hidden;*/ opacity:0.0; }
+
+
+.button-inlist { font-size: 90%; color: white; border-radius: 4px;
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); background: rgb(66, 184, 221);
+ padding: .25em 0.5em; line-height:200%; }
+.button-inlist-action { font-size: 90%; color: white; border-radius: 4px;
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); background: rgb(28, 184, 65);
+ padding: .25em 0.5em; line-height:200%; }
+.button-inlist:hover, .button-inlist-action:hover {color: white ;}
+.dup_line { background-color:yellow!important; }
+
+
+/* Tablets and smaller screens */
+@media only screen and (max-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) {
+ .main-content { margin-top: 0em; }
+}
+
+@media only screen and (max-width: 768px) {
+}
+
+@media only screen and (max-width: 640px) {
+ .navigation { position:fixed; display:block; width:100%; height:20%; left:0px; bottom:0px; background:#fff; border-top:1px solid grey; }
+ .navigation>a { display:none; }
+ .navigation ul { display:block; }
+ .navigation ul li { line-height:3em; width:30%; padding:0em; margin:0em; display:inline; border:0px solid white; }
+ .navigation ul li a { display:initial; }
+ .footer { display:none; }
+ .spacer { height:14em; display: block; }
+ .main-content { padding-left:0px; }
+ .pure-form .pure-u-1-6:first-child { display:none; }
+ .pure-u-19-24.main-content { width:100%; }
+}
+@media only screen and (max-width: 72em) {
+ .pure-form-aligned label { text-align: left!important; }
+ .pure-form-aligned input { }
+ .main-content { margin-top: 0.3em; /*padding-left:1.5em;*/ }
+}
+
+@media (max-width: 500px) {
+ .button-inlist, .button-inlist-action { font-size:75%; padding: 0.5em; }
+}
+
+
+
+.gavBlueText {color: #002868;}
+.gavRedText {color: #A32638;}
+.redText {color: #ff0000;}
+.greenText {color: #009900;}
+.blueText {color: #0000ff;}
+.yellowText {color: #ffff00;}
+.cyanText {color: #00ffff;}
+.magentaText {color: #ff00ff;}
+.whiteText {color: #fff;}
+.blackText {color: #000;}
+.whiteBkgd {background-color: #fff;}
+.blackBkgd {background-color: #000;}
+.greyBkgd {background-color: #ccc;}
+.lightGreyBkgd {background-color: #e9e9e9;}
+.gavRedBkgd {background-color: #A32638;}
+.gavBlueBkgd {background-color: #002868;}
+
+.overviewtable th.rotate {
+ /* Something you can count on */
+ height: 140px;
+ white-space: nowrap;
+}
+
+.overviewtable th.rotate > div {
+ transform:
+ /* Magic Numbers */
+ translate(5px, 57px)
+ /* 45 is really 360 - 45 */
+ rotate(315deg);
+ width: 30px;
+}
+.overviewtable th.rotate > div > span {
+ border-bottom: 1px solid #ccc;
+ padding: 5px 10px;
+}
+.overviewtable td {border: 1px solid lightgrey; }
diff --git a/default_welcome_letter.json b/default_welcome_letter.json
new file mode 100644
index 0000000..0e9d45b
--- /dev/null
+++ b/default_welcome_letter.json
@@ -0,0 +1,7 @@
+{ "what_expect": "sample text for what to expect ",
+ "assessments": "the assessments",
+ "textbook": "textbook or oei",
+ "other_info": "oi",
+ "introduction": "Introduction to this class",
+ "additional_resources": "Subsections like AEC, Tutoring/STEM/Academic Success/ Library Fresh success and more"
+}
\ No newline at end of file
diff --git a/dir.php b/dir.php
new file mode 100644
index 0000000..8463c2c
--- /dev/null
+++ b/dir.php
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+ Alert message
+
+
+
+
diff --git a/dir_api.20211021php b/dir_api.20211021php
new file mode 100644
index 0000000..2c7a13c
--- /dev/null
+++ b/dir_api.20211021php
@@ -0,0 +1,822 @@
+{$s}
\n"; }
+function p2($val){ echo ''; print_r($val); echo " \n"; }
+function d_err($s) { global $DEBUG; if ($DEBUG) { p($s); } }
+include('underscore.php');
+
+////////////////////
+////////////////////
+//
+// PHP SESSIONS .... needed?
+//
+
+/*
+header("Access-Control-Allow-Credentials: true");
+header("Access-Control-Allow-Methods: get,post");
+header("Access-Control-Allow-Headers: Content-Type, Accept");
+session_start();
+
+function logout() { session_destroy(); }
+*/
+
+
+////////////////////
+////////////////////
+//
+// DATABASE
+//
+// Yes, there's two different databases.
+//
+// $c = gavi_db
+// $c2 = PeterDB
+//
+// Why? Just to keep you on your toes.
+//
+// The $j argument is true for a json result, or false for a raw db object result.
+//
+
+
+$DBServer = 'localhost'; $DBUser = 'www';
+$DBPass = '@$df'; $DBName = 'gavi_db';
+
+$c = new mysqli($DBServer, $DBUser, $DBPass, $DBName);
+if ($c->connect_error) { die('Database connection failed: ' . $c->connect_error ); }
+if (!mysqli_select_db($c, $DBName)) { die("Uh oh, couldn't select database $DBName"); }
+
+$c2 = new mysqli($DBServer, "phowell", 'p^howell', 'PeterDB');
+if ($c2->connect_error) { die('Database connection failed: ' . $c2->connect_error ); }
+if (!mysqli_select_db($c2, 'PeterDB')) { die("Uh oh, couldn't select database 'PeterDB'"); }
+
+// Generic string cleaner
+function ok($str) { global $c; return mysqli_real_escape_string($c, strip_tags($str, '
')); }
+
+// 1. lookups, like a username
+function single_row_select($qry, $j=1, $c) {
+ $r = mysqli_query($c, $qry); d_err($qry);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ $a = mysqli_fetch_assoc($r);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ if (! $j) { return $a; } return json_encode($a); }
+
+// 1a. inserts
+function single_row_insert($qry, $j=1, $c) {
+ $r = mysqli_query($c, $qry); d_err($qry);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ $a = mysqli_fetch_assoc($c);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ if (! $j) { return $a; } return json_encode($a); }
+
+// 2. grid or fancier joins, like get all sessions, rosters, todos, etc
+function multi_row_select($qry, $j=1, $db) {
+ $rows = array();
+ $result = mysqli_query($db, $qry);
+ while($r = mysqli_fetch_assoc($result)) { $rows[] = $r; }
+ if (! $j) { return $rows; } return json_encode( $rows); }
+
+// 3. Check if an entry exists
+function does_exist($qry, $full_record=0, $db) { global $c, $c2;
+ $r = mysqli_query($db, $qry);
+ $a = mysqli_num_rows($r);
+ $row = mysqli_fetch_array($r, MYSQLI_NUM);
+ $id = $row[0]; // getting the id of that which exists... assuming first column has it.
+ d_err("does exist: {$a}");
+ $e = mysqli_error($db); if($e) { d_err("sql error: " . $e); }
+ if ($a && $full_record) { return $row; } if ($a) { return $id; } return 0; }
+
+
+
+////////////////////
+////////////////////
+//
+// SSO
+//
+// Set GLOBAL VARS corresponding to current logged in user.
+// They may only edit their own dir info.
+//
+
+
+$server = $_SERVER['SERVER_NAME'];
+
+
+if ( preg_match('/intranet1/', $server )) {
+
+ require 'mAuth.php';
+
+ $USER_TYPE = $attributes['http://wso2.org/claims/Roles'][0];
+ $USER_GOO = $attributes['http://wso2.org/claims/uid'][0];
+ $USER_EMAIL = strtolower($attributes['http://wso2.org/claims/emailaddress'][0]);
+
+ /*$USER_TYPE = "FACULTY"; //$attributes['http://wso2.org/claims/Roles'][0];
+ $USER_GOO = "G00102586"; //$attributes['http://wso2.org/claims/uid'][0];
+ $USER_EMAIL = "phowell@gavilan.edu"; //$attributes['http://wso2.org/claims/emailaddress'][0];
+
+ $status = "ID: {$USER_GOO} ";
+ $status .= "Email: {$USER_EMAIL} ";
+ $status .= "Employee type: {$USER_TYPE} ";
+
+ d_err($status); */
+} else {
+ echo json_encode( array("result"=>"not on intranet1") );
+ //exit();
+
+ $USER = 0;
+ $USER_NAME = 0;
+ $USER_PERS_ID = 0;
+ $USER_CONF_U_ID = 0;
+ $USER_PERS_EXT_ID = 0;
+
+}
+
+
+
+// Current academic year
+$AY = single_row_select("SELECT * FROM conf_academicyears WHERE label='2021-2022';",0, $c2);
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// Fetching a person's records
+//
+// 1. use their email to lookup PERSONNEL
+// - basic directory info
+//
+// 2. use their email to lookup CONF_USERS
+// - flex app, workshop signups
+//
+// 3. use conf_users.id to lookup in gavi_personnel_ext.c_users
+// - goo, depts, job title, image active
+//
+// 4. use personnel.id to lookup [webpages, welcomepages, etc]
+
+
+function user_record() { global $USER, $USER_EMAIL, $USER_NAME, $USER_PERS_ID, $USER_CONF_U_ID, $USER_PERS_EXT_ID, $c, $c2;
+ $q1 = "SELECT last_name, first_name, department, extension, phone_number, LOWER(email) AS email, room, user_id, time_updated, id, web_on FROM personnel WHERE email='" . $USER_EMAIL . "'";
+ //p2($q1);
+ $usr_dir = single_row_select($q1, 0, $c);
+ //p2($usr_dir);
+
+ $q2 = "SELECT id AS id_c_users, goo, LOWER(email) AS email_c_users, name, active FROM conf_users WHERE LOWER(email)='" . $USER_EMAIL . "'";
+ //p2($q2);
+ $usr_conf = single_row_select($q2, 0, $c2);
+ //p2($usr_conf);
+ $mega = __::extend( (object) $usr_dir, (object) $usr_conf );
+
+ $q3 = 'SELECT id AS ext_id, personnel AS personnel_id, role, goo_short, c_users AS c_users_id_ext, ilearn_id, sched_alias, dept1, dept2, gtitle, active, use_dir_photo, general_photo_release, etc FROM gavi_personnel_ext WHERE c_users=' . $mega->id_c_users;
+ //p2($q3);
+ $usr_ext = single_row_select($q3,0,$c2);
+ //p2($usr_ext);
+ $mega = __::extend( (object) $mega, (object) $usr_ext );
+
+ $q4 = 'SELECT person, officehours, title, picture, education, bio, courses, personal_page, changed FROM webpages WHERE person=' . $mega->id; // personnel=1');
+ //p2($q3);
+ $usr_web = single_row_select($q4,0,$c);
+ //p2($usr_ext);
+ $mega = __::extend( (object) $mega, (object) $usr_web );
+
+ $USER = $mega;
+}
+
+
+if ($USER_EMAIL) { user_record(); }
+
+
+
+
+// //
+// //
+// // LOG ENTRIES
+// //
+// //
+
+
+
+// Enter or get browser log entry
+function insert_or_get_browser($b) {
+ global $c2;
+ $BROWSER = ok($b);
+ $existing = does_exist( "SELECT id FROM www_browsers WHERE string='$BROWSER'", 0, $c2);
+ if ($existing) {
+ return $existing;
+ } else {
+ $q = "INSERT INTO www_browsers (string) VALUES ('$BROWSER')";
+ single_row_select($q,0,$c2);
+ return does_exist( "SELECT id FROM www_browsers WHERE string='$BROWSER'",0,$c2);
+ }
+ return 0; }
+
+
+// Log everything!
+function log_it($action,$extra='') {
+ global $USER, $c2;
+
+ if (! $USER) {
+ $USER = array( 'name'=>'unknown', 'id'=>-1 ); }
+ $user_browser = $_SERVER['HTTP_USER_AGENT'];
+ $user_ip = $_SERVER['REMOTE_ADDR'];
+
+ $BROWSER = insert_or_get_browser($user_browser);
+ $ACTION = ok($action);
+ $EXTRA = ok($extra);
+
+ //$id = ok($_POST['id']);
+ $qupdate = "INSERT INTO gavi_logs SET action='{$action}', personnel_id='{$USER->id}', name='{$USER->name}', extra='{$EXTRA}', browser=$BROWSER, ip='$user_ip'";
+ single_row_select($qupdate,0,$c2);
+ return array("result"=>"success","action"=>"logged","query"=>$qupdate,"err"=>mysqli_error($c2));
+}
+
+
+
+
+
+function unescape_commas($s) { return preg_replace('/\[CMA\]/', ',', $s); }
+
+function name_to_lc($fn,$ln) {
+ $fn = str_replace( array( '-', ' '), '', strtolower($fn) );
+ $ln = str_replace( array( '-', ' '), '', strtolower($ln) );
+ return $fn . "_" . $ln;
+}
+function name_to_file($fn,$ln) {
+ $fn = str_replace( array( '-', ' '), '', strtolower($fn) );
+ $ln = str_replace( array( '-', ' '), '', strtolower($ln) );
+ return $fn . "_" . $ln . ".jpg";
+}
+
+function check_dir_photo($fn,$ln) { global $USER;
+ $filename = name_to_file( $fn,$ln );
+ $path = '/gavilan.edu/staff/images_sm/' . $filename;
+ $dir_pic_exists = 0;
+ $dir_pic_path = 'images_sm/nobody.jpg';
+
+ if (file_exists($path)) {
+ $dir_pic_exists = 1;
+ $dir_pic_path = 'images_sm/' . $filename; }
+ $USER->dir_pic_exists = $dir_pic_exists;
+ $USER->dir_pic_path = $dir_pic_path;
+ return $dir_pic_exists;
+}
+
+check_dir_photo($USER->first_name, $USER->last_name);
+
+//
+//
+//
+////////////////////
+////////////////////
+
+
+
+//require __DIR__ . '/vendor/autoload.php';
+
+
+
+
+// Sample URL
+//
+// https://www.gavilan.edu/staff/dir_api.php?a=update&cols=name,msg&vals=peter,hello
+//
+// https://intranet1.gavilan.edu/dir/dir_api.php?a=update&cols=name,msg&vals=peter,hello
+
+
+
+
+
+/*
+
+
+NEXT STEPS:
+
+- figure out permissions system
+
+ - which means knowing dept / hierarchy
+
+ - which means cross referencing PERSONNEL and EXT and CONF_USERS.....
+
+
+
+## Permissions summary
+
+0. There is a list of table+column combos that users are allowed to edit.
+0.5 An activity "belongs" to the user who owns it (or created it).
+
+1. Simple cases:
+ - current user is updating their own (allowable) record. Allow.
+2. Superuser:
+ - current user is executive, hr, it, or root. (7,2,8,3) Allow.
+3. User is "Dept Editor" (4) and
+ -is updating a record belonging to someone in their dept. Allow.
+4. Harder: Updating events
+
+5. Updating attendance, approvals, or other restricted tables. Only FPLC (1) or superusers.
+
+*/
+
+
+function check_permission( $acting_user, $target_user, $table ) {
+
+ // TODO
+ return true;
+}
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Everyone. Basic dir. Include status==0 which is unpublished.
+function staff_dir() { global $c;
+ return multi_row_select('SELECT first_name,last_name,department,status, room,phone_number,email,web_on,id FROM personnel',1, $c);
+ // WHERE status IS null OR status=1
+}
+
+
+// Everyone. Basic dir
+function staff_dir_ext() { global $c;
+ //return multi_row_select('SELECT p.first_name,p.last_name,p.department,p.status, p.room,phone_number,p.email,p.web_on, p.id, e.id AS ext_id, e.role, e.goo_short, e.c_users AS c_users_id_ext, e.ilearn_id, e.sched_alias, e.dept1, e.dept2, e.gtitle, e.active, e.use_dir_photo, e.general_photo_release, e.dir_photo_path, e.etc FROM gavi_db.personnel p LEFT JOIN PeterDB.gavi_personnel_ext e ON p.id=e.personnel ORDER BY p.last_name LIMIT 5000',1, $c);
+
+ return multi_row_select('SELECT p.first_name,p.last_name,p.department,p.status, p.room,phone_number,p.email,p.web_on, p.id, e.id AS ext_id, e.role, e.goo_short, e.c_users AS c_users_id_ext, e.ilearn_id, e.sched_alias, e.dept1, e.dept2, e.gtitle, e.active, e.use_dir_photo, e.general_photo_release, e.dir_photo_path, e.etc, c.id AS conf_id, c.goo AS conf_goo, c.name AS conf_name FROM gavi_db.personnel p LEFT JOIN PeterDB.gavi_personnel_ext e ON p.id=e.personnel LEFT JOIN PeterDB.conf_users c ON LOWER(p.email)=LOWER(c.email) ORDER BY p.last_name LIMIT 5000',1, $c);
+ // WHERE p.status IS null OR p.status=1
+}
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='list') {
+ echo staff_dir_ext(); exit(); }
+
+
+// TODO what about people who don't have all three rows?
+//
+//
+
+//
+//
+//
+//
+//
+// Helper tables
+function sub_menus() { global $c2;
+ $ddd = multi_row_select('SELECT * FROM gavi_departments ORDER BY name',0, $c2);
+ $ttt = multi_row_select('SELECT * FROM gavi_titles ORDER BY name',0, $c2);
+ $rrr = multi_row_select("SELECT * FROM gavi_roles ORDER BY 'descr'",0, $c2);
+ $ccc = multi_row_select('SELECT * FROM gavi_committees ORDER BY name',0, $c2);
+
+ return json_encode( array( 'departments'=>$ddd, 'titles'=>$ttt, 'roles'=>$rrr, 'committees'=>$ccc ) );
+ exit();
+}
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='menus') {
+ echo sub_menus(); exit(); }
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// GET LIST OF ALL SESSIONS / WORKSHOPS / EVENTS
+//
+function get_sessions() {
+ global $c2, $AY;
+ echo json_encode( multi_row_select("SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,c.cal_uid,sst.type,sst.id AS typeId, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE c.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME) GROUP BY c.id ORDER BY c.track, c.starttime;",0, $c2)); exit(); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/sessions') { get_sessions(); }
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// LIST THE CURRENT USER'S SIGNED UP, (OR HOSTING,) SESSIONS / WORKSHOPS / EVENTS
+//
+function get_user_sessions() {
+ global $c2, $AY, $USER;
+ $my_sessions = multi_row_select("SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,sst.type,sst.id AS typeId, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c JOIN conf_signups as sup on c.id=sup.session JOIN conf_hosts as h ON h.session=c.id JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE (h.host='{$USER->id_c_users}' OR sup.user='{$USER->id_c_users}') AND c.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME) GROUP BY c.id ORDER BY c.track, c.starttime;",0,$c2);
+ echo json_encode($my_sessions);
+ exit(); }
+if (isset($_GET['a']) && $_GET['a'] == 'get/mysessions') { get_user_sessions(); }
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// SIGNUP for (possibly overlapping time) session ...
+//
+function signup() {
+ global $c2, $AY, $USER;
+ preg_match('/signup\/(\d+)$/', $_GET['a'], $matches);
+ $ses = $matches[1];
+ $ts = date("Y-m-d H:i:s");
+ $logaction = log_it("Signed up for session: {$ses}");
+
+ $existing = does_exist(
+ "SELECT i.id FROM conf_signups AS i JOIN conf_sessions AS s ON i.session=s.id WHERE s.id={$ses} AND i.user={$USER->id_c_users}",0,$c2);
+ if ($existing) {
+ $qupdate = "UPDATE conf_signups SET session={$ses}, timestamp='{$ts}' WHERE session={$ses} AND user={$USER->id_c_users}";
+ single_row_select($qupdate,1,$c2);
+ echo json_encode( array("result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$qupdate,"err"=>mysqli_error($c2)));
+ } else {
+ $q = "INSERT INTO conf_signups (session,user,timestamp) VALUES ({$ses},{$USER->id_c_users},'{$ts}')";
+ single_row_select($q,1,$c2);
+ echo json_encode( array("result"=>"success","action"=>"inserted","logaction"=>$logaction, "ses"=>$_SESSION,"query"=>$q,"err"=>mysqli_error($c2)));
+ } exit(); }
+
+if (isset($_GET['a']) && preg_match('/signup\/(\d+)$/', $_GET['a'], $matches)) { signup(); }
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// CANCEL a signup
+//
+function signdown() {
+ global $c2, $AY, $USER;
+ preg_match('/signdown\/(\d+)$/', $_GET['a'], $matches);
+ $ses = $matches[1];
+ $q = "DELETE FROM conf_signups WHERE session={$ses} AND user={$USER->id_c_users}";
+ single_row_select($q,1,$c2);
+ $logaction = log_it("Canceled signup for session: $ses");
+
+ echo json_encode( array("result"=>"success","action"=>"deleted","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ exit(); }
+
+if (isset($_GET['a']) && preg_match('/signdown\/(\d+)$/', $_GET['a'], $matches)) { signdown(); }
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// NEW SESSION
+//
+function new_session() {
+ global $c2, $AY, $USER;
+
+
+ $title = ok($_POST['title']); $starttime = ok($_POST['starttime']);
+ $length = ok($_POST['length']); if ($length=='') { $length=1; }
+ $track = ok($_POST['track']); $gets_survey = ok($_POST['gets_survey']);
+ $is_flex_approved = ok($_POST['is_flex_approved']); $category = ok($_POST['title']);
+ if ($category=='') { $category=0; }
+ $author = ok($_POST['author']); if ($author=='') { $author=1; } // $USER->id_c_users; }
+ $is_custom = ok($_POST['is_custom']); $parent = ok($_POST['parent']);
+ $desc = ok($_POST['desc']); $location = ok($_POST['location']);
+ $recording = ok($_POST['recording']); $instructions = ok($_POST['instructions']);
+ $type = ok($_POST['type']); if ($type=='') { $type=19; }
+ $cal_uid = ok($_POST['cal_uid']);
+
+
+ $q = "INSERT INTO conf_sessions (`title`,`starttime`,`length`,`track`,`gets_survey`,`is_flex_approved`,`category`,`author`,`is_custom`,`parent`,`desc`,`location`,`recording`,`instructions`,`type`,`cal_uid`) VALUES ('{$title}', '{$starttime}', '{$length}', '{$track}', '{$gets_survey}', '{$is_flex_approved}', '{$category}', '{$author}', '{$is_custom}', '{$parent}', '{$desc}', '{$location}', '{$recording}', '{$instructions}', '{$type}', '{$cal_uid}');";
+ $ins = single_row_insert($q,0,$c2);
+ $logaction = log_it("created new session: {$title}");
+ echo json_encode( array("result"=>"success","action"=>"inserted new session","insert"=>$ins, "query"=>$q,"logaction"=>$logaction,"err"=>mysqli_error($c2)));
+ exit(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='set/newsession') { new_session(); }
+
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Editing of session info
+//
+function set_sessioninfo() {
+ global $c, $c2, $AY, $USER;
+ $table = 'conf_sessions';
+
+ if (isset($_POST['id'])) {
+ $ID = ok($_REQUEST['id']);
+ if (! check_permission( $USER->id, $ID, $table)) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("edited session id: {$ID}");
+ $WHERECLAUSE = " WHERE id={$ID}";
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, "UPDATE {$table} SET ");
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+ single_row_select($q,0,$c1);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ }
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"no activity id specified") ); }
+ exit();
+}
+
+
+
+ /*$title = ok($_POST['title']);
+ $desc = ok($_POST['desc']);
+ $location = ok($_POST['location']);
+ $recording = ok($_POST['recording']);
+ $instructions = ok($_POST['instructions']);
+ $id = ok($_POST['id']);
+ $qupdate = "UPDATE conf_sessions SET title='$title', `desc`='$desc', location='$location', recording='$recording', instructions='$instructions' WHERE id=$id";
+ single_row_select($qupdate,0,$c2);
+ $logaction = log_it("edited session id: {$id}");
+ echo json_encode( array("result"=>"success","action"=>"updated","logaction"=>$logaction,"query"=>$qupdate,"err"=>mysqli_error($c2)));
+ //print_r($_POST);
+ exit();}
+ */
+
+//if (isset($_POST['a']) && $_POST['a']=='update/activity') { set_sessioninfo(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update/activity') { set_sessioninfo(); }
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update a name, lname, dept, phone, extension, email, type, room, status, user_id, or web_on
+function update_dir() {
+ global $USER, $c, $c2;
+
+ $WHERECLAUSE = " WHERE id={$USER->id}";
+
+ if (isset($_POST['id'])) { // editing another person's data
+ if (! check_permission( $USER->id, $_POST['id'], 'personnel')) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("updating personnel record of personnel id {$_POST['id']}");
+ $WHERECLAUSE = " WHERE id={$_POST['id']}";
+ }
+ } else {
+ $logaction = log_it("updating personnel record");
+ }
+
+ // date modified is now
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, "UPDATE personnel SET ");
+ //$q = substr($q, 0, -2);
+ $q .= "time_updated='" . $date . "'";
+ $q .= $WHERECLAUSE;
+ if ($USER->id) {
+ single_row_select($q,0,$c);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c)));
+ }
+ else {
+ $logaction2 = log_it("failed to update personnel record");
+ echo json_encode( array("result"=>"fail", "err"=>"dont have an id for user") );
+ }
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update') { update_dir(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update') { update_dir(); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update goo, dept1/dept2, title, active, use_dir_photo
+function update_dir_ext() {
+ global $USER, $c, $c2;
+
+ $WHERECLAUSE = " WHERE id={$USER->ext_id}";
+
+ if (isset($_POST['id'])) { // editing another person's data
+ if (! check_permission( $USER->id, $_POST['id'], 'personnel')) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("updating personnel_ext record of personnel id {$_POST['id']}");
+ $WHERECLAUSE = " WHERE id={$_POST['id']}";
+ }
+ } else {
+ $logaction = log_it("updating personnel_ext record");
+ }
+
+ // date modified is now
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, "UPDATE gavi_personnel_ext SET ");
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+ if ($USER->ext_id) {
+ single_row_select($q,0,$c2);
+ echo json_encode( array("result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ }
+ else {
+ $logaction2 = log_it("failed to update gavi_personnel_ext record. dont have id for user.",var_dump($USER) );
+ echo json_encode( array("result"=>"fail", "err"=>"dont have an id for user") );
+ }
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update_xt') { update_dir_ext(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update_xt') { update_dir_ext(); }
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update person, officehours, title, picture, education, bio, courses, personal_page, changed
+function update_webpage() {
+ global $USER_PERS_ID, $USER, $c, $c2;
+
+ $WHERECLAUSE = " WHERE person={$USER->id}";
+
+ if (isset($_POST['id'])) { // editing another person's data
+ if (! check_permission( $USER->id, $_POST['id'], 'personnel')) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("updating bio webpage record of personnel id {$_POST['id']}");
+ $WHERECLAUSE = " WHERE person={$_POST['id']}";
+ }
+ } else {
+ $logaction = log_it("updating bio webpage record");
+ }
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, "UPDATE webpages SET ");
+ $q .= "changed='" . $date . "'";
+ $q .= $WHERECLAUSE;
+ if ($USER->id) {
+ single_row_select($q,0,$c);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c)));
+ }
+ else {
+ $logaction2 = log_it("failed to update bio webpage record");
+ echo json_encode( array("result"=>"fail", "err"=>"dont have an id for user") );
+ }
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update_web') { update_webpage(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update_web') { update_webpage(); }
+
+
+
+
+
+
+
+
+function handle_pic_upload() { global $USER;
+ $uploaddir = '/gavilan.edu/staff/uploads/';
+ $date = date('Ymd_Hi');
+ $uploadfile = $uploaddir . name_to_lc($USER->first_name,$USER->last_name) . "_" . $date . "_" . basename($_FILES['file']['name']);
+
+
+ echo '';
+ if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) {
+ echo "File is valid, and was successfully uploaded.\n";
+ } else {
+ echo "Possible file upload attack!\n";
+ }
+
+ echo 'Here is some more debugging info:';
+ print_r($_FILES);
+
+ print " ";
+
+}
+//if (isset($_POST['a']) && $_POST['a']=='update_web') { update_webpage(); }
+//if (isset($_REQUEST['file'])) { handle_pic_upload(); }
+if (isset($_FILES['file'])) { handle_pic_upload(); }
+
+
+
+
+
+
+function get_a_user($user_email) { global $c, $c2;
+ $q1 = "SELECT last_name, first_name, department, extension, phone_number, email, room, user_id, time_updated, id, web_on FROM personnel WHERE email='" . $user_email . "'";
+ //p2($q1);
+ $usr_dir = single_row_select($q1, 0, $c);
+ //p2($usr_dir);
+
+ $q2 = "SELECT id AS id_c_users, goo, email AS email_c_users, name, active FROM conf_users WHERE email='" . $user_email . "'";
+ //p2($q2);
+ $usr_conf = single_row_select($q2, 0, $c2);
+ //p2($usr_conf);
+ $mega = __::extend( (object) $usr_dir, (object) $usr_conf );
+
+ $q3 = 'SELECT id AS ext_id, personnel AS personnel_id, goo_short, c_users AS c_users_id_ext, ilearn_id, sched_alias, dept1, dept2, title, active, use_dir_photo, etc FROM gavi_personnel_ext WHERE personnel=' . $mega->id;
+ //p2($q3);
+ $usr_ext = single_row_select($q3,0,$c2);
+ //p2($usr_ext);
+ $mega = __::extend( (object) $mega, (object) $usr_ext );
+
+ $q4 = 'SELECT person, officehours, title, picture, education, bio, courses, personal_page, changed FROM webpages WHERE person=' . $mega->id; // personnel=1');
+ //p2($q3);
+ $usr_web = single_row_select($q4,0,$c);
+ //p2($usr_ext);
+ $mega = __::extend( (object) $mega, (object) $usr_web );
+
+ if (!isset($mega->use_dir_photo)) {
+ $mega->pic_exists = check_dir_photo($mega->first_name, $mega->last_name);
+ if ($mega->pic_exists) {
+ $filename = "images_sm/" . name_to_file( $mega->first_name, $mega->last_name );
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=1, dir_photo_path='{$filename}' WHERE id='{$mega->ext_id}'";
+ } else {
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=0 WHERE id='{$mega->ext_id}'";
+ }
+ }
+ if (! isset($mega->ext_id)) {
+ $mega->aaqueryfix = "INSERT INTO gavi_personnel_ext (personnel) VALUES('{$mega->id}')"; }
+ elseif ($mega->id && ! $mega->personnel_id) {
+ $mega->aaqueryfix = "UPDATE gavi_personnel_ext SET personnel='{$mega->id}' WHERE id='{$mega->ext_id}'"; }
+
+ return $mega;
+
+}
+
+
+function insert_c2($q) {
+ global $c2;
+ $result = single_row_insert($q,0,$c2);
+ return $result; }
+
+function merge_tables() { global $c;
+ $all_personnel = multi_row_select('SELECT first_name,last_name,department,room,phone_number,email,web_on,id FROM personnel WHERE status IS null OR status=1',0, $c);
+
+ $emails = __::pluck($all_personnel, 'email');
+ //echo json_encode($emails);
+ //exit();
+
+ //$emails = array_slice($emails, 0, 10);
+
+ $full = __::map( $emails, get_a_user );
+
+ //echo json_encode($full);
+
+ //$results = __::map( __::pluck($full,'aaqueryfix'), insert_c2);
+
+ //$results = __::pluck($full,'bbqueryfix');
+ //$results = __::map( $results, insert_c2);
+ echo json_encode( $full );
+ exit();
+
+}
+
+if (isset($_REQUEST['merge'])) { merge_tables(); }
+
+
+
+
+
+//echo json_encode($_FILES);
+
+//echo json_encode($_REQUEST);
+
+
+// If no arguments were given:
+
+
+if ($USER_EMAIL) {
+// log it as an access
+ $logaction = log_it("accessed personnel record editor");
+
+ $USER->logresult = $logaction;
+
+ // Default case is current user data to be embedded in editor page
+ echo json_encode($USER);
+} else {
+ echo json_encode( array("result"=>"not logged in") );
+ exit();
+}
+?>
diff --git a/dir_api.php b/dir_api.php
new file mode 100644
index 0000000..f750773
--- /dev/null
+++ b/dir_api.php
@@ -0,0 +1,1765 @@
+connect_error) { die('Database connection failed: ' . $c->connect_error ); }
+if (!mysqli_select_db($c, $DBName)) { die("Uh oh, couldn't select database $DBName"); }
+
+$c2 = new mysqli($DBServer, $DBUser2, $DBPass2, $DBName2);
+if ($c2->connect_error) { die('Database connection failed: ' . $c2->connect_error ); }
+if (!mysqli_select_db($c2, $DBName2)) { die("Uh oh, couldn't select database 'PeterDB'"); }
+mysqli_set_charset($c, 'utf8');
+mysqli_set_charset($c2, 'utf8');
+
+include('underscore.php');
+$_ = new __();
+
+// _ _
+// | | | |
+// | |__ ___| |_ __ ___ _ __ ___
+// | '_ \ / _ \ | '_ \ / _ \ '__/ __|
+// | | | | __/ | |_) | __/ | \__ \
+// |_| |_|\___|_| .__/ \___|_| |___/
+// | |
+// |_|
+
+// Generic string cleaner
+// keep HTML tags string cleaner
+
+function ok($str) { global $c; return mysqli_real_escape_string($c, strip_tags($str, '
')); }
+function okh($str) { global $c; return mysqli_real_escape_string($c, $str); }
+function unescape_commas($s) { return preg_replace('/\[CMA\]/', ',', $s); }
+
+function p($s) { echo "{$s}
\n"; }
+function p2($val){ echo ''; print_r($val); echo " \n"; }
+function d_err($s) { global $DEBUG; if ($DEBUG) { p($s); } }
+function logout() { session_destroy(); }
+
+// Some helpful globals
+
+$server = $_SERVER['SERVER_NAME'];
+$options_query = "SELECT label,value FROM `conf_uinforecord` WHERE id>1";
+$options_array = multi_row_select($options_query, 0, $c2);
+
+$OPTIONS = array_reduce($options_array, function ($result, $item) {
+ $result[$item["label"]] = $item["value"];
+ return $result; }, []);
+
+$default_ay_query = "SELECT begin,end FROM conf_academicyears ca JOIN conf_uinforecord cu ON cu.value=ca.id WHERE cu.label='default_ay';";
+$AY = single_row_select($default_ay_query,0, $c2);
+$OPTIONS['year'] = $AY;
+
+$conf_query = "SELECT semester,date1,date2,title FROM conf_conferences cc JOIN conf_uinforecord cu ON cu.value=cc.id WHERE cu.label='default_conference';";
+$CONF = single_row_select($conf_query,0, $c2);
+$OPTIONS['conf'] = $CONF;
+
+
+function name_to_lc($fn,$ln) {
+ $fn = str_replace( array( '-', ' '), '', strtolower($fn) );
+ $ln = str_replace( array( '-', ' '), '', strtolower($ln) );
+ return $fn . "_" . $ln; }
+
+function name_to_file($fn,$ln) {
+ $fn = str_replace( array( '-', ' '), '', strtolower($fn) );
+ $ln = str_replace( array( '-', ' '), '', strtolower($ln) );
+ return $fn . "_" . $ln . ".jpg"; }
+
+
+// 1. lookups, like a username
+function single_row_select($qry, $j, $c) {
+ $r = mysqli_query($c, $qry); d_err($qry);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ if (!$r) { return $r; }
+ //echo("\n\n\n");
+ $a = mysqli_fetch_assoc($r);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ if (! $j) { return $a; } return json_encode($a); }
+
+// 1a. inserts
+function single_row_insert($qry, $j, $c) {
+ $r = mysqli_query($c, $qry);
+ //d_err($qry);
+ //$e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ $new_id = mysqli_insert_id($c);
+ return $new_id; }
+
+ /*$a = mysqli_fetch_assoc($c);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ if (! $j) { return $a; } return json_encode($a); } */
+
+// 1b. updates
+function single_row_update($qry, $j, $c) {
+ $r = mysqli_query($c, $qry);
+ return 1; }
+
+// 2. grid or fancier joins, like get all sessions, rosters, todos, etc
+function multi_row_select($qry, $j, $db) {
+ $rows = array();
+ $result = mysqli_query($db, $qry);
+ while($r = mysqli_fetch_assoc($result)) { $rows[] = $r; }
+ if (! $j) { return $rows; } return json_encode( $rows); }
+
+// 3. Check if an entry exists
+function does_exist($qry, $full_record, $db) { global $c, $c2;
+ $r = mysqli_query($db, $qry);
+ $a = mysqli_num_rows($r);
+ if (! $a ) { return 0; }
+ $row = mysqli_fetch_array($r, MYSQLI_NUM);
+ $id = $row[0]; // getting the id of that which exists... assuming first column has it.
+ $e = mysqli_error($db); if($e) { d_err("sql error: " . $e); }
+ if ($a && $full_record) { return $row; } if ($a) { return $id; } return 0; }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// //
+// // LOG ENTRIES
+// //
+// // Enter or get browser log entry
+function insert_or_get_browser($b) {
+ global $c2;
+ $BROWSER = ok($b);
+ $existing = does_exist( "SELECT id FROM www_browsers WHERE string='$BROWSER'", 0, $c2);
+ if ($existing) { return $existing;
+ } else {
+ $q = "INSERT INTO www_browsers (string) VALUES ('$BROWSER')";
+ single_row_insert($q,0,$c2);
+ return does_exist( "SELECT id FROM www_browsers WHERE string='$BROWSER'",0,$c2); } }
+
+function dumpit($var) {
+ ob_start();
+ var_dump($var);
+ $a=ob_get_contents();
+ ob_end_clean();
+ return $a;
+}
+// //
+// // Log everything!
+function log_it($action) {
+ global $USER, $USER_GOO, $USER_EMAIL, $c2;
+ //echo("\n\n\n");
+
+ if (! $USER) {
+ $USER = array( 'user_id'=>'unknown', 'id'=>-1 ); }
+ $user_browser = $_SERVER['HTTP_USER_AGENT'];
+ $user_ip = $_SERVER['REMOTE_ADDR'];
+
+ $BROWSER = insert_or_get_browser($user_browser);
+ $ACTION = ok($action) . " / " . dumpit($USER) . " / " . $USER_GOO . " / " . $USER_EMAIL;
+
+ //$persid = $USER->id;
+ //if (! $persid) { $persid = -1; }
+ $qupdate = "INSERT INTO gavi_logs SET action='{$ACTION}', " /*personnel_id='{$persid}',name='{$USER->user_id}', */ . "browser=$BROWSER, ip='$user_ip'";
+ single_row_insert($qupdate,0,$c2);
+ return array("result"=>"success","action"=>"logged","query"=>$qupdate,"err"=>mysqli_error($c2)); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Look in various folders for STAFF PICTURES
+function user_pic_look($first,$last,$g) {
+
+ $images = array();
+ $images[] = 'images_sm/missing.jpg';
+
+ $sm_exists = file_exists("/gavilan.edu/staff/images_sm");
+ $goo_exists = file_exists("/gavilan.edu/staff/images_goo");
+
+ if ($sm_exists && $goo_exists) {
+
+ $name_name = str_replace(' ','',str_replace('-','', strtolower($first) )) . "_" . str_replace(' ','',str_replace('-','', strtolower($last) ));
+ $name_name1 = $name_name . ".jpg";
+ $name_name2 = $name_name . "2" . ".jpg";
+ $name_name3 = $name_name . "3" . ".jpg";
+ $name_name4 = $name_name . "4" . ".jpg";
+
+ $name_dir = scandir("/gavilan.edu/staff/images_sm");
+ if ($name_dir && in_array($name_name1,$name_dir)) { $images[] = 'images_sm/' . $name_name1; }
+ if ($name_dir && in_array($name_name2,$name_dir)) { $images[] = 'images_sm/' . $name_name2; }
+ if ($name_dir && in_array($name_name3,$name_dir)) { $images[] = 'images_sm/' . $name_name3; }
+ if ($name_dir && in_array($name_name4,$name_dir)) { $images[] = 'images_sm/' . $name_name4; }
+
+ $badge_dir = scandir("/gavilan.edu/staff/images_goo");
+ $badge_name = $g . ".jpg";
+ if ($badge_dir && in_array($badge_name,$badge_dir)) { $images[] = 'images_goo/' . $badge_name; }
+ }
+ return $images; }
+
+
+//
+// Photos stuff. This shouldn't be needed anymore since we store pic path in the database.
+//
+function check_dir_photo($fn,$ln) { global $USER;
+ $filename = name_to_file( $fn,$ln );
+ $path = '/gavilan.edu/staff/images_sm/' . $filename;
+ $dir_pic_exists = 0;
+ $dir_pic_path = 'images_sm/nobody.jpg';
+
+ if (file_exists($path)) {
+ $dir_pic_exists = 1;
+ $dir_pic_path = 'images_sm/' . $filename; }
+ $USER->dir_pic_exists = $dir_pic_exists;
+ $USER->dir_pic_path = $dir_pic_path;
+ return $dir_pic_exists; }
+
+
+
+/////
+/////
+//
+// Insert new user
+//
+// For whatever reason, we haven't seen this person before. Insert their conf_user row
+// so they can have their choices recorded.
+//
+function insert_new_user() { global $USER, $USER_EMAIL, $USER_GOO, $USER_NAME, $USER_PERS_ID, $USER_CONF_U_ID, $USER_PERS_EXT_ID, $c, $c2;
+ $LC_EMAIL = strtolower($USER_EMAIL);
+ single_row_insert("INSERT INTO conf_users (goo, email, name) VALUES ('{$USER_GOO}','{$LC_EMAIL}','{$USER_NAME}');", 1, $c2);
+ $logaction = log_it("Made a new conf_users row for {$USER_NAME} / {$LC_EMAIL} / {$USER_GOO}");
+}
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Fetching a person's records
+//
+// 1. use their email to lookup PERSONNEL
+// - basic directory info
+//
+// 2. use their email to lookup CONF_USERS
+// - flex app, workshop signups
+//
+// 3. use conf_users.id to lookup in gavi_personnel_ext.c_users
+// - goo, depts, job title, image active
+//
+// 4. use personnel.id to lookup [webpages, welcomepages, etc]
+//
+//
+// Ultimately the user's data goes into the global $USER
+
+function user_record() { global $USER, $USER_EMAIL, $USER_GOO, $USER_NAME, $USER_PERS_ID, $USER_CONF_U_ID, $USER_PERS_EXT_ID, $c, $c2;
+ $LC_EMAIL = strtolower($USER_EMAIL);
+
+ if (! $USER_EMAIL) {
+ $goo = substr($USER_GOO, 3);
+ $q0 = "SELECT email FROM conf_users WHERE goo='{$goo}'";
+ $temp_usr = single_row_select($q0,0,$c2);
+
+ if (is_null($temp_usr)) {
+ // we have a new user here...
+ // and the missing email might be a problem....
+ insert_new_user();
+ }
+ //echo($goo);
+ //print_r($temp_usr);
+ //echo($temp_usr->email);
+ //echo("\n");
+ $LC_EMAIL = strtolower($temp_usr['email']);
+ }
+
+ $usr_check = single_row_select("SELECT id FROM conf_users WHERE LOWER(email)='{$LC_EMAIL}';",0,$c2);
+ if (is_null($usr_check)) {
+ // we have a new user here...
+ insert_new_user();
+ }
+
+ //$q1 = "SELECT last_name, first_name, department, extension, phone_number, email, room, user_id, time_updated, id, web_on, status FROM personnel WHERE LOWER(email)='{$LC_EMAIL}'";
+ //$usr_dir = single_row_select($q1, 0, $c);
+
+ $q2 = "SELECT id AS conf_id, goo AS conf_goo, email AS conf_email, name AS conf_name, active AS conf_active FROM conf_users WHERE LOWER(email)='{$LC_EMAIL}'";
+ $USER = single_row_select($q2, 0, $c2);
+ //$mega = $_->extend( (object) $usr_dir, (object) $usr_conf );
+
+ //$q3 = 'SELECT id AS ext_id, personnel AS personnel_id, role, goo_short, c_users AS c_users_id_ext, ilearn_id, sched_alias, dept1, dept2, gtitle, active, use_dir_photo, general_photo_release, etc, espanol, zoom, preferred_contact FROM gavi_personnel_ext WHERE personnel=' . $mega->id . ';'; // c_users={$mega->conf_id}';
+ //$usr_ext = single_row_select($q3,0,$c2);
+ //$mega = $_->extend( (object) $mega, (object) $usr_ext );
+
+ //$q4 = 'SELECT person, officehours, title, picture, education, bio, courses, personal_page, changed FROM webpages WHERE person=' . $mega->id . ';'; // '{$mega->id}'"; // personnel=1');
+ //$usr_web = single_row_select($q4,0,$c);
+ //$mega = $_->extend( (object) $mega, (object) $usr_web );
+ //$USER = $mega;
+ }
+
+
+
+
+
+
+// _____ _____ _ _ _____ _ ______ _ ____ _ _
+// / ____|_ _| \ | |/ ____| | | ____| (_) / __ \| \ | |
+// | (___ | | | \| | | __| | | |__ ___ _ __ _ _ __ | | | | \| |
+// \___ \ | | | . ` | | |_ | | | __| / __| |/ _` | '_ \ | | | | . ` |
+// ____) |_| |_| |\ | |__| | |____| |____ \__ \ | (_| | | | | | |__| | |\ |
+// |_____/|_____|_| \_|\_____|______|______| |___/_|\__, |_| |_| \____/|_| \_|
+// __/ |
+// |___/
+// SSO
+//
+// Set GLOBAL VARS corresponding to current logged in user.
+// They may only edit their own dir info.
+//
+
+
+
+
+if ( $server == 'intranet1.gavilan.edu' ) { // The SSO check should have happened on the actual page. If it gets
+// // stuck on an api call the app will break.
+ if ( session_id() == '' ) { // session_status() == PHP_SESSION_ACTIVE // newer php uses this
+ require 'mAuth.php';
+ $USER_TYPE = $attributes['http://wso2.org/claims/Roles'][0];
+ $USER_GOO = $attributes['http://wso2.org/claims/uid'][0];
+ $USER_EMAIL = $attributes['http://wso2.org/claims/emailaddress'][0];
+ ?>
+
+ first_name, $USER->last_name);
+ }
+
+//
+//
+//
+//
+
+
+
+
+
+
+
+
+
+// _ _
+// (_) (_)
+// _ __ ___ _ __ _ __ ___ _ ___ ___ _ ___ _ __ ___
+// | '_ \ / _ \ '__| '_ ` _ \| / __/ __| |/ _ \| '_ \/ __|
+// | |_) | __/ | | | | | | | \__ \__ \ | (_) | | | \__ \
+// | .__/ \___|_| |_| |_| |_|_|___/___/_|\___/|_| |_|___/
+// | |
+// |_|
+
+
+/*
+
+
+NEXT STEPS:
+
+- figure out permissions system
+
+ - which means knowing dept / hierarchy
+
+ - which means cross referencing PERSONNEL and EXT and CONF_USERS.....
+
+
+
+## Permissions summary
+
+0. There is a list of table+column combos that users are allowed to edit.
+0.5 An activity "belongs" to the user who owns it (or created it).
+
+1. Simple cases:
+ - current user is updating their own (allowable) record. Allow.
+2. Superuser:
+ - current user is executive, hr, it, or root. (7,2,8,3) Allow.
+3. User is "Dept Editor" (4) and
+ -is updating a record belonging to someone in their dept. Allow.
+4. Harder: Updating events
+
+5. Updating attendance, approvals, or other restricted tables. Only FPLC (1) or superusers.
+
+
+
+
+## Calls which edit the database
+
+Everything is sent in two arguments: cols and vals. They are comma separated and actual commas are replaced with [CMA]
+
+This relies on the app knowing the correct columns for the given table.
+
+Everything goes through the permission checker, which uses the: current user, target table, and target table row id
+to figure out if its allowed.
+
+
+TODO: permissions function
+
+TODO: prefer to POST these calls just to be a little cleaner.
+
+
+
+TODO: psuedo permissions but just to decide which navigation buttons to show:
+
+
+ - faculty see the welcome letters editor
+ - certain permissions see: big staff dir list editor (filtered per their dept), activities big list editor or results
+ - who sees the logs page?
+
+ also... determine who sees a particular "edit" button show up for activities...
+ who sees the "survey results, attendees reports" show up for past activities...
+
+
+Sample URLs:
+
+ https://www.gavilan.edu/staff/dir_api.php?a=update&cols=name,msg&vals=peter,hello
+
+ https://intranet1.gavilan.edu/dir/dir_api.php?a=update&cols=name,msg&vals=peter,hello
+*/
+
+
+function check_permission( $acting_user, $target_id, $table ) {
+
+ // TODO
+ return true;
+}
+
+
+
+
+
+
+
+
+
+
+// _ _ _
+// (_) | | | |
+// _ __ ___ _ ___ ___ | |__ ___| |_ __
+// | '_ ` _ \| / __|/ __| | '_ \ / _ \ | '_ \
+// | | | | | | \__ \ (__ | | | | __/ | |_) |
+// |_| |_| |_|_|___/\___| |_| |_|\___|_| .__/
+// | |
+//
+
+
+
+
+//
+// Helper tables
+//
+// JOB TITLES LIST
+function job_titles() { global $c2;
+ return multi_row_select("SELECT DISTINCT id, name FROM gavi_titles ORDER BY name",1, $c2); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='get/jobtitles') {
+ echo job_titles(); exit(); }
+
+// all SUB MENUS
+//
+function sub_menus() { global $c2;
+ $ddd = multi_row_select('SELECT * FROM gavi_departments ORDER BY name',0, $c2);
+ $ttt = multi_row_select('SELECT * FROM gavi_titles ORDER BY name',0, $c2);
+ $rrr = multi_row_select("SELECT * FROM gavi_roles ORDER BY 'descr'",0, $c2);
+ $ccc = multi_row_select('SELECT * FROM gavi_committees ORDER BY name',0, $c2);
+ $sss = multi_row_select('SELECT * FROM conf_sessiontypes ORDER BY id',0, $c2);
+ $ppp = multi_row_select("SELECT * FROM `conf_sessions` WHERE `type` = '20' OR `type` = '21' ORDER BY starttime",0, $c2);
+
+
+ return json_encode( array( 'departments'=>$ddd, 'titles'=>$ttt, 'roles'=>$rrr, 'committees'=>$ccc, 'sessiontypes'=>$sss, 'parents'=>$ppp ) ); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='menus') { echo sub_menus(); exit(); }
+
+
+
+// all NAMES
+//
+function get_names() {
+ global $c2, $AY, $USER;
+ $q = "SELECT u.id, u.name FROM conf_users AS u ORDER BY u.name";
+ echo json_encode( array("users"=>multi_row_select($q,0,$c2), "result"=>"success","err"=>mysqli_error($c2)));
+ exit(); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/names') { get_names(); }
+
+
+// get most RECENT LOGS
+//
+function get_recent_logs() {
+ global $c2, $USER;
+ $my_sessions = multi_row_select("SELECT * FROM `gavi_logs` ORDER BY `id` DESC LIMIT 150",0,$c2);
+ echo json_encode($my_sessions);
+ exit(); }
+if (isset($_GET['a']) && $_GET['a'] == 'get/logs') { get_recent_logs(); }
+
+
+// gavilan college EVENTS
+//
+function get_events() { global $c;
+ echo json_encode( multi_row_select("SELECT * FROM events WHERE date >= CURDATE() AND visible='1' ORDER BY time LIMIT 6;",0, $c)); }
+if (isset($_GET['a']) && $_GET['a'] == 'get/gavevents') { get_events(); exit(); }
+
+
+
+
+
+// GOTT and workshop signups
+// Export MySQL table as JSON grouped by 'training' + 'date_req' with unique 'email' within each group
+function signups()
+{
+ global $c;
+
+ // SQL query to fetch data from the table
+ $sql = "SELECT * FROM rsvp WHERE DATE(date_rsvp) >= '2023-01-01'";
+ $result = mysqli_query($c, $sql);
+
+ // Create an associative array to hold the grouped data
+ $groupedData = array();
+
+ // Loop through the result rows
+ while ($row = mysqli_fetch_assoc($result)) {
+ // Generate the group key by concatenating 'training' and 'date_req'
+ $groupKey = $row['training'] . $row['date_rsvp'];
+
+ // Check if the group key already exists in the grouped data array
+ if (!array_key_exists($groupKey, $groupedData)) {
+ // If the group key doesn't exist, create a new array for the group
+ $groupedData[$groupKey] = array();
+ }
+
+ // Check if the 'email' already exists within the group
+ $emailExists = false;
+ foreach ($groupedData[$groupKey] as $existingRow) {
+ if ($existingRow['email'] === $row['email']) {
+ $emailExists = true;
+ break;
+ }
+ }
+
+ // Add the row data to the corresponding group if the 'email' doesn't already exist
+ if (!$emailExists) {
+ $groupedData[$groupKey][] = $row;
+ }
+ }
+
+ // Return the grouped data as JSON
+ return json_encode($groupedData);
+}
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='signups') {
+ echo signups(); exit(); }
+
+
+
+
+
+
+
+
+
+
+
+
+
+// ___ | | | |
+// ___ ___ _ _ _ __ ___ ___ ___ ( _ ) | |_ ___ __ _ ___| |__ ___ _ __ ___
+// / __/ _ \| | | | '__/ __|/ _ \/ __| / _ \/\ | __/ _ \/ _` |/ __| '_ \ / _ \ '__/ __|
+// | (_| (_) | |_| | | \__ \ __/\__ \ | (_> < | || __/ (_| | (__| | | | __/ | \__ \
+// \___\___/ \__,_|_| |___/\___||___/ \___/\/ \__\___|\__,_|\___|_| |_|\___|_| |___/
+//
+//
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Courses in a semester
+function semester_sections() { global $c2;
+ return multi_row_select("SELECT * FROM `gavi_sections` s WHERE s.sem='fa21' ORDER BY s.teacher_id",1, $c2); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='list/semester') {
+ echo semester_sections(); exit(); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// STAFF + COURSES COMBINED
+function staff_dir_w_sections() { global $c;
+
+ // just one semesters sections?
+ $WHERE = "WHERE pgs.sem='fa21'";
+
+ // all recorded semesters
+ $WHERE = "";
+
+ return multi_row_select("SELECT p.first_name,p.last_name,p.department,p.status,p.staff_type, p.room,phone_number,LOWER(p.email) AS email,p.web_on, p.id, e.id AS ext_id, e.role, e.goo_short, e.c_users AS c_users_id_ext, e.ilearn_id, e.sched_alias, e.dept1, e.dept2, e.gtitle, e.active, e.use_dir_photo, e.general_photo_release, e.dir_photo_path, e.etc, e.espanol, e.zoom, e.preferred_contact, c.id AS conf_id, c.goo AS conf_goo, c.name AS conf_name, d.name AS dept1name, t.name AS titlename, d.parent AS deptparent, GROUP_CONCAT(DISTINCT s.code SEPARATOR ', ') AS sections, COUNT(s.code) AS num_taught FROM gavi_db.personnel p LEFT JOIN PeterDB.gavi_personnel_ext e ON p.id=e.personnel LEFT JOIN PeterDB.conf_users c ON LOWER(p.email)=LOWER(c.email) LEFT JOIN PeterDB.gavi_departments d ON e.dept1=d.id LEFT JOIN PeterDB.gavi_titles t ON e.gtitle=t.id LEFT JOIN ( SELECT * FROM PeterDB.gavi_sections pgs {$WHERE}) s ON e.id=s.teacher_id GROUP BY p.id ORDER BY p.last_name LIMIT 2500",0, $c); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='list/staffsemester') {
+ echo json_encode(staff_dir_w_sections()); exit(); }
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// SEARCH AN INSTRUCTOR BY NAME IN SCHEDULE
+//
+function get_instructor() { global $c2;
+ $i = ok($_REQUEST['inst']);
+ echo json_encode( single_row_select("SELECT * FROM gavi_personnel_ext WHERE sched_alias='{$i}';",0, $c2));
+ exit(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a'] == 'get/instructor/name' ) { get_instructor(); }
+
+function get_instructor_fuzzy() {
+ global $c2;
+ $i = ok($_REQUEST['inst']);
+ echo json_encode( single_row_select("SELECT * FROM gavi_personnel_ext WHERE sched_alias LIKE '{$i}';",0, $c2));
+ exit(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a'] == 'get/instructor/fuzzyname' ) { get_instructor_fuzzy(); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// COURSE SECTIONS in a semester
+//
+function get_sections($semester) { global $c;
+ $semester = ok($semester);
+ return multi_row_select("SELECT s.id,s.code,s.name,s.descr,s.teacher_id,s.days,s.start_date,s.end_date,s.units,s.ztc,s.location,s.delivery,s.status,s.pnp,s.note,s.crn,s.sem,p.personnel AS personnel_id,p.use_dir_photo,p.dir_photo_path,d.last_name,d.first_name,d.phone_number,d.email,d.room,d.web_on,s.sem FROM PeterDB.gavi_sections s LEFT JOIN PeterDB.gavi_personnel_ext p ON s.teacher_id=p.id LEFT JOIN personnel d ON d.id=p.personnel WHERE sem='{$semester}' ORDER BY code;",0, $c); }
+if (isset($_REQUEST['a']) && preg_match('/^get\/sections\/(\w\w\d\d)$/', $_REQUEST['a'], $matches)) { echo json_encode( get_sections( $matches[1] ) ); exit(); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// all COURSE SECTIONS by semester and crn only
+//
+function get_all_sections() { global $c;
+ echo json_encode( multi_row_select("SELECT s.id,s.code,s.crn,s.sem,s.teacher_id,s.delivery,s.status,p.personnel AS personnel_id,d.last_name,d.first_name FROM PeterDB.gavi_sections s LEFT JOIN PeterDB.gavi_personnel_ext p ON s.teacher_id=p.id LEFT JOIN personnel d ON d.id=p.personnel ORDER BY sem,code;",0, $c));
+ exit(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a'] == 'get/sections') { get_all_sections(); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// all COURSE SECTIONS of a single INSTRUCTOR
+//
+// use their gavi_personnel_ext id
+//
+function get_instructor_sections($teacherid) {
+ global $c;
+ echo json_encode( multi_row_select("SELECT s.id,s.code,s.name,s.descr,s.teacher_id,s.days,s.times,s.link,s.start_date,s.end_date,s.units,s.ztc,s.location,s.delivery,s.xlist_to,s.status,s.pnp,s.note,s.crn,s.sem,s.year FROM PeterDB.gavi_sections s WHERE s.teacher_id='{$teacherid}' ORDER BY s.sem,s.code;",0, $c));
+ exit(); }
+if (isset($_REQUEST['a']) && preg_match('/^get\/sections\/(\d+)$/', $_REQUEST['a'], $matches)) {
+ get_instructor_sections( $matches[1] ); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// COURSE SINGLE SECTION including welcome letter
+//
+// Housekeeping: if the gavi_welcome_letters row doesn't exist, we need to make it and populate it with the example text.
+//
+//
+function get_section($sem,$crn) {
+ global $c, $c2;
+ $sem = ok($sem);
+ $crn = ok($crn);
+ $sched_id = 0;
+
+ $sched_entry = single_row_select( "SELECT * FROM PeterDB.gavi_sections gs WHERE sem='{$sem}' AND crn='{$crn}';",0, $c2);
+ if ($sched_entry) {
+ $sched_id = $sched_entry['id']; }
+ else {
+ echo json_encode( array( "result"=>"fail", "reason"=>"no row for that section {$sem} {$crn}.") );
+ exit(); }
+
+ $wl_entry = single_row_select( "SELECT s.id,s.code,s.name,s.descr,s.teacher_id,s.days,s.start_date,s.end_date,s.units,s.ztc,s.location,s.delivery,s.status,s.pnp,s.note,s.crn,s.sem,w.id AS wl_id,w.photo_path,w.format,w.length,w.course_desc,w.what_expect,w.assessments,w.textbook,w.other_info,w.introduction,w.additional_resources FROM PeterDB.gavi_welcome_letters w LEFT JOIN PeterDB.gavi_sections s ON w.section_id=s.id WHERE w.section_id='{$sched_id}';",0, $c2);
+
+ if ($wl_entry) {
+ echo json_encode($wl_entry);
+ exit(); }
+ else {
+
+ // no WL row for that section
+ $logaction = log_it("Creating default welcome letter for Semester: $sem CRN: $crn");
+
+ $default = json_decode( file_get_contents('default_welcome_letter.json') );
+ $default->what_expect = okh($default->what_expect);
+ $default->assessments = okh($default->assessments);
+ $default->textbook = okh($default->textbook);
+ $default->other_info = okh($default->other_info);
+ $default->introduction = okh($default->introduction);
+ $default->additional_resources = okh($default->additional_resources);
+
+ $q = "INSERT INTO PeterDB.gavi_welcome_letters (section_id,format,length,text_title,course_desc,what_expect,assessments,textbook,other_info,introduction,additional_resources) VALUES ('{$sched_id}', '', '', '', '', '{$default->what_expect}', '{$default->assessments}', '{$default->textbook}', '{$default->other_info}', '{$default->introduction}', '{$default->additional_resources}');";
+ $new_id = single_row_insert($q,0,$c2);
+
+ $q4 = "SELECT s.id,s.code,s.name,s.descr,s.teacher_id,s.days,s.start_date,s.end_date,s.units,s.ztc,s.location,s.delivery,s.status,s.pnp,s.note,s.crn,s.sem,w.id AS wl_id, w.photo_path,w.format,w.length,w.course_desc,w.what_expect,w.assessments,w.textbook,w.other_info,w.introduction,w.additional_resources FROM PeterDB.gavi_welcome_letters w LEFT JOIN PeterDB.gavi_sections s ON w.section_id=s.id WHERE w.id=" . $new_id . ";";
+
+ $wl_entry = single_row_select( $q4, 0, $c2);
+ echo json_encode($wl_entry);
+ exit();
+ } }
+if (isset($_REQUEST['a']) && preg_match('/^get\/section\/(\w\w\d\d)\/(\d+)$/', $_REQUEST['a'], $matches)) {
+ get_section( $matches[1], $matches[2] ); }
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update a course section record
+/*function update_section($update=1) {
+ global $USER, $c2;
+ $WHERECLAUSE = "";
+ $START = "INSERT INTO gavi_sections SET ";
+ $action = "inserted";
+
+ if ( check_permission( $USER->id, 0, 'gavi_sections')) {
+ if ($update) {
+ $START = "UPDATE webpages SET ";
+ $WHERECLAUSE = " WHERE id={$_REQUEST['id']}";
+ $action = "updated";
+ $logaction = log_it("updating section id {$_REQUEST['id']}");
+ } else {
+ $logaction = log_it("inserting new section");
+ }
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ }
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = $_->map($vals, 'unescape_commas');
+ $cv = $_->zip($cols,$vals);
+ $q = $_->reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, $START);
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+
+ single_row_insert($q,0,$c2);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>$action,
+ "logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update/section') { update_section(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update/section') { update_section(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='add/section') { update_section(0); }
+
+*/
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update a WELCOME LETTER
+//
+/*function update_welcome_letter($update=1) {
+ global $USER, $c2, $_;
+ $WHERECLAUSE = "";
+ $START = "INSERT INTO gavi_welcome_letters SET ";
+ $action = "inserted";
+
+ if ( check_permission( $USER->id, 0, 'gavi_welcome_letters')) {
+ if ($update) {
+ $START = "UPDATE gavi_welcome_letters SET ";
+ $WHERECLAUSE = " WHERE id={$_REQUEST['id']}";
+ $action = "updated";
+ $logaction = log_it("updating welcome letter id {$_REQUEST['id']}");
+ } else {
+ $logaction = log_it("inserting new welcome letter");
+ }
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ }
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = $_->map($vals, 'unescape_commas');
+ $cv = $_->zip($cols,$vals);
+ $q = $_->reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . okh($a[1]) . "', "; }, $START);
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+
+ single_row_insert($q,0,$c2);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>$action,
+ "logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update/letter') { update_welcome_letter(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update/letter') { update_welcome_letter(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='add/letter') { update_welcome_letter(0); }
+
+*/
+
+
+
+
+
+
+
+
+
+
+
+// __ _ __ _ _
+// / _| | / / | | (_)
+// | |_| | _____ __ / / _ __ __| | ___ ___ ___ ___ _ ___ _ __ ___
+// | _| |/ _ \ \/ / / / | '_ \ / _` | / __|/ _ \/ __/ __| |/ _ \| '_ \/ __|
+// | | | | __/> < / / | |_) | (_| | \__ \ __/\__ \__ \ | (_) | | | \__ \
+// |_| |_|\___/_/\_\ /_/ | .__/ \__,_| |___/\___||___/___/_|\___/|_| |_|___/
+// | |
+// |_|
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// GET LIST OF ALL SESSIONS / WORKSHOPS / EVENTS
+//
+function get_sessions() { global $c2, $AY;
+ return multi_row_select("SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.location_irl,c.mode,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,c.cal_uid,sst.type AS typeStr, sst.id AS type, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c LEFT JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE c.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME) GROUP BY c.id ORDER BY c.track, c.starttime;",0, $c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/sessions') { echo json_encode(get_sessions()); exit(); }
+
+
+function multi_row_1d($qry, $c) {
+ $savedQuery = mysqli_query($c, $qry);
+ while($savedResult = mysqli_fetch_array($savedQuery)) {
+ $savedArray[] = $savedResult[0]; }
+ return $savedArray; }
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// GET LIST OF ALL SESSIONS + HOSTS
+//
+function get_ses_hosts() { global $c2, $AY;
+ return multi_row_select("select s.id, s.title, s.starttime, u.name, u.email, u.id AS hostid from conf_sessions as s LEFT OUTER JOIN conf_hosts as h ON h.session=s.id LEFT OUTER JOIN conf_users AS u ON h.host=u.id WHERE s.id>1319 ORDER BY u.name;",1, $c2); }
+ //return multi_row_1d("select DISTINCT(u.email) from conf_sessions as s LEFT OUTER JOIN conf_hosts as h ON h.session=s.id LEFT OUTER JOIN conf_users AS u ON h.host=u.id WHERE s.id>1319 ORDER BY u.name;", $c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/hosts') { echo get_ses_hosts(); exit(); }
+
+//
+// ALL HOST ENTRIES
+//
+/*function get_all_hosts() { global $c2, $_;
+ $hh = multi_row_select("select host,session FROM conf_hosts ORDER BY host;",0, $c2);
+ $byhost = $_->groupBy($hh, function($n) { return $n['host']; });
+ $_->map( $byhost, function($v,$k) use (&$allhost) { global $_;
+ $allhost[$k] = $_->pluck($v,'session');
+ return array( $k => $_->pluck($v,'session')); });
+ return $allhost; }
+if (isset($_GET['a']) && $_GET['a'] == 'get/allhosts') { echo json_encode(get_all_hosts()); exit(); }
+
+*/
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// LIST THE CURRENT USER'S SIGNED UP, (OR HOSTING,) SESSIONS / WORKSHOPS / EVENTS
+//
+function get_user_sessions() { global $c2, $AY, $USER;
+ $my_sessions = multi_row_select("SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.location_irl,c.mode,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,sst.type,sst.id AS typeId, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c JOIN conf_signups as sup on c.id=sup.session LEFT JOIN conf_hosts as h ON h.session=c.id JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE (h.host='{$USER->conf_id}' OR sup.user='{$USER->conf_id}') AND c.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME) GROUP BY c.id ORDER BY c.track, c.starttime;",0,$c2);
+ echo json_encode($my_sessions);
+ exit(); }
+if (isset($_GET['a']) && $_GET['a'] == 'get/mysessions') { get_user_sessions(); }
+
+
+//
+// GET ROSTERS OF ALL SESSIONS
+function get_rosters() {
+ global $AY, $c2;
+
+ /* "SELECT i.user, i.session, i.timestamp, u.goo, u.email, u.name, s.title, s.track, s.starttime, s.location, s.id AS sesid FROM conf_signups as i LEFT JOIN conf_users as u ON i.user=u.id RIGHT JOIN conf_sessions as s ON i.session=s.id WHERE s.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME) {$where} ORDER BY sesid;" */
+
+ $where = '';
+ if (isset($_REQUEST['id'])) {
+ $ID = ok($_REQUEST['id']);
+ $where = "AND s.id={$ID}"; }
+ return multi_row_select(
+ "SELECT i.user, i.session, u.goo, u.email, u.name, s.id AS sesid FROM conf_signups as i LEFT JOIN conf_users as u ON i.user=u.id RIGHT JOIN conf_sessions as s ON i.session=s.id WHERE s.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME) {$where} ORDER BY sesid;",0,$c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/rosters') { echo json_encode(get_rosters()); exit(); }
+
+
+
+//
+// GET ALL SIGNUPS
+function get_signups() {
+ global $AY, $c2;
+ $where = '';
+ if (isset($_REQUEST['id'])) {
+ $ID = ok($_REQUEST['id']);
+ $where = "WHERE s.id={$ID}"; }
+ return multi_row_select(
+ "SELECT i.id, i.user, i.session, i.timestamp, i.certified_at, i.badged_at, i.not_flex FROM conf_signups AS i JOIN conf_sessions AS s ON i.session=s.id WHERE s.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME) {$where} ORDER BY i.id DESC;",0,$c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/signups') { echo json_encode(get_signups()); exit(); }
+
+
+
+//
+// GET ALL USERS
+function get_users() {
+ global $AY, $c2;
+ return multi_row_select(
+ "SELECT * FROM conf_users AS u ORDER BY u.email;",0,$c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/users') { echo json_encode(get_users()); exit(); }
+
+
+//
+// GET ALL HOSTS
+function get_hosttable() {
+ global $AY, $c2;
+ return multi_row_select(
+ "SELECT * FROM conf_hosts;",0,$c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/hosttable') { echo json_encode(get_hosttable()); exit(); }
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// ARBITRARY USER'S SIGNED UP, (OR HOSTING,) SESSIONS / WORKSHOPS / EVENTS
+//
+// all years
+//
+function get_anyuser_sessions($usr) {
+ global $c2, $AY, $USER;
+ $my_sessions = multi_row_select("SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.location_irl,c.mode,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,sst.type,sst.id AS typeId, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c JOIN conf_signups as sup on c.id=sup.session LEFT JOIN conf_hosts as h ON h.session=c.id JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE (h.host='{$usr}' OR sup.user='{$usr}') GROUP BY c.id ORDER BY c.starttime LIMIT 150;",0,$c2);
+ // AND c.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME)
+
+ return $my_sessions; }
+if (isset($_GET['a']) && preg_match('/get\/sessions\/(\d+)$/', $_GET['a'], $matches)) { echo json_encode( get_anyuser_sessions($matches[1])); exit(); }
+
+
+// MY Survey ANSWERS
+function get_questions() { global $c2, $USER;
+ //return $USER->id;
+ return multi_row_select( "SELECT ses.id as ses_id, sup.id as sup_id, sup.certified_at as cert, sup.surveyed_at as surveyed, cus.id as user, qset.order, qq.id, qq.question, qq.type, qq.id as qid, ans.answer FROM conf_sessions as ses JOIN conf_signups as sup on ses.id = sup.session JOIN conf_users as cus on cus.id = sup.user JOIN conf_q_set as qset on ses.gets_survey = qset.q_set RIGHT JOIN conf_questions as qq on qset.question = qq.id LEFT OUTER JOIN conf_answers as ans on ans.user = sup.user AND ans.question = qq.id AND ans.session = ses.id WHERE (cus.id='{$USER->conf_id}') ORDER BY ses.starttime, ses.track asc, qset.order", 0, $c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/questions') { echo json_encode(get_questions()); exit(); }
+
+
+// Single session QUESTIONS and possibly ansers
+function get_session_questions($id) { global $c2, $USER;
+ //print_r($USER); exit();
+ $u = $USER->conf_id;
+ return multi_row_select( "SELECT ses.title, {$u} AS user, ses.id as session, q.id AS qid, q.question, q.type, ans.answer FROM conf_sessions AS ses JOIN conf_q_set AS qset ON ses.gets_survey=qset.q_set JOIN conf_questions AS q ON q.id=qset.question LEFT OUTER JOIN conf_answers AS ans ON ans.user={$u} AND ans.question=q.id AND ans.session=ses.id WHERE ses.id={$id}", 0, $c2); }
+
+if (isset($_GET['a'])&& preg_match('/get\/questions\/(\d+)$/', $_GET['a'], $matches)) { echo json_encode(get_session_questions($matches[1])); exit(); }
+
+
+// ALL Survey ANSWERS
+function get_answers_all() { global $c2;
+ return multi_row_select( "SELECT ses.id AS ses_id, ses.title as s_title, ses.starttime, qq.id as q_id, qq.question as question, qq.type as type, ans.answer AS answer FROM conf_sessions AS ses JOIN conf_signups as sup on ses.id = sup.session JOIN conf_users as cus on cus.id = sup.user JOIN conf_q_set as qset on ses.gets_survey = qset.q_set RIGHT JOIN conf_questions as qq on qset.question = qq.id LEFT OUTER JOIN conf_answers as ans on ans.user = sup.user AND ans.question = qq.id AND ans.session = ses.id WHERE ans.answer is not null ORDER BY ses.starttime, ses.track asc, qset.order", 0, $c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/answers/all') { echo json_encode(get_answers_all()); exit(); }
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+
+function set_answers() { global $c, $c2;
+ $ses_id = ok($_REQUEST['session']);
+ $u = ok($_REQUEST['user']);
+ $q = ok($_REQUEST['qid']);
+ $answer = ok($_REQUEST['answer']);
+
+ $existing = does_exist( "select * from `conf_answers` where `user`='$u' and `session`='$ses_id' and `question`='$q';",0,$c2 );
+
+ if ($existing) {
+ $qupdate = "UPDATE conf_answers SET answer='$answer' WHERE session=$ses_id AND user=$u AND question=$q";
+ single_row_update($qupdate,0, $c2);
+ $logaction = log_it("updated answer for session: $ses_id");
+ } else {
+ $qupdate = "INSERT INTO conf_answers SET user='$u', question='$q', session='$ses_id', answer='$answer'";
+ single_row_insert($qupdate,0,$c2);
+ $logaction = log_it("Saved answer for session: $ses_id");
+ }
+ echo json_encode( array("result"=>"success", "logaction"=>$logaction, "action"=>"save survey answer","query"=>$qupdate,"err"=>mysqli_error($c2)));
+ exit(); }
+
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update/answers') { set_answers(); }
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+
+function set_cert() {
+ #echo "saving";
+ global $USER, $c2;
+ $ses_id = ok($_REQUEST['ses_id']);
+ $cert = ok($_REQUEST['cert']);
+ $date = "'" . date('Y-m-d H:i:s') . "'";
+ if ($cert=="null") { $date = "NULL"; }
+ $qupdate = "UPDATE conf_signups SET `certified_at`=$date where `user`='$USER' and `session`='$ses_id'";
+ single_row_update($qupdate, 0, $c2);
+ $logaction = log_it("updated certified state for session: $ses_id");
+ echo json_encode( array("result"=>"success", "logaction"=>$logaction, "action"=>"save cert","query"=>$qupdate,"err"=>mysqli_error($c2)));
+ //print_r($_POST);
+ exit(); }
+
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='set/cert') { set_cert(); }
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// SIGNUP for (possibly overlapping time) session ... /// id_c_users
+//
+function signup() {
+ global $c2, $AY, $USER;
+ preg_match('/signup\/(\d+)$/', $_GET['a'], $matches);
+ $ses = $matches[1];
+ $ts = date("Y-m-d H:i:s");
+ $logaction = log_it("Signed up for session: " . $ses);
+
+ $sesh = "";
+ if (isset($_SESSION)) { $sesh = $_SESSION; }
+
+ $existing = does_exist(
+ "SELECT i.id FROM conf_signups AS i JOIN conf_sessions AS s ON i.session=s.id WHERE s.id={$ses} AND i.user=" . $USER->conf_id,0,$c2);
+ if ($existing) {
+ $qupdate = "UPDATE conf_signups SET session={$ses}, timestamp='{$ts}' WHERE session={$ses} AND user=" . $USER->conf_id;
+ single_row_select($qupdate,1,$c2);
+ echo json_encode( array("result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$qupdate,"err"=>mysqli_error($c2)));
+ } else {
+ $q = "INSERT INTO conf_signups (session,user,timestamp) VALUES ({$ses}," . $USER->conf_id . ",'{$ts}')";
+ single_row_insert($q,1,$c2);
+ echo json_encode( array( /* "userglobal"=>$USER, */ "result"=>"success","action"=>"inserted", /* "logaction"=>$logaction, */
+ "ses"=>$sesh,"query"=>$q,"err"=>mysqli_error($c2)));
+ } exit(); }
+
+if (isset($_GET['a']) && preg_match('/signup\/(\d+)$/', $_GET['a'], $matches)) { signup(); }
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// CANCEL a signup
+//
+function signdown() {
+ global $c2, $AY, $USER;
+ preg_match('/signdown\/(\d+)$/', $_GET['a'], $matches);
+ $ses = $matches[1];
+ $q = "DELETE FROM conf_signups WHERE session={$ses} AND user=" . $USER->conf_id;
+ single_row_update($q,1,$c2);
+ $logaction = log_it("Canceled signup for session: $ses");
+
+ echo json_encode( array("result"=>"success","action"=>"deleted","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ exit(); }
+
+if (isset($_GET['a']) && preg_match('/signdown\/(\d+)$/', $_GET['a'], $matches)) { signdown(); }
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// add a HOST for a session ...
+//
+function addhost($sesid,$hostid) {
+ global $c2;
+ $sesid = ok($sesid); $hostid = ok($hostid);
+ $existing = does_exist("SELECT h.host, h.session FROM conf_hosts AS h WHERE h.host={$hostid} AND h.session={$sesid}",0,$c2);
+ if ($existing) { return array("result"=>"success","action"=>"already a host"); }
+ else {
+ $qupdate = "INSERT INTO conf_hosts SET session='{$sesid}', host='{$hostid}';";
+ $new_id = single_row_insert($qupdate,0,$c2);
+ $e = mysqli_error($c2);
+ if ($new_id) { $success = " with new id {$new_id}"; }
+ else { $success = " -- error: {$e}"; }
+ $logaction = log_it("Added host {$hostid} to session: {$sesid}");
+ return array("result"=>"success".$success,"action"=>"added host","query"=>$qupdate,"err"=>$e); } }
+
+if (isset($_GET['a']) && preg_match('/add\/host\/(\d+)\/(\d+)$/', $_GET['a'], $matches)) {
+ echo json_encode(addhost($matches[1], $matches[2])); exit(); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// REMOVE a HOST for a session ...
+//
+function removehost($sesid,$hostid) {
+ global $c2;
+ $sesid = ok($sesid); $hostid = ok($hostid);
+ $qupdate = "DELETE FROM conf_hosts WHERE session='{$sesid}' AND host='{$hostid}';";
+ $new_id = single_row_update($qupdate,0,$c2);
+ $e = mysqli_error($c2);
+ $logaction = log_it("Removed host {$hostid} to session: {$sesid}");
+ return array("result"=>"success","action"=>"removed host","query"=>$qupdate,"err"=>$e); }
+
+if (isset($_GET['a']) && preg_match('/remove\/host\/(\d+)\/(\d+)$/', $_GET['a'], $matches)) {
+ echo json_encode(removehost($matches[1], $matches[2])); exit(); }
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// NEW SESSION
+//
+function new_session() {
+ global $c2, $AY, $USER;
+
+
+ $title = ok($_POST['title']); $starttime = ok($_POST['starttime']);
+ $length = ok($_POST['length']); if ($length=='') { $length=1; }
+ $track = ok($_POST['track']); $gets_survey = ok($_POST['gets_survey']);
+ $is_flex_approved = ok($_POST['is_flex_approved']); $category = ok($_POST['title']);
+ if ($category=='') { $category=0; }
+ $author = ok($_POST['author']); if ($author=='') { $author=1; } // $USER->id_c_users; }
+ $is_custom = ok($_POST['is_custom']); $parent = ok($_POST['parent']);
+ $desc = okh($_POST['desc']); $location = okh($_POST['location']);
+ $recording = okh($_POST['recording']); $instructions = okh($_POST['instructions']);
+ $type = ok($_POST['type']); if ($type=='') { $type=19; }
+ $cal_uid = ok($_POST['cal_uid']); $mode = okh($_POST['mode']);
+ $location_irl = okh($_POST['location_irl']);
+
+
+ $q = "INSERT INTO conf_sessions (`title`,`starttime`,`length`,`track`,`gets_survey`,`is_flex_approved`,`category`,`author`,`is_custom`,`parent`,`desc`,`location`,`mode`,`recording`,`instructions`,`type`,`cal_uid`) VALUES ('{$title}', '{$starttime}', '{$length}', '{$track}', '{$gets_survey}', '{$is_flex_approved}', '{$category}', '{$author}', '{$is_custom}', '{$parent}', '{$desc}', '{$location}', '{$location_irl}', '{$mode}', '{$recording}', '{$instructions}', '{$type}', '{$cal_uid}');";
+
+ $ins = single_row_insert($q,0,$c2);
+ $logaction = log_it("created new session id: {$ins}: {$title}");
+ echo json_encode( array( /*"all_args"=>$_POST,*/ "result"=>"success","action"=>"inserted new session","new_id"=>$ins, "query"=>$q,"logaction"=>$logaction,"err"=>mysqli_error($c2)));
+ exit(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='set/newsession') { new_session(); }
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Editing of session info
+//
+function reducer ($memo, $a) { return $memo . "`" . ok($a[0]) . "` = '" . okh($a[1]) . "', "; }
+
+function set_sessioninfo() {
+ global $c, $c2, $AY, $USER, $_;
+ $table = 'conf_sessions';
+
+ $DO_CHECKING = 0;
+
+ if (isset($_POST['id'])) {
+ $ID = ok($_REQUEST['id']);
+ if ($DO_CHECKING) {
+ // (! check_permission( $USER->conf_id, $ID, $table)) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("edited session id: {$ID}");
+ $WHERECLAUSE = " WHERE id={$ID}";
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = array_map('unescape_commas', $vals);
+ $cv = array_map(null,$cols,$vals);
+ $q = array_reduce($cv, 'reducer', "UPDATE `{$table}` SET ");
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+ single_row_update($q,0,$c2);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated", "query"=>$q,"err"=>mysqli_error($c2)));
+ }
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"no activity id specified") ); }
+ exit(); }
+//if (isset($_POST['a']) && $_POST['a']=='update/activity') { set_sessioninfo(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update/activity') { set_sessioninfo(); }
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// App SETTINGS
+//
+
+
+//
+// GET
+function get_settings() { global $AY, $c2;
+ return multi_row_select( "SELECT * FROM conf_uinforecord;",0,$c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/settings') { echo json_encode(get_settings()); exit(); }
+
+
+
+
+function set_settings() {
+ global $c, $c2, $AY, $USER, $_;
+ $table = 'conf_uinforecord';
+
+ $DO_CHECKING = 0;
+
+ if (isset($_POST['id'])) {
+ $ID = ok($_REQUEST['id']);
+ if ($DO_CHECKING) {
+ // (! check_permission( $USER->conf_id, $ID, $table)) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("edited session id: {$ID}");
+ $WHERECLAUSE = " WHERE id={$ID}";
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = array_map('unescape_commas', $vals);
+ $cv = array_map(null,$cols,$vals);
+ $q = array_reduce($cv, 'reducer', "UPDATE `{$table}` SET ");
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+ single_row_update($q,0,$c2);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated", "query"=>$q,"err"=>mysqli_error($c2)));
+ }
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"no activity id specified") ); }
+ exit(); }
+//if (isset($_POST['a']) && $_POST['a']=='update/activity') { set_sessioninfo(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update/activity') { set_sessioninfo(); }
+
+
+
+
+
+
+
+
+// _ __ __ ______ ___________ _____ _____ _____ _____________ __
+// | | / _|/ _| | _ \_ _| ___ \ ___/ __ \_ _| _ | ___ \ \ / /
+// ___| |_ __ _| |_| |_ | | | | | | | |_/ / |__ | / \/ | | | | | | |_/ /\ V /
+// / __| __/ _` | _| _| | | | | | | | /| __|| | | | | | | | / \ /
+// \__ \ || (_| | | | | | |/ / _| |_| |\ \| |___| \__/\ | | \ \_/ / |\ \ | |
+// |___/\__\__,_|_| |_| |___/ \___/\_| \_\____/ \____/ \_/ \___/\_| \_| \_/
+//
+//
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Everyone. Basic dir. Include status==0 which is unpublished.
+function staff_dir() { global $c;
+ return multi_row_select('SELECT first_name,last_name,department,status, room,phone_number,email,web_on,id FROM personnel',1, $c); }
+
+
+// Everyone. Basic dir
+function staff_dir_ext() { global $c;
+ return multi_row_select('SELECT p.first_name,p.last_name,p.department,p.status, p.room,phone_number,LOWER(p.email) AS email,p.web_on, p.id, e.id AS ext_id, e.role, e.goo_short, e.c_users AS c_users_id_ext, e.ilearn_id, e.sched_alias, e.dept1, e.dept2, e.gtitle, e.active, e.use_dir_photo, e.general_photo_release, e.dir_photo_path, e.etc, c.id AS conf_id, c.goo AS conf_goo, c.name AS conf_name FROM gavi_db.personnel p LEFT JOIN PeterDB.gavi_personnel_ext e ON p.id=e.personnel LEFT JOIN PeterDB.conf_users c ON LOWER(p.email)=LOWER(c.email) ORDER BY p.last_name LIMIT 5000',1, $c); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='list') {
+ echo staff_dir_ext(); exit(); }
+
+
+// Everyone. Directory info with DEPTS and TITLES added
+function staff_dir_full_ext() { global $c;
+ return multi_row_select('SELECT p.first_name,p.last_name,p.department,p.status, p.room,phone_number,LOWER(p.email) AS email,p.web_on, p.id, e.id AS ext_id, e.role, e.goo_short, e.c_users AS c_users_id_ext, e.ilearn_id, e.sched_alias, e.dept1, e.dept2, e.gtitle, e.active, e.use_dir_photo, e.general_photo_release, e.dir_photo_path, e.etc, e.espanol, e.zoom, e.preferred_contact, c.id AS conf_id, c.goo AS conf_goo, c.name AS conf_name, d.name AS dept1name, t.name AS titlename, d.parent AS deptparent FROM gavi_db.personnel p LEFT JOIN PeterDB.gavi_personnel_ext e ON p.id=e.personnel LEFT JOIN PeterDB.conf_users c ON LOWER(p.email)=LOWER(c.email) LEFT JOIN PeterDB.gavi_departments d ON e.dept1=d.id LEFT JOIN PeterDB.gavi_titles t ON e.gtitle=t.id ORDER BY p.last_name LIMIT 5000',1, $c); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='list2') { echo staff_dir_full_ext(); exit(); }
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update a name, lname, dept, phone, extension, email, type, room, status, user_id, or web_on
+/*function update_dir() {
+ global $USER, $c, $c2, $_;
+
+ $WHERECLAUSE = " WHERE id={$USER->id}";
+
+ if (isset($_POST['id'])) { // editing another person's data
+ if (! check_permission( $USER->id, $_POST['id'], 'personnel')) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("updating personnel record of personnel id {$_POST['id']}");
+ $WHERECLAUSE = " WHERE id={$_POST['id']}";
+ }
+ } else {
+ $logaction = log_it("updating personnel record");
+ }
+
+ // date modified is now
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = $_->map($vals, 'unescape_commas');
+ $cv = $_->zip($cols,$vals);
+ $q = $_->reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, "UPDATE personnel SET ");
+ //$q = substr($q, 0, -2);
+ $q .= "time_updated='" . $date . "'";
+ $q .= $WHERECLAUSE;
+ if ($USER->id) {
+ single_row_update($q,0,$c);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c)));
+ }
+ else {
+ $logaction2 = log_it("failed to update personnel record");
+ echo json_encode( array("result"=>"fail", "err"=>"dont have an id for user") );
+ }
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update') { update_dir(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update') { update_dir(); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update goo, dept1/dept2, title, active, use_dir_photo
+function update_dir_ext() {
+ global $USER, $c, $c2, $_;
+
+ $WHERECLAUSE = " WHERE id={$USER->ext_id}";
+
+ #print_r($_REQUEST);
+
+ if (isset($_REQUEST['id'])) { // editing another person's data
+ if (! check_permission( $USER->id, $_REQUEST['id'], 'personnel_ext')) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("updating personnel_ext record of personnel id {$_REQUEST['id']}");
+ $WHERECLAUSE = " WHERE id={$_REQUEST['id']}";
+ }
+ } else {
+ $logaction = log_it("updating personnel_ext record");
+ }
+
+ // date modified is now
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = $_->map($vals, 'unescape_commas');
+ $cv = $_->zip($cols,$vals);
+ $q = $_->reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, "UPDATE gavi_personnel_ext SET ");
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+ single_row_update($q,0,$c2);
+ echo json_encode( array("result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update_xt') { update_dir_ext(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update_xt') { update_dir_ext(); }
+
+*/
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update person, officehours, title, picture, education, bio, courses, personal_page, changed
+/*function update_webpage() {
+ global $USER_PERS_ID, $USER, $c, $c2, $_;
+
+ $WHERECLAUSE = " WHERE person={$USER->id}";
+
+ if (isset($_POST['id'])) { // editing another person's data
+ if (! check_permission( $USER->id, $_POST['id'], 'personnel')) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("updating bio webpage record of personnel id {$_POST['id']}");
+ $WHERECLAUSE = " WHERE person={$_POST['id']}";
+ }
+ } else {
+ $logaction = log_it("updating bio webpage record");
+ }
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = $_->map($vals, 'unescape_commas');
+ $cv = $_->zip($cols,$vals);
+ $q = $_->reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . okh($a[1]) . "', "; }, "UPDATE webpages SET ");
+ $q .= "changed='" . $date . "'";
+ $q .= $WHERECLAUSE;
+ if ($USER->id) {
+ single_row_update($q,0,$c);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c)));
+ }
+ else {
+ $logaction2 = log_it("failed to update bio webpage record");
+ echo json_encode( array("result"=>"fail", "err"=>"dont have an id for user") );
+ }
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update_web') { update_webpage(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update_web') { update_webpage(); }
+
+
+
+*/
+
+
+
+
+
+
+// _ _ __ __
+// | | | | / _|/ _|
+// _ __ __ _ _ __ __| | ___ _ __ ___ ___| |_ _ _| |_| |_
+// | '__/ _` | '_ \ / _` |/ _ \| '_ ` _ \ / __| __| | | | _| _|
+// | | | (_| | | | | (_| | (_) | | | | | | \__ \ |_| |_| | | | |
+// |_| \__,_|_| |_|\__,_|\___/|_| |_| |_| |___/\__|\__,_|_| |_|
+//
+//
+
+
+
+
+//
+//
+//
+// Next couple functions are for importing, merging, or just dealing w/ historical data
+//
+// and/or transition tasks......
+//
+//
+
+function handle_pic_upload() { global $USER;
+ $uploaddir = '/gavilan.edu/staff/uploads/';
+ $date = date('Ymd_Hi');
+ $uploadfile = $uploaddir . name_to_lc($USER->first_name,$USER->last_name) . "_" . $date . "_" . basename($_FILES['file']['name']);
+
+
+ echo '';
+ if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) {
+ echo "File is valid, and was successfully uploaded.\n";
+ } else {
+ echo "Possible file upload attack!\n";
+ }
+
+ echo 'Here is some more debugging info:';
+ print_r($_FILES);
+
+ print " ";
+
+}
+//if (isset($_REQUEST['file'])) { handle_pic_upload(); }
+if (isset($_FILES['file'])) { handle_pic_upload(); }
+
+function get_a_user_by_pid($user_pid) { global $c, $c2, $_;
+ $q1 = "SELECT last_name, first_name, department, extension, phone_number, email, room, user_id, time_updated, id, web_on FROM personnel WHERE id='{$user_pid}'";
+ $usr_dir = single_row_select($q1, 0, $c);
+ $q2 = "SELECT id AS id_c_users, goo, email AS email_c_users, name, active FROM conf_users WHERE email='{$usr_dir['email']}'";
+ $usr_conf = single_row_select($q2, 0, $c2);
+ $mega = $_->extend( (object) $usr_dir, (object) $usr_conf );
+ $q3 = "SELECT id AS ext_id, personnel AS personnel_id, goo_short, c_users AS c_users_id_ext, ilearn_id, sched_alias, dept1, dept2, gtitle, active, use_dir_photo, etc FROM gavi_personnel_ext WHERE personnel='{$mega->id}'";
+ $usr_ext = single_row_select($q3,0,$c2);
+ $mega = $_->extend( (object) $mega, (object) $usr_ext );
+ $q4 = 'SELECT person, officehours, title, picture, education, bio, courses, personal_page, changed FROM webpages WHERE person=' . $mega->id; // personnel=1');
+ $usr_web = single_row_select($q4,0,$c);
+ $mega = $_->extend( (object) $mega, (object) $usr_web );
+
+ // ?????
+
+
+ /* if (!isset($mega->use_dir_photo)) {
+ $mega->pic_exists = check_dir_photo($mega->first_name, $mega->last_name);
+ if ($mega->pic_exists) {
+ $filename = "images_sm/" . name_to_file( $mega->first_name, $mega->last_name );
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=1, dir_photo_path='{$filename}' WHERE id='{$mega->ext_id}'";
+ } else {
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=0 WHERE id='{$mega->ext_id}'";
+ }
+ }
+ if (! isset($mega->ext_id)) {
+ $mega->aaqueryfix = "INSERT INTO gavi_personnel_ext (personnel) VALUES('{$mega->id}')"; }
+ elseif ($mega->id && ! $mega->personnel_id) {
+ $mega->aaqueryfix = "UPDATE gavi_personnel_ext SET personnel='{$mega->id}' WHERE id='{$mega->ext_id}'"; }
+ */
+
+ echo json_encode( $mega );
+ exit();
+
+}
+if (isset($_REQUEST['a']) && preg_match('/^get\/user\/(\d+)$/', $_REQUEST['a'], $matches)) { get_a_user_by_pid( $matches[1] ); }
+
+
+function get_a_user($user_email) { global $c, $c2, $_;
+ $q1 = "SELECT last_name, first_name, department, extension, phone_number, email, room, user_id, time_updated, id, web_on FROM personnel WHERE email='" . $user_email . "'";
+ //p2($q1);
+ $usr_dir = single_row_select($q1, 0, $c);
+ //p2($usr_dir);
+
+ $q2 = "SELECT id AS id_c_users, goo, email AS email_c_users, name, active FROM conf_users WHERE email='" . $user_email . "'";
+ //p2($q2);
+ $usr_conf = single_row_select($q2, 0, $c2);
+ //p2($usr_conf);
+ $mega = $_->extend( (object) $usr_dir, (object) $usr_conf );
+
+ $q3 = 'SELECT id AS ext_id, personnel AS personnel_id, goo_short, c_users AS c_users_id_ext, ilearn_id, sched_alias, dept1, dept2, gtitle, active, use_dir_photo, etc FROM gavi_personnel_ext WHERE personnel=' . $mega->id;
+ //p2($q3);
+ $usr_ext = single_row_select($q3,0,$c2);
+ //p2($usr_ext);
+ $mega = $_->extend( (object) $mega, (object) $usr_ext );
+
+ $q4 = 'SELECT person, officehours, title, picture, education, bio, courses, personal_page, changed FROM webpages WHERE person=' . $mega->id; // personnel=1');
+ //p2($q3);
+ $usr_web = single_row_select($q4,0,$c);
+ //p2($usr_ext);
+ $mega = $_->extend( (object) $mega, (object) $usr_web );
+
+ /*
+ if (!isset($mega->use_dir_photo)) {
+ $mega->pic_exists = check_dir_photo($mega->first_name, $mega->last_name);
+ if ($mega->pic_exists) {
+ $filename = "images_sm/" . name_to_file( $mega->first_name, $mega->last_name );
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=1, dir_photo_path='{$filename}' WHERE id='{$mega->ext_id}'";
+ } else {
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=0 WHERE id='{$mega->ext_id}'";
+ }
+ }*/
+ if (! isset($mega->ext_id)) {
+ $mega->aaqueryfix = "INSERT INTO gavi_personnel_ext (personnel) VALUES('{$mega->id}')"; }
+ elseif ($mega->id && ! $mega->personnel_id) {
+ $mega->aaqueryfix = "UPDATE gavi_personnel_ext SET personnel='{$mega->id}' WHERE id='{$mega->ext_id}'"; }
+
+
+ return $mega; }
+
+
+function insert_c2($q) {
+ global $c2;
+ $result = single_row_insert($q,0,$c2);
+ return $result; }
+
+function merge_tables() { global $c, $_;
+ $all_personnel = multi_row_select('SELECT first_name,last_name,department,room,phone_number,email,web_on,id FROM personnel WHERE status IS null OR status=1',0, $c);
+
+ $emails = $_->pluck($all_personnel, 'email');
+ echo json_encode($emails);
+ //exit();
+
+ $emails = array_slice($emails, 0, 10);
+
+ $full = $_->map( $emails, "get_a_user" );
+
+ echo json_encode($full);
+
+ //$results = $_->map( $_->pluck($full,'aaqueryfix'), insert_c2);
+
+ //$results = $_->pluck($full,'bbqueryfix');
+ //$results = $_->map( $results, insert_c2);
+ //echo json_encode( $full );
+ exit(); }
+if (isset($_REQUEST['merge'])) { merge_tables(); }
+
+
+
+
+
+
+
+function fetch_personnel_dir() { global $c;
+ $all_personnel = multi_row_select('SELECT * FROM personnel',0, $c);
+ echo json_encode($all_personnel);
+ exit(); }
+if (isset($_REQUEST['personnel'])) { fetch_personnel_dir(); }
+
+function fetch_conf_users() { global $c2;
+ $all_personnel = multi_row_select('SELECT * FROM conf_users',0, $c2);
+ echo json_encode($all_personnel);
+ exit(); }
+if (isset($_REQUEST['users'])) { fetch_conf_users(); }
+
+function fetch_personnel_ext() { global $c2;
+ $all_personnel = multi_row_select('SELECT * FROM gavi_personnel_ext',0, $c2);
+ echo json_encode($all_personnel);
+ exit(); }
+if (isset($_REQUEST['personnelext'])) { fetch_personnel_ext(); }
+
+
+
+/*
+
+
+in ilearn but not personnel dir or others
+
+
+in personnel but not others
+
+
+
+
+*/
+
+
+
+//
+//
+// NAVIGATION
+
+function navigation($user) {
+?>
+
+
+
+
+
+';
+ var_dump($temp_usr);
+ echo '';
+
+ exit(); }
+if (isset($_REQUEST['test'])) { test_sso(); }
+
+// __ ____ ____ __ _ ____
+// ____/ /__ / __/___ ___ __/ / /_ ________ / /___ ___________ __ __________ _____ (_)___ / __/___
+// / __ / _ \/ /_/ __ `/ / / / / __/ ______ / ___/ _ \/ __/ / / / ___/ __ \ / / / / ___/ _ \/ ___/ / / __ \/ /_/ __ \
+// / /_/ / __/ __/ /_/ / /_/ / / /_ /_____/ / / / __/ /_/ /_/ / / / / / / / /_/ (__ ) __/ / / / / / / __/ /_/ /
+// \__,_/\___/_/ \__,_/\__,_/_/\__/ /_/ \___/\__/\__,_/_/ /_/ /_/ \__,_/____/\___/_/ /_/_/ /_/_/ \____/
+//
+//
+// ........finally, if no parameters were matched.......
+//
+// DO NOTHING IF FILE WAS INCLUDED from another php page.
+//
+// OTHERWISE, RETURN BASIC USER INFO
+//
+//
+if (basename(__FILE__) == basename($_SERVER["SCRIPT_FILENAME"])) {
+ // Called directly as api or in browser
+ //
+ if ($USER_GOO) {
+ // Default case is current user data to be embedded in editor page. Log the access
+ //$USER->logresult = log_it("accessed dir app (in intranet folder)");
+ //$USER->pics = user_pic_look( $USER->first_name, $USER->last_name, $USER->conf_goo );
+ //$USER->options = $OPTIONS;
+ echo json_encode($USER); exit();
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"not logged in") ); exit(); } }
+
+
+
+//
+// ELSE it was "included"... do nothing.
+
+
+
+
+//
+// draw big text
+// https://patorjk.com/software/taag/#p=display&c=c%2B%2B&f=Doom&t=sup
+//
+
+
+
+// __ __ _______ ______ __ __ __
+// / /_/ /_ ___ / ____/ | / / __ \ / /_/ /_ ____ _____ / /__ __ ______ __ __
+// / __/ __ \/ _ \ / __/ / |/ / / / / / __/ __ \/ __ `/ __ \/ //_/ / / / / __ \/ / / /
+// / /_/ / / / __/ / /___/ /| / /_/ / / /_/ / / / /_/ / / / / ,< / /_/ / /_/ / /_/ /
+// \__/_/ /_/\___/ /_____/_/ |_/_____/ \__/_/ /_/\__,_/_/ /_/_/|_| \__, /\____/\__,_/
+// /____/
+
+
+
+// peter h 2021
+
+
+
+
+?>
diff --git a/dir_api20211102.php b/dir_api20211102.php
new file mode 100644
index 0000000..6fc903b
--- /dev/null
+++ b/dir_api20211102.php
@@ -0,0 +1,1235 @@
+{$s}\n"; }
+function p2($val){ echo ''; print_r($val); echo " \n"; }
+function d_err($s) { global $DEBUG; if ($DEBUG) { p($s); } }
+include('underscore.php');
+
+////////////////////
+////////////////////
+//
+// PHP SESSIONS .... needed?
+//
+
+/*
+header("Access-Control-Allow-Credentials: true");
+header("Access-Control-Allow-Methods: get,post");
+header("Access-Control-Allow-Headers: Content-Type, Accept");
+session_start();
+
+function logout() { session_destroy(); }
+*/
+
+
+////////////////////
+////////////////////
+//
+// DATABASE
+//
+// Yes, there's two different databases.
+//
+// $c = gavi_db
+// $c2 = PeterDB
+//
+// Why? Just to keep you on your toes.
+//
+// The $j argument is true for a json result, or false for a raw db object result.
+//
+
+
+$DBServer = 'localhost'; $DBUser = 'www';
+$DBPass = '@$df'; $DBName = 'gavi_db';
+
+$c = new mysqli($DBServer, $DBUser, $DBPass, $DBName);
+if ($c->connect_error) { die('Database connection failed: ' . $c->connect_error ); }
+if (!mysqli_select_db($c, $DBName)) { die("Uh oh, couldn't select database $DBName"); }
+
+$c2 = new mysqli($DBServer, "phowell", 'p^howell', 'PeterDB');
+if ($c2->connect_error) { die('Database connection failed: ' . $c2->connect_error ); }
+if (!mysqli_select_db($c2, 'PeterDB')) { die("Uh oh, couldn't select database 'PeterDB'"); }
+
+mysqli_set_charset('utf8', $c);
+
+mysqli_set_charset('utf8', $c2);
+
+// Generic string cleaner
+function ok($str) { global $c; return mysqli_real_escape_string($c, strip_tags($str, '
')); }
+
+
+// keep HTML tags string cleaner
+function okh($str) { global $c; return mysqli_real_escape_string($c, $str); }
+
+
+// 1. lookups, like a username
+function single_row_select($qry, $j=1, $c) {
+ $r = mysqli_query($c, $qry); d_err($qry);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ $a = mysqli_fetch_assoc($r);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ if (! $j) { return $a; } return json_encode($a); }
+
+// 1a. inserts
+function single_row_insert($qry, $j=1, $c) {
+ $r = mysqli_query($c, $qry);
+ //d_err($qry);
+ //$e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ $new_id = mysqli_insert_id($c);
+ return $new_id; }
+
+ /*$a = mysqli_fetch_assoc($c);
+ $e = mysqli_error($c); if($e) { d_err("sql error: " . $e ); }
+ if (! $j) { return $a; } return json_encode($a); } */
+
+// 2. grid or fancier joins, like get all sessions, rosters, todos, etc
+function multi_row_select($qry, $j=1, $db) {
+ $rows = array();
+ $result = mysqli_query($db, $qry);
+ while($r = mysqli_fetch_assoc($result)) { $rows[] = $r; }
+ if (! $j) { return $rows; } return json_encode( $rows); }
+
+// 3. Check if an entry exists
+function does_exist($qry, $full_record=0, $db) { global $c, $c2;
+ $r = mysqli_query($db, $qry);
+ $a = mysqli_num_rows($r);
+ $row = mysqli_fetch_array($r, MYSQLI_NUM);
+ $id = $row[0]; // getting the id of that which exists... assuming first column has it.
+ d_err("does exist: {$a}");
+ $e = mysqli_error($db); if($e) { d_err("sql error: " . $e); }
+ if ($a && $full_record) { return $row; } if ($a) { return $id; } return 0; }
+
+
+
+////////////////////
+////////////////////
+//
+// SSO
+//
+// Set GLOBAL VARS corresponding to current logged in user.
+// They may only edit their own dir info.
+//
+
+
+
+
+$server = $_SERVER['SERVER_NAME'];
+
+
+if ( $server == 'intranet1.gavilan.edu' ) {
+
+ // The SSO check should have happened on the actual page. If it gets
+ // stuck on an api call the app will break.
+
+ if ( session_id() == '' ) { // session_status() == PHP_SESSION_ACTIVE
+
+ require 'mAuth.php';
+
+ $USER_TYPE = $attributes['http://wso2.org/claims/Roles'][0];
+ $USER_GOO = $attributes['http://wso2.org/claims/uid'][0];
+ $USER_EMAIL = $attributes['http://wso2.org/claims/emailaddress'][0];
+
+ session_start();
+
+ $_SESSION['USER_TYPE'] = $USER_TYPE;
+ $_SESSION['USER_GOO'] = $USER_GOO;
+ $_SESSION['USER_EMAIL'] = $USER_EMAIL;
+ } else {
+
+ $USER_TYPE = $_SESSION['USER_TYPE'];
+ $USER_GOO = $_SESSION['USER_GOO'];
+ $USER_EMAIL = $_SESSION['USER_EMAIL'];
+
+ }
+
+} else {
+ //echo json_encode( array("result"=>"not logged in") );
+ exit();
+
+
+
+ /*$USER = 0;
+ $USER_NAME = 0;
+ $USER_PERS_ID = 0;
+ $USER_CONF_U_ID = 0;
+ $USER_PERS_EXT_ID = 0; */
+
+}
+
+$status = "ID: {$USER_GOO} ";
+$status .= "Email: {$USER_EMAIL} ";
+$status .= "Employee type: {$USER_TYPE} ";
+
+d_err($status);
+
+
+// Current academic year
+$AY = single_row_select("SELECT * FROM conf_academicyears WHERE label='2021-2022';",0, $c2);
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// Fetching a person's records
+//
+// 1. use their email to lookup PERSONNEL
+// - basic directory info
+//
+// 2. use their email to lookup CONF_USERS
+// - flex app, workshop signups
+//
+// 3. use conf_users.id to lookup in gavi_personnel_ext.c_users
+// - goo, depts, job title, image active
+//
+// 4. use personnel.id to lookup [webpages, welcomepages, etc]
+
+
+function user_record() { global $USER, $USER_EMAIL, $USER_NAME, $USER_PERS_ID, $USER_CONF_U_ID, $USER_PERS_EXT_ID, $c, $c2;
+ $LC_EMAIL = strtolower($USER_EMAIL);
+
+ $q1 = "SELECT last_name, first_name, department, extension, phone_number, email, room, user_id, time_updated, id, web_on, status FROM personnel WHERE LOWER(email)='{$LC_EMAIL}'";
+ //p2($q1);
+ $usr_dir = single_row_select($q1, 0, $c);
+ //p2($usr_dir);
+
+ $q2 = "SELECT id AS conf_id, goo AS conf_goo, email AS conf_email, name AS conf_name, active AS conf_active FROM conf_users WHERE LOWER(email)='{$LC_EMAIL}'";
+ //p2($q2);
+ $usr_conf = single_row_select($q2, 0, $c2);
+ //p2($usr_conf);
+ $mega = __::extend( (object) $usr_dir, (object) $usr_conf );
+
+ $q3 = 'SELECT id AS ext_id, personnel AS personnel_id, role, goo_short, c_users AS c_users_id_ext, ilearn_id, sched_alias, dept1, dept2, gtitle, active, use_dir_photo, general_photo_release, etc, espanol, zoom, preferred_contact FROM gavi_personnel_ext WHERE personnel=' . $mega->id . ';'; // c_users={$mega->conf_id}';
+ //p2($q3);
+ $usr_ext = single_row_select($q3,0,$c2);
+
+ $mega = __::extend( (object) $mega, (object) $usr_ext );
+
+ $q4 = 'SELECT person, officehours, title, picture, education, bio, courses, personal_page, changed FROM webpages WHERE person=' . $mega->id . ';'; // '{$mega->id}'"; // personnel=1');
+
+ //p2($q4);
+ $usr_web = single_row_select($q4,0,$c);
+ //p2($usr_ext);
+ $mega = __::extend( (object) $mega, (object) $usr_web );
+
+ $USER = $mega;
+
+}
+
+
+if ($USER_EMAIL) { user_record(); }
+
+
+
+
+// //
+// //
+// // LOG ENTRIES
+// //
+// //
+
+
+
+// Enter or get browser log entry
+function insert_or_get_browser($b) {
+ global $c2;
+ $BROWSER = ok($b);
+ $existing = does_exist( "SELECT id FROM www_browsers WHERE string='$BROWSER'", 0, $c2);
+ if ($existing) {
+ return $existing;
+ } else {
+ $q = "INSERT INTO www_browsers (string) VALUES ('$BROWSER')";
+ single_row_select($q,0,$c2);
+ return does_exist( "SELECT id FROM www_browsers WHERE string='$BROWSER'",0,$c2);
+ }
+ return 0; }
+
+
+// Log everything!
+function log_it($action) {
+ global $USER, $c2;
+
+ if (! $USER) {
+ $USER = array( 'name'=>'unknown', 'id'=>-1 ); }
+ $user_browser = $_SERVER['HTTP_USER_AGENT'];
+ $user_ip = $_SERVER['REMOTE_ADDR'];
+
+ $BROWSER = insert_or_get_browser($user_browser);
+ $ACTION = ok($action);
+
+ //$id = ok($_POST['id']);
+ $qupdate = "INSERT INTO gavi_logs SET action='{$action}', personnel_id='{$USER->id}', name='{$USER->name}', browser=$BROWSER, ip='$user_ip'";
+ single_row_select($qupdate,0,$c2);
+ return array("result"=>"success","action"=>"logged","query"=>$qupdate,"err"=>mysqli_error($c2));
+}
+
+
+
+
+
+function unescape_commas($s) { return preg_replace('/\[CMA\]/', ',', $s); }
+
+function name_to_lc($fn,$ln) {
+ $fn = str_replace( array( '-', ' '), '', strtolower($fn) );
+ $ln = str_replace( array( '-', ' '), '', strtolower($ln) );
+ return $fn . "_" . $ln;
+}
+function name_to_file($fn,$ln) {
+ $fn = str_replace( array( '-', ' '), '', strtolower($fn) );
+ $ln = str_replace( array( '-', ' '), '', strtolower($ln) );
+ return $fn . "_" . $ln . ".jpg";
+}
+
+function check_dir_photo($fn,$ln) { global $USER;
+ $filename = name_to_file( $fn,$ln );
+ $path = '/gavilan.edu/staff/images_sm/' . $filename;
+ $dir_pic_exists = 0;
+ $dir_pic_path = 'images_sm/nobody.jpg';
+
+ if (file_exists($path)) {
+ $dir_pic_exists = 1;
+ $dir_pic_path = 'images_sm/' . $filename; }
+ $USER->dir_pic_exists = $dir_pic_exists;
+ $USER->dir_pic_path = $dir_pic_path;
+ return $dir_pic_exists;
+}
+
+check_dir_photo($USER->first_name, $USER->last_name);
+
+//
+//
+//
+////////////////////
+////////////////////
+
+
+
+//require __DIR__ . '/vendor/autoload.php';
+
+
+
+
+// Sample URL
+//
+// https://www.gavilan.edu/staff/dir_api.php?a=update&cols=name,msg&vals=peter,hello
+//
+// https://intranet1.gavilan.edu/dir/dir_api.php?a=update&cols=name,msg&vals=peter,hello
+
+
+
+
+
+/*
+
+
+NEXT STEPS:
+
+- figure out permissions system
+
+ - which means knowing dept / hierarchy
+
+ - which means cross referencing PERSONNEL and EXT and CONF_USERS.....
+
+
+
+## Permissions summary
+
+0. There is a list of table+column combos that users are allowed to edit.
+0.5 An activity "belongs" to the user who owns it (or created it).
+
+1. Simple cases:
+ - current user is updating their own (allowable) record. Allow.
+2. Superuser:
+ - current user is executive, hr, it, or root. (7,2,8,3) Allow.
+3. User is "Dept Editor" (4) and
+ -is updating a record belonging to someone in their dept. Allow.
+4. Harder: Updating events
+
+5. Updating attendance, approvals, or other restricted tables. Only FPLC (1) or superusers.
+
+*/
+
+
+function check_permission( $acting_user, $target_user, $table ) {
+
+ // TODO
+ return true;
+}
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Everyone. Basic dir. Include status==0 which is unpublished.
+function staff_dir() { global $c;
+ return multi_row_select('SELECT first_name,last_name,department,status, room,phone_number,email,web_on,id FROM personnel',1, $c);
+ // WHERE status IS null OR status=1
+}
+
+
+// Everyone. Basic dir
+function staff_dir_ext() { global $c;
+ return multi_row_select('SELECT p.first_name,p.last_name,p.department,p.status, p.room,phone_number,LOWER(p.email) AS email,p.web_on, p.id, e.id AS ext_id, e.role, e.goo_short, e.c_users AS c_users_id_ext, e.ilearn_id, e.sched_alias, e.dept1, e.dept2, e.gtitle, e.active, e.use_dir_photo, e.general_photo_release, e.dir_photo_path, e.etc, c.id AS conf_id, c.goo AS conf_goo, c.name AS conf_name FROM gavi_db.personnel p LEFT JOIN PeterDB.gavi_personnel_ext e ON p.id=e.personnel LEFT JOIN PeterDB.conf_users c ON LOWER(p.email)=LOWER(c.email) ORDER BY p.last_name LIMIT 5000',1, $c);
+}
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='list') {
+ echo staff_dir_ext(); exit(); }
+
+
+// Everyone. Directory info with DEPTS and TITLES added
+function staff_dir_full_ext() { global $c;
+ return multi_row_select('SELECT p.first_name,p.last_name,p.department,p.status, p.room,phone_number,LOWER(p.email) AS email,p.web_on, p.id, e.id AS ext_id, e.role, e.goo_short, e.c_users AS c_users_id_ext, e.ilearn_id, e.sched_alias, e.dept1, e.dept2, e.gtitle, e.active, e.use_dir_photo, e.general_photo_release, e.dir_photo_path, e.etc, e.espanol, e.zoom, e.preferred_contact, c.id AS conf_id, c.goo AS conf_goo, c.name AS conf_name, d.name AS dept1name, t.name AS titlename, d.parent AS deptparent FROM gavi_db.personnel p LEFT JOIN PeterDB.gavi_personnel_ext e ON p.id=e.personnel LEFT JOIN PeterDB.conf_users c ON LOWER(p.email)=LOWER(c.email) LEFT JOIN PeterDB.gavi_departments d ON e.dept1=d.id LEFT JOIN PeterDB.gavi_titles t ON e.gtitle=t.id ORDER BY p.last_name LIMIT 5000',1, $c);
+}
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='list2') { echo staff_dir_full_ext(); exit(); }
+
+
+
+
+
+// Courses in a semester
+function semester_sections() { global $c2;
+ return multi_row_select("SELECT * FROM `gavi_sections` s WHERE s.sem='fa21' ORDER BY s.teacher_id",1, $c2); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='list/semester') {
+ echo semester_sections(); exit(); }
+
+
+
+
+
+
+// STAFF + COURSES COMBINED
+function staff_dir_w_sections() { global $c;
+
+ // just one semesters sections?
+ $WHERE = "WHERE pgs.sem='fa21'";
+
+ // all recorded semesters
+ $WHERE = "";
+
+ return multi_row_select("SELECT p.first_name,p.last_name,p.department,p.status,p.staff_type, p.room,phone_number,LOWER(p.email) AS email,p.web_on, p.id, e.id AS ext_id, e.role, e.goo_short, e.c_users AS c_users_id_ext, e.ilearn_id, e.sched_alias, e.dept1, e.dept2, e.gtitle, e.active, e.use_dir_photo, e.general_photo_release, e.dir_photo_path, e.etc, e.espanol, e.zoom, e.preferred_contact, c.id AS conf_id, c.goo AS conf_goo, c.name AS conf_name, d.name AS dept1name, t.name AS titlename, d.parent AS deptparent, GROUP_CONCAT(DISTINCT s.code SEPARATOR ', ') AS sections, COUNT(s.code) AS num_taught FROM gavi_db.personnel p LEFT JOIN PeterDB.gavi_personnel_ext e ON p.id=e.personnel LEFT JOIN PeterDB.conf_users c ON LOWER(p.email)=LOWER(c.email) LEFT JOIN PeterDB.gavi_departments d ON e.dept1=d.id LEFT JOIN PeterDB.gavi_titles t ON e.gtitle=t.id LEFT JOIN ( SELECT * FROM PeterDB.gavi_sections pgs {$WHERE}) s ON e.id=s.teacher_id GROUP BY p.id ORDER BY p.last_name LIMIT 2500",0, $c);
+
+}
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='list/staffsemester') {
+ echo json_encode(staff_dir_w_sections()); exit(); }
+
+
+
+
+// JOB TITLES LIST
+function job_titles() { global $c2;
+
+ return multi_row_select("SELECT DISTINCT id, name FROM gavi_titles ORDER BY name",1, $c2);
+
+}
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='get/jobtitles') {
+ echo job_titles(); exit(); }
+
+
+
+
+
+//
+//
+//
+//
+//
+// Helper tables
+function sub_menus() { global $c2;
+ $ddd = multi_row_select('SELECT * FROM gavi_departments ORDER BY name',0, $c2);
+ $ttt = multi_row_select('SELECT * FROM gavi_titles ORDER BY name',0, $c2);
+ $rrr = multi_row_select("SELECT * FROM gavi_roles ORDER BY 'descr'",0, $c2);
+ $ccc = multi_row_select('SELECT * FROM gavi_committees ORDER BY name',0, $c2);
+
+ return json_encode( array( 'departments'=>$ddd, 'titles'=>$ttt, 'roles'=>$rrr, 'committees'=>$ccc ) );
+ exit();
+}
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='menus') {
+ echo sub_menus(); exit(); }
+
+
+
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// GAVILAN COLLEGE EVENTS
+//
+function get_events() {
+ global $c;
+ echo json_encode( multi_row_select("SELECT * FROM events WHERE date >= CURDATE() AND visible='1' ORDER BY time LIMIT 6;",0, $c));
+ // no exit cause it gets called in pages
+}
+if (isset($_GET['a']) && $_GET['a'] == 'get/gavevents') { get_events(); }
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// SEARCH AN INSTRUCTOR BY NAME IN SCHEDULE
+//
+function get_instructor() {
+ global $c2;
+ $i = ok($_REQUEST['inst']);
+ echo json_encode( single_row_select("SELECT * FROM gavi_personnel_ext WHERE sched_alias='{$i}';",0, $c2));
+ exit(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a'] == 'get/instructor/name' ) { get_instructor(); }
+
+function get_instructor_fuzzy() {
+ global $c2;
+ $i = ok($_REQUEST['inst']);
+ echo json_encode( single_row_select("SELECT * FROM gavi_personnel_ext WHERE sched_alias LIKE '{$i}';",0, $c2));
+ exit(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a'] == 'get/instructor/fuzzyname' ) { get_instructor_fuzzy(); }
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// COURSE SECTIONS in a semester
+//
+function get_sections($semester) {
+ global $c;
+ $semester = ok($semester);
+ echo json_encode( multi_row_select("SELECT s.id,s.code,s.name,s.descr,s.teacher_id,s.days,s.start_date,s.end_date,s.units,s.ztc,s.location,s.delivery,s.status,s.pnp,s.note,s.crn,s.sem,p.personnel AS personnel_id,p.use_dir_photo,p.dir_photo_path,d.last_name,d.first_name,d.phone_number,d.email,d.room,d.web_on,s.sem FROM PeterDB.gavi_sections s LEFT JOIN PeterDB.gavi_personnel_ext p ON s.teacher_id=p.id LEFT JOIN personnel d ON d.id=p.personnel WHERE sem='{$semester}' ORDER BY code;",0, $c));
+ exit(); }
+if (isset($_REQUEST['a']) && preg_match('/^get\/sections\/(\w\w\d\d)$/', $_REQUEST['a'], $matches)) {
+ get_sections( $matches[1] ); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// all COURSE SECTIONS by semester and crn only
+//
+function get_all_sections() {
+ global $c;
+ echo json_encode( multi_row_select("SELECT s.id,s.code,s.crn,s.sem,s.teacher_id,s.delivery,s.status,p.personnel AS personnel_id,d.last_name,d.first_name FROM PeterDB.gavi_sections s LEFT JOIN PeterDB.gavi_personnel_ext p ON s.teacher_id=p.id LEFT JOIN personnel d ON d.id=p.personnel ORDER BY sem,code;",0, $c));
+ exit(); }
+if (isset($_REQUEST['a']) && $_GET['a'] == 'get/sections') { get_all_sections(); }
+
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// all COURSE SECTIONS of a single INSTRUCTOR
+//
+// use their gavi_personnel_ext id
+//
+function get_instructor_sections($teacherid) {
+ global $c;
+ echo json_encode( multi_row_select("SELECT s.id,s.code,s.name,s.descr,s.teacher_id,s.days,s.times,s.link,s.start_date,s.end_date,s.units,s.ztc,s.location,s.delivery,s.xlist_to,s.status,s.pnp,s.note,s.crn,s.sem,s.year FROM PeterDB.gavi_sections s WHERE s.teacher_id='{$teacherid}' ORDER BY s.sem,s.code;",0, $c));
+ exit(); }
+if (isset($_REQUEST['a']) && preg_match('/^get\/sections\/(\d+)$/', $_REQUEST['a'], $matches)) {
+ get_instructor_sections( $matches[1] ); }
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// get COURSE SINGLE SECTION including welcome letter
+//
+// Housekeeping: if the gavi_welcome_letters row doesn't exist, we need to make it and populate it with the example text.
+//
+//
+function get_section($sem,$crn) {
+ global $c, $c2;
+ $sem = ok($sem);
+ $crn = ok($crn);
+ //echo $sem;
+ //echo $crn;
+
+
+ $sched_id = 0;
+
+ $sched_entry = single_row_select( "SELECT * FROM PeterDB.gavi_sections gs WHERE sem='{$sem}' AND crn='{$crn}';",0, $c2);
+ if ($sched_entry) {
+ $sched_id = $sched_entry['id'];
+ }
+ else {
+ echo "no row for that section ";
+ exit();
+ }
+
+ $wl_entry = single_row_select( "SELECT s.id,s.code,s.name,s.descr,s.teacher_id,s.days,s.start_date,s.end_date,s.units,s.ztc,s.location,s.delivery,s.status,s.pnp,s.note,s.crn,s.sem,w.id AS wl_id,w.photo_path,w.format,w.length,w.course_desc,w.what_expect,w.assessments,w.textbook,w.other_info,w.introduction,w.additional_resources FROM PeterDB.gavi_welcome_letters w LEFT JOIN PeterDB.gavi_sections s ON w.section_id=s.id WHERE w.section_id='{$sched_id}';",0, $c2);
+ if ($wl_entry) {
+ echo json_encode($wl_entry);
+ exit();
+ }
+ else {
+ // no WL row for that section
+
+ $logaction = log_it("Creating default welcome letter for Semester: $sem CRN: $crn");
+
+ $default = json_decode( file_get_contents('default_welcome_letter.json') );
+ $default->what_expect = okh($default->what_expect);
+ $default->assessments = okh($default->assessments);
+ $default->textbook = okh($default->textbook);
+ $default->other_info = okh($default->other_info);
+ $default->introduction = okh($default->introduction);
+ $default->additional_resources = okh($default->additional_resources);
+
+ $q = "INSERT INTO PeterDB.gavi_welcome_letters (section_id,format,length,text_title,course_desc,what_expect,assessments,textbook,other_info,introduction,additional_resources) VALUES ('{$sched_id}', '', '', '', '', '{$default->what_expect}', '{$default->assessments}', '{$default->textbook}', '{$default->other_info}', '{$default->introduction}', '{$default->additional_resources}');";
+ $new_id = single_row_insert($q,0,$c2);
+
+ $q4 = "SELECT s.id,s.code,s.name,s.descr,s.teacher_id,s.days,s.start_date,s.end_date,s.units,s.ztc,s.location,s.delivery,s.status,s.pnp,s.note,s.crn,s.sem,w.id AS wl_id, w.photo_path,w.format,w.length,w.course_desc,w.what_expect,w.assessments,w.textbook,w.other_info,w.introduction,w.additional_resources FROM PeterDB.gavi_welcome_letters w LEFT JOIN PeterDB.gavi_sections s ON w.section_id=s.id WHERE w.id=" . $new_id . ";";
+
+ $wl_entry = single_row_select( $q4, 0, $c2);
+
+ echo json_encode($wl_entry);
+ exit();
+ }
+ exit(); }
+if (isset($_REQUEST['a']) && preg_match('/^get\/section\/(\w\w\d\d)\/(\d+)$/', $_REQUEST['a'], $matches)) {
+ get_section( $matches[1], $matches[2] ); }
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// GET LIST OF ALL SESSIONS / WORKSHOPS / EVENTS
+//
+function get_sessions() {
+ global $c2, $AY;
+ return multi_row_select("SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,c.cal_uid,sst.type,sst.id AS typeId, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c LEFT JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE c.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME) GROUP BY c.id ORDER BY c.track, c.starttime;",0, $c2); }
+
+if (isset($_GET['a']) && $_GET['a'] == 'get/sessions') { echo json_encode(get_sessions()); exit(); }
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// LIST THE CURRENT USER'S SIGNED UP, (OR HOSTING,) SESSIONS / WORKSHOPS / EVENTS
+//
+function get_user_sessions() {
+ global $c2, $AY, $USER;
+ $my_sessions = multi_row_select("SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,sst.type,sst.id AS typeId, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c JOIN conf_signups as sup on c.id=sup.session LEFT JOIN conf_hosts as h ON h.session=c.id JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE (h.host='{$USER->conf_id}' OR sup.user='{$USER->conf_id}') AND c.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME) GROUP BY c.id ORDER BY c.track, c.starttime;",0,$c2);
+ echo json_encode($my_sessions);
+ exit(); }
+if (isset($_GET['a']) && $_GET['a'] == 'get/mysessions') { get_user_sessions(); }
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// ARBITRARY USER'S SIGNED UP, (OR HOSTING,) SESSIONS / WORKSHOPS / EVENTS
+//
+// all years
+//
+function get_anyuser_sessions($usr) {
+ global $c2, $AY, $USER;
+ $my_sessions = multi_row_select("SELECT c.id,c.title,c.desc,c.length,c.starttime,c.track,c.location,c.gets_survey,c.category,c.parent,c.recording,c.instructions,c.image_url,c.is_flex_approved,sst.type,sst.id AS typeId, GROUP_CONCAT(ctg.tag) AS tags FROM conf_sessions c JOIN conf_signups as sup on c.id=sup.session LEFT JOIN conf_hosts as h ON h.session=c.id JOIN conf_sessiontypes sst ON c.type=sst.id LEFT JOIN conf_tagmember ct ON c.id=ct.session LEFT JOIN conf_tags ctg ON ctg.id=ct.tag WHERE (h.host='{$usr}' OR sup.user='{$usr}') GROUP BY c.id ORDER BY c.starttime LIMIT 150;",0,$c2);
+ // AND c.starttime BETWEEN CAST('{$AY['begin']}' AS DATE) AND CAST('{$AY['end']}' AS DATETIME)
+
+ return $my_sessions; }
+if (isset($_GET['a']) && preg_match('/get\/sessions\/(\d+)$/', $_GET['a'], $matches)) { echo json_encode( get_anyuser_sessions($matches[1])); exit(); }
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// get most RECENT LOGS
+//
+function get_recent_logs() {
+ global $c2, $USER;
+ $my_sessions = multi_row_select("SELECT * FROM `gavi_logs` ORDER BY `id` DESC LIMIT 150",0,$c2);
+ echo json_encode($my_sessions);
+ exit(); }
+if (isset($_GET['a']) && $_GET['a'] == 'get/logs') { get_recent_logs(); }
+
+
+
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// SIGNUP for (possibly overlapping time) session ...
+//
+function signup() {
+ global $c2, $AY, $USER;
+ preg_match('/signup\/(\d+)$/', $_GET['a'], $matches);
+ $ses = $matches[1];
+ $ts = date("Y-m-d H:i:s");
+ $logaction = log_it("Signed up for session: {$ses}");
+
+ $existing = does_exist(
+ "SELECT i.id FROM conf_signups AS i JOIN conf_sessions AS s ON i.session=s.id WHERE s.id={$ses} AND i.user={$USER->id_c_users}",0,$c2);
+ if ($existing) {
+ $qupdate = "UPDATE conf_signups SET session={$ses}, timestamp='{$ts}' WHERE session={$ses} AND user={$USER->id_c_users}";
+ single_row_select($qupdate,1,$c2);
+ echo json_encode( array("result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$qupdate,"err"=>mysqli_error($c2)));
+ } else {
+ $q = "INSERT INTO conf_signups (session,user,timestamp) VALUES ({$ses},{$USER->id_c_users},'{$ts}')";
+ single_row_select($q,1,$c2);
+ echo json_encode( array("result"=>"success","action"=>"inserted","logaction"=>$logaction, "ses"=>$_SESSION,"query"=>$q,"err"=>mysqli_error($c2)));
+ } exit(); }
+
+if (isset($_GET['a']) && preg_match('/signup\/(\d+)$/', $_GET['a'], $matches)) { signup(); }
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// CANCEL a signup
+//
+function signdown() {
+ global $c2, $AY, $USER;
+ preg_match('/signdown\/(\d+)$/', $_GET['a'], $matches);
+ $ses = $matches[1];
+ $q = "DELETE FROM conf_signups WHERE session={$ses} AND user={$USER->id_c_users}";
+ single_row_select($q,1,$c2);
+ $logaction = log_it("Canceled signup for session: $ses");
+
+ echo json_encode( array("result"=>"success","action"=>"deleted","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ exit(); }
+
+if (isset($_GET['a']) && preg_match('/signdown\/(\d+)$/', $_GET['a'], $matches)) { signdown(); }
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// NEW SESSION
+//
+function new_session() {
+ global $c2, $AY, $USER;
+
+
+ $title = ok($_POST['title']); $starttime = ok($_POST['starttime']);
+ $length = ok($_POST['length']); if ($length=='') { $length=1; }
+ $track = ok($_POST['track']); $gets_survey = ok($_POST['gets_survey']);
+ $is_flex_approved = ok($_POST['is_flex_approved']); $category = ok($_POST['title']);
+ if ($category=='') { $category=0; }
+ $author = ok($_POST['author']); if ($author=='') { $author=1; } // $USER->id_c_users; }
+ $is_custom = ok($_POST['is_custom']); $parent = ok($_POST['parent']);
+ $desc = okh($_POST['desc']); $location = okh($_POST['location']);
+ $recording = okh($_POST['recording']); $instructions = okh($_POST['instructions']);
+ $type = ok($_POST['type']); if ($type=='') { $type=19; }
+ $cal_uid = ok($_POST['cal_uid']);
+
+
+ $q = "INSERT INTO conf_sessions (`title`,`starttime`,`length`,`track`,`gets_survey`,`is_flex_approved`,`category`,`author`,`is_custom`,`parent`,`desc`,`location`,`recording`,`instructions`,`type`,`cal_uid`) VALUES ('{$title}', '{$starttime}', '{$length}', '{$track}', '{$gets_survey}', '{$is_flex_approved}', '{$category}', '{$author}', '{$is_custom}', '{$parent}', '{$desc}', '{$location}', '{$recording}', '{$instructions}', '{$type}', '{$cal_uid}');";
+ $ins = single_row_insert($q,0,$c2);
+ $logaction = log_it("created new session: {$title}");
+ echo json_encode( array("result"=>"success","action"=>"inserted new session","insert"=>$ins, "query"=>$q,"logaction"=>$logaction,"err"=>mysqli_error($c2)));
+ exit(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='set/newsession') { new_session(); }
+
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// Editing of session info
+//
+function set_sessioninfo() {
+ global $c, $c2, $AY, $USER;
+ $table = 'conf_sessions';
+
+ if (isset($_POST['id'])) {
+ $ID = ok($_REQUEST['id']);
+ if (! check_permission( $USER->id, $ID, $table)) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("edited session id: {$ID}");
+ $WHERECLAUSE = " WHERE id={$ID}";
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . okh($a[1]) . "', "; }, "UPDATE {$table} SET ");
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+ single_row_select($q,0,$c1);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ }
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"no activity id specified") ); }
+ exit(); }
+//if (isset($_POST['a']) && $_POST['a']=='update/activity') { set_sessioninfo(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update/activity') { set_sessioninfo(); }
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update a name, lname, dept, phone, extension, email, type, room, status, user_id, or web_on
+function update_dir() {
+ global $USER, $c, $c2;
+
+ $WHERECLAUSE = " WHERE id={$USER->id}";
+
+ if (isset($_POST['id'])) { // editing another person's data
+ if (! check_permission( $USER->id, $_POST['id'], 'personnel')) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("updating personnel record of personnel id {$_POST['id']}");
+ $WHERECLAUSE = " WHERE id={$_POST['id']}";
+ }
+ } else {
+ $logaction = log_it("updating personnel record");
+ }
+
+ // date modified is now
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, "UPDATE personnel SET ");
+ //$q = substr($q, 0, -2);
+ $q .= "time_updated='" . $date . "'";
+ $q .= $WHERECLAUSE;
+ if ($USER->id) {
+ single_row_select($q,0,$c);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c)));
+ }
+ else {
+ $logaction2 = log_it("failed to update personnel record");
+ echo json_encode( array("result"=>"fail", "err"=>"dont have an id for user") );
+ }
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update') { update_dir(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update') { update_dir(); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update goo, dept1/dept2, title, active, use_dir_photo
+function update_dir_ext() {
+ global $USER, $c, $c2;
+
+ $WHERECLAUSE = " WHERE id={$USER->ext_id}";
+
+ #print_r($_REQUEST);
+
+ if (isset($_REQUEST['id'])) { // editing another person's data
+ if (! check_permission( $USER->id, $_REQUEST['id'], 'personnel_ext')) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("updating personnel_ext record of personnel id {$_REQUEST['id']}");
+ $WHERECLAUSE = " WHERE id={$_REQUEST['id']}";
+ }
+ } else {
+ $logaction = log_it("updating personnel_ext record");
+ }
+
+ // date modified is now
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, "UPDATE gavi_personnel_ext SET ");
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+ single_row_select($q,0,$c2);
+ echo json_encode( array("result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update_xt') { update_dir_ext(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update_xt') { update_dir_ext(); }
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update person, officehours, title, picture, education, bio, courses, personal_page, changed
+function update_webpage() {
+ global $USER_PERS_ID, $USER, $c, $c2;
+
+ $WHERECLAUSE = " WHERE person={$USER->id}";
+
+ if (isset($_POST['id'])) { // editing another person's data
+ if (! check_permission( $USER->id, $_POST['id'], 'personnel')) {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ } else {
+ $logaction = log_it("updating bio webpage record of personnel id {$_POST['id']}");
+ $WHERECLAUSE = " WHERE person={$_POST['id']}";
+ }
+ } else {
+ $logaction = log_it("updating bio webpage record");
+ }
+ $date = date('Y-m-d H:i:s');
+
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . okh($a[1]) . "', "; }, "UPDATE webpages SET ");
+ $q .= "changed='" . $date . "'";
+ $q .= $WHERECLAUSE;
+ if ($USER->id) {
+ single_row_select($q,0,$c);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>"updated","logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c)));
+ }
+ else {
+ $logaction2 = log_it("failed to update bio webpage record");
+ echo json_encode( array("result"=>"fail", "err"=>"dont have an id for user") );
+ }
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update_web') { update_webpage(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update_web') { update_webpage(); }
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update a course section record
+function update_section($update=1) {
+ global $USER, $c2;
+ $WHERECLAUSE = "";
+ $START = "INSERT INTO gavi_sections SET ";
+ $action = "inserted";
+
+ if ( check_permission( $USER->id, 0, 'gavi_sections')) {
+ if ($update) {
+ $START = "UPDATE webpages SET ";
+ $WHERECLAUSE = " WHERE id={$_REQUEST['id']}";
+ $action = "updated";
+ $logaction = log_it("updating section id {$_REQUEST['id']}");
+ } else {
+ $logaction = log_it("inserting new section");
+ }
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ }
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . ok($a[1]) . "', "; }, $START);
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+
+ single_row_select($q,0,$c2);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>$action,
+ "logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update/section') { update_section(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update/section') { update_section(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='add/section') { update_section(0); }
+
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// update a WELCOME LETTER
+//
+function update_welcome_letter($update=1) {
+ global $USER, $c2;
+ $WHERECLAUSE = "";
+ $START = "INSERT INTO gavi_welcome_letters SET ";
+ $action = "inserted";
+
+ if ( check_permission( $USER->id, 0, 'gavi_welcome_letters')) {
+ if ($update) {
+ $START = "UPDATE gavi_welcome_letters SET ";
+ $WHERECLAUSE = " WHERE id={$_REQUEST['id']}";
+ $action = "updated";
+ $logaction = log_it("updating welcome letter id {$_REQUEST['id']}");
+ } else {
+ $logaction = log_it("inserting new welcome letter");
+ }
+ } else {
+ echo json_encode( array("result"=>"fail", "err"=>"dont have permission to edit this") );
+ exit();
+ }
+ $cols = explode(',', $_REQUEST['cols']); $vals = explode(',', $_REQUEST['vals']);
+ $vals = __::map($vals, unescape_commas);
+ $cv = __::zip($cols,$vals);
+ $q = __::reduce($cv, function($memo, $a) { return $memo . ok($a[0]) . "='" . okh($a[1]) . "', "; }, $START);
+ $q = substr($q, 0, -2);
+ $q .= $WHERECLAUSE;
+
+ single_row_select($q,0,$c2);
+ echo json_encode( array("rawvalstr"=>$_REQUEST['vals'], "result"=>"success","action"=>$action,
+ "logaction"=>$logaction, "query"=>$q,"err"=>mysqli_error($c2)));
+ exit();
+}
+
+//if (isset($_POST['a']) && $_POST['a']=='update/letter') { update_welcome_letter(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='update/letter') { update_welcome_letter(); }
+if (isset($_REQUEST['a']) && $_REQUEST['a']=='add/letter') { update_welcome_letter(0); }
+
+
+
+
+
+
+
+
+function handle_pic_upload() { global $USER;
+ $uploaddir = '/gavilan.edu/staff/uploads/';
+ $date = date('Ymd_Hi');
+ $uploadfile = $uploaddir . name_to_lc($USER->first_name,$USER->last_name) . "_" . $date . "_" . basename($_FILES['file']['name']);
+
+
+ echo '';
+ if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) {
+ echo "File is valid, and was successfully uploaded.\n";
+ } else {
+ echo "Possible file upload attack!\n";
+ }
+
+ echo 'Here is some more debugging info:';
+ print_r($_FILES);
+
+ print " ";
+
+}
+//if (isset($_REQUEST['file'])) { handle_pic_upload(); }
+if (isset($_FILES['file'])) { handle_pic_upload(); }
+
+
+
+
+
+
+function get_a_user_by_pid($user_pid) { global $c, $c2;
+ $q1 = "SELECT last_name, first_name, department, extension, phone_number, email, room, user_id, time_updated, id, web_on FROM personnel WHERE id='{$user_pid}'";
+ //p2($q1);
+ $usr_dir = single_row_select($q1, 0, $c);
+ //p2($usr_dir);
+
+ $q2 = "SELECT id AS id_c_users, goo, email AS email_c_users, name, active FROM conf_users WHERE email='{$usr_dir['email']}'";
+ //p2($q2);
+ $usr_conf = single_row_select($q2, 0, $c2);
+ //p2($usr_conf);
+ $mega = __::extend( (object) $usr_dir, (object) $usr_conf );
+
+ $q3 = "SELECT id AS ext_id, personnel AS personnel_id, goo_short, c_users AS c_users_id_ext, ilearn_id, sched_alias, dept1, dept2, gtitle, active, use_dir_photo, etc FROM gavi_personnel_ext WHERE personnel='{$mega->id}'";
+ $usr_ext = single_row_select($q3,0,$c2);
+ //p2($usr_ext);
+ $mega = __::extend( (object) $mega, (object) $usr_ext );
+
+ $q4 = 'SELECT person, officehours, title, picture, education, bio, courses, personal_page, changed FROM webpages WHERE person=' . $mega->id; // personnel=1');
+ //p2($q3);
+ $usr_web = single_row_select($q4,0,$c);
+ //p2($usr_ext);
+ $mega = __::extend( (object) $mega, (object) $usr_web );
+
+ // ?????
+
+
+ /* if (!isset($mega->use_dir_photo)) {
+ $mega->pic_exists = check_dir_photo($mega->first_name, $mega->last_name);
+ if ($mega->pic_exists) {
+ $filename = "images_sm/" . name_to_file( $mega->first_name, $mega->last_name );
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=1, dir_photo_path='{$filename}' WHERE id='{$mega->ext_id}'";
+ } else {
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=0 WHERE id='{$mega->ext_id}'";
+ }
+ }
+ if (! isset($mega->ext_id)) {
+ $mega->aaqueryfix = "INSERT INTO gavi_personnel_ext (personnel) VALUES('{$mega->id}')"; }
+ elseif ($mega->id && ! $mega->personnel_id) {
+ $mega->aaqueryfix = "UPDATE gavi_personnel_ext SET personnel='{$mega->id}' WHERE id='{$mega->ext_id}'"; }
+ */
+
+ echo json_encode( $mega );
+ exit();
+
+}
+if (isset($_REQUEST['a']) && preg_match('/^get\/user\/(\d+)$/', $_REQUEST['a'], $matches)) { get_a_user_by_pid( $matches[1] ); }
+
+
+function get_a_user($user_email) { global $c, $c2;
+ $q1 = "SELECT last_name, first_name, department, extension, phone_number, email, room, user_id, time_updated, id, web_on FROM personnel WHERE email='" . $user_email . "'";
+ //p2($q1);
+ $usr_dir = single_row_select($q1, 0, $c);
+ //p2($usr_dir);
+
+ $q2 = "SELECT id AS id_c_users, goo, email AS email_c_users, name, active FROM conf_users WHERE email='" . $user_email . "'";
+ //p2($q2);
+ $usr_conf = single_row_select($q2, 0, $c2);
+ //p2($usr_conf);
+ $mega = __::extend( (object) $usr_dir, (object) $usr_conf );
+
+ $q3 = 'SELECT id AS ext_id, personnel AS personnel_id, goo_short, c_users AS c_users_id_ext, ilearn_id, sched_alias, dept1, dept2, gtitle, active, use_dir_photo, etc FROM gavi_personnel_ext WHERE personnel=' . $mega->id;
+ //p2($q3);
+ $usr_ext = single_row_select($q3,0,$c2);
+ //p2($usr_ext);
+ $mega = __::extend( (object) $mega, (object) $usr_ext );
+
+ $q4 = 'SELECT person, officehours, title, picture, education, bio, courses, personal_page, changed FROM webpages WHERE person=' . $mega->id; // personnel=1');
+ //p2($q3);
+ $usr_web = single_row_select($q4,0,$c);
+ //p2($usr_ext);
+ $mega = __::extend( (object) $mega, (object) $usr_web );
+
+ /*
+ if (!isset($mega->use_dir_photo)) {
+ $mega->pic_exists = check_dir_photo($mega->first_name, $mega->last_name);
+ if ($mega->pic_exists) {
+ $filename = "images_sm/" . name_to_file( $mega->first_name, $mega->last_name );
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=1, dir_photo_path='{$filename}' WHERE id='{$mega->ext_id}'";
+ } else {
+ $mega->bbqueryfix = "UPDATE gavi_personnel_ext SET use_dir_photo=0 WHERE id='{$mega->ext_id}'";
+ }
+ }
+ if (! isset($mega->ext_id)) {
+ $mega->aaqueryfix = "INSERT INTO gavi_personnel_ext (personnel) VALUES('{$mega->id}')"; }
+ elseif ($mega->id && ! $mega->personnel_id) {
+ $mega->aaqueryfix = "UPDATE gavi_personnel_ext SET personnel='{$mega->id}' WHERE id='{$mega->ext_id}'"; }
+ */
+
+ return $mega;
+
+}
+
+
+function insert_c2($q) {
+ global $c2;
+ $result = single_row_insert($q,0,$c2);
+ return $result; }
+
+function merge_tables() { global $c;
+ $all_personnel = multi_row_select('SELECT first_name,last_name,department,room,phone_number,email,web_on,id FROM personnel WHERE status IS null OR status=1',0, $c);
+
+ $emails = __::pluck($all_personnel, 'email');
+ //echo json_encode($emails);
+ //exit();
+
+ //$emails = array_slice($emails, 0, 10);
+
+ $full = __::map( $emails, get_a_user );
+
+ //echo json_encode($full);
+
+ //$results = __::map( __::pluck($full,'aaqueryfix'), insert_c2);
+
+ //$results = __::pluck($full,'bbqueryfix');
+ //$results = __::map( $results, insert_c2);
+ echo json_encode( $full );
+ exit(); }
+if (isset($_REQUEST['merge'])) { merge_tables(); }
+
+
+
+/*
+echo basename(__FILE__);
+echo " ";
+echo basename($_SERVER["SCRIPT_FILENAME"]);
+*/
+
+
+
+
+//
+//
+// DO NOTHING IF FILE WAS INCLUDED
+//
+// OTHERWISE, RETURN BASIC USER INFO
+//
+//
+if (basename(__FILE__) == basename($_SERVER["SCRIPT_FILENAME"])) {
+ // Called directly as api or in browser
+ //
+ if ($USER_EMAIL) {
+ // log it as an access
+ $logaction = log_it("accessed personnel record editor (in peters hhh tester folder)");
+
+ $USER->logresult = $logaction;
+
+ // Default case is current user data to be embedded in editor page
+ echo json_encode($USER);
+ exit();
+ } else {
+ echo json_encode( array("result"=>"not logged in") );
+ exit();
+ }
+}
+
+//
+// ELSE it was "included"...
+
+?>
diff --git a/ed_act.php b/ed_act.php
new file mode 100644
index 0000000..bfa060b
--- /dev/null
+++ b/ed_act.php
@@ -0,0 +1,78 @@
+
+
+
+
+ Activities & Events > Edit Activity";
+ $MY_PATH = $_SERVER['PHP_SELF'];
+ $MOD_DATE = '(?)';
+ if (file_exists(__FILE__)) { $MOD_DATE = date ("F d Y H:i:s.", filemtime(__FILE__)); }
+
+ $WHICH = 0;
+ if (isset($_REQUEST['w'])) { $WHICH = $_REQUEST['w']; }
+ else {
+ $MY_TITLE = "Create Activity";
+ }
+ ?>
+
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+
+ Alert message
+
+
+
+
diff --git a/flex.php b/flex.php
new file mode 100644
index 0000000..f666763
--- /dev/null
+++ b/flex.php
@@ -0,0 +1,81 @@
+
+
+
+
+ Staff > Activities";
+ $MY_PATH = $_SERVER['PHP_SELF'];
+ $MOD_DATE = '(?)';
+ if (file_exists(__FILE__)) { $MOD_DATE = date ("F d Y H:i:s.", filemtime(__FILE__)); }
+ if (isset($_GET['s'])) { $FOCUS = "'" . $_GET['s'] . "'"; }
+ else { $FOCUS = "'all'"; }
+
+ ?>
+
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+
+
+
+
+
+
+
+
+ choose academic year
+ dates / hours of flex days
+ add a conf, workshop, meeting
+ add, edit, display project
+ add, edit, display courses
+ show required hours
+ show total planned / actual hours
+ show timeline / deadlines / stage
+ ask achievements
+ icons for approved, clarification
+ show overall status
+
+
+
+
+
+
+
+
+ Alert message
+
+
+
+
diff --git a/graf/X_simple_2.png b/graf/X_simple_2.png
new file mode 100644
index 0000000..b99d372
Binary files /dev/null and b/graf/X_simple_2.png differ
diff --git a/graf/bird_logo.png b/graf/bird_logo.png
new file mode 100644
index 0000000..902850e
Binary files /dev/null and b/graf/bird_logo.png differ
diff --git a/graf/flag_1_red.png b/graf/flag_1_red.png
new file mode 100644
index 0000000..7495eed
Binary files /dev/null and b/graf/flag_1_red.png differ
diff --git a/graf/pic_1.png b/graf/pic_1.png
new file mode 100644
index 0000000..8423564
Binary files /dev/null and b/graf/pic_1.png differ
diff --git a/graf/pic_1_add.png b/graf/pic_1_add.png
new file mode 100644
index 0000000..510a949
Binary files /dev/null and b/graf/pic_1_add.png differ
diff --git a/graf/play_video.png b/graf/play_video.png
new file mode 100644
index 0000000..a8fe72d
Binary files /dev/null and b/graf/play_video.png differ
diff --git a/graf/profile_card.png b/graf/profile_card.png
new file mode 100644
index 0000000..e8bd7dd
Binary files /dev/null and b/graf/profile_card.png differ
diff --git a/graf/profile_close_2.png b/graf/profile_close_2.png
new file mode 100644
index 0000000..f424e7a
Binary files /dev/null and b/graf/profile_close_2.png differ
diff --git a/graf/smile_happy_1.png b/graf/smile_happy_1.png
new file mode 100644
index 0000000..264cb2e
Binary files /dev/null and b/graf/smile_happy_1.png differ
diff --git a/graf/smile_meh.png b/graf/smile_meh.png
new file mode 100644
index 0000000..649bf6c
Binary files /dev/null and b/graf/smile_meh.png differ
diff --git a/graf/smile_sad_1.png b/graf/smile_sad_1.png
new file mode 100644
index 0000000..0d57344
Binary files /dev/null and b/graf/smile_sad_1.png differ
diff --git a/graf/textlogo_120.gif b/graf/textlogo_120.gif
new file mode 100644
index 0000000..c7aff86
Binary files /dev/null and b/graf/textlogo_120.gif differ
diff --git a/graf/time_1.png b/graf/time_1.png
new file mode 100644
index 0000000..55dba9f
Binary files /dev/null and b/graf/time_1.png differ
diff --git a/graf/time_2.png b/graf/time_2.png
new file mode 100644
index 0000000..d2ff5e6
Binary files /dev/null and b/graf/time_2.png differ
diff --git a/graf/video_2.png b/graf/video_2.png
new file mode 100644
index 0000000..6429e77
Binary files /dev/null and b/graf/video_2.png differ
diff --git a/graf/zm.png b/graf/zm.png
new file mode 100644
index 0000000..975fc9e
Binary files /dev/null and b/graf/zm.png differ
diff --git a/graf/zoom.png b/graf/zoom.png
new file mode 100644
index 0000000..ddde386
Binary files /dev/null and b/graf/zoom.png differ
diff --git a/index.php b/index.php
new file mode 100644
index 0000000..450ffa9
--- /dev/null
+++ b/index.php
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+
+
+ Alert message
+
+
+
+
diff --git a/index20211021.php b/index20211021.php
new file mode 100644
index 0000000..6aea0a2
--- /dev/null
+++ b/index20211021.php
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+ Alert message
+
+
+
+
diff --git a/js/dir_app.js b/js/dir_app.js
new file mode 100644
index 0000000..4160e61
--- /dev/null
+++ b/js/dir_app.js
@@ -0,0 +1,2296 @@
+
+
+var PROD = 0
+
+
+if (PROD && location.protocol !== 'https:') {
+ location.replace(`https:${location.href.substring(location.protocol.length)}`);
+}
+
+
+
+
+// _ _
+// | | | |
+// | |__ ___| |_ __ ___ _ __ ___
+// | '_ \ / _ \ | '_ \ / _ \ '__/ __|
+// | | | | __/ | |_) | __/ | \__ \
+// |_| |_|\___|_| .__/ \___|_| |___/
+// | |
+// |_|
+
+
+
+function init_file_dropzone(parameter_name) {
+ Dropzone.options.myGreatDropzone = { // camelized version of the `id`
+ paramName: parameter_name, // The name that will be used to transfer the file
+ maxFilesize: 6 }; // MB
+}
+// init_file_dropzone("staffpicupload")
+
+
+function parsesqltime(mysqldate) { // 2021-01-29 09:00:00
+ if (! mysqldate) { return 0 }
+ var field = mysqldate.match(/^(\d\d\d\d)\-(\d+)\-(\d+)[T|\s](\d+)\:(\d+)\:(\d+)$/)
+ var mydate = new Date(field[1], field[2] - 1 , field[3], field[4], field[5], field[6])
+ return mydate }
+
+function dj(mysqldate) { return dayjs(parsesqltime(mysqldate)) }
+
+Object.defineProperty(Vue.prototype, '$dj', { value: dj });
+Object.defineProperty(Vue.prototype, '$parsesqltime', { value: parsesqltime });
+
+
+
+
+// ________ __
+// | ____\ \ / /
+// | |__ \ V /
+// | __| > <
+// | | / . \
+// |_| /_/ \_\
+//
+//
+//
+// VISUAL EFFECTS
+//
+
+
+
+function fade_message(theselector='#alert') {
+ var a_dom = document.querySelector(theselector);
+ TinyAnimate.animateCSS(a_dom, 'opacity', '', 1.0, 0.0, 750, 'easeInOutQuart', function() { }); }
+
+function alert_message(msg,color='yellow') {
+ var a = $('#alert')
+ a.text(msg)
+ a.css('background-color',color)
+ var a_dom = document.querySelector('#alert');
+ TinyAnimate.animateCSS(a_dom, 'opacity', '', 0.0, 1.0, 500, 'easeInOutQuart', function() {
+ setTimeout( fade_message, 2500 ) }); }
+
+function fadein_message(theclass='success') {
+ //var a = $('#'+theclass)
+ //a.css('visibility','visible')
+ var a_dom = document.querySelector('.'+theclass);
+ TinyAnimate.animateCSS(a_dom, 'opacity', '', 0.0, 1.0, 500, 'easeInOutQuart', function() {
+ setTimeout( function() { fade_message('.'+theclass) }, 2500 ) }); }
+
+
+// _
+// | |
+// ___ ___ _ __ ___ _ __ ___ _ __ ___ _ __ | |_ ___
+// / __/ _ \| '_ ` _ \| '_ \ / _ \| '_ \ / _ \ '_ \| __/ __|
+// | (_| (_) | | | | | | |_) | (_) | | | | __/ | | | |_\__ \
+// \___\___/|_| |_| |_| .__/ \___/|_| |_|\___|_| |_|\__|___/
+// | |
+// |_|
+
+//
+// FORM COMPONENTS
+//
+
+
+// TODO these should know if they're modifying the current user or someone else.
+
+// A single text style question
+const TQuestion = Vue.component('field', {
+ props: [ 'table', 'qid', 'question', 'answer', 'placeholder', 'targetid', ],
+ data: function () {
+ return { "a":this.answer } },
+ watch: {
+ "answer": function(val,Oldval) { this.a = val },
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) }, },
+ template: `{{ question }}
+
`,
+})
+
+// A single INLINE text style question
+const TIQuestion = Vue.component('ifield', {
+ props: [ 'table', 'qid', 'question', 'answer', 'placeholder', 'myclass', 'targetid', ],
+ data: function () {
+ return { "a":this.answer } },
+ watch: {
+ "answer": function(val,Oldval) { this.a = val },
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) }, },
+ template: ` `,
+})
+
+// A single checkbox
+const Checkbox = Vue.component('checkbox', {
+ props: [ 'table', 'qid', 'question', 'answer', 'targetid', ],
+ data: function () {
+ return { "a":this.answer } },
+ watch: {
+ "answer": function(val,Oldval) { this.a = val },
+ "a": function (val, oldVal) {
+ var newVal = 0
+ if (val==true) { newVal = 1 }
+ this.$root.events.trigger('changed',[this.qid,this.table, newVal, this.targetid]) }, },
+ template: `
+
+
+ {{ question }}
`
+})
+
+// A single long format text question
+const TAQuestion = Vue.component('tfield', {
+ props: [ 'table', 'qid', 'question', 'answer', 'targetid', 'myclass' ],
+ data: function () {
+ return { "a": this.answer } },
+ watch: {
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) },
+ "answer": function (val, oldVal) { this.a = val },
+ },
+ template: `{{ question }}
+
` })
+
+
+
+// long format text WYSIWYG HTML
+const HTAQuestion = Vue.component('htfield', {
+ props: [ 'table', 'qid', 'question', 'answer', 'targetid', 'myclass' ],
+ data: function () { return { "a": this.answer, "p":0, } }, // the pell editor object
+ mounted: function() {
+ var self = this
+ var element = document.getElementById(self.qid)
+ console.log(element)
+ this.p = pell.init( { element: element, onChange: function(h) {
+ self.$root.events.trigger('changed',[self.qid, self.table, h, self.targetid]) } } )
+ self.p.content.innerHTML = self.answer },
+ watch: {
+ "answer": function (val, oldVal) { this.p.content.innerHTML = val }, },
+ template: `` })
+
+// long format text WYSIWYG HTML FORM ALIGNED STYLE
+const HTAQuestionFA = Vue.component('htfield_fa', {
+ props: [ 'table', 'qid', 'question', 'answer', 'targetid', 'myclass' ],
+ data: function () { return { "a": this.answer, "p":0, } }, // the pell editor object
+ mounted: function() {
+ var self = this
+ var element = document.getElementById(self.qid)
+ console.log(element)
+ this.p = pell.init( { element: element, onChange: function(h) {
+ self.$root.events.trigger('changed',[self.qid, self.table, h, self.targetid]) } } )
+ self.p.content.innerHTML = self.answer },
+ watch: {
+ "answer": function (val, oldVal) { this.p.content.innerHTML = val }, },
+ template: `` })
+
+// A single numeric question
+const NQuestioon = Vue.component('n-question', {
+ props: [ 'qq' ],
+ data: function () { return { "answer": this.qq.answer } },
+ watch: { "answer": function (val, oldVal) {
+ this.$root.events.trigger('update_survey', [this.qq.user, this.qq.session, this.qq.qid, val]) }, },
+ template: ``
+})
+
+// A single survey text question
+const STQuestion = Vue.component('st-question', {
+ props: [ 'qq' ],
+ data: function () { return { "answer": this.qq.answer } },
+ watch: { "answer": function (val, oldVal) {
+ this.$emit('dirty')
+ this.$root.events.trigger('update_survey', [this.qq.user, this.qq.session, this.qq.qid, val]); }, },
+ template: `{{ qq.question }}
+
`,
+})
+
+
+
+// The "I Certify" question
+const ICertify = Vue.component('icertify', {
+ props: [ 'c' ],
+ data: function () { return { "checked": this.c } },
+ watch: { checked() { console.log('checked 1'); console.log(this.checked);
+ this.$emit('dirty')
+ this.$parent.docert(this.checked); },
+ },
+ template: `
+ I certify that I have attended this event.
+
` });
+
+
+
+// Select menu
+/*
+table: name of database table
+qid: what column of the table to edit
+question: label displayed to user
+answer: data item used for v-model
+menu: key of root vue object with menu items
+labelfield: key of 'menu' object that should be displayed as choices
+targetid: when editing existing row: the id of the row
+*/
+const SelMenu = Vue.component('selectmenu', {
+ props: [ 'table', 'qid', 'question', 'answer', 'menu', 'labelfield', 'targetid', ],
+ data: function () { return { "a": this.answer } },
+ watch: {
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) },
+ "answer": function (val, oldVal) { this.a = val }, },
+ template: `
+ {{o[labelfield]}}
+ ` })
+
+
+// Select menu FORM ALIGNED STYLE
+const SelMenuFA = Vue.component('selectmenu_fa', {
+ props: [ 'table', 'qid', 'question', 'answer', 'menu', 'labelfield', 'targetid', ],
+ data: function () { return { "a": this.answer } },
+ watch: {
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) },
+ "answer": function (val, oldVal) { this.a = val }, },
+ template: `{{ question }}
+
+ {{o[labelfield]}}
+
` })
+
+
+// A date time picker
+const DTPicker = Vue.component('dtpicker', {
+ props: [ 'table', 'qid', 'question', 'answer', 'targetid', ],
+ methods: { },
+ mounted: function() { },
+ data: function () { return { "a":this.answer } },
+ watch: {
+ "answer": function(val,Oldval) { this.a = val },
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) }, },
+ template: `{{ question }}
+
`,
+})
+
+
+// Accordion style box
+const ExpandyBox = Vue.component('expandybox', {
+ props: [ 'header', 'body', ],
+ methods: {
+ toggle: function() {
+ if (this.state=='close') { this.state='open'; this.symbol='-' }
+ else { this.state='close'; this.symbol='+' }
+ }
+ },
+ mounted: function() { },
+ data: function () { return { "state":'close', "symbol":"+", } },
+ watch: {
+ "answer": function(val,Oldval) { this.a = val },
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) }, },
+ template: ``,
+})
+
+
+
+// _ __ __ _____ _____ _____
+// | | / _|/ _| | __ \_ _| __ \
+// ___| |_ __ _| |_| |_ | | | || | | |__) |
+// / __| __/ _` | _| _| | | | || | | _ /
+// \__ \ || (_| | | | | | |__| || |_| | \ \
+// |___/\__\__,_|_| |_| |_____/_____|_| \_\
+//
+//
+
+//
+// ONE LINE OF THE STAFF DIR EDITOR listing
+//
+const StaffLine = Vue.component('staff_line', {
+ props: [ 's', 'i', 'dup_class', ],
+ //data: function() { return { } },
+ methods: {
+ nope: function() { return 1; },
+ odd: function(i) { if (i % 2 ==0) { return "even" } return "odd" },
+ bio: function() { return "bio.php?p=" + this.s.id },
+ gtitle: function() { if (this.s.gtitle) {return _.findWhere(this.$root.titles_menu, {id:this.s.gtitle}).name}; return "" },
+ gdept1: function() { if (this.s.dept1) {return _.findWhere(this.$root.depts_menu, {id:this.s.dept1}).name}; return "" },
+ gdept2: function() { if (this.s.dept2) {return _.findWhere(this.$root.depts_menu, {id:this.s.dept2}).name}; return "-" },
+ grole: function() { if (this.s.role) {return _.findWhere(this.$root.roles_menu, {id:this.s.role}).descr}; return "" },
+ swapedit: function() { console.log("edit " + this.s.first_name + " " + this.s.last_name)
+ this.$emit('swapout', this.s.id) }
+ },
+ template: `
+
+
+status: {{ s.status }}
+permissions: {{ grole() }}
+pers id: {{ s.id }}
+ext id: {{ s.ext_id }}
+bio page: {{ s.web_on }}
+Photo - use: {{s.use_dir_photo}} release: {{s.general_photo_release}}
+ path: {{s.dir_photo_path}}
+# Sections: {{s.num_taught}}
+{{ s.sections }}
+
+
+staff: {{ s.staff_type }}
+conf_id: {{ s.conf_id }}
+G00{{s.conf_goo}}
+espanol: {{s.espanol}}
+
+
+
+{{s.first_name}} {{s.last_name}}
+{{gtitle()}}
+{{gdept1()}}
+{{gdept2()}}
+(old dept: {{s.department}} )
+
+
+email: {{s.email}}
+room: {{s.room}}
+phone: {{s.phone_number}}
+Zoom: {{s.zoom}}
+Preferred contact: {{s.preferred_contact}}
+ edit
+
+
+
`
+});
+
+
+
+//
+//
+// STAFF DIR LISTING
+//
+// ONE LINE - BUT EDITING!
+//
+const StaffLineEdit = Vue.component('staff_line_edit', {
+ props: [ 's', 'i' ],
+ //data: function() { return { } },
+ methods: {
+ nope: function() { return 1; },
+ odd: function(i) { if (i % 2 ==0) { return "even" } return "odd" },
+ bio: function() { return "bio.php?p=" + this.s.id },
+ done: function() { this.$emit('done_edit') },
+ gtitle: function() { if (this.s.gtitle) {return _.findWhere(this.$root.titles_menu, {id:this.s.gtitle}).name}; return "" },
+ gdept1: function() { if (this.s.dept1) {return _.findWhere(this.$root.depts_menu, {id:this.s.dept1}).name}; return "" },
+ gdept2: function() { if (this.s.dept2) {return _.findWhere(this.$root.depts_menu, {id:this.s.dept2}).name}; return "-" },
+ grole: function() { if (this.s.role) {return _.findWhere(this.$root.roles_menu, {id:this.s.role}).descr}; return "" },
+ }, //v-lazy-container="{ selector: 'img' }"
+ template: `
+ `
+});
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// STAFF DIR LISTING MAIN CONTAINER
+//
+const DirList = Vue.component('dirlist', {
+ data: function () {
+ return { "personnel":[], sortby:'last_name', search:'', reversed: false, id_list:[], id_dups:[],
+ components: {n:StaffLine, e: StaffLineEdit }, editing: -1, } },
+ mounted: function() {
+ var self = this;
+ this.$root.fetch_menus();
+
+ fetch('dir_api.php?a=list/staffsemester', { method: 'GET' }).then(function (response) {
+ if (response.ok) {
+ response.json().then( function(r2) {
+ self.personnel = r2;
+ _.each( self.personnel, function(x) {
+ if (x.sections==null) { x.num_taught=0 }
+ if (x.dir_photo_path==null) { x.dir_photo_path='images_sm/nobody.jpg' }
+ if (x.use_dir_photo == "0") { x.use_dir_photo = false } else { x.use_dir_photo = true }
+ if (x.espanol == "0" || !x.espanol) { x.espanol = false } else { x.espanol = true }
+ if (x.general_photo_release == "0") { x.general_photo_release = false
+ } else { x.general_photo_release = true }
+ if (self.id_list.includes(x.id)) { self.id_dups.push(x.id) }
+ else { self.id_list.push(x.id) }
+ x.searchable = ''
+ if (x.first_name) { x.searchable += ' ' + x.first_name.toLowerCase() }
+ if (x.last_name) { x.searchable += ' ' + x.last_name.toLowerCase() }
+ if (x.dept1name) { x.searchable += ' ' + x.dept1name.toLowerCase() }
+ if (x.titlename) { x.searchable += ' ' + x.titlename.toLowerCase() }
+ if (x.status == "1" || x.status == null) { x.status = "1"
+ } else { x.status = false; x.searchable += ' inactive' }
+ } ) } ) } else { return Promise.reject(response) }
+ }).then(function (data) { }).catch(function (err) { console.warn('Something went wrong.', err); });
+ },
+ methods: {
+ setsort: function(ss) {
+ if (this.sortby == ss) { this.reversed = ! this.reversed }
+ else {
+ this.reversed = false
+ this.sortby = ss
+ }
+ },
+ swapme: function(x) {
+ this.editing = x
+ },
+ done_edit: function(id) {
+ this.editing = -1
+ },
+ am_editing: function(id) {
+ if (id == this.editing) { return StaffLineEdit }
+ return StaffLine
+ },
+ is_dup_id_class: function(id) { return this.id_dups.includes(id) ? " dup_line" : "" },
+ },
+ computed: {
+ filtered: function() {
+ var ff = this.personnel
+ var self = this
+ if (this.search) {
+ var ss = self.search.toLowerCase()
+ ff = ff.filter(function(x) { return x.searchable.includes(ss) }) }
+
+ ff = _.sortBy(ff, function(x) {
+ if (x[self.sortby]) {
+ var s = x[self.sortby];
+ return s.trim().toLowerCase() }
+ return 'zzzzzzzzzz' })
+ if (this.reversed) {
+ ff.reverse()
+ }
+ return ff
+ }
+ },
+ watch: {
+ },
+
+ template: `` })
+
+
+
+// https://www.daterangepicker.com/
+// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime-local
+
+
+
+
+
+// __ _ _ _ _ _ _
+// / _| | | | (_) (_) | (_)
+// | |_| | _____ __ __ _ ___| |_ ___ ___| |_ _ ___ ___
+// | _| |/ _ \ \/ / / _` |/ __| __| \ \ / / | __| |/ _ \/ __|
+// | | | | __/> < | (_| | (__| |_| |\ V /| | |_| | __/\__ \
+// |_| |_|\___/_/\_\ \__,_|\___|\__|_| \_/ |_|\__|_|\___||___/
+//
+//
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// EDIT / CREATE activity or event
+//
+const ActivityEditor = Vue.component('activityedit', {
+ props: [ 'which', ],
+ data: function () {
+ return { my_activity:0, creating:0,
+ everyname:[], everyone:[], hosts_by_sesid:{}, this_hosts:[], host_search:[], host_search_str:'',
+ activities:[], this_activity:{}, editing: -1, active:-1, } },
+ mounted: function() {
+ this.fetch_mypeople()
+ this.$root.fetch_menus()
+ if (this.which==0) {
+ this.creating = 1
+ this.$root.creating = 1
+ this.this_activity = {"title":"","desc":"","length":"1","starttime":"",
+ "track":"","location":"","gets_survey":"1","category":"1",
+ "parent":"","recording":"","instructions":"","image_url":"",
+ "is_flex_approved":"1","typeId":"101"}
+ } else { this.my_activity = this.which
+ this.fetch_myevents() } },
+ methods: {
+ set_id: function(new_id) { this.this_activity.id = new_id; this.creating=0; this.$root.creating=0 },
+ month_year: function(d) { var b = this.$root.$dj(d).format('MMM D YYYY'); return b },
+ setsort: function(ss) {
+ if (this.sortby == ss) { this.reversed = ! this.reversed }
+ else { this.reversed = false; this.sortby = ss } },
+ swapme: function(x) { this.editing = x },
+ done_edit: function(id) { this.editing = -1 },
+ am_editing: function(id) { return 0 },
+ remove: function(hostid) {
+ var self = this
+ basic_get('dir_api.php?a=remove/host/' + this.my_activity + '/' + hostid,
+ function(r2) {
+ self.this_hosts = _.reject(self.this_hosts, function(x) { return x.hostid == hostid} )
+ alert_message('Saved') } )
+ },
+ add: function(hostid) {
+ var self = this
+ basic_get('dir_api.php?a=add/host/' + this.my_activity + '/' + hostid,
+ function(r2) {
+ self.this_hosts.push( _.findWhere(self.everyone, {id:hostid} ) )
+ alert_message('Saved') } )
+ },
+ hostlookup: function() {
+ var self = this
+ if (this.host_search_str=='') { this.host_search=[] }
+ else { this.host_search_str = this.host_search_str.toLowerCase()
+ this.host_search = _.first(_.filter(self.everyone, function(x) { return x.name.toLowerCase().search( self.host_search_str) != -1 }),7) } },
+ save_new_event: function() {
+ this.$root.events.trigger('create_new_session',this.this_activity)
+ },
+ fetch_mypeople: function() {
+ var self = this;
+ basic_get('dir_api.php?a=get/names',
+ function(r2) {
+ self.everyone = r2.users
+ _.each( self.everyone, function(x) {
+ x.hostid = x.id } )
+ self.everyname = _.pluck(r2.users,'name') } ) },
+ fetch_myevents: function() {
+ var self = this;
+ basic_get('dir_api.php?a=get/sessions',
+ function(r2) {
+ self.activities = _.indexBy(r2,function(x) { return x.id } ); self.$forceUpdate()
+ self.active += 1;
+ _.each( self.activities, function(x) {
+ x.searchable = x.title.toLowerCase() + ' ' + x.desc.toLowerCase() } )
+ self.this_activity = self.activities[ self.my_activity ]
+ self.this_activity.starttime = self.this_activity.starttime.replace(' ','T')} )
+ basic_get('dir_api.php?a=get/hosts',
+ function(r2) {
+ self.hosts_by_sesid = _.groupBy(r2,function(x) { return x.id } )
+ self.this_hosts = self.hosts_by_sesid[ self.my_activity ]
+ } )
+ },
+ },
+ template: `` })
+
+
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// DISPLAY / EDIT activity or event
+//
+const ActivityInlineEditor = Vue.component('activityinlineedit', {
+ props: [ 'which', ],
+ data: function () {
+ return { my_activity:0, creating:0,
+ everyname:[], everyone:[], hosts_by_sesid:{}, this_hosts:[], host_search:[], host_search_str:'',
+ activities:[], this_activity:{}, editing: 0, active:-1, } },
+ mounted: function() {
+ this.fetch_mypeople()
+ this.$root.fetch_menus()
+ if (this.which==0) {
+ this.creating = 1
+ this.$root.creating = 1
+ this.this_activity = {"title":"","desc":"","length":"1","starttime":"",
+ "track":"","location":"","gets_survey":"1","category":"1",
+ "parent":"","recording":"","instructions":"","image_url":"",
+ "is_flex_approved":"1","typeId":"101"}
+ } else { this.my_activity = this.which
+ this.fetch_myevents() } },
+ methods: {
+ set_id: function(new_id) { this.this_activity.id = new_id; this.creating=0; this.$root.creating=0 },
+ month_year: function(d) { var b = this.$root.$dj(d).format('MMM D YYYY'); return b },
+ setsort: function(ss) {
+ if (this.sortby == ss) { this.reversed = ! this.reversed }
+ else { this.reversed = false; this.sortby = ss } },
+ swapme: function(x) { this.editing = x },
+ done_edit: function(id) { this.editing = -1 },
+ am_editing: function(id) { return 0 },
+ remove: function(hostid) {
+ var self = this
+ basic_get('dir_api.php?a=remove/host/' + this.my_activity + '/' + hostid,
+ function(r2) {
+ self.this_hosts = _.reject(self.this_hosts, function(x) { return x.hostid == hostid} )
+ alert_message('Saved') } )
+ },
+ add: function(hostid) {
+ var self = this
+ basic_get('dir_api.php?a=add/host/' + this.my_activity + '/' + hostid,
+ function(r2) {
+ self.this_hosts.push( _.findWhere(self.everyone, {id:hostid} ) )
+ alert_message('Saved') } )
+ },
+ hostlookup: function() {
+ var self = this
+ if (this.host_search_str=='') { this.host_search=[] }
+ else { this.host_search_str = this.host_search_str.toLowerCase()
+ this.host_search = _.first(_.filter(self.everyone, function(x) { return x.name.toLowerCase().search( self.host_search_str) != -1 }),7) } },
+ save_new_event: function() {
+ this.$root.events.trigger('create_new_session',this.this_activity)
+ },
+ fetch_mypeople: function() {
+ var self = this;
+ basic_get('dir_api.php?a=get/names',
+ function(r2) {
+ self.everyone = r2.users
+ _.each( self.everyone, function(x) {
+ x.hostid = x.id } )
+ self.everyname = _.pluck(r2.users,'name') } ) },
+ fetch_myevents: function() {
+ var self = this;
+ basic_get('dir_api.php?a=get/sessions',
+ function(r2) {
+ self.activities = _.indexBy(r2,function(x) { return x.id } ); self.$forceUpdate()
+ self.active += 1;
+ _.each( self.activities, function(x) {
+ x.searchable = x.title.toLowerCase() + ' ' + x.desc.toLowerCase() } )
+ self.this_activity = self.activities[ self.my_activity ]
+ self.this_activity.starttime = self.this_activity.starttime.replace(' ','T')} )
+ basic_get('dir_api.php?a=get/hosts',
+ function(r2) {
+ self.hosts_by_sesid = _.groupBy(r2,function(x) { return x.id } )
+ self.this_hosts = self.hosts_by_sesid[ self.my_activity ]
+ } )
+ },
+ },
+ template: `` })
+
+
+
+
+
+//
+//
+//
+//
+//
+//
+// ACTIVITIES LIST MAIN CONTAINER
+// ------------------------------
+//
+//
+//
+const ActivityList = Vue.component('activitylist', {
+ props: [ 'itineraryview','static' ],
+ data: function () {
+ return { activities:[], mysessions:[], search:'', sortby:'starttime', reversed:false, my_ses_ids:[], my_host_ids:[],
+ show_filters: 'all', expanded: 1, editing: -1, active:-1, hosts:{},
+ hosts_by_sesid: {}, options:{}, conference:{}, ay:{}, conf:-1, survey_on:0, zoom_on:0, } },
+ mounted: function() {
+ this.fetch_myevents()
+ },
+ methods: {
+ hoststr: function(id) { var self = this
+ return _.reduce( self.hosts_by_sesid[id], function(mem,val) { if (val.name) { return mem + val.name + ", " } return mem }, '') },
+ mode_string: function(a) { if (this.active>3) { return _.findWhere(this.$root.modes_menu, { 'id': a.mode })['string'] } return a.mode },
+ get_day_title: function(day) {
+ console.log(day)
+ var d = dayjs(day, 'MMM DD YYYY')
+ convertedDateString = d.format('YYYY-MM-DD')
+ return _.findWhere( this.conference, {date1:convertedDateString} ).title
+ },
+ month_year: function(d) { var b = this.$root.$dj(d).format('MMM D YYYY'); return b },
+ setsort: function(ss) {
+ if (this.sortby == ss) { this.reversed = ! this.reversed }
+ else { this.reversed = false; this.sortby = ss } },
+ swapme: function(x) { this.editing = x },
+ done_edit: function(id) { this.editing = -1 },
+ am_editing: function(id) { return 0 },
+ fetch_myevents: function() {
+ var self = this;
+ basic_get('api/app',
+ function(r2) {
+ self.mysessions = r2.mysessions
+ self.activities = r2.sessions
+ self.my_host_ids = r2.host
+ self.options = r2.options
+ self.conference = r2.conference
+ self.ay = r2.ay
+ self.active = 1
+
+ self.survey_on = parseInt( _.findWhere(self.options, { label:'survey_on' }).value )
+ self.zoom_on = parseInt( _.findWhere(self.options, { label:'zoom_on' }).value )
+ self.$forceUpdate();
+
+ } )
+ },
+ joinme: function(id) {
+ var self = this
+ basic_get('dir_api.php?a=signup/' + id,
+ function(r2) {
+ self.mysessions.push(_.findWhere(self.activities, {'id':id}))
+ self.my_ses_ids.push(id)
+ alert_message("Added activity") })
+ },
+ dumpme: function(id) {
+ var self = this
+ basic_get('dir_api.php?a=signdown/' + id,
+ function(r2) {
+ self.mysessions = _.without( self.mysessions, _.findWhere(self.activities, {'id':id}))
+ self.my_ses_ids = _.without( self.my_ses_ids, id)
+ self.$forceUpdate()
+ alert_message("Removed activity") })
+ },
+ filtered: function(ff) {
+ var self = this
+ if (this.search) {
+ var ss = self.search.toLowerCase()
+ console.log('one')
+ ff = ff.filter(function(x) { return ('searchable' in x ? x.searchable.includes(ss) : 0) })
+ }
+
+ if (this.active>0) {
+ var default_conf_id = _.findWhere(self.options, {label:'default_conference'}).value
+ self.conf = _.findWhere(self.conference, {id:default_conf_id})
+ var start = dayjs( self.conf.date1)
+ var end = dayjs(self.conf.date2)
+ ff = ff.filter( function(item,index) {
+ this_time = dayjs(item.starttime)
+ return this_time.isBefore(end) && start.isBefore(this_time) } )
+ ff = _.sortBy(ff, function(x) {
+ if (x[self.sortby]) { var s = x[self.sortby]; return s.trim().toLowerCase() }
+ return '' })
+ if (this.reversed) { ff.reverse() }
+ return ff
+ }
+
+ return []
+ }, },
+ computed: {
+ current_time: function() { return dayjs().format('MMM D, h:mma') },
+ activities_filtered: function() { var a = this.filtered(this.activities); return a; },
+ mysessions_filtered: function() { return this.filtered(this.mysessions) },
+
+ activities_g_filtered: function() { if (this.active<1) { return {} }
+ var self=this;
+ return _.groupBy(self.activities_filtered, function(x) { return self.month_year(x.starttime) } ); },
+ mysessions_g_filtered: function() { if (this.active<1) { return {} }
+ var self=this; return _.groupBy(self.mysessions_filtered, function(x) { return self.month_year(x.starttime) } ); }, },
+ watch: { },
+ template: `
+
+ Current time is: {{ current_time }}. Return here for the ZOOM links on the day of your sessions.
+
+
+
+
It looks like you haven't signed up for any sessions yet!
+ Go to the
Sessions List to sign up.
+
+
+
{{mmyy}} {{get_day_title(mmyy)}}
+
+
+
+
{{a.title}}
+
+ {{ $root.$dj(a.starttime).format('h:mma') }}
+
+ - In person at {{a.location_irl}} or
+ online
+
+ - In person at {{a.location_irl}}
+ - Online
+ - Online
+
+
+
+
+
+
+
+
{{mmyy}} {{get_day_title(mmyy)}}
+
+
+
+ ` })
+
+
+
+
+// A CHART LABEL
+//
+
+const ChartLabel = Vue.component('chartlabel', {
+ props: [ 'title','start','end' ],
+ data: function () {
+ return { max_tracks: 6 } },
+ template: `
+ {{title}}
+
` })
+
+
+//
+//
+// A CHART SESSION
+//
+
+const ChartSesh = Vue.component('chartsesh', {
+ props: [ 'title','desc','track','start','end','start_h','end_h','mode','presenter','loc' ],
+ data: function () {
+ return { max_tracks: 6 } },
+ methods: {
+ t_start: function() {
+ if (this.track==0 || this.track==123) { return "track-1-start" }
+ return "track-" + this.track + "-start"
+ },
+ t_end: function() {
+ if (this.track==0 || this.track==123) { return "track-" + this.max_tracks + "-end" }
+ return "track-" + this.track + "-end"
+ },
+ },
+
+ template: `
+
{{title}}
+ {{start_h}} - {{end_h}}
+ {{desc}}
+ {{presenter}}
+ {{mode}}
+ {{loc}}
+ ` })
+
+
+//
+//
+//
+//
+//
+//
+// ACTIVITIES LIST CHART STYLE VIEW
+// --------------------------------
+//
+//
+//
+const ChartView = Vue.component('chartview', {
+ props: [ 'day'],
+ data: function () {
+ return { activities:[], mysessions:[], search:'', sortby:'starttime', reversed:false, my_ses_ids:[], my_host_ids:[],
+ show_filters: 'all', expanded: 1, editing: -1, active:-1, hosts:{},
+ filters: {'sp23':['2023-01-01','2023-02-02'],'fa22':['2022-08-17','2022-08-20'], 'sp22':['2022-01-26','2022-01-30'], 'all':['2022-01-01','2023-11-30'] },
+ //day_titles: {'Aug 18 2022':" - Optional PD Day", 'Aug 19 2022':' - Convocation Day'},
+ day_titles: {'Jan 26 2023':" - Optional Day", 'Jan 27 2023':' - Mandatory Day'},
+ time_labels: [['0900','0930','9am'],
+['0930','1000','9:30am'],
+['1000','1030','10am'],
+['1030','1100','10:30am'],
+['1100','1130','11am'],
+['1130','1200','11:30am'],
+['1200','1230','12pm'],
+['1230','1300','12:30pm'],
+['1300','1330','1pm'],
+['1330','1400','1:30pm'],
+['1400','1430','2pm'],
+['1430','1500','2:30pm'],
+['1500','1530','3pm'],
+['1530','1600','3:30pm'],
+['1600','1630','4pm'],
+['1630','1700','4:30pm'],
+['1700','1730','5pm'],
+['1730','1800','5:30pm'],
+ ],
+ hosts_by_sesid: {}, } },
+ mounted: function() {
+ this.$root.fetch_menus();
+ this.fetch_myevents()
+ },
+ methods: {
+ hoststr: function(id) { var self = this
+ return _.reduce( self.hosts_by_sesid[id], function(mem,val) { if (val.name) { return mem + val.name + ", " } return mem }, '') },
+ mode_string: function(a) { return _.findWhere(this.$root.modes_menu, { 'id': a.mode })['string'] },
+ get_day_title: function(day) { if (day in this.day_titles) { return this.day_titles[day] } return '' },
+ month_year: function(d) { var b = this.$root.$dj(d).format('MMM D YYYY'); return b },
+ setsort: function(ss) {
+ if (this.sortby == ss) { this.reversed = ! this.reversed }
+ else { this.reversed = false; this.sortby = ss } },
+ swapme: function(x) { this.editing = x },
+ done_edit: function(id) { this.editing = -1 },
+ am_editing: function(id) { return 0 },
+ fetch_myevents: function() {
+ var self = this;
+ basic_get('api/ses/'+self.day,
+ function(r2) {
+ r2 = r2.data
+ self.activities = _.sortBy(r2,function(x) { return x.starttime } ); self.$forceUpdate()
+ self.active += 1;
+ _.each( self.activities, function(x) {
+ var field = x.starttime.match(/^(\d\d\d\d)\-(\d+)\-(\d+)\s(\d+)\:(\d+)\:(\d+)$/)
+ var mydate = new Date(field[1], field[2] - 1 , field[3], field[4], field[5], field[6])
+ x.dj = dayjs(mydate)
+ x.searchable = x.title.toLowerCase() + ' ' + x.desc.toLowerCase() } )
+ self.$forceUpdate();
+ self.active += 1; } )
+ basic_get('dir_api.php?a=get/hosts', function(r2) {
+ self.hosts_by_sesid = _.groupBy(r2,function(x) { return x.id } )
+ } )
+
+ },
+ joinme: function(id) {
+ var self = this
+ basic_get('dir_api.php?a=signup/' + id,
+ function(r2) {
+ self.mysessions.push(_.findWhere(self.activities, {'id':id}))
+ self.my_ses_ids.push(id)
+ alert_message("Added activity") })
+ },
+ dumpme: function(id) {
+ var self = this
+ basic_get('dir_api.php?a=signdown/' + id,
+ function(r2) {
+ self.mysessions = _.without( self.mysessions, _.findWhere(self.activities, {'id':id}))
+ self.my_ses_ids = _.without( self.my_ses_ids, id)
+ self.$forceUpdate()
+ alert_message("Removed activity") })
+ },
+ filtered: function(ff) { if (this.active<1) { return [] }
+ var self = this
+ if (this.search) {
+ var ss = self.search.toLowerCase()
+ console.log('one')
+ ff = ff.filter(function(x) { return ('searchable' in x ? x.searchable.includes(ss) : 0) }) }
+ if (this.focus && 'options' in this.$root.$data.user ) {
+ var start = dayjs(this.$root.$data.user.options.conf.date1)
+ var end = dayjs(this.$root.$data.user.options.conf.date2)
+ ff = ff.filter( function(item,index) {
+ this_time = dayjs(item.starttime)
+ return this_time.isBefore(end) && start.isBefore(this_time) } )
+ }
+ ff = _.sortBy(ff, function(x) {
+ if (x[self.sortby]) { var s = x[self.sortby]; return s.trim().toLowerCase() }
+ return '' })
+ if (this.reversed) { ff.reverse() }
+ return ff }, },
+ computed: {
+ current_time: function() { return dayjs().format('MMM D, h:ma') },
+ activities_filtered: function() { var a = this.filtered(this.activities); return a; },
+ mysessions_filtered: function() { return this.filtered(this.mysessions) },
+
+ activities_g_filtered: function() { if (this.active<1) { return {} }
+ var self=this;
+ return _.groupBy(self.activities_filtered, function(x) { return self.month_year(x.starttime) } ); },
+ mysessions_g_filtered: function() { if (this.active<1) { return {} }
+ var self=this; return _.groupBy(self.mysessions_filtered, function(x) { return self.month_year(x.starttime) } ); }, },
+ watch: { },
+ template: `
+
+
+
+
` })
+
+
+
+
+//
+//
+//
+//
+//
+//
+// Activity EDITOR List
+// ------------------------------
+//
+//
+//
+const ActivityEditorList = Vue.component('activityeditorlist', {
+ props: [ ],
+ data: function () {
+ return { activities:[], mysessions:[], search:'', sortby:'starttime', reversed:false, my_ses_ids:[], my_host_ids:[],
+ show_filters: 'all', expanded: 1, editing: -1, active:-1, hosts:{},
+ filters: {'fa23':['2023-08-21','2023-08-26'], 'sp23':['2023-01-01','2023-02-02'],'fa22':['2022-08-17','2022-08-20'], 'sp22':['2022-01-26','2022-01-30'], 'all':['2022-01-01','2023-11-30'] },
+ //day_titles: {'Aug 18 2022':" - Optional PD Day", 'Aug 19 2022':' - Convocation Day'},
+ day_titles: {'Jan 26 2023':" - Optional Day", 'Jan 27 2023':' - Mandatory Day',
+ 'Aug 24 2023':" - Optional Day", 'Aug 25 2023':' - Mandatory Day'},
+ hosts_by_sesid: {}, } },
+ mounted: function() {
+ this.$root.fetch_menus();
+ this.fetch_myevents()
+ },
+ methods: {
+ hoststr: function(id) { var self = this
+ return _.reduce( self.hosts_by_sesid[id], function(mem,val) { if (val.name) { return mem + val.name + ", " } return mem }, '') },
+ mode_string: function(a) { return _.findWhere(this.$root.modes_menu, { 'id': a.mode })['string'] },
+ get_day_title: function(day) { if (day in this.day_titles) { return this.day_titles[day] } return '' },
+ month_year: function(d) { var b = this.$root.$dj(d).format('MMM D YYYY'); return b },
+ setsort: function(ss) {
+ if (this.sortby == ss) { this.reversed = ! this.reversed }
+ else { this.reversed = false; this.sortby = ss } },
+ fetch_myevents: function() {
+ var self = this;
+ basic_get('dir_api.php?a=get/mysessions',
+ function(r2) {
+ self.mysessions = _.sortBy(r2,function(x) { return x.starttime || 0} );
+ self.my_ses_ids = _.pluck(r2, 'id')
+ self.$forceUpdate();
+ self.active += 1;
+ } )
+ basic_get('dir_api.php?a=get/sessions',
+ function(r2) {
+ self.activities = _.sortBy(r2,function(x) { return x.starttime } ); self.$forceUpdate()
+ self.active += 1;
+ _.each( self.activities, function(x) {
+ var field = x.starttime.match(/^(\d\d\d\d)\-(\d+)\-(\d+)\s(\d+)\:(\d+)\:(\d+)$/)
+ var mydate = new Date(field[1], field[2] - 1 , field[3], field[4], field[5], field[6])
+ x.dj = dayjs(mydate)
+ x.searchable = x.title.toLowerCase() + ' ' + x.desc.toLowerCase() } )
+ self.$forceUpdate();
+ self.active += 1; } )
+ basic_get('dir_api.php?a=get/hosts', function(r2) {
+ self.hosts_by_sesid = _.groupBy(r2,function(x) { return x.id } )
+ } )
+ basic_get('dir_api.php?a=get/allhosts',
+ function(r2) {
+ self.hosts = r2
+ setTimeout(function () {
+ self.my_host_ids = r2[ self.$root.user.conf_id ]
+ if (! self.my_host_ids) { self.my_host_ids = [] }
+ }, 750);
+ self.active += 1;
+ } )
+ },
+ filtered: function(ff) { if (this.active<1) { return [] }
+ var self = this
+ if (this.search) {
+ var ss = self.search.toLowerCase()
+ console.log('one')
+ ff = ff.filter(function(x) { return ('searchable' in x ? x.searchable.includes(ss) : 0) }) }
+ if (this.focus) {
+ var start = dayjs(this.filters.sp23[0]) /* UPDATE */
+ var end = dayjs(this.filters.sp23[1])
+ ff = ff.filter( function(item,index) {
+ this_time = dayjs(item.starttime)
+ return this_time.isBefore(end) && start.isBefore(this_time) } )
+ }
+ ff = _.sortBy(ff, function(x) {
+ if (x[self.sortby]) { var s = x[self.sortby]; return s.trim().toLowerCase() }
+ return '' })
+ if (this.reversed) { ff.reverse() }
+ return ff }, },
+ computed: {
+ current_time: function() { return dayjs().format('MMM D, h:ma') },
+ activities_filtered: function() { var a = this.filtered(this.activities); return a; },
+ mysessions_filtered: function() { return this.filtered(this.mysessions) },
+
+ activities_g_filtered: function() { if (this.active<1) { return {} }
+ var self=this;
+ return _.groupBy(self.activities_filtered, function(x) { return self.month_year(x.starttime) } ); },
+ mysessions_g_filtered: function() { if (this.active<1) { return {} }
+ var self=this; return _.groupBy(self.mysessions_filtered, function(x) { return self.month_year(x.starttime) } ); }, },
+ watch: { },
+ template: `
+
+
+
{{mmyy}} {{get_day_title(mmyy)}}
+
+
+
+
` })
+
+
+
+
+ //
+//
+//
+//
+//
+//
+// Table of all signups and hosts in a conference
+// ------------------------------
+//
+//
+//
+
+const Overview = Vue.component('overview', {
+ name: 'Overview',
+ data() {
+ return {
+ sessions: [
+ // Define your sessions data here
+ // Each session should have an id and title property
+ ],
+ users: [
+ // Define your users data here
+ // Each user should have an id and name property
+ ],
+ signups: [
+ // Define your signups data here
+ // Each signup should have a userId and sessionId property
+ ],
+ hosts: [
+ // Define your hosts data here
+ // Each host should have a userId and sessionId property
+ ],
+ fetched:0,
+ };
+ },
+ computed: {
+ sortedSessions() {
+ // Sort sessions by startdate (modify the property name as per your data)
+ return this.sessions.sort((a, b) => a.starttime.localeCompare(b.starttime));
+ },
+ sortedUsers() {
+ // Sort users by name (modify the property name as per your data)
+ return this.users.sort((a, b) => a.name.localeCompare(b.name));
+ },
+ filteredUsers() {
+ // Filter users who have signup or host entries
+ var sorted = this.users.sort((a, b) => a.name.localeCompare(b.name))
+ return sorted.filter((user) =>
+ this.signups.some((signup) => signup.user === user.id) ||
+ this.hosts.some((host) => host.user === user.id)
+ );
+ },
+ },
+ methods: {
+ start: function() {
+ var self = this
+ basic_get('dir_api.php?a=get/sessions',
+ function(r2) { self.sessions = r2; self.fetched += 1; })
+ basic_get('dir_api.php?a=get/hosttable',
+ function(r2) { self.hosts = r2; self.fetched += 1; })
+ basic_get('dir_api.php?a=get/signups',
+ function(r2) { self.signups = r2; self.fetched += 1; })
+ basic_get('dir_api.php?a=get/users',
+ function(r2) { self.users = r2; self.fetched += 1; })
+ },
+ getSignupHostStatus(userId, sessionId) {
+ // Check if the user signed up for the session
+ // Check if the user hosted the session
+ const host = this.hosts.find((host) => host.host === userId && host.session === sessionId);
+
+ if (host) {
+ return 'H'; // User hosted
+ }
+
+ const signup = this.signups.find((signup) => signup.user === userId && signup.session === sessionId);
+
+ if (signup) {
+ return 'S'; // User signed up
+ }
+
+ return ''; // User didn't sign up or host
+ }
+ },
+ mounted: function() { this.start() },
+ template: `
+
+
+
+
+ {{ session.title }}
+
+
+
+
+
+ {{ user.name }}
+
+
+ {{ getSignupHostStatus(user.id, session.id) }}
+
+
+
+
+
`
+});
+
+
+
+
+
+/*
+
+ - show upcoming, past, dropdown for category
+
+ - show signup status, signup/cancel button
+
+ - navigation: check permission, show edit / new button
+
+ - page: create / edit activity.
+
+*/
+
+
+const AskSurvey = Vue.component('asksurvey', {
+ name: 'AskSurvey',
+ components: { 'essay-question': STQuestion, 'number-question': NQuestioon },
+ props: ['id', ],
+ data () { return {
+ questions: [] } },
+ methods: {
+ start: function() {
+ var self = this
+ basic_get('dir_api.php?a=get/questions/'+self.id,
+ function(r2) {
+ self.questions = r2 })
+ },
+ },
+ mounted: function() { this.start() },
+ template: `
+
{{ questions[0].title }}
+
+
+
+
+
`
+});
+
+
+
+
+const ShowSurveys = Vue.component('show-survey', {
+ name: 'ShowSurveys',
+ //components: { 'essay-question': EssayQuestion, 'number-question': NumberQuestion },
+ props: ['answer', ],
+ methods: {
+ logger: function() { console.log('logger'); console.log(this); console.log( this.answer ); return ''; },
+ ses_name: function() {
+ if (this.answer) {
+ return this.answer[0][0].s_title }
+ return '' }
+ },
+ template: `
+ {{ logger() }}
+
+ {{ q[0]['question'] }}
+
+
+
+
`
+});
+
+
+const Survey = Vue.component('surveydisplay', {
+ props: [ 'answers' ],
+ data () {
+ return {
+ qa_all: [ ],
+ sesh: {},
+ questions: [],
+ one: {},
+ qdata: [],
+ answer: ""
+ }
+ },
+ created: function() {
+ var self = this
+ self.questions = _.where(this.$root.$data.myquestions,
+ {'ses_id':self.$route.params.take_ses_id})
+ self.$forceUpdate()
+ /*this.$axios.get(this.$server + this.$api + '?a=get/questions', {withCredentials: true}).then( function(resp2) {
+ self.qdata = resp2.data
+ setTimeout(self.continueExecution, 1000) //wait 1 seconds before continuing
+ } )*/
+
+ this.$axios.get(this.$server + this.$api + '?a=get/answers/all', {withCredentials: true}).then( function(resp2) {
+ } ) },
+ methods: {
+ continueExecution: function() {self.questions = _.where( this.qdata, {'ses_id': this.$route.params.take_ses_id } )},
+ one_session: function() {
+ if (this.$route.params.take_ses_id) {
+ var self = this
+ var my_id = self.$route.params.take_ses_id
+ console.log("My id is: " + my_id)
+ var my_ses = _.find(this.$root.$data.activities, function(x) { return x.id==my_id } )
+ /*console.log('The session: ')
+ console.log(my_ses)*/
+ return my_ses }
+ console.log('no session found ')
+ return {'title':''}
+ },
+ answers: function() {
+ var a = this.sesh[parseInt( this.$route.params.ses_id)]
+ //console.log(a)
+ if (a) { return a }
+ return 0
+ },
+ requested_session: function() {
+ var self = this
+ return _.find(this.$root.$data.activities, function(x) { console.log(x.id); console.log(self.$route.params.ses_id); return x.id == self.$route.params.ses_id } )
+ /*
+ a = _.find(this.$root.$data.activities, function(x) { console.log(x.id); console.log(self.$route.params.ses_id); return x.id == self.$route.params.ses_id } )
+ console.log(a)
+ return a */
+ }
+ },
+ template: `
+ {{ q[0]['question'] }}
+
+
+
+
+
+
+
+
+
+
+
+`
+})
+
+
+
+
+
+// ACTIVITIY REPORT - SINGLE - SIGNUPS & SURVEYS
+// -----------------------------------
+//
+//
+//
+const ActivityInfoReport = Vue.component('activityinforeport', {
+ props: [ 'a', 'host','num','user','emails','survey' ],
+ methods: {
+ mode_string: function(a) { return _.findWhere(this.$root.modes_menu, { 'id': a.mode })['string'] },
+ },
+ computed: {
+ },
+ watch: { },
+ template: `
+ ` })
+
+
+
+
+
+//
+//
+//
+//
+//
+//
+// ACTIVITIES LIST - SIGNUPS & SURVEYS
+// -----------------------------------
+//
+//
+//
+const ActivityReport = Vue.component('activityreport', {
+ props: [ 'which' ],
+ data: function () {
+ return { activities:[],hosts:[], hosts_by_sesid:[], everyone:[], questions:[], answers:{}, answers2:{}, rosters:[] } },
+ mounted: function() {
+ var self = this
+ basic_get('dir_api.php?a=get/sessions', function(r2) {
+ self.activities = _.sortBy(r2,function(x) { return x.starttime } ); self.$forceUpdate()
+ if (self.which=='sp22') {
+ var start = dayjs('2022-01-26')
+ var end = dayjs('2022-01-29')
+ self.activities = self.activities.filter( function(item,index) {
+ this_time = dayjs(item.starttime)
+ return this_time.isBefore(end) && start.isBefore(this_time) } )
+ }
+ if (self.which=='fa22') { /* UPDATE */
+ var start = dayjs('2022-08-17')
+ var end = dayjs('2022-08-20')
+ self.activities = self.activities.filter( function(item,index) {
+ this_time = dayjs(item.starttime)
+ return this_time.isBefore(end) && start.isBefore(this_time) } )
+ }
+
+ if (self.which.match( /^\d+$/ )) { self.activities = self.activities.filter( function(item,index) {
+ return item.id == self.which } )
+ }
+
+ self.active += 1;
+ _.each( self.activities, function(x) {
+ var field = x.starttime.match(/^(\d\d\d\d)\-(\d+)\-(\d+)\s(\d+)\:(\d+)\:(\d+)$/)
+ var mydate = new Date(field[1], field[2] - 1 , field[3], field[4], field[5], field[6])
+ x.dj = dayjs(mydate)
+ x.searchable = x.title.toLowerCase() + ' ' + x.desc.toLowerCase() } )
+ self.$forceUpdate();
+ self.active += 1; } )
+ basic_get('dir_api.php?a=get/hosts', function(r2) {
+ self.hosts_by_sesid = _.groupBy(r2,function(x) { return x.id } )
+ } )
+ basic_get('dir_api.php?a=get/rosters', function(r2) {
+ self.rosters = _.groupBy(r2,function(x) { return x.sesid } )
+ } )
+ basic_get('dir_api.php?a=get/allhosts', function(r2) {
+ self.hosts = r2
+ setTimeout(function () { self.hosts = r2; self.$forceUpdate() }, 750);
+ self.active += 1;
+ } )
+ basic_get('dir_api.php?a=get/names', function(r2) {
+ self.everyone = []
+ _.each( r2.users, function(x) { self.everyone[x.id] = x.name } ) } )
+ basic_get('dir_api.php?a=get/questions', function(r2) {
+ self.questions = r2 })
+ basic_get('dir_api.php?a=get/answers/all', function(r2) {
+ var organized = _.groupBy(r2, function(x) { return x.ses_id; } )
+ // TODO are answers and answers2 the same?
+ _.each( organized, function(val,key,lis) { self.answers[key] = _.groupBy( val, function(y) { return y.q_id; }); } )
+ _.each( self.answers, function(val,key,lis) { self.answers2[key] = _.sortBy( val, "q_id" ) } )
+ self.$forceUpdate()
+ } )
+ },
+ methods: {
+ hoststr: function(id) {
+ var self = this
+ return _.reduce( self.hosts_by_sesid[id], function(mem,val) { if (val.name) { return mem + val.name + ", " } return mem }, '')
+ },
+ userstr: function(id) { return _.pluck(this.rosters[id], "name").join(', ') },
+ usernum: function(id) { if (id in this.rosters) { return this.rosters[id].length } return 0 },
+ useremails: function(id) { return _.pluck(this.rosters[id], "email").join('; ') },
+ surveystr: function(id) {
+ var self = this
+ var result = ""
+ if (this.answers2[id]) {
+ _.each( this.answers2[id], function (qlist) {
+ result += "" + qlist[0]['question'] + " \n"
+ _.each( qlist, function(qanswer) {
+ result += "" + qanswer['answer'] + " \n"
+ })
+ result += " \n"
+ })
+ return result
+ }
+ return "no survey results? "
+ var answers = _.find(this.activities, function(x) { return x.id == id } )
+ //console.log('found these answers')
+ //console.log(answers)
+ return "Surveys"
+ return _.reduce( self.hosts_by_sesid[id], function(mem,val) { if (val.name) { return mem + val.name + ", " } return mem }, '')
+ },
+ },
+ computed: {
+ },
+ watch: { },
+ template: `` })
+
+
+
+//
+//
+// _ _ _
+// | | | | (_)
+// ___ ___| |_| |_ _ _ __ __ _ ___
+// / __|/ _ \ __| __| | '_ \ / _` / __|
+// \__ \ __/ |_| |_| | | | | (_| \__ \
+// |___/\___|\__|\__|_|_| |_|\__, |___/
+// __/ |
+// |___/
+//
+//
+const Settings = Vue.component('settings', {
+ props: [ ],
+ data: function () {
+ return { 'zoom_on':'', 'survey_on':'', 'ay':'', 'default_conference':'' } },
+ mounted: function() {
+ var self = this
+ this.zoom_on = this.$parent.settings.zoom_on
+ this.survey_on = this.$parent.settings.survey_on
+ this.ay = this.$parent.settings.default_ay
+ this.default_conference = this.$parent.settings.default_conference
+ },
+ methods: {
+ },
+ computed: {
+ },
+ watch: { },
+ template: `` })
+
+
+
+// _ _
+// | | | |
+// ___ __ _| | ___ _ __ __| | __ _ _ __
+// / __/ _` | |/ _ \ '_ \ / _` |/ _` | '__|
+// | (_| (_| | | __/ | | | (_| | (_| | |
+// \___\__,_|_|\___|_| |_|\__,_|\__,_|_|
+//
+//
+
+
+// VERY SIMPLE CALENDAR
+//
+const MyCal = Vue.component('mycal', {
+ data: function () {
+ return { today:new Date(), currentMonth:0, currentYear:0, selectYear:'', selectMonth:'',
+ months:["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+ activities:[],
+ by_date: {},
+ editing: -1, } },
+ mounted: function() {
+ var self = this
+ this.currentYear = this.today.getFullYear()
+ this.currentMonth = this.today.getMonth()
+ this.selectYear = this.currentYear
+ this.selectMonth = this.currentMonth
+ basic_get('dir_api.php?a=get/sessions',
+ function(r2) { self.activities = _.map(r2, function(x) {
+ var dd = new Date(x.starttime);
+ var [m,d,y] = [dd.getMonth(), dd.getDate(), dd.getFullYear()] // months start at 0....
+ var d_string = d + "-" + m + "-" + y
+ if (self.by_date[d_string]) { self.by_date[d_string].push(x) }
+ else { self.by_date[d_string] = [x, ] } } )
+ self.$forceUpdate() } )
+ },
+ methods: {
+ thisDay: function(i,j) {
+ var dayOfMonth = ((7*(i-1))+j)-this.firstDay()
+ return dayOfMonth },
+ eventsThisDay: function(i,j) {
+ var dayOfMonth = ((7*(i-1))+j)-this.firstDay()
+ var d_string = dayOfMonth + "-" + this.selectMonth + "-" + this.selectYear
+ var day_text = ''
+ if (this.by_date[d_string]) {
+ evts = _.filter( this.by_date[d_string], function(x) { return x.typeId!="101" } )
+ return evts } return [] },
+ cleanTime: function(e) {
+ var dd = new Date(e.starttime);
+ var [h,m] = [dd.getHours(), dd.getMinutes()]
+ var ampm = 'am'
+ if (h > 12) { h -= 12; ampm = 'pm' }
+ if (m == 0) { m = '' }
+ else { m = ':' + m }
+ return h + m + ampm },
+ daysInMonth: function() {
+ return 32 - new Date(this.selectYear, this.selectMonth, 32).getDate() },
+ firstDay: function() {
+ return (new Date(this.selectYear, this.selectMonth)).getDay() },
+ next: function() {
+ this.selectYear = (this.selectYear === 11) ? this.selectYear + 1 : this.selectYear;
+ this.selectMonth = (this.selectMonth + 1) % 12; },
+ previous: function() {
+ this.selectYear = (this.selectYear === 0) ? this.selectYear - 1 : this.selectYear;
+ this.selectMonth = (this.selectMonth === 0) ? 11 : this.selectMonth - 1; },
+ },
+ computed: {
+ },
+ watch: {
+ },
+ template:`
+
{{months[selectMonth] + " " + selectYear}}
+
+
+
+ Sun Mon Tue Wed Thu Fri Sat
+
+
+
+
+
+ {{ thisDay(i,j) }}
+ {{cleanTime(ev)}} {{ ev.title }}
+
+
+
+
+
` })
+
+
+
+
+
+
+// _ _ _ _ _
+// | | | | | | | | | |
+// __ _____| | ___ ___ _ __ ___ ___ | | ___| |_| |_ ___ _ __ | |
+// \ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \ | |/ _ \ __| __/ _ \ '__| | |
+// \ V V / __/ | (_| (_) | | | | | | __/ | | __/ |_| || __/ | |_|
+// \_/\_/ \___|_|\___\___/|_| |_| |_|\___| |_|\___|\__|\__\___|_| (_)
+//
+//
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// WELCOME LETTER main component
+//
+const WelcomeLetter = Vue.component('welcomeletter', {
+ props: [ 'mysem','mycrn', 'teacher_ext_id', ],
+ data: function () {
+ return { courses_by_semester:[], wl_sem:'', wl_crn:'', section_wl:{}, sortby:'code', reversed:false, active:-1, } },
+ watch: {
+ "teacher_ext_id": function (val, oldVal) { console.log('tch ext id changed'); this.fetch_sections() },
+ },
+ mounted: function() {
+ var self = this
+ if (this.mysem && this.mycrn) { this.fetch_wletters(this.mysem, this.mycrn) }
+ else { this.$root.do_after_load( self.fetch_sections) }
+ },
+ methods: {
+ swap_section: function(section_obj) { this.fetch_wletters(section_obj.sem,section_obj.crn) },
+ show_list: function() { this.section_wl = {} },
+ fetch_wletters: function(ss,cc) {
+ var self = this;
+ fetch('dir_api.php?a=get/section/' + ss + '/' + cc,
+ { method: 'GET' }).then(function (response) {
+ // The API call was successful!
+ if (response.ok) {
+ response.json().then( function(r2) {
+ self.section_wl = r2;
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { console.warn('Something went wrong.', err); });
+ },
+ fetch_sections: function() {
+ var self = this;
+ basic_get('dir_api.php?a=get/sections/' + this.$root.user.ext_id,
+ function(r2) { self.courses_by_semester = _.groupBy(r2,function(x) { return x.sem || 0} ); self.$forceUpdate(); self.active += 1; console.log(self.active) } )
+ },
+ },
+ template: `` })
+
+
+
+
+// _ _ _
+// | | | | | |
+// _____ _____ _ __ | |_ ___ | |__ ___| |_ __ ___ _ __
+// / _ \ \ / / _ \ '_ \| __/ __| | '_ \ / _ \ | '_ \ / _ \ '__|
+// | __/\ V / __/ | | | |_\__ \ | | | | __/ | |_) | __/ |
+// \___| \_/ \___|_| |_|\__|___/ |_| |_|\___|_| .__/ \___|_|
+// | |
+// |_| //
+// AJAX POST UPDATES TO API
+//
+
+function post_update(table,cols,vals,id=0) {
+ action = "nothing"
+ //if (table=="update_survey") { action = "update" }
+ if (table=="personnel") { action = "update" }
+ if (table=="personnel_ext") { action = "update_xt" }
+ if (table=="conf_users") { action = "update_cf" }
+ if (table=="conf_sessions") { action = "update/activity" }
+ if (table=="webpages") { action = "update_web" }
+ if (table=="welcome_letters") { action = "update/letter" } // or insert?
+ if (table=="uniforecord") { action = "update/settings" }
+ var idstr = ""
+ if (id) { idstr = "&id=" + id }
+ fetch('dir_api.php', {
+ method: 'POST',
+ headers: new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' }),
+ body: "a="+action+"&cols="+cols+"&vals="+vals+idstr,
+ }).then(function (response) {
+ if (response.ok) {
+ response.json().then( function(r2) {
+ // display success alert
+ alert_message('Saved.')
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { alert_message("Couldn't save!",pink); console.warn('Something went wrong.', err); });
+}
+
+function generic_fail(err,x="Something went wrong with an ajax fetch") {
+ console.log(x); console.log(err) }
+
+function basic_get( url, after_fxn, fail_fxn=generic_fail ) {
+ fetch(url, { method: 'GET' }).then(function (response) {
+ if (response.ok) {response.json().then( function(r2) { after_fxn(r2) } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) { }).catch(function (err) { fail_fxn(err) } ) }
+
+var evt = {
+ clear_tables: function() {
+ var self = this
+ _.each( this.tables, function(x) { self[x] = [] } )
+ this.data = {}
+ this.target_ids = {} },
+ send_update: function() {
+ var self = this
+ _.each( this.tables, function(x) {
+ if (self[x].length) {
+ var cols = ""
+ var vals = ""
+ _.each(self[x], function(y) {
+ if (cols.length) { cols += "," }
+ if (vals.length) { vals += "," }
+ cols += y
+ if (typeof self.data[y] == "string") {
+ re = /,/g
+ vals += encodeURIComponent(self.data[y].replace(re,'[CMA]') ) }
+ else { vals += self.data[y] }
+ })
+ var edit_other = 0
+ if (self.target_ids[x]) { edit_other = self.target_ids[x] }
+ post_update(x, cols, vals, edit_other)
+ }
+ } ) },
+ data: {},
+ target_ids: {},
+ tables: ['personnel','personnel_ext','webpages','welcome_letters','conf_sessions','conf_hosts',
+ 'pers_departments','pers_committees','pers_titles'],
+}
+
+
+
+evt.clear_tables()
+MicroEvent.mixin(evt)
+
+
+
+
+
+
+
+// _ _____ _____
+// (_) /\ | __ \| __ \
+// _ __ ___ __ _ _ _ __ / \ | |__) | |__) |
+// | '_ ` _ \ / _` | | '_ \ / /\ \ | ___/| ___/
+// | | | | | | (_| | | | | | / ____ \| | | |
+// |_| |_| |_|\__,_|_|_| |_| /_/ \_\_| |_|
+//
+//
+var app = new Vue({
+ el: '#dir_editor',
+ data: { events: evt,
+ msg: 'hello', active: false, creating:0,
+ user: {'last_name':'', 'first_name':'', 'department':'', 'extension':'', 'phone_number':'', 'email':'',
+ 'staff_type':'', 'room':'', 'status':'', 'user_id':'', 'password':'', 'time_created':'', 'time_updated':'',
+ 'id':'', ext_id:false, 'web_on':'', use_dir_photo:0, general_photo_release:0, espanol:0, zoom:'', preferred_contact:'',
+ officehours:'', title:'', picture:'', education:'', bio:'', courses:'', personal_page:'', changed:'' },
+ settings:{},
+ filter: [],
+ roles_menu: [],
+ depts_menu: [],
+ titles_menu: [],
+ sessiontypes_menu: [],
+ parents_menu: [],
+ ay_menu: [],
+ modes_menu: [ {'id':'online','string':'Online'}, {'id':'inperson','string':'In Person'}, {'id':'hybrid','string':'Hybrid'}, {'id':'','string':''}, ],
+ waiting_fxns: [],
+ data_loaded: 0,
+ committees_menu: [],
+ menus_fetched: false,
+ },
+ watch: {
+ 'data_loaded': function(newVal,oldVal) {
+ if (newVal > 0) { _.each( this.waiting_fxns, function(fx) { fx() }) } }, },
+ methods: {
+ do_after_load: function(do_fxn) { this.waiting_fxns.push(do_fxn) /*....*/ },
+ fetch_menus: function() {
+ if (! this.menus_fetched) {
+ var self = this;
+ fetch('dir_api.php?a=menus', { method: 'GET' }).then(function (response) {
+ // The API call was successful!
+ if (response.ok) {
+ response.json().then( function(r2) {
+ self.depts_menu = r2.departments;
+ self.roles_menu = r2.roles;
+ self.titles_menu = r2.titles;
+ self.committees_menu = r2.committees;
+ self.sessiontypes_menu = r2.sessiontypes;
+ self.parents_menu = r2.parents;
+ self.menus_fetched = true;
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) {
+ // FAILED TO LOAD. MOST LIKELY THE SSO/SESSION TIMED OUT
+ // .... reload whole page to get redirect...?
+ console.warn('Something went wrong.', err);
+ });
+ }
+ },
+ my_subscribe_calendar: function() { return "webcal://hhh.gavilan.edu/phowell/map/calendar" + this.user.conf_id + ".ics" },
+ clip_copy: function(x) {
+ // see the .htaccess file for the mod_rewrite that makes the ics file work. //
+
+ var data = [new ClipboardItem({ "text/plain": new Blob([this.my_subscribe_calendar()], { type: "text/plain" }) })];
+ navigator.clipboard.write(data).then(function() {
+ console.log("Copied to clipboard successfully!");
+ fadein_message()
+ }, function() { console.error("Unable to write to clipboard. :-("); }) }, },
+ computed: { },
+ mounted: function() {
+ var self = this;
+ fetch('api/start', { method: 'GET' }).then(function (response) {
+ // The API call was successful!
+ if (response.ok) {
+ response.json().then( function(r2) {
+ var x = self.user.mysessions
+ self.user = r2.user;
+ self.depts_menu = r2.departments;
+ self.roles_menu = r2.roles;
+ self.titles_menu = r2.titles;
+ self.committees_menu = r2.committees;
+ self.sessiontypes_menu = r2.sessiontypes;
+ self.parents_menu = r2.parents;
+ self.ay_menu = r2.ay;
+ self.settings = r2.settings;
+ self.menus_fetched = true;
+ self.data_loaded += 1
+ // pause half a second for the children to get populated before registering update events...
+ setTimeout(function() {
+ self.active = true;
+ // fancier text editors...
+ //pell.init( { element: document.getElementById('bio2'), onChange: function(h) { console.log(h) } } )
+ }, 1600);
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { console.warn('Something went wrong.', err); }) } })
+
+
+
+
+// _
+// | |
+// _____ _____ _ __ | |_ ___
+// / _ \ \ / / _ \ '_ \| __/ __|
+// | __/\ V / __/ | | | |_\__ \
+// \___| \_/ \___|_| |_|\__|___/
+//
+//
+
+
+//
+// SIMPLE EVENTS
+//
+
+var update_fxn = _.debounce( function() {
+ alert_message('saving...','lightgreen')
+ evt.send_update(); evt.clear_tables(); }, 1300 )
+
+
+var update_survey_fxn = function() {
+
+}
+
+evt.bind('update_survey',_.debounce( function(dat) {
+ if (app.active) {
+ console.log(dat)
+ fetch('dir_api.php?a=update/answers', {
+ method: 'POST',
+ headers: new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' }),
+ body: "session=" +dat[1] + "&user=" +dat[0] + "&qid=" +dat[2] + "&answer="+dat[3],
+ }).then(function (response) {
+ if (response.ok) {
+ response.json().then( function(r2) {
+ // display success alert
+ alert_message('Saved.')
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { alert_message("Couldn't save!",pink); console.warn('Something went wrong.', err); });
+} } , 1300 ) );
+
+evt.bind('changed', function(dat) {
+ if (app.active) {
+ var column = dat[0]
+ var table = dat[1]
+ var value = dat[2]
+ var target = dat[3]
+ this.data[column] = value
+ if (!this[table].includes(column) ) {this[table].push(column)}
+ if (target) { this.target_ids[table] = target } }
+ if (app.active && !app.creating) { update_fxn() }
+});
+
+evt.bind('create_new_session', function(dat) {
+ var default_activity = {"title":"","desc":"","length":"1","starttime":"","track":"","location":"","gets_survey":"1","category":"1",
+ "parent":"","recording":"","instructions":"","image_url":"","is_flex_approved":"1","typeId":"101"}
+ var new_activity = _.extend(default_activity, evt.data)
+
+ if ('typeId' in new_activity) { new_activity.type = new_activity.typeId; delete new_activity.typeId; }
+ let formData = new FormData();
+ _.each( Object.keys(new_activity), function(x) { console.log(x); formData.append(x, new_activity[x]) } )
+
+ fetch('dir_api.php?a=set/newsession', {
+ method: 'POST',
+ body: formData, }).then(function (response) {
+ if (response.ok) {
+ response.json().then( function(r2) {
+ alert_message('Saved new activity.')
+ app.$children[0].set_id(r2.new_id) } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { alert_message("Couldn't create the activity!",pink); console.warn('Something went wrong.', err); }) })
+
+
+// bold the current page
+
+function bold_nav() {
+ var currentFileName = window.location.pathname.split('/').pop();
+
+ // Select the tag with the matching href value and apply the class
+ $('#nav a[href="' + currentFileName + '"]').addClass('highlight');
+}
+
+
+$(document).ready(function() {
+ bold_nav()
+})
+
+//
+//
+// MISC
+//
+//
+
+//
+//
+// v-lazy-container="{ selector: 'img' }"
+//
diff --git a/js/dir_app20211021.js b/js/dir_app20211021.js
new file mode 100644
index 0000000..e49d032
--- /dev/null
+++ b/js/dir_app20211021.js
@@ -0,0 +1,767 @@
+
+
+function init_file_dropzone(parameter_name) {
+ Dropzone.options.myGreatDropzone = { // camelized version of the `id`
+ paramName: parameter_name, // The name that will be used to transfer the file
+ maxFilesize: 6 }; // MB
+}
+// init_file_dropzone("staffpicupload")
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// VISUAL EFFECTS
+//
+
+
+
+function fade_message() {
+ var a_dom = document.querySelector('#alert');
+ TinyAnimate.animateCSS(a_dom, 'opacity', '', 1.0, 0.0, 750, 'easeInOutQuart', function() {
+ });
+}
+
+function alert_message(msg,color='yellow') {
+ var a = $('#alert')
+ a.text(msg)
+ a.css('background-color',color)
+ var a_dom = document.querySelector('#alert');
+ TinyAnimate.animateCSS(a_dom, 'opacity', '', 0.0, 1.0, 500, 'easeInOutQuart', function() {
+ setTimeout( fade_message, 2500 )
+ });
+
+ //a.css('visibility','visible')
+}
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// FORM COMPONENTS
+//
+
+
+// TODO these should know if they're modifying the current user or someone else.
+
+
+
+// A single text style question
+const TQuestion = Vue.component('field', {
+ props: [ 'table', 'qid', 'question', 'answer', 'placeholder', 'targetid', ],
+ data: function () {
+ return { "a":this.answer } },
+ watch: {
+ "answer": function(val,Oldval) { this.a = val },
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) }, },
+ template: `{{ question }}
+
`,
+})
+
+// A single INLINE text style question
+const TIQuestion = Vue.component('ifield', {
+ props: [ 'table', 'qid', 'question', 'answer', 'placeholder', 'myclass', 'targetid', ],
+ data: function () {
+ return { "a":this.answer } },
+ watch: {
+ "answer": function(val,Oldval) { this.a = val },
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) }, },
+ template: ` `,
+})
+
+// A single checkbox
+const Checkbox = Vue.component('checkbox', {
+ props: [ 'table', 'qid', 'question', 'answer', 'targetid', ],
+ data: function () {
+ return { "a":this.answer } },
+ watch: {
+ "answer": function(val,Oldval) { this.a = val },
+ "a": function (val, oldVal) {
+ var newVal = 0
+ if (val==true) { newVal = 1 }
+ this.$root.events.trigger('changed',[this.qid,this.table, newVal, this.targetid]) }, },
+ template: `
+
+
+ {{ question }}
`
+})
+
+// A single long format text question
+const TAQuestion = Vue.component('tfield', {
+ props: [ 'table', 'qid', 'question', 'answer', 'targetid', ],
+ data: function () {
+ return { "a": this.answer } },
+ watch: {
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) },
+ "answer": function (val, oldVal) { this.a = val },
+ },
+ template: `{{ question }}
+
` })
+
+
+
+// Select menu
+const SelMenu = Vue.component('selectmenu', {
+ props: [ 'table', 'qid', 'question', 'answer', 'menu', 'labelfield', 'targetid', ],
+ data: function () {
+ return { "a": this.answer } },
+ watch: {
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) },
+ "answer": function (val, oldVal) { this.a = val },
+ },
+ template: `
+ {{o[labelfield]}}
+ ` })
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// ONE LINE OF THE STAFF DIR LISTING
+//
+const StaffLine = Vue.component('staff_line', {
+ props: [ 's', 'i' ],
+ //data: function() { return { } },
+ methods: {
+ nope: function() { return 1; },
+ odd: function(i) { if (i % 2 ==0) { return "even" } return "odd" },
+ bio: function() { return "bio.php?p=" + this.s.id },
+ gtitle: function() { if (this.s.gtitle) {return _.findWhere(this.$root.titles_menu, {id:this.s.gtitle}).name}; return "" },
+ gdept1: function() { if (this.s.dept1) {return _.findWhere(this.$root.depts_menu, {id:this.s.dept1}).name}; return "" },
+ grole: function() { if (this.s.role) {return _.findWhere(this.$root.roles_menu, {id:this.s.role}).descr}; return "" },
+ swapedit: function() { console.log("edit " + this.s.first_name + " " + this.s.last_name)
+ this.$emit('swapout', this.s.id) }
+ },
+ template: `
+
+
{{s.first_name}} {{s.last_name}}
+
{{s.department}}
+
{{s.email}}
+
{{s.phone_number}}
+
{{s.room}}
+
edit
+
+
+
{{gtitle()}}
+
{{gdept1()}}
+
{{grole()}}
+
+ Published: Yes No
+ personnel_ext: Yes No
+ c_users: Yes No
+
+
+
+
+ `
+});
+
+
+
+//
+//
+// STAFF DIR LISTING
+//
+// ONE LINE - BUT EDITING!
+//
+const StaffLineEdit = Vue.component('staff_line_edit', {
+ props: [ 's', 'i' ],
+ //data: function() { return { } },
+ methods: {
+ nope: function() { return 1; },
+ odd: function(i) { if (i % 2 ==0) { return "even" } return "odd" },
+ bio: function() { return "bio.php?p=" + this.s.id },
+ done: function() { this.$emit('done_edit') },
+
+ }, //v-lazy-container="{ selector: 'img' }"
+ template: `
+ `
+});
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// STAFF DIR LISTING MAIN CONTAINER
+//
+const DirList = Vue.component('dirlist', {
+ data: function () {
+ return { "personnel":[], sortby:'last_name', search:'', reversed: false,
+ components: {n:StaffLine, e: StaffLineEdit }, editing: -1, } },
+ mounted: function() {
+ var self = this;
+ this.$root.fetch_menus();
+
+ fetch('dir_api.php?a=list', { method: 'GET' }).then(function (response) {
+ // The API call was successful!
+ if (response.ok) {
+ response.json().then( function(r2) {
+ self.personnel = r2;
+ _.each( self.personnel, function(x) {
+ if (x.dir_photo_path==null) { x.dir_photo_path='images_sm/nobody.jpg' }
+ x.searchable = x.first_name.toLowerCase() + ' ' + x.last_name.toLowerCase()
+ if (x.department) { x.searchable += ' ' + x.department.toLowerCase() }
+ } )
+ //if (self.user.use_dir_photo == "0") { self.user.use_dir_photo = false }
+ //if (self.user.general_photo_release == "0") { self.user.general_photo_release = false }
+ // pause half a second for the children to get populated before registering update events...
+ setTimeout(function() {
+ //self.active = true;
+ // fancier text editors...
+ //pell.init( { element: document.getElementById('bio2'), onChange: function(h) { console.log(h) } } )
+ }, 1600);
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { console.warn('Something went wrong.', err); });
+ },
+ methods: {
+ setsort: function(ss) {
+ if (this.sortby == ss) { this.reversed = ! this.reversed }
+ else {
+ this.reversed = false
+ this.sortby = ss
+ }
+ },
+ swapme: function(x) {
+ this.editing = x
+ },
+ done_edit: function(id) {
+ this.editing = -1
+ },
+ am_editing: function(id) {
+ if (id == this.editing) { return StaffLineEdit }
+ return StaffLine
+ },
+ },
+ computed: {
+ filtered: function() {
+ var ff = this.personnel
+ var self = this
+ if (this.search) {
+ var ss = self.search.toLowerCase()
+ ff = ff.filter(function(x) { return x.searchable.includes(ss) }) }
+
+ ff = _.sortBy(ff, function(x) {
+ if (x[self.sortby]) {
+ var s = x[self.sortby];
+ return s.trim().toLowerCase() }
+ return '' })
+ if (this.reversed) {
+ ff.reverse()
+ }
+ return ff
+ }
+ },
+ watch: {
+ },
+ template: `` })
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// ACTIVITIES LIST MAIN CONTAINER
+//
+const ActivityList = Vue.component('activitylist', {
+ data: function () {
+ return { activities:[], sortby:'title', reversed:false, editing: -1, } },
+ mounted: function() {
+ var self = this;
+ this.$root.fetch_menus();
+
+ fetch('dir_api.php?a=get/sessions', { method: 'GET' }).then(function (response) {
+ // The API call was successful!
+ if (response.ok) {
+ response.json().then( function(r2) {
+ self.activities = r2;
+ _.each( self.activities, function(x) {
+ x.searchable = x.title.toLowerCase() + ' ' + x.desc.toLowerCase()
+ //if (x.department) { x.searchable += ' ' + x.department.toLowerCase() }
+ } )
+ //if (self.user.use_dir_photo == "0") { self.user.use_dir_photo = false }
+ //if (self.user.general_photo_release == "0") { self.user.general_photo_release = false }
+ // pause half a second for the children to get populated before registering update events...
+ setTimeout(function() {
+ //self.active = true;
+ // fancier text editors...
+ //pell.init( { element: document.getElementById('bio2'), onChange: function(h) { console.log(h) } } )
+ }, 1600);
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { console.warn('Something went wrong.', err); });
+ },
+ methods: {
+ setsort: function(ss) {
+ if (this.sortby == ss) { this.reversed = ! this.reversed }
+ else {
+ this.reversed = false
+ this.sortby = ss
+ }
+ },
+ swapme: function(x) {
+ this.editing = x
+ },
+ done_edit: function(id) {
+ this.editing = -1
+ },
+ am_editing: function(id) {
+ return 0;
+ },
+ },
+ computed: {
+ filtered: function() {
+ var ff = this.activities
+ var self = this
+ if (this.search) {
+ var ss = self.search.toLowerCase()
+ ff = ff.filter(function(x) { return x.searchable.includes(ss) }) }
+
+ ff = _.sortBy(ff, function(x) {
+ if (x[self.sortby]) {
+ var s = x[self.sortby];
+ return s.trim().toLowerCase() }
+ return '' })
+ if (this.reversed) {
+ ff.reverse()
+ }
+ return ff
+ }
+ },
+ watch: {
+ },
+ template: `` })
+
+
+
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// VERY SIMPLE CALENDAR
+//
+const MyCal = Vue.component('mycal', {
+ data: function () {
+ return { today:new Date(), currentMonth:0, currentYear:0, selectYear:'', selectMonth:'',
+ months:["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+ activities:[],
+ by_date: {},
+ editing: -1, } },
+ mounted: function() {
+ var self = this
+ this.currentYear = this.today.getFullYear()
+ this.currentMonth = this.today.getMonth()
+ this.selectYear = this.currentYear
+ this.selectMonth = this.currentMonth
+
+ fetch('dir_api.php?a=get/sessions', { method: 'GET' }).then(function (response) {
+ if (response.ok) {
+ response.json().then( function(r2) {
+ self.activities = r2
+ _.each( self.activities, function(x) {
+ var dd = new Date(x.starttime);
+ var [m,d,y] = [dd.getMonth(), dd.getDate(), dd.getFullYear()] // months start at 0....
+ var d_string = d + "-" + m + "-" + y
+ if (self.by_date[d_string]) { self.by_date[d_string].push(x) }
+ else { self.by_date[d_string] = [x, ] } } )
+ self.$forceUpdate()
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { console.warn('Something went wrong.', err); });
+ },
+ methods: {
+ thisDay: function(i,j) {
+ var dayOfMonth = ((7*(i-1))+j)-this.firstDay()
+ return dayOfMonth
+ },
+ eventsThisDay: function(i,j) {
+ var dayOfMonth = ((7*(i-1))+j)-this.firstDay()
+ var d_string = dayOfMonth + "-" + this.selectMonth + "-" + this.selectYear
+ var day_text = ''
+
+ if (this.by_date[d_string]) {
+ evts = _.filter( this.by_date[d_string], function(x) { console.log(x); return x.typeId!="101" } )
+ console.log(evts)
+ return evts
+ }
+ return []
+ },
+ cleanTime: function(e) {
+ var dd = new Date(e.starttime);
+ var [h,m] = [dd.getHours(), dd.getMinutes()]
+ var ampm = 'am'
+ if (h > 12) { h -= 12; ampm = 'pm' }
+ if (m == 0) { m = '' }
+ else { m = ':' + m }
+ return h + m + ampm
+ },
+ daysInMonth: function() {
+ return 32 - new Date(this.selectYear, this.selectMonth, 32).getDate()
+ },
+ firstDay: function() {
+ return (new Date(this.selectYear, this.selectMonth)).getDay()
+ },
+ next: function() {
+ this.selectYear = (this.selectYear === 11) ? this.selectYear + 1 : this.selectYear;
+ this.selectMonth = (this.selectMonth + 1) % 12;
+ },
+ previous: function() {
+ this.selectYear = (this.selectYear === 0) ? this.selectYear - 1 : this.selectYear;
+ this.selectMonth = (this.selectMonth === 0) ? 11 : this.selectMonth - 1;
+ },
+ },
+ computed: {
+ },
+ watch: {
+ },
+ template: `
+
{{months[selectMonth] + " " + selectYear}}
+
+
+
+
+
+ Sun
+ Mon
+ Tue
+ Wed
+ Thu
+ Fri
+ Sat
+
+
+
+
+
+
+
+ {{ thisDay(i,j) }}
+ {{cleanTime(ev)}} {{ ev.title }}
+
+
+
+
+
+
+
` })
+
+
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// AJAX POST UPDATES TO API
+//
+
+function post_update(table,cols,vals,id=0) {
+ action = "nothing"
+ if (table=="personnel") { action = "update" }
+ if (table=="personnel_ext") { action = "update_xt" }
+ if (table=="webpages") { action = "update_web" }
+ var idstr = ""
+ if (id) { idstr = "&id=" + id }
+
+ console.log("a="+action+"&cols="+cols+"&vals="+vals+idstr)
+
+ fetch('dir_api.php', {
+ method: 'POST',
+ headers: new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' }),
+ body: "a="+action+"&cols="+cols+"&vals="+vals+idstr,
+ }).then(function (response) {
+ // The API call was successful!
+ if (response.ok) {
+ response.json().then( function(r2) {
+ // display success alert
+ alert_message('Saved.')
+
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { alert_message("Couldn't save!",pink); console.warn('Something went wrong.', err); });
+}
+
+var evt = {
+ clear_tables: function() {
+ var self = this
+ _.each( this.tables, function(x) { self[x] = [] } )
+ this.data = {}
+ this.target_ids = {} },
+ send_update: function() {
+ var self = this
+ //console.log("Sending update... (not really)")
+ _.each( this.tables, function(x) {
+ if (self[x].length) {
+ var cols = ""
+ var vals = ""
+ _.each(self[x], function(y) {
+ if (cols.length) { cols += "," }
+ if (vals.length) { vals += "," }
+ cols += y
+ if (typeof self.data[y] == "string") {
+ re = /,/g
+ vals += encodeURIComponent(self.data[y].replace(re,'[CMA]') ) }
+ else { vals += self.data[y] }
+ })
+ //console.log("table: " + x + " Columns: " + cols + ".. Vals: " + vals)
+ var edit_other = 0
+ if (self.target_ids[x]) { edit_other = self.target_ids[x] }
+ post_update(x, cols, vals, edit_other)
+ }
+ } ) },
+ info: "what am I?" ,
+ data: {},
+ target_ids: {},
+ tables: ['personnel','personnel_ext','webpages','welcomepages','conf_sessions','conf_hosts',
+ 'pers_departments','pers_committees','pers_titles'],
+}
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// INITIALIZE THE APP
+//
+
+evt.clear_tables()
+MicroEvent.mixin(evt);
+
+var app = new Vue({
+ el: '#dir_editor',
+ data: { events: evt,
+ msg: 'hello', active: false,
+ user: {'last_name':'', 'first_name':'', 'department':'', 'extension':'', 'phone_number':'', 'email':'',
+ 'staff_type':'', 'room':'', 'status':'', 'user_id':'', 'password':'', 'time_created':'', 'time_updated':'',
+ 'id':'', 'web_on':'', use_dir_photo:0, general_photo_release:0,
+ officehours:'', title:'', picture:'', education:'', bio:'', courses:'', personal_page:'', changed:'' },
+ filter: [],
+ roles_menu: [],
+ depts_menu: [],
+ titles_menu: [],
+ committees_menu: [],
+ menus_fetched: false,
+ },
+ watch: { },
+ methods: {
+ fetch_menus: function() {
+ if (! this.menus_fetched) {
+ var self = this;
+ fetch('dir_api.php?a=menus', { method: 'GET' }).then(function (response) {
+ // The API call was successful!
+ if (response.ok) {
+ response.json().then( function(r2) {
+ self.depts_menu = r2.departments;
+ self.roles_menu = r2.roles;
+ self.titles_menu = r2.titles;
+ self.committees_menu = r2.committees;
+ self.menus_fetched = true;
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { console.warn('Something went wrong.', err); });
+ }
+
+
+
+ },
+ },
+ computed: { },
+ mounted: function() {
+ var self = this;
+ fetch('dir_api.php', { method: 'GET' }).then(function (response) {
+ // The API call was successful!
+ if (response.ok) {
+ response.json().then( function(r2) {
+ self.user = r2;
+ if (self.user.use_dir_photo == "0") { self.user.use_dir_photo = false }
+ if (self.user.general_photo_release == "0") { self.user.general_photo_release = false }
+ // pause half a second for the children to get populated before registering update events...
+ setTimeout(function() {
+ self.active = true;
+ // fancier text editors...
+ //pell.init( { element: document.getElementById('bio2'), onChange: function(h) { console.log(h) } } )
+ }, 1600);
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { console.warn('Something went wrong.', err); });
+ }
+})
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// SIMPLE EVENTS
+//
+
+var update_fxn = _.debounce( function() {
+ alert_message('saving...','lightgreen')
+ evt.send_update(); evt.clear_tables(); }, 1300 )
+
+evt.bind('changed', function(dat) {
+ if (app.active) {
+ var column = dat[0]
+ var table = dat[1]
+ var value = dat[2]
+ var target = dat[3]
+ console.log(dat)
+ this.data[column] = value
+ if (!this[table].includes(column) ) {this[table].push(column)}
+ if (target) { this.target_ids[table] = target }
+ update_fxn() }
+});
+
+
+
+
+
+
+
+
+
+
+//
+//
+// MISC
+//
+//
+
+//
+//
+// v-lazy-container="{ selector: 'img' }"
+//
+
+
+
+
+
+
+
diff --git a/js/dir_app202111022.js b/js/dir_app202111022.js
new file mode 100644
index 0000000..dcf7ca5
--- /dev/null
+++ b/js/dir_app202111022.js
@@ -0,0 +1,878 @@
+
+
+function init_file_dropzone(parameter_name) {
+ Dropzone.options.myGreatDropzone = { // camelized version of the `id`
+ paramName: parameter_name, // The name that will be used to transfer the file
+ maxFilesize: 6 }; // MB
+}
+// init_file_dropzone("staffpicupload")
+
+
+function parsesqltime(mysqldate) { // 2021-01-29 09:00:00
+ if (! mysqldate) { return 0 }
+ var field = mysqldate.match(/^(\d\d\d\d)\-(\d+)\-(\d+)\s(\d+)\:(\d+)\:(\d+)$/)
+ var mydate = new Date(field[1], field[2] - 1 , field[3], field[4], field[5], field[6])
+ return mydate }
+
+function dj(mysqldate) { return dayjs(parsesqltime(mysqldate)) }
+
+Object.defineProperty(Vue.prototype, '$dj', { value: dj });
+Object.defineProperty(Vue.prototype, '$parsesqltime', { value: parsesqltime });
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// VISUAL EFFECTS
+//
+
+
+
+function fade_message(theselector='#alert') {
+ var a_dom = document.querySelector(theselector);
+ TinyAnimate.animateCSS(a_dom, 'opacity', '', 1.0, 0.0, 750, 'easeInOutQuart', function() { }); }
+
+function alert_message(msg,color='yellow') {
+ var a = $('#alert')
+ a.text(msg)
+ a.css('background-color',color)
+ var a_dom = document.querySelector('#alert');
+ TinyAnimate.animateCSS(a_dom, 'opacity', '', 0.0, 1.0, 500, 'easeInOutQuart', function() {
+ setTimeout( fade_message, 2500 ) }); }
+
+function fadein_message(theclass='success') {
+ //var a = $('#'+theclass)
+ //a.css('visibility','visible')
+ var a_dom = document.querySelector('.'+theclass);
+ TinyAnimate.animateCSS(a_dom, 'opacity', '', 0.0, 1.0, 500, 'easeInOutQuart', function() {
+ setTimeout( function() { fade_message('.'+theclass) }, 2500 ) }); }
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// FORM COMPONENTS
+//
+
+
+// TODO these should know if they're modifying the current user or someone else.
+
+// A single text style question
+const TQuestion = Vue.component('field', {
+ props: [ 'table', 'qid', 'question', 'answer', 'placeholder', 'targetid', ],
+ data: function () {
+ return { "a":this.answer } },
+ watch: {
+ "answer": function(val,Oldval) { this.a = val },
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) }, },
+ template: `{{ question }}
+
`,
+})
+
+// A single INLINE text style question
+const TIQuestion = Vue.component('ifield', {
+ props: [ 'table', 'qid', 'question', 'answer', 'placeholder', 'myclass', 'targetid', ],
+ data: function () {
+ return { "a":this.answer } },
+ watch: {
+ "answer": function(val,Oldval) { this.a = val },
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) }, },
+ template: ` `,
+})
+
+// A single checkbox
+const Checkbox = Vue.component('checkbox', {
+ props: [ 'table', 'qid', 'question', 'answer', 'targetid', ],
+ data: function () {
+ return { "a":this.answer } },
+ watch: {
+ "answer": function(val,Oldval) { this.a = val },
+ "a": function (val, oldVal) {
+ var newVal = 0
+ if (val==true) { newVal = 1 }
+ this.$root.events.trigger('changed',[this.qid,this.table, newVal, this.targetid]) }, },
+ template: `
+
+
+ {{ question }}
`
+})
+
+// A single long format text question
+const TAQuestion = Vue.component('tfield', {
+ props: [ 'table', 'qid', 'question', 'answer', 'targetid', ],
+ data: function () {
+ return { "a": this.answer } },
+ watch: {
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) },
+ "answer": function (val, oldVal) { this.a = val },
+ },
+ template: `{{ question }}
+
` })
+
+
+
+// Select menu
+const SelMenu = Vue.component('selectmenu', {
+ props: [ 'table', 'qid', 'question', 'answer', 'menu', 'labelfield', 'targetid', ],
+ data: function () {
+ return { "a": this.answer } },
+ watch: {
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) },
+ "answer": function (val, oldVal) { this.a = val },
+ },
+ template: `
+ {{o[labelfield]}}
+ ` })
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// ONE LINE OF THE STAFF DIR EDITOR listing
+//
+const StaffLine = Vue.component('staff_line', {
+ props: [ 's', 'i', 'dup_class', ],
+ //data: function() { return { } },
+ methods: {
+ nope: function() { return 1; },
+ odd: function(i) { if (i % 2 ==0) { return "even" } return "odd" },
+ bio: function() { return "bio.php?p=" + this.s.id },
+ gtitle: function() { if (this.s.gtitle) {return _.findWhere(this.$root.titles_menu, {id:this.s.gtitle}).name}; return "" },
+ gdept1: function() { if (this.s.dept1) {return _.findWhere(this.$root.depts_menu, {id:this.s.dept1}).name}; return "" },
+ gdept2: function() { if (this.s.dept2) {return _.findWhere(this.$root.depts_menu, {id:this.s.dept2}).name}; return "-" },
+ grole: function() { if (this.s.role) {return _.findWhere(this.$root.roles_menu, {id:this.s.role}).descr}; return "" },
+ swapedit: function() { console.log("edit " + this.s.first_name + " " + this.s.last_name)
+ this.$emit('swapout', this.s.id) }
+ },
+ template: `
+
+
+status: {{ s.status }}
+permissions: {{ grole() }}
+pers id: {{ s.id }}
+ext id: {{ s.ext_id }}
+bio page: {{ s.web_on }}
+Photo - use: {{s.use_dir_photo}} release: {{s.general_photo_release}}
+ path: {{s.dir_photo_path}}
+# Sections: {{s.num_taught}}
+{{ s.sections }}
+
+
+staff: {{ s.staff_type }}
+conf_id: {{ s.conf_id }}
+G00{{s.conf_goo}}
+espanol: {{s.espanol}}
+
+
+
+{{s.first_name}} {{s.last_name}}
+{{gtitle()}}
+{{gdept1()}}
+{{gdept2()}}
+(old dept: {{s.department}} )
+
+
+email: {{s.email}}
+room: {{s.room}}
+phone: {{s.phone_number}}
+Zoom: {{s.zoom}}
+Preferred contact: {{s.preferred_contact}}
+ edit
+
+
+
`
+});
+
+/*
+
+ *
+ * status: {{ s.status }} staff: {{ s.staff_type }}
+ * permissions: {{ s.role }} {{s.first_name}} {{s.last_name}} {{gdept1()}} # Sections: {{s.num_taught}}
+ * ext id: {{ s.ext_id }} {{ s.conf_id }} {{gtitle()}} {{s.room}}
+ * bio page: {{ s.web_on }} {{s.espanol}} {{s.goo}} {{s.phone}}
+ * Photo - use: {{s.use_dir_photo}} release: {{s.general_photo_release}} {{s.email}} {{s.preferred_contact}}
+ * {{s.zoom}} {{s.dir_photo_path}}
+
+ * [ status stafftype ] fname lname dept1 num_courses --> need_welcome pg
+ * [ no pext? perms ] title room dept2 num_flx_activities --> [ ? badges ? tickets ? ]
+ * [ no conf? ] goo phone log last updated num_hosted acts
+ * [ web on espanol ] email prefcontact dir last updated num_log_entries
+ * [ photo on release ] zoom photo path committees?
+ */
+
+
+
+
+//
+//
+// STAFF DIR LISTING
+//
+// ONE LINE - BUT EDITING! // todo active / inactive switch
+//
+const StaffLineEdit = Vue.component('staff_line_edit', {
+ props: [ 's', 'i' ],
+ //data: function() { return { } },
+ methods: {
+ nope: function() { return 1; },
+ odd: function(i) { if (i % 2 ==0) { return "even" } return "odd" },
+ bio: function() { return "bio.php?p=" + this.s.id },
+ done: function() { this.$emit('done_edit') },
+ gtitle: function() { if (this.s.gtitle) {return _.findWhere(this.$root.titles_menu, {id:this.s.gtitle}).name}; return "" },
+ gdept1: function() { if (this.s.dept1) {return _.findWhere(this.$root.depts_menu, {id:this.s.dept1}).name}; return "" },
+ gdept2: function() { if (this.s.dept2) {return _.findWhere(this.$root.depts_menu, {id:this.s.dept2}).name}; return "-" },
+ grole: function() { if (this.s.role) {return _.findWhere(this.$root.roles_menu, {id:this.s.role}).descr}; return "" },
+ }, //v-lazy-container="{ selector: 'img' }"
+ template: `
+ `
+});
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// STAFF DIR LISTING MAIN CONTAINER
+//
+const DirList = Vue.component('dirlist', {
+ data: function () {
+ return { "personnel":[], sortby:'last_name', search:'', reversed: false, id_list:[], id_dups:[],
+ components: {n:StaffLine, e: StaffLineEdit }, editing: -1, } },
+ mounted: function() {
+ var self = this;
+ this.$root.fetch_menus();
+
+ fetch('dir_api.php?a=list/staffsemester', { method: 'GET' }).then(function (response) {
+ if (response.ok) {
+ response.json().then( function(r2) {
+ self.personnel = r2;
+ _.each( self.personnel, function(x) {
+ if (x.sections==null) { x.num_taught=0 }
+ if (x.dir_photo_path==null) { x.dir_photo_path='images_sm/nobody.jpg' }
+ if (x.use_dir_photo == "0") { x.use_dir_photo = false } else { x.use_dir_photo = true }
+ if (x.espanol == "0" || !x.espanol) { x.espanol = false } else { x.espanol = true }
+ if (x.general_photo_release == "0") { x.general_photo_release = false
+ } else { x.general_photo_release = true }
+ if (self.id_list.includes(x.id)) { self.id_dups.push(x.id) }
+ else { self.id_list.push(x.id) }
+ x.searchable = ''
+ if (x.first_name) { x.searchable += ' ' + x.first_name.toLowerCase() }
+ if (x.last_name) { x.searchable += ' ' + x.last_name.toLowerCase() }
+ if (x.dept1name) { x.searchable += ' ' + x.dept1name.toLowerCase() }
+ if (x.titlename) { x.searchable += ' ' + x.titlename.toLowerCase() }
+ if (x.status == "1" || x.status == null) { x.status = "1"
+ } else { x.status = false; x.searchable += ' inactive' }
+ } ) } ) } else { return Promise.reject(response) }
+ }).then(function (data) { }).catch(function (err) { console.warn('Something went wrong.', err); });
+ },
+ methods: {
+ setsort: function(ss) {
+ if (this.sortby == ss) { this.reversed = ! this.reversed }
+ else {
+ this.reversed = false
+ this.sortby = ss
+ }
+ },
+ swapme: function(x) {
+ this.editing = x
+ },
+ done_edit: function(id) {
+ this.editing = -1
+ },
+ am_editing: function(id) {
+ if (id == this.editing) { return StaffLineEdit }
+ return StaffLine
+ },
+ is_dup_id_class: function(id) { return this.id_dups.includes(id) ? " dup_line" : "" },
+ },
+ computed: {
+ filtered: function() {
+ var ff = this.personnel
+ var self = this
+ if (this.search) {
+ var ss = self.search.toLowerCase()
+ ff = ff.filter(function(x) { return x.searchable.includes(ss) }) }
+
+ ff = _.sortBy(ff, function(x) {
+ if (x[self.sortby]) {
+ var s = x[self.sortby];
+ return s.trim().toLowerCase() }
+ return 'zzzzzzzzzz' })
+ if (this.reversed) {
+ ff.reverse()
+ }
+ return ff
+ }
+ },
+ watch: {
+ },
+
+ template: `` })
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// ACTIVITIES LIST MAIN CONTAINER
+//
+const ActivityList = Vue.component('activitylist', {
+ props: [ 'itineraryview', ],
+ data: function () {
+ return { activities:[], mysessions:[], search:'', sortby:'starttime', reversed:false,
+ expanded: 1,
+ editing: -1, active:-1, } },
+ mounted: function() {
+ this.$root.fetch_menus();
+ this.fetch_myevents()
+ },
+ methods: {
+ month_year: function(d) { console.log(d); var b = this.$root.$dj(d).format('MMM D YYYY'); console.log(b); return b },
+ setsort: function(ss) {
+ if (this.sortby == ss) { this.reversed = ! this.reversed }
+ else { this.reversed = false; this.sortby = ss } },
+ swapme: function(x) { this.editing = x },
+ done_edit: function(id) { this.editing = -1 },
+ am_editing: function(id) { return 0 },
+ fetch_myevents: function() {
+ var self = this;
+ basic_get('dir_api.php?a=get/mysessions',
+ function(r2) { self.mysessions = _.sortBy(r2,function(x) { return x.starttime || 0} ); self.$forceUpdate(); self.active += 1; console.log(self.active) } )
+ basic_get('dir_api.php?a=get/sessions',
+ function(r2) {
+ self.activities = _.sortBy(r2,function(x) { return x.starttime } ); self.$forceUpdate()
+ self.active += 1; console.log(self.active)
+ _.each( self.activities, function(x) {
+ x.searchable = x.title.toLowerCase() + ' ' + x.desc.toLowerCase() } ) } )
+ },
+ filtered: function(ff) { if (this.active<1) { return [] }
+ var self = this
+ if (this.search) {
+ var ss = self.search.toLowerCase()
+ ff = ff.filter(function(x) { return x.searchable.includes(ss) }) }
+ ff = _.sortBy(ff, function(x) { console.log(x);
+ if (x[self.sortby]) { var s = x[self.sortby]; return s.trim().toLowerCase() }
+ return '' })
+ if (this.reversed) { ff.reverse() }
+ console.log(ff)
+ return ff },
+ },
+ computed: {
+ activities_filtered: function() { var a = this.filtered(this.activities); console.log(a); return a; },
+ mysessions_filtered: function() { return this.filtered(this.mysessions) },
+
+ activities_g_filtered: function() { if (this.active<1) { return {} }
+ var self=this; return _.groupBy(self.activities_filtered, function(x) { return self.month_year(x.starttime) } ); },
+ mysessions_g_filtered: function() { if (this.active<1) { return {} }
+ var self=this; return _.groupBy(self.mysessions_filtered, function(x) { return self.month_year(x.starttime) } ); },
+
+ },
+ watch: {
+ },
+ template: `` })
+
+
+
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// WELCOME LETTER main component
+//
+const WelcomeLetter = Vue.component('welcomeletter', {
+ props: [ 'mysem','mycrn', 'teacher_ext_id', ],
+ data: function () {
+ return { courses_by_semester:[], wl_sem:'', wl_crn:'', section_wl:{}, sortby:'code', reversed:false, active:-1, } },
+ watch: {
+ "teacher_ext_id": function (val, oldVal) { console.log('tch ext id changed'); this.fetch_sections() },
+ },
+ mounted: function() {
+ var self = this
+ if (this.mysem && this.mycrn) { this.fetch_wletters(this.mysem, this.mycrn) }
+ else { this.$root.do_after_load( self.fetch_sections) }
+ },
+ methods: {
+ swap_section: function(section_obj) { this.fetch_wletters(section_obj.sem,section_obj.crn) },
+ show_list: function() { this.section_wl = {} },
+ fetch_wletters: function(ss,cc) {
+ var self = this;
+ fetch('dir_api.php?a=get/section/' + ss + '/' + cc,
+ { method: 'GET' }).then(function (response) {
+ // The API call was successful!
+ if (response.ok) {
+ response.json().then( function(r2) {
+ self.section_wl = r2;
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { console.warn('Something went wrong.', err); });
+ },
+ fetch_sections: function() {
+ var self = this;
+ basic_get('dir_api.php?a=get/sections/' + this.$root.user.ext_id,
+ function(r2) { self.courses_by_semester = _.groupBy(r2,function(x) { return x.sem || 0} ); self.$forceUpdate(); self.active += 1; console.log(self.active) } )
+ },
+ },
+ template: `` })
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// VERY SIMPLE CALENDAR
+//
+const MyCal = Vue.component('mycal', {
+ data: function () {
+ return { today:new Date(), currentMonth:0, currentYear:0, selectYear:'', selectMonth:'',
+ months:["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+ activities:[],
+ by_date: {},
+ editing: -1, } },
+ mounted: function() {
+ var self = this
+ this.currentYear = this.today.getFullYear()
+ this.currentMonth = this.today.getMonth()
+ this.selectYear = this.currentYear
+ this.selectMonth = this.currentMonth
+ basic_get('dir_api.php?a=get/sessions',
+ function(r2) { self.activities = _.map(r2, function(x) {
+ var dd = new Date(x.starttime);
+ var [m,d,y] = [dd.getMonth(), dd.getDate(), dd.getFullYear()] // months start at 0....
+ var d_string = d + "-" + m + "-" + y
+ if (self.by_date[d_string]) { self.by_date[d_string].push(x) }
+ else { self.by_date[d_string] = [x, ] } } )
+ self.$forceUpdate() } )
+ },
+ methods: {
+ thisDay: function(i,j) {
+ var dayOfMonth = ((7*(i-1))+j)-this.firstDay()
+ return dayOfMonth },
+ eventsThisDay: function(i,j) {
+ var dayOfMonth = ((7*(i-1))+j)-this.firstDay()
+ var d_string = dayOfMonth + "-" + this.selectMonth + "-" + this.selectYear
+ var day_text = ''
+ if (this.by_date[d_string]) {
+ evts = _.filter( this.by_date[d_string], function(x) { return x.typeId!="101" } )
+ return evts } return [] },
+ cleanTime: function(e) {
+ var dd = new Date(e.starttime);
+ var [h,m] = [dd.getHours(), dd.getMinutes()]
+ var ampm = 'am'
+ if (h > 12) { h -= 12; ampm = 'pm' }
+ if (m == 0) { m = '' }
+ else { m = ':' + m }
+ return h + m + ampm },
+ daysInMonth: function() {
+ return 32 - new Date(this.selectYear, this.selectMonth, 32).getDate() },
+ firstDay: function() {
+ return (new Date(this.selectYear, this.selectMonth)).getDay() },
+ next: function() {
+ this.selectYear = (this.selectYear === 11) ? this.selectYear + 1 : this.selectYear;
+ this.selectMonth = (this.selectMonth + 1) % 12; },
+ previous: function() {
+ this.selectYear = (this.selectYear === 0) ? this.selectYear - 1 : this.selectYear;
+ this.selectMonth = (this.selectMonth === 0) ? 11 : this.selectMonth - 1; },
+ },
+ computed: {
+ },
+ watch: {
+ },
+ template:`
+
{{months[selectMonth] + " " + selectYear}}
+
+
+
+ Sun Mon Tue Wed Thu Fri Sat
+
+
+
+
+
+ {{ thisDay(i,j) }}
+ {{cleanTime(ev)}} {{ ev.title }}
+
+
+
+
+
` })
+
+
+
+
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// AJAX POST UPDATES TO API
+//
+
+function post_update(table,cols,vals,id=0) {
+ action = "nothing"
+ if (table=="personnel") { action = "update" }
+ if (table=="personnel_ext") { action = "update_xt" }
+ if (table=="conf_users") { action = "update_cf" }
+ if (table=="webpages") { action = "update_web" }
+ if (table=="welcome_letters") { action = "update/letter" } // or insert?
+ var idstr = ""
+ if (id) { idstr = "&id=" + id }
+ fetch('dir_api.php', {
+ method: 'POST',
+ headers: new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' }),
+ body: "a="+action+"&cols="+cols+"&vals="+vals+idstr,
+ }).then(function (response) {
+ if (response.ok) {
+ response.json().then( function(r2) {
+ // display success alert
+ alert_message('Saved.')
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { alert_message("Couldn't save!",pink); console.warn('Something went wrong.', err); });
+}
+
+function generic_fail(err,x="Something went wrong with an ajax fetch") {
+ console.log(x); console.log(err) }
+
+function basic_get( url, after_fxn, fail_fxn=generic_fail ) {
+ fetch(url, { method: 'GET' }).then(function (response) {
+ if (response.ok) {response.json().then( function(r2) { after_fxn(r2) } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) { }).catch(function (err) { fail_fxn(err) } ) }
+
+var evt = {
+ clear_tables: function() {
+ var self = this
+ _.each( this.tables, function(x) { self[x] = [] } )
+ this.data = {}
+ this.target_ids = {} },
+ send_update: function() {
+ var self = this
+ //console.log("Sending update... (not really)")
+ _.each( this.tables, function(x) {
+ if (self[x].length) {
+ var cols = ""
+ var vals = ""
+ _.each(self[x], function(y) {
+ if (cols.length) { cols += "," }
+ if (vals.length) { vals += "," }
+ cols += y
+ if (typeof self.data[y] == "string") {
+ re = /,/g
+ vals += encodeURIComponent(self.data[y].replace(re,'[CMA]') ) }
+ else { vals += self.data[y] }
+ })
+ var edit_other = 0
+ if (self.target_ids[x]) { edit_other = self.target_ids[x] }
+ post_update(x, cols, vals, edit_other)
+ }
+ } ) },
+ data: {},
+ target_ids: {},
+ tables: ['personnel','personnel_ext','webpages','welcome_letters','conf_sessions','conf_hosts',
+ 'pers_departments','pers_committees','pers_titles'],
+}
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// INITIALIZE THE APP
+//
+
+evt.clear_tables()
+MicroEvent.mixin(evt);
+
+
+// welcome letter ?
+/*var doing_welcomeletter = 1
+if (typeof editing_crn === 'undefined' || editing_crn === null) {
+ // variable is undefined or null
+ doing_welcomeletter = 0
+ editing_crn = ''
+ editing_sem = ''
+} */
+
+var app = new Vue({
+ el: '#dir_editor',
+ data: { events: evt,
+ msg: 'hello', active: false,
+ user: {'last_name':'', 'first_name':'', 'department':'', 'extension':'', 'phone_number':'', 'email':'',
+ 'staff_type':'', 'room':'', 'status':'', 'user_id':'', 'password':'', 'time_created':'', 'time_updated':'',
+ 'id':'', ext_id:false, 'web_on':'', use_dir_photo:0, general_photo_release:0, espanol:0, zoom:'', preferred_contact:'',
+ officehours:'', title:'', picture:'', education:'', bio:'', courses:'', personal_page:'', changed:'' },
+ filter: [],
+ roles_menu: [],
+ depts_menu: [],
+ titles_menu: [],
+ waiting_fxns: [],
+ data_loaded: 0,
+ committees_menu: [],
+ menus_fetched: false,
+ },
+ watch: {
+ 'data_loaded': function(newVal,oldVal) {
+ if (newVal > 0) { _.each( this.waiting_fxns, function(fx) { fx() }) }
+ },
+ },
+ methods: {
+ do_after_load: function(do_fxn) { this.waiting_fxns.push(do_fxn) /*....*/ },
+ fetch_menus: function() {
+ if (! this.menus_fetched) {
+ var self = this;
+ fetch('dir_api.php?a=menus', { method: 'GET' }).then(function (response) {
+ // The API call was successful!
+ if (response.ok) {
+ response.json().then( function(r2) {
+ self.depts_menu = r2.departments;
+ self.roles_menu = r2.roles;
+ self.titles_menu = r2.titles;
+ self.committees_menu = r2.committees;
+ self.menus_fetched = true;
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { console.warn('Something went wrong.', err); });
+ }
+ },
+ my_subscribe_calendar: function() { return "webcal://hhh.gavilan.edu/phowell/map/calendar" + this.user.conf_id + ".ics" },
+ clip_copy: function(x) {
+ // see the .htaccess file for the mod_rewrite that makes the ics file work. //
+
+ var data = [new ClipboardItem({ "text/plain": new Blob([this.my_subscribe_calendar()], { type: "text/plain" }) })];
+ navigator.clipboard.write(data).then(function() {
+ console.log("Copied to clipboard successfully!");
+ fadein_message()
+ }, function() {
+ console.error("Unable to write to clipboard. :-(");
+ });
+ },
+ },
+ computed: { },
+ mounted: function() {
+ var self = this;
+ this.fetch_menus()
+ fetch('dir_api.php', { method: 'GET' }).then(function (response) {
+ // The API call was successful!
+ if (response.ok) {
+ response.json().then( function(r2) {
+ var x = self.user.mysessions
+ self.user = r2;
+ self.user.mysessions = x
+ if (self.user.use_dir_photo == "0") { self.user.use_dir_photo = false }
+ if (self.user.espanol == "0") { self.user.espanol = false }
+ if (self.user.general_photo_release == "0") { self.user.general_photo_release = false }
+ self.data_loaded += 1
+ // pause half a second for the children to get populated before registering update events...
+ setTimeout(function() {
+ self.active = true;
+ // fancier text editors...
+ //pell.init( { element: document.getElementById('bio2'), onChange: function(h) { console.log(h) } } )
+ }, 1600);
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { console.warn('Something went wrong.', err); });
+ }
+})
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// SIMPLE EVENTS
+//
+
+var update_fxn = _.debounce( function() {
+ alert_message('saving...','lightgreen')
+ evt.send_update(); evt.clear_tables(); }, 1300 )
+
+evt.bind('changed', function(dat) {
+ if (app.active) {
+ var column = dat[0]
+ var table = dat[1]
+ var value = dat[2]
+ var target = dat[3]
+ console.log(dat)
+ this.data[column] = value
+ if (!this[table].includes(column) ) {this[table].push(column)}
+ if (target) { this.target_ids[table] = target }
+ update_fxn() }
+});
+
+
+
+//
+//
+// MISC
+//
+//
+
+//
+//
+// v-lazy-container="{ selector: 'img' }"
+//
diff --git a/js/dir_app20220118.js b/js/dir_app20220118.js
new file mode 100644
index 0000000..72536cd
--- /dev/null
+++ b/js/dir_app20220118.js
@@ -0,0 +1,1477 @@
+
+
+
+
+
+if (location.protocol !== 'https:') {
+ location.replace(`https:${location.href.substring(location.protocol.length)}`);
+}
+
+
+
+
+// _ _
+// | | | |
+// | |__ ___| |_ __ ___ _ __ ___
+// | '_ \ / _ \ | '_ \ / _ \ '__/ __|
+// | | | | __/ | |_) | __/ | \__ \
+// |_| |_|\___|_| .__/ \___|_| |___/
+// | |
+// |_|
+
+
+
+function init_file_dropzone(parameter_name) {
+ Dropzone.options.myGreatDropzone = { // camelized version of the `id`
+ paramName: parameter_name, // The name that will be used to transfer the file
+ maxFilesize: 6 }; // MB
+}
+// init_file_dropzone("staffpicupload")
+
+
+function parsesqltime(mysqldate) { // 2021-01-29 09:00:00
+ if (! mysqldate) { return 0 }
+ var field = mysqldate.match(/^(\d\d\d\d)\-(\d+)\-(\d+)\s(\d+)\:(\d+)\:(\d+)$/)
+ var mydate = new Date(field[1], field[2] - 1 , field[3], field[4], field[5], field[6])
+ return mydate }
+
+function dj(mysqldate) { return dayjs(parsesqltime(mysqldate)) }
+
+Object.defineProperty(Vue.prototype, '$dj', { value: dj });
+Object.defineProperty(Vue.prototype, '$parsesqltime', { value: parsesqltime });
+
+
+
+
+// ________ __
+// | ____\ \ / /
+// | |__ \ V /
+// | __| > <
+// | | / . \
+// |_| /_/ \_\
+//
+//
+//
+// VISUAL EFFECTS
+//
+
+
+
+function fade_message(theselector='#alert') {
+ var a_dom = document.querySelector(theselector);
+ TinyAnimate.animateCSS(a_dom, 'opacity', '', 1.0, 0.0, 750, 'easeInOutQuart', function() { }); }
+
+function alert_message(msg,color='yellow') {
+ var a = $('#alert')
+ a.text(msg)
+ a.css('background-color',color)
+ var a_dom = document.querySelector('#alert');
+ TinyAnimate.animateCSS(a_dom, 'opacity', '', 0.0, 1.0, 500, 'easeInOutQuart', function() {
+ setTimeout( fade_message, 2500 ) }); }
+
+function fadein_message(theclass='success') {
+ //var a = $('#'+theclass)
+ //a.css('visibility','visible')
+ var a_dom = document.querySelector('.'+theclass);
+ TinyAnimate.animateCSS(a_dom, 'opacity', '', 0.0, 1.0, 500, 'easeInOutQuart', function() {
+ setTimeout( function() { fade_message('.'+theclass) }, 2500 ) }); }
+
+
+// _
+// | |
+// ___ ___ _ __ ___ _ __ ___ _ __ ___ _ __ | |_ ___
+// / __/ _ \| '_ ` _ \| '_ \ / _ \| '_ \ / _ \ '_ \| __/ __|
+// | (_| (_) | | | | | | |_) | (_) | | | | __/ | | | |_\__ \
+// \___\___/|_| |_| |_| .__/ \___/|_| |_|\___|_| |_|\__|___/
+// | |
+// |_|
+
+//
+// FORM COMPONENTS
+//
+
+
+// TODO these should know if they're modifying the current user or someone else.
+
+// A single text style question
+const TQuestion = Vue.component('field', {
+ props: [ 'table', 'qid', 'question', 'answer', 'placeholder', 'targetid', ],
+ data: function () {
+ return { "a":this.answer } },
+ watch: {
+ "answer": function(val,Oldval) { this.a = val },
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) }, },
+ template: `{{ question }}
+
`,
+})
+
+// A single INLINE text style question
+const TIQuestion = Vue.component('ifield', {
+ props: [ 'table', 'qid', 'question', 'answer', 'placeholder', 'myclass', 'targetid', ],
+ data: function () {
+ return { "a":this.answer } },
+ watch: {
+ "answer": function(val,Oldval) { this.a = val },
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) }, },
+ template: ` `,
+})
+
+// A single checkbox
+const Checkbox = Vue.component('checkbox', {
+ props: [ 'table', 'qid', 'question', 'answer', 'targetid', ],
+ data: function () {
+ return { "a":this.answer } },
+ watch: {
+ "answer": function(val,Oldval) { this.a = val },
+ "a": function (val, oldVal) {
+ var newVal = 0
+ if (val==true) { newVal = 1 }
+ this.$root.events.trigger('changed',[this.qid,this.table, newVal, this.targetid]) }, },
+ template: `
+
+
+ {{ question }}
`
+})
+
+// A single long format text question
+const TAQuestion = Vue.component('tfield', {
+ props: [ 'table', 'qid', 'question', 'answer', 'targetid', 'myclass' ],
+ data: function () {
+ return { "a": this.answer } },
+ watch: {
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) },
+ "answer": function (val, oldVal) { this.a = val },
+ },
+ template: `{{ question }}
+
` })
+
+
+
+// long format text WYSIWYG HTML
+const HTAQuestion = Vue.component('htfield', {
+ props: [ 'table', 'qid', 'question', 'answer', 'targetid', 'myclass' ],
+ data: function () { return { "a": this.answer, "p":0, } }, // the pell editor object
+ mounted: function() {
+ var self = this
+ var element = document.getElementById(self.qid)
+ console.log(element)
+ this.p = pell.init( { element: element, onChange: function(h) {
+ self.$root.events.trigger('changed',[self.qid, self.table, h, self.targetid]) } } )
+ self.p.content.innerHTML = self.answer },
+ watch: {
+ "answer": function (val, oldVal) { this.p.content.innerHTML = val }, },
+ template: `` })
+
+// long format text WYSIWYG HTML FORM ALIGNED STYLE
+const HTAQuestionFA = Vue.component('htfield_fa', {
+ props: [ 'table', 'qid', 'question', 'answer', 'targetid', 'myclass' ],
+ data: function () { return { "a": this.answer, "p":0, } }, // the pell editor object
+ mounted: function() {
+ var self = this
+ var element = document.getElementById(self.qid)
+ console.log(element)
+ this.p = pell.init( { element: element, onChange: function(h) {
+ self.$root.events.trigger('changed',[self.qid, self.table, h, self.targetid]) } } )
+ self.p.content.innerHTML = self.answer },
+ watch: {
+ "answer": function (val, oldVal) { this.p.content.innerHTML = val }, },
+ template: `` })
+
+// A single numeric question
+const NQuestioon = Vue.component('n-question', {
+ props: [ 'qq' ],
+ data: function () { return { "answer": "" } },
+ watch: { "qq.answer": function (val, oldVal) {
+ this.$emit('dirty')
+ this.$emit('update', this.qq.qid, val); }, },
+ template: ``
+})
+
+
+
+// The "I Certify" question
+const ICertify = Vue.component('icertify', {
+ props: [ 'c' ],
+ data: function () { return { "checked": this.c } },
+ watch: { checked() { console.log('checked 1'); console.log(this.checked);
+ this.$emit('dirty')
+ this.$parent.docert(this.checked); },
+ },
+ template: `
+ I certify that I have attended this event.
+
` });
+
+
+
+// Select menu
+const SelMenu = Vue.component('selectmenu', {
+ props: [ 'table', 'qid', 'question', 'answer', 'menu', 'labelfield', 'targetid', ],
+ data: function () { return { "a": this.answer } },
+ watch: {
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) },
+ "answer": function (val, oldVal) { this.a = val }, },
+ template: `
+ {{o[labelfield]}}
+ ` })
+
+
+// Select menu FORM ALIGNED STYLE
+const SelMenuFA = Vue.component('selectmenu_fa', {
+ props: [ 'table', 'qid', 'question', 'answer', 'menu', 'labelfield', 'targetid', ],
+ data: function () { return { "a": this.answer } },
+ watch: {
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) },
+ "answer": function (val, oldVal) { this.a = val }, },
+ template: `{{ question }}
+
+ {{o[labelfield]}}
+
` })
+
+
+// A date time picker
+const DTPicker = Vue.component('dtpicker', {
+ props: [ 'table', 'qid', 'question', 'answer', 'targetid', ],
+ methods: { },
+ mounted: function() { },
+ data: function () { return { "a":this.answer } },
+ watch: {
+ "answer": function(val,Oldval) { this.a = val },
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) }, },
+ template: `{{ question }}
+
`,
+})
+
+
+// Accordion style box
+const ExpandyBox = Vue.component('expandybox', {
+ props: [ 'header', 'body', ],
+ methods: {
+ toggle: function() {
+ if (this.state=='close') { this.state='open'; this.symbol='-' }
+ else { this.state='close'; this.symbol='+' }
+ }
+ },
+ mounted: function() { },
+ data: function () { return { "state":'close', "symbol":"+", } },
+ watch: {
+ "answer": function(val,Oldval) { this.a = val },
+ "a": function (val, oldVal) {
+ this.$root.events.trigger('changed',[this.qid,this.table, val, this.targetid]) }, },
+ template: ``,
+})
+
+
+
+// _ __ __ _____ _____ _____
+// | | / _|/ _| | __ \_ _| __ \
+// ___| |_ __ _| |_| |_ | | | || | | |__) |
+// / __| __/ _` | _| _| | | | || | | _ /
+// \__ \ || (_| | | | | | |__| || |_| | \ \
+// |___/\__\__,_|_| |_| |_____/_____|_| \_\
+//
+//
+
+//
+// ONE LINE OF THE STAFF DIR EDITOR listing
+//
+const StaffLine = Vue.component('staff_line', {
+ props: [ 's', 'i', 'dup_class', ],
+ //data: function() { return { } },
+ methods: {
+ nope: function() { return 1; },
+ odd: function(i) { if (i % 2 ==0) { return "even" } return "odd" },
+ bio: function() { return "bio.php?p=" + this.s.id },
+ gtitle: function() { if (this.s.gtitle) {return _.findWhere(this.$root.titles_menu, {id:this.s.gtitle}).name}; return "" },
+ gdept1: function() { if (this.s.dept1) {return _.findWhere(this.$root.depts_menu, {id:this.s.dept1}).name}; return "" },
+ gdept2: function() { if (this.s.dept2) {return _.findWhere(this.$root.depts_menu, {id:this.s.dept2}).name}; return "-" },
+ grole: function() { if (this.s.role) {return _.findWhere(this.$root.roles_menu, {id:this.s.role}).descr}; return "" },
+ swapedit: function() { console.log("edit " + this.s.first_name + " " + this.s.last_name)
+ this.$emit('swapout', this.s.id) }
+ },
+ template: `
+
+
+status: {{ s.status }}
+permissions: {{ grole() }}
+pers id: {{ s.id }}
+ext id: {{ s.ext_id }}
+bio page: {{ s.web_on }}
+Photo - use: {{s.use_dir_photo}} release: {{s.general_photo_release}}
+ path: {{s.dir_photo_path}}
+# Sections: {{s.num_taught}}
+{{ s.sections }}
+
+
+staff: {{ s.staff_type }}
+conf_id: {{ s.conf_id }}
+G00{{s.conf_goo}}
+espanol: {{s.espanol}}
+
+
+
+{{s.first_name}} {{s.last_name}}
+{{gtitle()}}
+{{gdept1()}}
+{{gdept2()}}
+(old dept: {{s.department}} )
+
+
+email: {{s.email}}
+room: {{s.room}}
+phone: {{s.phone_number}}
+Zoom: {{s.zoom}}
+Preferred contact: {{s.preferred_contact}}
+ edit
+
+
+
`
+});
+
+
+
+//
+//
+// STAFF DIR LISTING
+//
+// ONE LINE - BUT EDITING!
+//
+const StaffLineEdit = Vue.component('staff_line_edit', {
+ props: [ 's', 'i' ],
+ //data: function() { return { } },
+ methods: {
+ nope: function() { return 1; },
+ odd: function(i) { if (i % 2 ==0) { return "even" } return "odd" },
+ bio: function() { return "bio.php?p=" + this.s.id },
+ done: function() { this.$emit('done_edit') },
+ gtitle: function() { if (this.s.gtitle) {return _.findWhere(this.$root.titles_menu, {id:this.s.gtitle}).name}; return "" },
+ gdept1: function() { if (this.s.dept1) {return _.findWhere(this.$root.depts_menu, {id:this.s.dept1}).name}; return "" },
+ gdept2: function() { if (this.s.dept2) {return _.findWhere(this.$root.depts_menu, {id:this.s.dept2}).name}; return "-" },
+ grole: function() { if (this.s.role) {return _.findWhere(this.$root.roles_menu, {id:this.s.role}).descr}; return "" },
+ }, //v-lazy-container="{ selector: 'img' }"
+ template: `
+ `
+});
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// STAFF DIR LISTING MAIN CONTAINER
+//
+const DirList = Vue.component('dirlist', {
+ data: function () {
+ return { "personnel":[], sortby:'last_name', search:'', reversed: false, id_list:[], id_dups:[],
+ components: {n:StaffLine, e: StaffLineEdit }, editing: -1, } },
+ mounted: function() {
+ var self = this;
+ this.$root.fetch_menus();
+
+ fetch('dir_api.php?a=list/staffsemester', { method: 'GET' }).then(function (response) {
+ if (response.ok) {
+ response.json().then( function(r2) {
+ self.personnel = r2;
+ _.each( self.personnel, function(x) {
+ if (x.sections==null) { x.num_taught=0 }
+ if (x.dir_photo_path==null) { x.dir_photo_path='images_sm/nobody.jpg' }
+ if (x.use_dir_photo == "0") { x.use_dir_photo = false } else { x.use_dir_photo = true }
+ if (x.espanol == "0" || !x.espanol) { x.espanol = false } else { x.espanol = true }
+ if (x.general_photo_release == "0") { x.general_photo_release = false
+ } else { x.general_photo_release = true }
+ if (self.id_list.includes(x.id)) { self.id_dups.push(x.id) }
+ else { self.id_list.push(x.id) }
+ x.searchable = ''
+ if (x.first_name) { x.searchable += ' ' + x.first_name.toLowerCase() }
+ if (x.last_name) { x.searchable += ' ' + x.last_name.toLowerCase() }
+ if (x.dept1name) { x.searchable += ' ' + x.dept1name.toLowerCase() }
+ if (x.titlename) { x.searchable += ' ' + x.titlename.toLowerCase() }
+ if (x.status == "1" || x.status == null) { x.status = "1"
+ } else { x.status = false; x.searchable += ' inactive' }
+ } ) } ) } else { return Promise.reject(response) }
+ }).then(function (data) { }).catch(function (err) { console.warn('Something went wrong.', err); });
+ },
+ methods: {
+ setsort: function(ss) {
+ if (this.sortby == ss) { this.reversed = ! this.reversed }
+ else {
+ this.reversed = false
+ this.sortby = ss
+ }
+ },
+ swapme: function(x) {
+ this.editing = x
+ },
+ done_edit: function(id) {
+ this.editing = -1
+ },
+ am_editing: function(id) {
+ if (id == this.editing) { return StaffLineEdit }
+ return StaffLine
+ },
+ is_dup_id_class: function(id) { return this.id_dups.includes(id) ? " dup_line" : "" },
+ },
+ computed: {
+ filtered: function() {
+ var ff = this.personnel
+ var self = this
+ if (this.search) {
+ var ss = self.search.toLowerCase()
+ ff = ff.filter(function(x) { return x.searchable.includes(ss) }) }
+
+ ff = _.sortBy(ff, function(x) {
+ if (x[self.sortby]) {
+ var s = x[self.sortby];
+ return s.trim().toLowerCase() }
+ return 'zzzzzzzzzz' })
+ if (this.reversed) {
+ ff.reverse()
+ }
+ return ff
+ }
+ },
+ watch: {
+ },
+
+ template: `` })
+
+
+
+// https://www.daterangepicker.com/
+// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime-local
+
+
+
+
+
+// __ _ _ _ _ _ _
+// / _| | | | (_) (_) | (_)
+// | |_| | _____ __ __ _ ___| |_ ___ ___| |_ _ ___ ___
+// | _| |/ _ \ \/ / / _` |/ __| __| \ \ / / | __| |/ _ \/ __|
+// | | | | __/> < | (_| | (__| |_| |\ V /| | |_| | __/\__ \
+// |_| |_|\___/_/\_\ \__,_|\___|\__|_| \_/ |_|\__|_|\___||___/
+//
+//
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// EDIT / CREATE activity or event
+//
+const ActivityEditor = Vue.component('activityedit', {
+ props: [ 'which', ],
+ data: function () {
+ return { creating:0,
+ everyname:[], everyone:[], hosts_by_sesid:{}, this_hosts:[], host_search:[], host_search_str:'',
+ activities:[], this_activity:{}, editing: -1, active:-1, } },
+ mounted: function() {
+ this.fetch_mypeople()
+ this.$root.fetch_menus()
+ if (this.which==0) {
+ this.creating = 1
+ this.$root.creating = 1
+ this.this_activity = {"title":"","desc":"","length":"1","starttime":"",
+ "track":"","location":"","gets_survey":"1","category":"1",
+ "parent":"","recording":"","instructions":"","image_url":"",
+ "is_flex_approved":"1","typeId":"101"}
+ } else { this.fetch_myevents() } },
+ methods: {
+ set_id: function(new_id) { this.this_activity.id = new_id; this.creating=0; this.$root.creating=0 },
+ month_year: function(d) { var b = this.$root.$dj(d).format('MMM D YYYY'); return b },
+ setsort: function(ss) {
+ if (this.sortby == ss) { this.reversed = ! this.reversed }
+ else { this.reversed = false; this.sortby = ss } },
+ swapme: function(x) { this.editing = x },
+ done_edit: function(id) { this.editing = -1 },
+ am_editing: function(id) { return 0 },
+ remove: function(hostid) {
+ var self = this
+ basic_get('dir_api.php?a=remove/host/' + this.which + '/' + hostid,
+ function(r2) {
+ self.this_hosts = _.reject(self.this_hosts, function(x) { return x.hostid == hostid} )
+ alert_message('Saved') } )
+ },
+ add: function(hostid) {
+ var self = this
+ basic_get('dir_api.php?a=add/host/' + this.which + '/' + hostid,
+ function(r2) {
+ self.this_hosts.push( _.findWhere(self.everyone, {id:hostid} ) )
+ alert_message('Saved') } )
+ },
+ hostlookup: function() {
+ var self = this
+ if (this.host_search_str=='') { this.host_search=[] }
+ else { this.host_search_str = this.host_search_str.toLowerCase()
+ this.host_search = _.first(_.filter(self.everyone, function(x) { return x.name.toLowerCase().search( self.host_search_str) != -1 }),7) } },
+ save_new_event: function() {
+ this.$root.events.trigger('create_new_session',this.this_activity)
+ },
+ fetch_mypeople: function() {
+ var self = this;
+ basic_get('dir_api.php?a=get/names',
+ function(r2) {
+ self.everyone = r2.users
+ _.each( self.everyone, function(x) {
+ x.hostid = x.id } )
+ self.everyname = _.pluck(r2.users,'name') } ) },
+ fetch_myevents: function() {
+ var self = this;
+ basic_get('dir_api.php?a=get/sessions',
+ function(r2) {
+ self.activities = _.indexBy(r2,function(x) { return x.id } ); self.$forceUpdate()
+ self.active += 1;
+ _.each( self.activities, function(x) {
+ x.searchable = x.title.toLowerCase() + ' ' + x.desc.toLowerCase() } )
+ self.this_activity = self.activities[ self.which ]
+ self.this_activity.starttime = self.this_activity.starttime.replace(' ','T')} )
+ basic_get('dir_api.php?a=get/hosts',
+ function(r2) {
+ self.hosts_by_sesid = _.groupBy(r2,function(x) { return x.id } )
+ self.this_hosts = self.hosts_by_sesid[ self.which ]
+ } )
+ },
+ },
+ template: `` })
+
+//
+//
+//
+//
+//
+//
+// ACTIVITIES LIST MAIN CONTAINER
+// ------------------------------
+//
+//
+//
+const ActivityList = Vue.component('activitylist', {
+ props: [ 'itineraryview','focus' ],
+ data: function () {
+ return { activities:[], mysessions:[], search:'', sortby:'starttime', reversed:false, my_ses_ids:[], my_host_ids:[],
+ show_filters: 'all', expanded: 1, editing: -1, active:-1, hosts:{},
+ filters: {'sp22':['2022-01-26','2022-01-30'], 'all':['2022-01-01','2022-11-30'] },
+ day_titles: {'Jan 27 2022':" - Optional Flex Day", 'Jan 28 2022':' - Mandatory Flex Day'} } },
+ mounted: function() {
+ this.$root.fetch_menus();
+ this.fetch_myevents()
+ },
+ methods: {
+ get_day_title: function(day) { if (day in this.day_titles) { return this.day_titles[day] } return '' },
+ month_year: function(d) { var b = this.$root.$dj(d).format('MMM D YYYY'); return b },
+ setsort: function(ss) {
+ if (this.sortby == ss) { this.reversed = ! this.reversed }
+ else { this.reversed = false; this.sortby = ss } },
+ swapme: function(x) { this.editing = x },
+ done_edit: function(id) { this.editing = -1 },
+ am_editing: function(id) { return 0 },
+ fetch_myevents: function() {
+ var self = this;
+ basic_get('dir_api.php?a=get/mysessions',
+ function(r2) {
+ self.mysessions = _.sortBy(r2,function(x) { return x.starttime || 0} );
+ self.my_ses_ids = _.pluck(r2, 'id')
+ self.$forceUpdate();
+ self.active += 1;
+ } )
+ basic_get('dir_api.php?a=get/sessions',
+ function(r2) {
+ self.activities = _.sortBy(r2,function(x) { return x.starttime } ); self.$forceUpdate()
+ self.active += 1;
+ _.each( self.activities, function(x) {
+ var field = x.starttime.match(/^(\d\d\d\d)\-(\d+)\-(\d+)\s(\d+)\:(\d+)\:(\d+)$/)
+ var mydate = new Date(field[1], field[2] - 1 , field[3], field[4], field[5], field[6])
+ x.dj = dayjs(mydate)
+ x.searchable = x.title.toLowerCase() + ' ' + x.desc.toLowerCase() } )
+ self.$forceUpdate();
+ self.active += 1; } )
+ basic_get('dir_api.php?a=get/allhosts',
+ function(r2) {
+ self.hosts = r2
+ setTimeout(function () {
+ self.my_host_ids = r2[ self.$root.user.conf_id ]
+ if (! self.my_host_ids) { self.my_host_ids = [] }
+ }, 750);
+ self.active += 1;
+ } )
+ },
+ joinme: function(id) {
+ var self = this
+ basic_get('dir_api.php?a=signup/' + id,
+ function(r2) {
+ self.mysessions.push(_.findWhere(self.activities, {'id':id}))
+ self.my_ses_ids.push(id)
+ alert_message("Added activity") })
+ },
+ dumpme: function(id) {
+ var self = this
+ basic_get('dir_api.php?a=signdown/' + id,
+ function(r2) {
+ self.mysessions = _.without( self.mysessions, _.findWhere(self.activities, {'id':id}))
+ self.my_ses_ids = _.without( self.my_ses_ids, id)
+ self.$forceUpdate()
+ alert_message("Removed activity") })
+ },
+ filtered: function(ff) { if (this.active<1) { return [] }
+ var self = this
+ if (this.search) {
+ var ss = self.search.toLowerCase()
+ console.log('one')
+ ff = ff.filter(function(x) { return ('searchable' in x ? x.searchable.includes(ss) : 0) }) }
+ if (this.focus) {
+ var start = dayjs(this.filters.sp22[0])
+ var end = dayjs(this.filters.sp22[1])
+ ff = ff.filter( function(item,index) {
+ this_time = dayjs(item.starttime)
+ return this_time.isBefore(end) && start.isBefore(this_time) } )
+ }
+ ff = _.sortBy(ff, function(x) {
+ if (x[self.sortby]) { var s = x[self.sortby]; return s.trim().toLowerCase() }
+ return '' })
+ if (this.reversed) { ff.reverse() }
+ return ff }, },
+ computed: {
+ activities_filtered: function() { var a = this.filtered(this.activities); return a; },
+ mysessions_filtered: function() { return this.filtered(this.mysessions) },
+
+ activities_g_filtered: function() { if (this.active<1) { return {} }
+ var self=this;
+ return _.groupBy(self.activities_filtered, function(x) { return self.month_year(x.starttime) } ); },
+ mysessions_g_filtered: function() { if (this.active<1) { return {} }
+ var self=this; return _.groupBy(self.mysessions_filtered, function(x) { return self.month_year(x.starttime) } ); }, },
+ watch: { },
+ template: `
+
+
+
{{mmyy}} {{get_day_title(mmyy)}}
+
+
+
` })
+
+
+/*
+
+ - show upcoming, past, dropdown for category
+
+ - show signup status, signup/cancel button
+
+ - navigation: check permission, show edit / new button
+
+ - page: create / edit activity.
+
+*/
+
+
+
+
+
+const ShowSurveys = Vue.component('show-survey', {
+ name: 'ShowSurveys',
+ //components: { 'essay-question': EssayQuestion, 'number-question': NumberQuestion },
+ props: ['answer', ],
+ methods: {
+ logger: function() { console.log('logger'); console.log(this); console.log( this.answer ); return ''; },
+ ses_name: function() {
+ if (this.answer) {
+ return this.answer[0][0].s_title }
+ return '' }
+ },
+ template: `
+ {{ logger() }}
+
+ {{ q[0]['question'] }}
+
+
+
+
`
+});
+
+
+const Survey = Vue.component('surveydisplay', {
+ props: [ 'answers' ],
+ data () {
+ return {
+ qa_all: [ ],
+ sesh: {},
+ questions: [],
+ one: {},
+ qdata: [],
+ answer: ""
+ }
+ },
+ created: function() {
+ var self = this
+ self.questions = _.where(this.$root.$data.myquestions,
+ {'ses_id':self.$route.params.take_ses_id})
+ self.$forceUpdate()
+ /*this.$axios.get(this.$server + this.$api + '?a=get/questions', {withCredentials: true}).then( function(resp2) {
+ self.qdata = resp2.data
+ setTimeout(self.continueExecution, 1000) //wait 1 seconds before continuing
+ } )*/
+
+ this.$axios.get(this.$server + this.$api + '?a=get/answers/all', {withCredentials: true}).then( function(resp2) {
+ } ) },
+ methods: {
+ continueExecution: function() {self.questions = _.where( this.qdata, {'ses_id': this.$route.params.take_ses_id } )},
+ one_session: function() {
+ if (this.$route.params.take_ses_id) {
+ var self = this
+ var my_id = self.$route.params.take_ses_id
+ console.log("My id is: " + my_id)
+ var my_ses = _.find(this.$root.$data.activities, function(x) { return x.id==my_id } )
+ /*console.log('The session: ')
+ console.log(my_ses)*/
+ return my_ses }
+ console.log('no session found ')
+ return {'title':''}
+ },
+ answers: function() {
+ var a = this.sesh[parseInt( this.$route.params.ses_id)]
+ //console.log(a)
+ if (a) { return a }
+ return 0
+ },
+ requested_session: function() {
+ var self = this
+ return _.find(this.$root.$data.activities, function(x) { console.log(x.id); console.log(self.$route.params.ses_id); return x.id == self.$route.params.ses_id } )
+ /*
+ a = _.find(this.$root.$data.activities, function(x) { console.log(x.id); console.log(self.$route.params.ses_id); return x.id == self.$route.params.ses_id } )
+ console.log(a)
+ return a */
+ }
+ },
+ template: `
+ {{ q[0]['question'] }}
+
+
+
+
+
+
+
+
+
+
+
+`
+})
+
+
+
+
+
+
+
+
+
+//
+//
+//
+//
+//
+//
+// ACTIVITIES LIST - SIGNUPS & SURVEYS
+// -----------------------------------
+//
+//
+//
+const ActivityReport = Vue.component('activityreport', {
+ props: [ 'which' ],
+ data: function () {
+ return { activities:[],hosts:[], hosts_by_sesid:[], everyone:[], questions:[], answers:{}, answers2:{}, rosters:[] } },
+ mounted: function() {
+ var self = this
+ basic_get('dir_api.php?a=get/sessions', function(r2) {
+ self.activities = _.sortBy(r2,function(x) { return x.starttime } ); self.$forceUpdate()
+ self.active += 1;
+ _.each( self.activities, function(x) {
+ var field = x.starttime.match(/^(\d\d\d\d)\-(\d+)\-(\d+)\s(\d+)\:(\d+)\:(\d+)$/)
+ var mydate = new Date(field[1], field[2] - 1 , field[3], field[4], field[5], field[6])
+ x.dj = dayjs(mydate)
+ x.searchable = x.title.toLowerCase() + ' ' + x.desc.toLowerCase() } )
+ self.$forceUpdate();
+ self.active += 1; } )
+ basic_get('dir_api.php?a=get/hosts', function(r2) {
+ self.hosts_by_sesid = _.groupBy(r2,function(x) { return x.id } )
+ } )
+ basic_get('dir_api.php?a=get/rosters', function(r2) {
+ self.rosters = _.groupBy(r2,function(x) { return x.sesid } )
+ } )
+ basic_get('dir_api.php?a=get/allhosts', function(r2) {
+ self.hosts = r2
+ setTimeout(function () { self.hosts = r2; self.$forceUpdate() }, 750);
+ self.active += 1;
+ } )
+ basic_get('dir_api.php?a=get/names', function(r2) {
+ self.everyone = []
+ _.each( r2.users, function(x) { self.everyone[x.id] = x.name } ) } )
+ basic_get('dir_api.php?a=get/questions', function(r2) {
+ self.questions = r2 })
+ basic_get('dir_api.php?a=get/answers/all', function(r2) {
+ var organized = _.groupBy(r2, function(x) { return x.ses_id; } )
+ // TODO are answers and answers2 the same?
+ _.each( organized, function(val,key,lis) { self.answers[key] = _.groupBy( val, function(y) { return y.q_id; }); } )
+ _.each( self.answers, function(val,key,lis) { self.answers2[key] = _.sortBy( val, "q_id" ) } )
+ self.$forceUpdate()
+ } )
+ },
+ methods: {
+ hoststr: function(id) {
+ var self = this
+ return _.reduce( self.hosts_by_sesid[id], function(mem,val) { if (val.name) { return mem + val.name + ", " } return mem }, '')
+ },
+ userstr: function(id) { return _.pluck(this.rosters[id], "name").join(', ') },
+ surveystr: function(id) {
+ var self = this
+ var answers = _.find(this.activities, function(x) { console.log(x.id); return x.id == id } )
+ console.log('found these answers')
+ console.log(answers)
+ return "Surveys"
+ return _.reduce( self.hosts_by_sesid[id], function(mem,val) { if (val.name) { return mem + val.name + ", " } return mem }, '')
+ },
+ },
+ computed: {
+ },
+ watch: { },
+ template: `` })
+
+
+
+// _ _
+// | | | |
+// ___ __ _| | ___ _ __ __| | __ _ _ __
+// / __/ _` | |/ _ \ '_ \ / _` |/ _` | '__|
+// | (_| (_| | | __/ | | | (_| | (_| | |
+// \___\__,_|_|\___|_| |_|\__,_|\__,_|_|
+//
+//
+
+
+// VERY SIMPLE CALENDAR
+//
+const MyCal = Vue.component('mycal', {
+ data: function () {
+ return { today:new Date(), currentMonth:0, currentYear:0, selectYear:'', selectMonth:'',
+ months:["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+ activities:[],
+ by_date: {},
+ editing: -1, } },
+ mounted: function() {
+ var self = this
+ this.currentYear = this.today.getFullYear()
+ this.currentMonth = this.today.getMonth()
+ this.selectYear = this.currentYear
+ this.selectMonth = this.currentMonth
+ basic_get('dir_api.php?a=get/sessions',
+ function(r2) { self.activities = _.map(r2, function(x) {
+ var dd = new Date(x.starttime);
+ var [m,d,y] = [dd.getMonth(), dd.getDate(), dd.getFullYear()] // months start at 0....
+ var d_string = d + "-" + m + "-" + y
+ if (self.by_date[d_string]) { self.by_date[d_string].push(x) }
+ else { self.by_date[d_string] = [x, ] } } )
+ self.$forceUpdate() } )
+ },
+ methods: {
+ thisDay: function(i,j) {
+ var dayOfMonth = ((7*(i-1))+j)-this.firstDay()
+ return dayOfMonth },
+ eventsThisDay: function(i,j) {
+ var dayOfMonth = ((7*(i-1))+j)-this.firstDay()
+ var d_string = dayOfMonth + "-" + this.selectMonth + "-" + this.selectYear
+ var day_text = ''
+ if (this.by_date[d_string]) {
+ evts = _.filter( this.by_date[d_string], function(x) { return x.typeId!="101" } )
+ return evts } return [] },
+ cleanTime: function(e) {
+ var dd = new Date(e.starttime);
+ var [h,m] = [dd.getHours(), dd.getMinutes()]
+ var ampm = 'am'
+ if (h > 12) { h -= 12; ampm = 'pm' }
+ if (m == 0) { m = '' }
+ else { m = ':' + m }
+ return h + m + ampm },
+ daysInMonth: function() {
+ return 32 - new Date(this.selectYear, this.selectMonth, 32).getDate() },
+ firstDay: function() {
+ return (new Date(this.selectYear, this.selectMonth)).getDay() },
+ next: function() {
+ this.selectYear = (this.selectYear === 11) ? this.selectYear + 1 : this.selectYear;
+ this.selectMonth = (this.selectMonth + 1) % 12; },
+ previous: function() {
+ this.selectYear = (this.selectYear === 0) ? this.selectYear - 1 : this.selectYear;
+ this.selectMonth = (this.selectMonth === 0) ? 11 : this.selectMonth - 1; },
+ },
+ computed: {
+ },
+ watch: {
+ },
+ template:`
+
{{months[selectMonth] + " " + selectYear}}
+
+
+
+ Sun Mon Tue Wed Thu Fri Sat
+
+
+
+
+
+ {{ thisDay(i,j) }}
+ {{cleanTime(ev)}} {{ ev.title }}
+
+
+
+
+
` })
+
+
+
+
+
+
+// _ _ _ _ _
+// | | | | | | | | | |
+// __ _____| | ___ ___ _ __ ___ ___ | | ___| |_| |_ ___ _ __ | |
+// \ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \ | |/ _ \ __| __/ _ \ '__| | |
+// \ V V / __/ | (_| (_) | | | | | | __/ | | __/ |_| || __/ | |_|
+// \_/\_/ \___|_|\___\___/|_| |_| |_|\___| |_|\___|\__|\__\___|_| (_)
+//
+//
+
+
+
+
+
+
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+// // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // // //
+//
+// WELCOME LETTER main component
+//
+const WelcomeLetter = Vue.component('welcomeletter', {
+ props: [ 'mysem','mycrn', 'teacher_ext_id', ],
+ data: function () {
+ return { courses_by_semester:[], wl_sem:'', wl_crn:'', section_wl:{}, sortby:'code', reversed:false, active:-1, } },
+ watch: {
+ "teacher_ext_id": function (val, oldVal) { console.log('tch ext id changed'); this.fetch_sections() },
+ },
+ mounted: function() {
+ var self = this
+ if (this.mysem && this.mycrn) { this.fetch_wletters(this.mysem, this.mycrn) }
+ else { this.$root.do_after_load( self.fetch_sections) }
+ },
+ methods: {
+ swap_section: function(section_obj) { this.fetch_wletters(section_obj.sem,section_obj.crn) },
+ show_list: function() { this.section_wl = {} },
+ fetch_wletters: function(ss,cc) {
+ var self = this;
+ fetch('dir_api.php?a=get/section/' + ss + '/' + cc,
+ { method: 'GET' }).then(function (response) {
+ // The API call was successful!
+ if (response.ok) {
+ response.json().then( function(r2) {
+ self.section_wl = r2;
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { console.warn('Something went wrong.', err); });
+ },
+ fetch_sections: function() {
+ var self = this;
+ basic_get('dir_api.php?a=get/sections/' + this.$root.user.ext_id,
+ function(r2) { self.courses_by_semester = _.groupBy(r2,function(x) { return x.sem || 0} ); self.$forceUpdate(); self.active += 1; console.log(self.active) } )
+ },
+ },
+ template: `` })
+
+
+
+
+// _ _ _
+// | | | | | |
+// _____ _____ _ __ | |_ ___ | |__ ___| |_ __ ___ _ __
+// / _ \ \ / / _ \ '_ \| __/ __| | '_ \ / _ \ | '_ \ / _ \ '__|
+// | __/\ V / __/ | | | |_\__ \ | | | | __/ | |_) | __/ |
+// \___| \_/ \___|_| |_|\__|___/ |_| |_|\___|_| .__/ \___|_|
+// | |
+// |_| //
+// AJAX POST UPDATES TO API
+//
+
+function post_update(table,cols,vals,id=0) {
+ action = "nothing"
+ if (table=="personnel") { action = "update" }
+ if (table=="personnel_ext") { action = "update_xt" }
+ if (table=="conf_users") { action = "update_cf" }
+ if (table=="conf_sessions") { action = "update/activity" }
+ if (table=="webpages") { action = "update_web" }
+ if (table=="welcome_letters") { action = "update/letter" } // or insert?
+ var idstr = ""
+ if (id) { idstr = "&id=" + id }
+ fetch('dir_api.php', {
+ method: 'POST',
+ headers: new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' }),
+ body: "a="+action+"&cols="+cols+"&vals="+vals+idstr,
+ }).then(function (response) {
+ if (response.ok) {
+ response.json().then( function(r2) {
+ // display success alert
+ alert_message('Saved.')
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { alert_message("Couldn't save!",pink); console.warn('Something went wrong.', err); });
+}
+
+function generic_fail(err,x="Something went wrong with an ajax fetch") {
+ console.log(x); console.log(err) }
+
+function basic_get( url, after_fxn, fail_fxn=generic_fail ) {
+ fetch(url, { method: 'GET' }).then(function (response) {
+ if (response.ok) {response.json().then( function(r2) { after_fxn(r2) } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) { }).catch(function (err) { fail_fxn(err) } ) }
+
+var evt = {
+ clear_tables: function() {
+ var self = this
+ _.each( this.tables, function(x) { self[x] = [] } )
+ this.data = {}
+ this.target_ids = {} },
+ send_update: function() {
+ var self = this
+ _.each( this.tables, function(x) {
+ if (self[x].length) {
+ var cols = ""
+ var vals = ""
+ _.each(self[x], function(y) {
+ if (cols.length) { cols += "," }
+ if (vals.length) { vals += "," }
+ cols += y
+ if (typeof self.data[y] == "string") {
+ re = /,/g
+ vals += encodeURIComponent(self.data[y].replace(re,'[CMA]') ) }
+ else { vals += self.data[y] }
+ })
+ var edit_other = 0
+ if (self.target_ids[x]) { edit_other = self.target_ids[x] }
+ post_update(x, cols, vals, edit_other)
+ }
+ } ) },
+ data: {},
+ target_ids: {},
+ tables: ['personnel','personnel_ext','webpages','welcome_letters','conf_sessions','conf_hosts',
+ 'pers_departments','pers_committees','pers_titles'],
+}
+
+
+
+evt.clear_tables()
+MicroEvent.mixin(evt)
+
+
+
+
+
+
+
+// _ _____ _____
+// (_) /\ | __ \| __ \
+// _ __ ___ __ _ _ _ __ / \ | |__) | |__) |
+// | '_ ` _ \ / _` | | '_ \ / /\ \ | ___/| ___/
+// | | | | | | (_| | | | | | / ____ \| | | |
+// |_| |_| |_|\__,_|_|_| |_| /_/ \_\_| |_|
+//
+//
+var app = new Vue({
+ el: '#dir_editor',
+ data: { events: evt,
+ msg: 'hello', active: false, creating:0,
+ user: {'last_name':'', 'first_name':'', 'department':'', 'extension':'', 'phone_number':'', 'email':'',
+ 'staff_type':'', 'room':'', 'status':'', 'user_id':'', 'password':'', 'time_created':'', 'time_updated':'',
+ 'id':'', ext_id:false, 'web_on':'', use_dir_photo:0, general_photo_release:0, espanol:0, zoom:'', preferred_contact:'',
+ officehours:'', title:'', picture:'', education:'', bio:'', courses:'', personal_page:'', changed:'' },
+ filter: [],
+ roles_menu: [],
+ depts_menu: [],
+ titles_menu: [],
+ sessiontypes_menu: [],
+ parents_menu: [],
+ waiting_fxns: [],
+ data_loaded: 0,
+ committees_menu: [],
+ menus_fetched: false,
+ },
+ watch: {
+ 'data_loaded': function(newVal,oldVal) {
+ if (newVal > 0) { _.each( this.waiting_fxns, function(fx) { fx() }) } }, },
+ methods: {
+ do_after_load: function(do_fxn) { this.waiting_fxns.push(do_fxn) /*....*/ },
+ fetch_menus: function() {
+ if (! this.menus_fetched) {
+ var self = this;
+ fetch('dir_api.php?a=menus', { method: 'GET' }).then(function (response) {
+ // The API call was successful!
+ if (response.ok) {
+ response.json().then( function(r2) {
+ self.depts_menu = r2.departments;
+ self.roles_menu = r2.roles;
+ self.titles_menu = r2.titles;
+ self.committees_menu = r2.committees;
+ self.sessiontypes_menu = r2.sessiontypes;
+ self.parents_menu = r2.parents;
+ self.menus_fetched = true;
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { console.warn('Something went wrong.', err); });
+ }
+ },
+ my_subscribe_calendar: function() { return "webcal://hhh.gavilan.edu/phowell/map/calendar" + this.user.conf_id + ".ics" },
+ clip_copy: function(x) {
+ // see the .htaccess file for the mod_rewrite that makes the ics file work. //
+
+ var data = [new ClipboardItem({ "text/plain": new Blob([this.my_subscribe_calendar()], { type: "text/plain" }) })];
+ navigator.clipboard.write(data).then(function() {
+ console.log("Copied to clipboard successfully!");
+ fadein_message()
+ }, function() { console.error("Unable to write to clipboard. :-("); }) }, },
+ computed: { },
+ mounted: function() {
+ var self = this;
+ this.fetch_menus()
+ fetch('dir_api.php', { method: 'GET' }).then(function (response) {
+ // The API call was successful!
+ if (response.ok) {
+ response.json().then( function(r2) {
+ var x = self.user.mysessions
+ self.user = r2;
+ self.user.mysessions = x
+ if (self.user.use_dir_photo == "0") { self.user.use_dir_photo = false }
+ if (self.user.espanol == "0") { self.user.espanol = false }
+ if (self.user.general_photo_release == "0") { self.user.general_photo_release = false }
+ self.data_loaded += 1
+ // pause half a second for the children to get populated before registering update events...
+ setTimeout(function() {
+ self.active = true;
+ // fancier text editors...
+ //pell.init( { element: document.getElementById('bio2'), onChange: function(h) { console.log(h) } } )
+ }, 1600);
+ } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { console.warn('Something went wrong.', err); }) } })
+
+
+
+
+// _
+// | |
+// _____ _____ _ __ | |_ ___
+// / _ \ \ / / _ \ '_ \| __/ __|
+// | __/\ V / __/ | | | |_\__ \
+// \___| \_/ \___|_| |_|\__|___/
+//
+//
+
+
+//
+// SIMPLE EVENTS
+//
+
+var update_fxn = _.debounce( function() {
+ alert_message('saving...','lightgreen')
+ evt.send_update(); evt.clear_tables(); }, 1300 )
+
+evt.bind('changed', function(dat) {
+ if (app.active) {
+ var column = dat[0]
+ var table = dat[1]
+ var value = dat[2]
+ var target = dat[3]
+ this.data[column] = value
+ if (!this[table].includes(column) ) {this[table].push(column)}
+ if (target) { this.target_ids[table] = target } }
+ if (app.active && !app.creating) { update_fxn() }
+});
+
+evt.bind('create_new_session', function(dat) {
+ var default_activity = {"title":"","desc":"","length":"1","starttime":"","track":"","location":"","gets_survey":"1","category":"1",
+ "parent":"","recording":"","instructions":"","image_url":"","is_flex_approved":"1","typeId":"101"}
+ var new_activity = _.extend(default_activity, evt.data)
+
+ if ('typeId' in new_activity) { new_activity.type = new_activity.typeId; delete new_activity.typeId; }
+ let formData = new FormData();
+ _.each( Object.keys(new_activity), function(x) { console.log(x); formData.append(x, new_activity[x]) } )
+
+ fetch('dir_api.php?a=set/newsession', {
+ method: 'POST',
+ body: formData, }).then(function (response) {
+ if (response.ok) {
+ response.json().then( function(r2) {
+ alert_message('Saved new activity.')
+ app.$children[0].set_id(r2.new_id) } )
+ } else { return Promise.reject(response) }
+ }).then(function (data) {
+ }).catch(function (err) { alert_message("Couldn't create the activity!",pink); console.warn('Something went wrong.', err); }) })
+
+
+
+
+//
+//
+// MISC
+//
+//
+
+//
+//
+// v-lazy-container="{ selector: 'img' }"
+//
diff --git a/js/intranet_libs.js b/js/intranet_libs.js
new file mode 100644
index 0000000..f77f31d
--- /dev/null
+++ b/js/intranet_libs.js
@@ -0,0 +1,831 @@
+
+// Underscore.js 1.8.3
+// http://underscorejs.org
+// (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+// Underscore may be freely distributed under the MIT license.
+(function(){function n(n){function t(t,r,e,u,i,o){for(;i>=0&&o>i;i+=n){var a=u?u[i]:i;e=r(e,t[a],a,t)}return e}return function(r,e,u,i){e=b(e,i,4);var o=!k(r)&&m.keys(r),a=(o||r).length,c=n>0?0:a-1;return arguments.length<3&&(u=r[o?o[c]:c],c+=n),t(r,e,u,o,c,a)}}function t(n){return function(t,r,e){r=x(r,e);for(var u=O(t),i=n>0?0:u-1;i>=0&&u>i;i+=n)if(r(t[i],i,t))return i;return-1}}function r(n,t,r){return function(e,u,i){var o=0,a=O(e);if("number"==typeof i)n>0?o=i>=0?i:Math.max(i+a,o):a=i>=0?Math.min(i+1,a):i+a+1;else if(r&&i&&a)return i=r(e,u),e[i]===u?i:-1;if(u!==u)return i=t(l.call(e,o,a),m.isNaN),i>=0?i+o:-1;for(i=n>0?o:a-1;i>=0&&a>i;i+=n)if(e[i]===u)return i;return-1}}function e(n,t){var r=I.length,e=n.constructor,u=m.isFunction(e)&&e.prototype||a,i="constructor";for(m.has(n,i)&&!m.contains(t,i)&&t.push(i);r--;)i=I[r],i in n&&n[i]!==u[i]&&!m.contains(t,i)&&t.push(i)}var u=this,i=u._,o=Array.prototype,a=Object.prototype,c=Function.prototype,f=o.push,l=o.slice,s=a.toString,p=a.hasOwnProperty,h=Array.isArray,v=Object.keys,g=c.bind,y=Object.create,d=function(){},m=function(n){return n instanceof m?n:this instanceof m?void(this._wrapped=n):new m(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=m),exports._=m):u._=m,m.VERSION="1.8.3";var b=function(n,t,r){if(t===void 0)return n;switch(null==r?3:r){case 1:return function(r){return n.call(t,r)};case 2:return function(r,e){return n.call(t,r,e)};case 3:return function(r,e,u){return n.call(t,r,e,u)};case 4:return function(r,e,u,i){return n.call(t,r,e,u,i)}}return function(){return n.apply(t,arguments)}},x=function(n,t,r){return null==n?m.identity:m.isFunction(n)?b(n,t,r):m.isObject(n)?m.matcher(n):m.property(n)};m.iteratee=function(n,t){return x(n,t,1/0)};var _=function(n,t){return function(r){var e=arguments.length;if(2>e||null==r)return r;for(var u=1;e>u;u++)for(var i=arguments[u],o=n(i),a=o.length,c=0;a>c;c++){var f=o[c];t&&r[f]!==void 0||(r[f]=i[f])}return r}},j=function(n){if(!m.isObject(n))return{};if(y)return y(n);d.prototype=n;var t=new d;return d.prototype=null,t},w=function(n){return function(t){return null==t?void 0:t[n]}},A=Math.pow(2,53)-1,O=w("length"),k=function(n){var t=O(n);return"number"==typeof t&&t>=0&&A>=t};m.each=m.forEach=function(n,t,r){t=b(t,r);var e,u;if(k(n))for(e=0,u=n.length;u>e;e++)t(n[e],e,n);else{var i=m.keys(n);for(e=0,u=i.length;u>e;e++)t(n[i[e]],i[e],n)}return n},m.map=m.collect=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=Array(u),o=0;u>o;o++){var a=e?e[o]:o;i[o]=t(n[a],a,n)}return i},m.reduce=m.foldl=m.inject=n(1),m.reduceRight=m.foldr=n(-1),m.find=m.detect=function(n,t,r){var e;return e=k(n)?m.findIndex(n,t,r):m.findKey(n,t,r),e!==void 0&&e!==-1?n[e]:void 0},m.filter=m.select=function(n,t,r){var e=[];return t=x(t,r),m.each(n,function(n,r,u){t(n,r,u)&&e.push(n)}),e},m.reject=function(n,t,r){return m.filter(n,m.negate(x(t)),r)},m.every=m.all=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=0;u>i;i++){var o=e?e[i]:i;if(!t(n[o],o,n))return!1}return!0},m.some=m.any=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=0;u>i;i++){var o=e?e[i]:i;if(t(n[o],o,n))return!0}return!1},m.contains=m.includes=m.include=function(n,t,r,e){return k(n)||(n=m.values(n)),("number"!=typeof r||e)&&(r=0),m.indexOf(n,t,r)>=0},m.invoke=function(n,t){var r=l.call(arguments,2),e=m.isFunction(t);return m.map(n,function(n){var u=e?t:n[t];return null==u?u:u.apply(n,r)})},m.pluck=function(n,t){return m.map(n,m.property(t))},m.where=function(n,t){return m.filter(n,m.matcher(t))},m.findWhere=function(n,t){return m.find(n,m.matcher(t))},m.max=function(n,t,r){var e,u,i=-1/0,o=-1/0;if(null==t&&null!=n){n=k(n)?n:m.values(n);for(var a=0,c=n.length;c>a;a++)e=n[a],e>i&&(i=e)}else t=x(t,r),m.each(n,function(n,r,e){u=t(n,r,e),(u>o||u===-1/0&&i===-1/0)&&(i=n,o=u)});return i},m.min=function(n,t,r){var e,u,i=1/0,o=1/0;if(null==t&&null!=n){n=k(n)?n:m.values(n);for(var a=0,c=n.length;c>a;a++)e=n[a],i>e&&(i=e)}else t=x(t,r),m.each(n,function(n,r,e){u=t(n,r,e),(o>u||1/0===u&&1/0===i)&&(i=n,o=u)});return i},m.shuffle=function(n){for(var t,r=k(n)?n:m.values(n),e=r.length,u=Array(e),i=0;e>i;i++)t=m.random(0,i),t!==i&&(u[i]=u[t]),u[t]=r[i];return u},m.sample=function(n,t,r){return null==t||r?(k(n)||(n=m.values(n)),n[m.random(n.length-1)]):m.shuffle(n).slice(0,Math.max(0,t))},m.sortBy=function(n,t,r){return t=x(t,r),m.pluck(m.map(n,function(n,r,e){return{value:n,index:r,criteria:t(n,r,e)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index-t.index}),"value")};var F=function(n){return function(t,r,e){var u={};return r=x(r,e),m.each(t,function(e,i){var o=r(e,i,t);n(u,e,o)}),u}};m.groupBy=F(function(n,t,r){m.has(n,r)?n[r].push(t):n[r]=[t]}),m.indexBy=F(function(n,t,r){n[r]=t}),m.countBy=F(function(n,t,r){m.has(n,r)?n[r]++:n[r]=1}),m.toArray=function(n){return n?m.isArray(n)?l.call(n):k(n)?m.map(n,m.identity):m.values(n):[]},m.size=function(n){return null==n?0:k(n)?n.length:m.keys(n).length},m.partition=function(n,t,r){t=x(t,r);var e=[],u=[];return m.each(n,function(n,r,i){(t(n,r,i)?e:u).push(n)}),[e,u]},m.first=m.head=m.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:m.initial(n,n.length-t)},m.initial=function(n,t,r){return l.call(n,0,Math.max(0,n.length-(null==t||r?1:t)))},m.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:m.rest(n,Math.max(0,n.length-t))},m.rest=m.tail=m.drop=function(n,t,r){return l.call(n,null==t||r?1:t)},m.compact=function(n){return m.filter(n,m.identity)};var S=function(n,t,r,e){for(var u=[],i=0,o=e||0,a=O(n);a>o;o++){var c=n[o];if(k(c)&&(m.isArray(c)||m.isArguments(c))){t||(c=S(c,t,r));var f=0,l=c.length;for(u.length+=l;l>f;)u[i++]=c[f++]}else r||(u[i++]=c)}return u};m.flatten=function(n,t){return S(n,t,!1)},m.without=function(n){return m.difference(n,l.call(arguments,1))},m.uniq=m.unique=function(n,t,r,e){m.isBoolean(t)||(e=r,r=t,t=!1),null!=r&&(r=x(r,e));for(var u=[],i=[],o=0,a=O(n);a>o;o++){var c=n[o],f=r?r(c,o,n):c;t?(o&&i===f||u.push(c),i=f):r?m.contains(i,f)||(i.push(f),u.push(c)):m.contains(u,c)||u.push(c)}return u},m.union=function(){return m.uniq(S(arguments,!0,!0))},m.intersection=function(n){for(var t=[],r=arguments.length,e=0,u=O(n);u>e;e++){var i=n[e];if(!m.contains(t,i)){for(var o=1;r>o&&m.contains(arguments[o],i);o++);o===r&&t.push(i)}}return t},m.difference=function(n){var t=S(arguments,!0,!0,1);return m.filter(n,function(n){return!m.contains(t,n)})},m.zip=function(){return m.unzip(arguments)},m.unzip=function(n){for(var t=n&&m.max(n,O).length||0,r=Array(t),e=0;t>e;e++)r[e]=m.pluck(n,e);return r},m.object=function(n,t){for(var r={},e=0,u=O(n);u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},m.findIndex=t(1),m.findLastIndex=t(-1),m.sortedIndex=function(n,t,r,e){r=x(r,e,1);for(var u=r(t),i=0,o=O(n);o>i;){var a=Math.floor((i+o)/2);r(n[a])i;i++,n+=r)u[i]=n;return u};var E=function(n,t,r,e,u){if(!(e instanceof t))return n.apply(r,u);var i=j(n.prototype),o=n.apply(i,u);return m.isObject(o)?o:i};m.bind=function(n,t){if(g&&n.bind===g)return g.apply(n,l.call(arguments,1));if(!m.isFunction(n))throw new TypeError("Bind must be called on a function");var r=l.call(arguments,2),e=function(){return E(n,e,t,this,r.concat(l.call(arguments)))};return e},m.partial=function(n){var t=l.call(arguments,1),r=function(){for(var e=0,u=t.length,i=Array(u),o=0;u>o;o++)i[o]=t[o]===m?arguments[e++]:t[o];for(;e=e)throw new Error("bindAll must be passed function names");for(t=1;e>t;t++)r=arguments[t],n[r]=m.bind(n[r],n);return n},m.memoize=function(n,t){var r=function(e){var u=r.cache,i=""+(t?t.apply(this,arguments):e);return m.has(u,i)||(u[i]=n.apply(this,arguments)),u[i]};return r.cache={},r},m.delay=function(n,t){var r=l.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},m.defer=m.partial(m.delay,m,1),m.throttle=function(n,t,r){var e,u,i,o=null,a=0;r||(r={});var c=function(){a=r.leading===!1?0:m.now(),o=null,i=n.apply(e,u),o||(e=u=null)};return function(){var f=m.now();a||r.leading!==!1||(a=f);var l=t-(f-a);return e=this,u=arguments,0>=l||l>t?(o&&(clearTimeout(o),o=null),a=f,i=n.apply(e,u),o||(e=u=null)):o||r.trailing===!1||(o=setTimeout(c,l)),i}},m.debounce=function(n,t,r){var e,u,i,o,a,c=function(){var f=m.now()-o;t>f&&f>=0?e=setTimeout(c,t-f):(e=null,r||(a=n.apply(i,u),e||(i=u=null)))};return function(){i=this,u=arguments,o=m.now();var f=r&&!e;return e||(e=setTimeout(c,t)),f&&(a=n.apply(i,u),i=u=null),a}},m.wrap=function(n,t){return m.partial(t,n)},m.negate=function(n){return function(){return!n.apply(this,arguments)}},m.compose=function(){var n=arguments,t=n.length-1;return function(){for(var r=t,e=n[t].apply(this,arguments);r--;)e=n[r].call(this,e);return e}},m.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},m.before=function(n,t){var r;return function(){return--n>0&&(r=t.apply(this,arguments)),1>=n&&(t=null),r}},m.once=m.partial(m.before,2);var M=!{toString:null}.propertyIsEnumerable("toString"),I=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"];m.keys=function(n){if(!m.isObject(n))return[];if(v)return v(n);var t=[];for(var r in n)m.has(n,r)&&t.push(r);return M&&e(n,t),t},m.allKeys=function(n){if(!m.isObject(n))return[];var t=[];for(var r in n)t.push(r);return M&&e(n,t),t},m.values=function(n){for(var t=m.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=n[t[u]];return e},m.mapObject=function(n,t,r){t=x(t,r);for(var e,u=m.keys(n),i=u.length,o={},a=0;i>a;a++)e=u[a],o[e]=t(n[e],e,n);return o},m.pairs=function(n){for(var t=m.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=[t[u],n[t[u]]];return e},m.invert=function(n){for(var t={},r=m.keys(n),e=0,u=r.length;u>e;e++)t[n[r[e]]]=r[e];return t},m.functions=m.methods=function(n){var t=[];for(var r in n)m.isFunction(n[r])&&t.push(r);return t.sort()},m.extend=_(m.allKeys),m.extendOwn=m.assign=_(m.keys),m.findKey=function(n,t,r){t=x(t,r);for(var e,u=m.keys(n),i=0,o=u.length;o>i;i++)if(e=u[i],t(n[e],e,n))return e},m.pick=function(n,t,r){var e,u,i={},o=n;if(null==o)return i;m.isFunction(t)?(u=m.allKeys(o),e=b(t,r)):(u=S(arguments,!1,!1,1),e=function(n,t,r){return t in r},o=Object(o));for(var a=0,c=u.length;c>a;a++){var f=u[a],l=o[f];e(l,f,o)&&(i[f]=l)}return i},m.omit=function(n,t,r){if(m.isFunction(t))t=m.negate(t);else{var e=m.map(S(arguments,!1,!1,1),String);t=function(n,t){return!m.contains(e,t)}}return m.pick(n,t,r)},m.defaults=_(m.allKeys,!0),m.create=function(n,t){var r=j(n);return t&&m.extendOwn(r,t),r},m.clone=function(n){return m.isObject(n)?m.isArray(n)?n.slice():m.extend({},n):n},m.tap=function(n,t){return t(n),n},m.isMatch=function(n,t){var r=m.keys(t),e=r.length;if(null==n)return!e;for(var u=Object(n),i=0;e>i;i++){var o=r[i];if(t[o]!==u[o]||!(o in u))return!1}return!0};var N=function(n,t,r,e){if(n===t)return 0!==n||1/n===1/t;if(null==n||null==t)return n===t;n instanceof m&&(n=n._wrapped),t instanceof m&&(t=t._wrapped);var u=s.call(n);if(u!==s.call(t))return!1;switch(u){case"[object RegExp]":case"[object String]":return""+n==""+t;case"[object Number]":return+n!==+n?+t!==+t:0===+n?1/+n===1/t:+n===+t;case"[object Date]":case"[object Boolean]":return+n===+t}var i="[object Array]"===u;if(!i){if("object"!=typeof n||"object"!=typeof t)return!1;var o=n.constructor,a=t.constructor;if(o!==a&&!(m.isFunction(o)&&o instanceof o&&m.isFunction(a)&&a instanceof a)&&"constructor"in n&&"constructor"in t)return!1}r=r||[],e=e||[];for(var c=r.length;c--;)if(r[c]===n)return e[c]===t;if(r.push(n),e.push(t),i){if(c=n.length,c!==t.length)return!1;for(;c--;)if(!N(n[c],t[c],r,e))return!1}else{var f,l=m.keys(n);if(c=l.length,m.keys(t).length!==c)return!1;for(;c--;)if(f=l[c],!m.has(t,f)||!N(n[f],t[f],r,e))return!1}return r.pop(),e.pop(),!0};m.isEqual=function(n,t){return N(n,t)},m.isEmpty=function(n){return null==n?!0:k(n)&&(m.isArray(n)||m.isString(n)||m.isArguments(n))?0===n.length:0===m.keys(n).length},m.isElement=function(n){return!(!n||1!==n.nodeType)},m.isArray=h||function(n){return"[object Array]"===s.call(n)},m.isObject=function(n){var t=typeof n;return"function"===t||"object"===t&&!!n},m.each(["Arguments","Function","String","Number","Date","RegExp","Error"],function(n){m["is"+n]=function(t){return s.call(t)==="[object "+n+"]"}}),m.isArguments(arguments)||(m.isArguments=function(n){return m.has(n,"callee")}),"function"!=typeof/./&&"object"!=typeof Int8Array&&(m.isFunction=function(n){return"function"==typeof n||!1}),m.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},m.isNaN=function(n){return m.isNumber(n)&&n!==+n},m.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"===s.call(n)},m.isNull=function(n){return null===n},m.isUndefined=function(n){return n===void 0},m.has=function(n,t){return null!=n&&p.call(n,t)},m.noConflict=function(){return u._=i,this},m.identity=function(n){return n},m.constant=function(n){return function(){return n}},m.noop=function(){},m.property=w,m.propertyOf=function(n){return null==n?function(){}:function(t){return n[t]}},m.matcher=m.matches=function(n){return n=m.extendOwn({},n),function(t){return m.isMatch(t,n)}},m.times=function(n,t,r){var e=Array(Math.max(0,n));t=b(t,r,1);for(var u=0;n>u;u++)e[u]=t(u);return e},m.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))},m.now=Date.now||function(){return(new Date).getTime()};var B={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},T=m.invert(B),R=function(n){var t=function(t){return n[t]},r="(?:"+m.keys(n).join("|")+")",e=RegExp(r),u=RegExp(r,"g");return function(n){return n=null==n?"":""+n,e.test(n)?n.replace(u,t):n}};m.escape=R(B),m.unescape=R(T),m.result=function(n,t,r){var e=null==n?void 0:n[t];return e===void 0&&(e=r),m.isFunction(e)?e.call(n):e};var q=0;m.uniqueId=function(n){var t=++q+"";return n?n+t:t},m.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var K=/(.)^/,z={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},D=/\\|'|\r|\n|\u2028|\u2029/g,L=function(n){return"\\"+z[n]};m.template=function(n,t,r){!t&&r&&(t=r),t=m.defaults({},t,m.templateSettings);var e=RegExp([(t.escape||K).source,(t.interpolate||K).source,(t.evaluate||K).source].join("|")+"|$","g"),u=0,i="__p+='";n.replace(e,function(t,r,e,o,a){return i+=n.slice(u,a).replace(D,L),u=a+t.length,r?i+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'":e?i+="'+\n((__t=("+e+"))==null?'':__t)+\n'":o&&(i+="';\n"+o+"\n__p+='"),t}),i+="';\n",t.variable||(i="with(obj||{}){\n"+i+"}\n"),i="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+i+"return __p;\n";try{var o=new Function(t.variable||"obj","_",i)}catch(a){throw a.source=i,a}var c=function(n){return o.call(this,n,m)},f=t.variable||"obj";return c.source="function("+f+"){\n"+i+"}",c},m.chain=function(n){var t=m(n);return t._chain=!0,t};var P=function(n,t){return n._chain?m(t).chain():t};m.mixin=function(n){m.each(m.functions(n),function(t){var r=m[t]=n[t];m.prototype[t]=function(){var n=[this._wrapped];return f.apply(n,arguments),P(this,r.apply(m,n))}})},m.mixin(m),m.each(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=o[n];m.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!==n&&"splice"!==n||0!==r.length||delete r[0],P(this,r)}}),m.each(["concat","join","slice"],function(n){var t=o[n];m.prototype[n]=function(){return P(this,t.apply(this._wrapped,arguments))}}),m.prototype.value=function(){return this._wrapped},m.prototype.valueOf=m.prototype.toJSON=m.prototype.value,m.prototype.toString=function(){return""+this._wrapped},"function"==typeof define&&define.amd&&define("underscore",[],function(){return m})}).call(this);
+//# sourceMappingURL=underscore-min.map
+
+
+/* MIT https://github.com/fabiospampinato/cash */
+(function(){
+'use strict';var e={"class":"className",contenteditable:"contentEditable","for":"htmlFor",readonly:"readOnly",maxlength:"maxLength",tabindex:"tabIndex",colspan:"colSpan",rowspan:"rowSpan",usemap:"useMap"};function aa(a,b){try{return a(b)}catch(c){return b}}
+var k=document,m=window,ba=k.documentElement,n=k.createElement.bind(k),ca=n("div"),p=n("table"),da=n("tbody"),ea=n("tr"),q=Array.isArray,r=Array.prototype,fa=r.concat,t=r.filter,ha=r.indexOf,ia=r.map,ja=r.push,ka=r.slice,u=r.some,la=r.splice,ma=/^#(?:[\w-]|\\.|[^\x00-\xa0])*$/,na=/^\.(?:[\w-]|\\.|[^\x00-\xa0])*$/,oa=/<.+>/,pa=/^\w+$/;function v(a,b){return a&&(w(b)||x(b))?na.test(a)?b.getElementsByClassName(a.slice(1)):pa.test(a)?b.getElementsByTagName(a):b.querySelectorAll(a):[]}
+var B=function(){function a(a,c){if(a){if(a instanceof B)return a;var b=a;if(C(a)){if(b=(c instanceof B?c[0]:c)||k,b=ma.test(a)?b.getElementById(a.slice(1)):oa.test(a)?qa(a):v(a,b),!b)return}else if(D(a))return this.ready(a);if(b.nodeType||b===m)b=[b];this.length=b.length;a=0;for(c=this.length;aa?a+this.length:a]};E.eq=function(a){return F(this.get(a))};E.first=function(){return this.eq(0)};
+E.last=function(){return this.eq(-1)};function J(a,b,c){if(c)for(c=a.length;c--&&!1!==b.call(a[c],c,a[c]););else if(I(a)){var d=Object.keys(a);c=0;for(var h=d.length;carguments.length?this[0]&&this[0][a]:this.each(function(c,h){h[a]=b});for(var c in a)this.prop(c,a[c]);return this}};
+E.removeProp=function(a){return this.each(function(b,c){delete c[e[a]||a]})};function K(){for(var a=[],b=0;barguments.length){if(!this[0]||!x(this[0]))return;var c=this[0].getAttribute(a);return null===c?void 0:c}return void 0===b?this:null===b?this.removeAttr(a):this.each(function(c,h){x(h)&&h.setAttribute(a,b)})}for(c in a)this.attr(c,a[c]);return this}};
+E.toggleClass=function(a,b){var c=N(a),d=void 0!==b;return this.each(function(a,f){x(f)&&J(c,function(a,c){d?b?f.classList.add(c):f.classList.remove(c):f.classList.toggle(c)})})};E.addClass=function(a){return this.toggleClass(a,!0)};E.removeClass=function(a){return arguments.length?this.toggleClass(a,!1):this.attr("class","")};
+function O(a,b,c,d){for(var h=[],f=D(b),g=d&&L(d),y=0,z=a.length;yarguments.length)return this[0]&&Q(this[0],a,c);if(!a)return this;b=za(a,b,c);return this.each(function(d,f){x(f)&&(c?f.style.setProperty(a,b):f.style[a]=b)})}for(var d in a)this.css(d,a[d]);return this};var Aa=/^\s+|\s+$/;function Ba(a,b){a=a.dataset[b]||a.dataset[G(b)];return Aa.test(a)?a:aa(JSON.parse,a)}
+E.data=function(a,b){if(!a){if(!this[0])return;var c={},d;for(d in this[0].dataset)c[d]=Ba(this[0],d);return c}if(C(a))return 2>arguments.length?this[0]&&Ba(this[0],a):void 0===b?this:this.each(function(c,d){c=b;c=aa(JSON.stringify,c);d.dataset[G(a)]=c});for(d in a)this.data(d,a[d]);return this};function Ca(a,b){var c=a.documentElement;return Math.max(a.body["scroll"+b],c["scroll"+b],a.body["offset"+b],c["offset"+b],c["client"+b])}
+function Da(a,b){return R(a,"border"+(b?"Left":"Top")+"Width")+R(a,"padding"+(b?"Left":"Top"))+R(a,"padding"+(b?"Right":"Bottom"))+R(a,"border"+(b?"Right":"Bottom")+"Width")}
+J([!0,!1],function(a,b){J(["Width","Height"],function(a,d){E[(b?"outer":"inner")+d]=function(c){if(this[0])return H(this[0])?b?this[0]["inner"+d]:this[0].document.documentElement["client"+d]:w(this[0])?Ca(this[0],d):this[0][(b?"offset":"client")+d]+(c&&b?R(this[0],"margin"+(a?"Top":"Left"))+R(this[0],"margin"+(a?"Bottom":"Right")):0)}})});
+J(["Width","Height"],function(a,b){var c=b.toLowerCase();E[c]=function(d){if(!this[0])return void 0===d?void 0:this;if(!arguments.length)return H(this[0])?this[0].document.documentElement["client"+b]:w(this[0])?Ca(this[0],b):this[0].getBoundingClientRect()[c]-Da(this[0],!a);var h=parseInt(d,10);return this.each(function(b,d){x(d)&&(b=Q(d,"boxSizing"),d.style[c]=za(c,h+("border-box"===b?Da(d,!a):0)))})}});var U={};
+E.toggle=function(a){return this.each(function(b,c){if(x(c))if(void 0===a?"none"===Q(c,"display"):a){if(c.style.display=c.___cd||"","none"===Q(c,"display")){b=c.style;c=c.tagName;if(U[c])c=U[c];else{var d=n(c);k.body.insertBefore(d,null);var h=Q(d,"display");k.body.removeChild(d);c=U[c]="none"!==h?h:"block"}b.display=c}}else c.___cd=Q(c,"display"),c.style.display="none"})};E.hide=function(){return this.toggle(!1)};E.show=function(){return this.toggle(!0)};
+function Ea(a,b){return!b||!u.call(b,function(b){return 0>a.indexOf(b)})}var V={focus:"focusin",blur:"focusout"},W={mouseenter:"mouseover",mouseleave:"mouseout"},Fa=/^(mouse|pointer|contextmenu|drag|drop|click|dblclick)/i;function Ga(a,b,c,d,h){var f=a.___ce=a.___ce||{};f[b]=f[b]||[];f[b].push([c,d,h]);a.addEventListener(b,h)}function X(a){a=a.split(".");return[a[0],a.slice(1).sort()]}
+function Y(a,b,c,d,h){var f=a.___ce=a.___ce||{};if(b)f[b]&&(f[b]=f[b].filter(function(f){var g=f[0],z=f[1];f=f[2];if(h&&f.guid!==h.guid||!Ea(g,c)||d&&d!==z)return!0;a.removeEventListener(b,f)}));else for(b in f)Y(a,b,c,d,h)}
+E.off=function(a,b,c){var d=this;if(void 0===a)this.each(function(a,b){(x(b)||w(b)||H(b))&&Y(b)});else if(C(a))D(b)&&(c=b,b=""),J(N(a),function(a,h){a=X(h);h=a[0];var f=a[1],g=W[h]||V[h]||h;d.each(function(a,d){(x(d)||w(d)||H(d))&&Y(d,g,f,b,c)})});else for(var h in a)this.off(h,a[h]);return this};
+E.on=function(a,b,c,d,h){var f=this;if(!C(a)){for(var g in a)this.on(g,b,c,a[g],h);return this}C(b)||(void 0!==b&&null!==b&&(void 0!==c&&(d=c),c=b),b="");D(d)||(d=c,c=void 0);if(!d)return this;J(N(a),function(a,g){a=X(g);g=a[0];var l=a[1],z=W[g]||V[g]||g,y=g in W,Ka=g in V;z&&f.each(function(a,f){if(x(f)||w(f)||H(f))a=function La(a){if(a.target["___i"+a.type])return a.stopImmediatePropagation();if(!a.namespace||Ea(l,a.namespace.split(".")))if(b||!(Ka&&(a.target!==f||a.___ot===z)||y&&a.relatedTarget&&
+f.contains(a.relatedTarget))){var g=f;if(b){for(var A=a.target;!sa(A,b);){if(A===f)return;A=A.parentNode;if(!A)return}g=A;a.___cd=!0}a.___cd&&Object.defineProperty(a,"currentTarget",{configurable:!0,get:function(){return g}});Object.defineProperty(a,"data",{configurable:!0,get:function(){return c}});A=d.call(g,a,a.___td);h&&Y(f,z,l,b,La);!1===A&&(a.preventDefault(),a.stopPropagation())}},a.guid=d.guid=d.guid||F.guid++,Ga(f,z,l,b,a)})});return this};E.one=function(a,b,c,d){return this.on(a,b,c,d,!0)};
+E.ready=function(a){function b(){return setTimeout(a,0,F)}"loading"!==k.readyState?b():k.addEventListener("DOMContentLoaded",b);return this};E.trigger=function(a,b){if(C(a)){var c=X(a),d=c[0];c=c[1];var h=W[d]||V[d]||d;if(!h)return this;var f=Fa.test(h)?"MouseEvents":"HTMLEvents";a=k.createEvent(f);a.initEvent(h,!0,!0);a.namespace=c.join(".");a.___ot=d}a.___td=b;var g=a.___ot in V;return this.each(function(b,c){g&&D(c[a.___ot])&&(c["___i"+a.type]=!0,c[a.___ot](),c["___i"+a.type]=!1);c.dispatchEvent(a)})};
+function Ha(a){return a.multiple&&a.options?O(t.call(a.options,function(a){return a.selected&&!a.disabled&&!a.parentNode.disabled}),"value"):a.value||""}var Ia=/%20/g,Ja=/\r?\n/g,Ma=/file|reset|submit|button|image/i,Na=/radio|checkbox/i;
+E.serialize=function(){var a="";this.each(function(b,c){J(c.elements||[c],function(b,c){c.disabled||!c.name||"FIELDSET"===c.tagName||Ma.test(c.type)||Na.test(c.type)&&!c.checked||(b=Ha(c),void 0!==b&&(b=q(b)?b:[b],J(b,function(b,d){b=a;d="&"+encodeURIComponent(c.name)+"="+encodeURIComponent(d.replace(Ja,"\r\n")).replace(Ia,"+");a=b+d})))})});return a.slice(1)};
+E.val=function(a){return arguments.length?this.each(function(b,c){if((b=c.multiple&&c.options)||Na.test(c.type)){var d=q(a)?ia.call(a,String):null===a?[]:[String(a)];b?J(c.options,function(a,b){b.selected=0<=d.indexOf(b.value)},!0):c.checked=0<=d.indexOf(c.value)}else c.value=void 0===a||null===a?"":a}):this[0]&&Ha(this[0])};E.clone=function(){return this.map(function(a,b){return b.cloneNode(!0)})};E.detach=function(a){M(this,a).each(function(a,c){c.parentNode&&c.parentNode.removeChild(c)});return this};
+var Oa=/^\s*<(\w+)[^>]*>/,Pa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,Qa={"*":ca,tr:da,td:ea,th:ea,thead:p,tbody:p,tfoot:p};function qa(a){if(!C(a))return[];if(Pa.test(a))return[n(RegExp.$1)];var b=Oa.test(a)&&RegExp.$1;b=Qa[b]||Qa["*"];b.innerHTML=a;return F(b.childNodes).detach().get()}F.parseHTML=qa;E.empty=function(){return this.each(function(a,b){for(;b.firstChild;)b.removeChild(b.firstChild)})};
+E.html=function(a){return arguments.length?void 0===a?this:this.each(function(b,c){x(c)&&(c.innerHTML=a)}):this[0]&&this[0].innerHTML};E.remove=function(a){M(this,a).detach().off();return this};E.text=function(a){return void 0===a?this[0]?this[0].textContent:"":this.each(function(b,c){x(c)&&(c.textContent=a)})};E.unwrap=function(){this.parent().each(function(a,b){"BODY"!==b.tagName&&(a=F(b),a.replaceWith(a.children()))});return this};
+E.offset=function(){var a=this[0];if(a)return a=a.getBoundingClientRect(),{top:a.top+m.pageYOffset,left:a.left+m.pageXOffset}};E.offsetParent=function(){return this.map(function(a,b){for(a=b.offsetParent;a&&"static"===Q(a,"position");)a=a.offsetParent;return a||ba})};
+E.position=function(){var a=this[0];if(a){var b="fixed"===Q(a,"position"),c=b?a.getBoundingClientRect():this.offset();if(!b){var d=a.ownerDocument;for(b=a.offsetParent||d.documentElement;(b===d.body||b===d.documentElement)&&"static"===Q(b,"position");)b=b.parentNode;b!==a&&x(b)&&(d=F(b).offset(),c.top-=d.top+R(b,"borderTopWidth"),c.left-=d.left+R(b,"borderLeftWidth"))}return{top:c.top-R(a,"marginTop"),left:c.left-R(a,"marginLeft")}}};
+E.children=function(a){return M(F(P(O(this,function(a){return a.children}))),a)};E.contents=function(){return F(P(O(this,function(a){return"IFRAME"===a.tagName?[a.contentDocument]:"TEMPLATE"===a.tagName?a.content.childNodes:a.childNodes})))};E.find=function(a){return F(P(O(this,function(b){return v(a,b)})))};var Ra=/^\s*\s*$/g,Sa=/^$|^module$|\/(java|ecma)script/i,Ta=["type","src","nonce","noModule"];
+function Ua(a,b){a=F(a);a.filter("script").add(a.find("script")).each(function(a,d){if(Sa.test(d.type)&&ba.contains(d)){var c=n("script");c.text=d.textContent.replace(Ra,"");J(Ta,function(a,b){d[b]&&(c[b]=d[b])});b.head.insertBefore(c,null);b.head.removeChild(c)}})}
+function Z(a,b,c,d,h,f,g,y){J(a,function(a,f){J(F(f),function(a,f){J(F(b),function(b,g){var l=c?g:f;b=c?a:b;g=c?f:g;l=b?l.cloneNode(!0):l;b=!b;h?g.insertBefore(l,d?g.firstChild:null):g.parentNode.insertBefore(l,d?g:g.nextSibling);b&&Ua(l,g.ownerDocument)},y)},g)},f);return b}E.after=function(){return Z(arguments,this,!1,!1,!1,!0,!0)};E.append=function(){return Z(arguments,this,!1,!1,!0)};E.appendTo=function(a){return Z(arguments,this,!0,!1,!0)};E.before=function(){return Z(arguments,this,!1,!0)};
+E.insertAfter=function(a){return Z(arguments,this,!0,!1,!1,!1,!1,!0)};E.insertBefore=function(a){return Z(arguments,this,!0,!0)};E.prepend=function(){return Z(arguments,this,!1,!0,!0,!0,!0)};E.prependTo=function(a){return Z(arguments,this,!0,!0,!0,!1,!1,!0)};E.replaceWith=function(a){return this.before(a).remove()};E.replaceAll=function(a){F(a).replaceWith(this);return this};E.wrapAll=function(a){a=F(a);for(var b=a[0];b.children.length;)b=b.firstElementChild;this.first().before(a);return this.appendTo(b)};
+E.wrap=function(a){return this.each(function(b,c){var d=F(a)[0];F(c).wrapAll(b?d.cloneNode(!0):d)})};E.wrapInner=function(a){return this.each(function(b,c){b=F(c);c=b.contents();c.length?c.wrapAll(a):b.append(a)})};E.has=function(a){var b=C(a)?function(b,d){return v(a,d).length}:function(b,d){return d.contains(a)};return this.filter(b)};E.is=function(a){var b=L(a);return u.call(this,function(a,d){return b.call(a,d,a)})};E.next=function(a,b,c){return M(F(P(O(this,"nextElementSibling",b,c))),a)};
+E.nextAll=function(a){return this.next(a,!0)};E.nextUntil=function(a,b){return this.next(b,!0,a)};E.not=function(a){var b=L(a);return this.filter(function(c,d){return(!C(a)||x(d))&&!b.call(d,c,d)})};E.parent=function(a){return M(F(P(O(this,"parentNode"))),a)};E.index=function(a){var b=a?F(a)[0]:this[0];a=a?this:F(b).parent().children();return ha.call(a,b)};E.closest=function(a){var b=this.filter(a);if(b.length)return b;var c=this.parent();return c.length?c.closest(a):b};
+E.parents=function(a,b){return M(F(P(O(this,"parentElement",!0,b))),a)};E.parentsUntil=function(a,b){return this.parents(b,a)};E.prev=function(a,b,c){return M(F(P(O(this,"previousElementSibling",b,c))),a)};E.prevAll=function(a){return this.prev(a,!0)};E.prevUntil=function(a,b){return this.prev(b,!0,a)};E.siblings=function(a){return M(F(P(O(this,function(a){return F(a).parent().children().not(a)}))),a)};"undefined"!==typeof exports?module.exports=F:m.cash=m.$=F;
+})();
+
+
+// tiny animate
+!function(n,t){"function"==typeof define&&define.amd?define(["exports"],function(e){t(n.TinyAnimate=e)}):t("object"==typeof exports?exports:n.TinyAnimate={})}(this,function(n){n.animate=function(n,e,u,a,r,i){function o(t){if(!f){var M=(t||+new Date)-h;M>=0&&a(r(M,n,s,u)),M>=0&&M>=u?(a(e),i()):c(o)}}if("number"==typeof n&&"number"==typeof e&&"number"==typeof u&&"function"==typeof a){"string"==typeof r&&t[r]&&(r=t[r]),"function"!=typeof r&&(r=t.linear),"function"!=typeof i&&(i=function(){});var c=window.requestAnimationFrame||function(n){window.setTimeout(n,1e3/60)},f=!1,s=e-n;a(n);var h=window.performance&&window.performance.now?window.performance.now():+new Date;return c(o),{cancel:function(){f=!0}}}},n.animateCSS=function(t,e,u,a,r,i,o,c){var f=function(n){t.style[e]=n+u};return n.animate(a,r,i,f,o,c)},n.cancel=function(n){n&&n.cancel()};var t=n.easings={};t.linear=function(n,t,e,u){return e*n/u+t},t.easeInQuad=function(n,t,e,u){return e*(n/=u)*n+t},t.easeOutQuad=function(n,t,e,u){return-e*(n/=u)*(n-2)+t},t.easeInOutQuad=function(n,t,e,u){return(n/=u/2)<1?e/2*n*n+t:-e/2*(--n*(n-2)-1)+t},t.easeInCubic=function(n,t,e,u){return e*(n/=u)*n*n+t},t.easeOutCubic=function(n,t,e,u){return e*((n=n/u-1)*n*n+1)+t},t.easeInOutCubic=function(n,t,e,u){return(n/=u/2)<1?e/2*n*n*n+t:e/2*((n-=2)*n*n+2)+t},t.easeInQuart=function(n,t,e,u){return e*(n/=u)*n*n*n+t},t.easeOutQuart=function(n,t,e,u){return-e*((n=n/u-1)*n*n*n-1)+t},t.easeInOutQuart=function(n,t,e,u){return(n/=u/2)<1?e/2*n*n*n*n+t:-e/2*((n-=2)*n*n*n-2)+t},t.easeInQuint=function(n,t,e,u){return e*(n/=u)*n*n*n*n+t},t.easeOutQuint=function(n,t,e,u){return e*((n=n/u-1)*n*n*n*n+1)+t},t.easeInOutQuint=function(n,t,e,u){return(n/=u/2)<1?e/2*n*n*n*n*n+t:e/2*((n-=2)*n*n*n*n+2)+t},t.easeInSine=function(n,t,e,u){return-e*Math.cos(n/u*(Math.PI/2))+e+t},t.easeOutSine=function(n,t,e,u){return e*Math.sin(n/u*(Math.PI/2))+t},t.easeInOutSine=function(n,t,e,u){return-e/2*(Math.cos(Math.PI*n/u)-1)+t},t.easeInExpo=function(n,t,e,u){return 0==n?t:e*Math.pow(2,10*(n/u-1))+t},t.easeOutExpo=function(n,t,e,u){return n==u?t+e:e*(-Math.pow(2,-10*n/u)+1)+t},t.easeInOutExpo=function(n,t,e,u){return 0==n?t:n==u?t+e:(n/=u/2)<1?e/2*Math.pow(2,10*(n-1))+t:e/2*(-Math.pow(2,-10*--n)+2)+t},t.easeInCirc=function(n,t,e,u){return-e*(Math.sqrt(1-(n/=u)*n)-1)+t},t.easeOutCirc=function(n,t,e,u){return e*Math.sqrt(1-(n=n/u-1)*n)+t},t.easeInOutCirc=function(n,t,e,u){return(n/=u/2)<1?-e/2*(Math.sqrt(1-n*n)-1)+t:e/2*(Math.sqrt(1-(n-=2)*n)+1)+t},t.easeInElastic=function(n,t,e,u){var a=0,r=e;if(0==n)return t;if(1==(n/=u))return t+e;if(a||(a=.3*u),rn?-.5*(r*Math.pow(2,10*(n-=1))*Math.sin((n*u-i)*(2*Math.PI)/a))+t:r*Math.pow(2,-10*(n-=1))*Math.sin((n*u-i)*(2*Math.PI)/a)*.5+e+t},t.easeInBack=function(n,t,e,u,a){return void 0==a&&(a=1.70158),e*(n/=u)*n*((a+1)*n-a)+t},t.easeOutBack=function(n,t,e,u,a){return void 0==a&&(a=1.70158),e*((n=n/u-1)*n*((a+1)*n+a)+1)+t},t.easeInOutBack=function(n,t,e,u,a){return void 0==a&&(a=1.70158),(n/=u/2)<1?e/2*(n*n*(((a*=1.525)+1)*n-a))+t:e/2*((n-=2)*n*(((a*=1.525)+1)*n+a)+2)+t},t.easeInBounce=function(n,e,u,a){return u-t.easeOutBounce(a-n,0,u,a)+e},t.easeOutBounce=function(n,t,e,u){return(n/=u)<1/2.75?e*(7.5625*n*n)+t:2/2.75>n?e*(7.5625*(n-=1.5/2.75)*n+.75)+t:2.5/2.75>n?e*(7.5625*(n-=2.25/2.75)*n+.9375)+t:e*(7.5625*(n-=2.625/2.75)*n+.984375)+t},t.easeInOutBounce=function(n,e,u,a){return a/2>n?.5*t.easeInBounce(2*n,0,u,a)+e:.5*t.easeOutBounce(2*n-a,0,u,a)+.5*u+e}});
+//# sourceMappingURL=TinyAnimate.js.map
+
+
+
+// microevent
+var MicroEvent=function(){};MicroEvent.prototype={bind:function(event,fct){this._events=this._events||{};this._events[event]=this._events[event]||[];this._events[event].push(fct);},unbind:function(event,fct){this._events=this._events||{};if(event in this._events===false)return;this._events[event].splice(this._events[event].indexOf(fct),1);},trigger:function(event){this._events=this._events||{};if(event in this._events===false)return;for(var i=0;i>8&255]},z=function(e){return[255&e,e>>8&255,e>>16&255,e>>24&255]},P=function(e){return e[3]<<24|e[2]<<16|e[1]<<8|e[0]},j=function(e){return U(e,23,4)},D=function(e){return U(e,52,8)},N=function(e,t){g(e.prototype,t,{get:function(){return w(this)[t]}})},B=function(e,t,n,r){var i=p(n),o=w(e);if(i+t>o.byteLength)throw I(S);var a=w(o.buffer).bytes,u=i+o.byteOffset,s=a.slice(u,u+t);return r?s:s.reverse()},q=function(e,t,n,r,i,o){var a=p(n),u=w(e);if(a+t>u.byteLength)throw I(S);for(var s=w(u.buffer).bytes,l=a+u.byteOffset,c=r(+i),f=0;fG;)(W=Y[G++])in T||a(T,W,F[W]);H.constructor=T}v&&d(L)!==R&&v(L,R);var Q=new C(new T(2)),$=L.setInt8;Q.setInt8(0,2147483648),Q.setInt8(1,2147483649),!Q.getInt8(0)&&Q.getInt8(1)||u(L,{setInt8:function(e,t){$.call(this,e,t<<24>>24)},setUint8:function(e,t){$.call(this,e,t<<24>>24)}},{unsafe:!0})}else T=function(e){l(this,T,k);var t=p(e);E(this,{bytes:m.call(new Array(t),0),byteLength:t}),i||(this.byteLength=t)},C=function(e,t,n){l(this,C,A),l(e,T,A);var r=w(e).byteLength,o=c(t);if(o<0||o>r)throw I("Wrong offset");if(o+(n=void 0===n?r-o:f(n))>r)throw I("Wrong length");E(this,{buffer:e,byteLength:n,byteOffset:o}),i||(this.buffer=e,this.byteLength=n,this.byteOffset=o)},i&&(N(T,"byteLength"),N(C,"buffer"),N(C,"byteLength"),N(C,"byteOffset")),u(C.prototype,{getInt8:function(e){return B(this,1,e)[0]<<24>>24},getUint8:function(e){return B(this,1,e)[0]},getInt16:function(e){var t=B(this,2,e,arguments.length>1?arguments[1]:void 0);return(t[1]<<8|t[0])<<16>>16},getUint16:function(e){var t=B(this,2,e,arguments.length>1?arguments[1]:void 0);return t[1]<<8|t[0]},getInt32:function(e){return P(B(this,4,e,arguments.length>1?arguments[1]:void 0))},getUint32:function(e){return P(B(this,4,e,arguments.length>1?arguments[1]:void 0))>>>0},getFloat32:function(e){return O(B(this,4,e,arguments.length>1?arguments[1]:void 0),23)},getFloat64:function(e){return O(B(this,8,e,arguments.length>1?arguments[1]:void 0),52)},setInt8:function(e,t){q(this,1,e,_,t)},setUint8:function(e,t){q(this,1,e,_,t)},setInt16:function(e,t){q(this,2,e,M,t,arguments.length>2?arguments[2]:void 0)},setUint16:function(e,t){q(this,2,e,M,t,arguments.length>2?arguments[2]:void 0)},setInt32:function(e,t){q(this,4,e,z,t,arguments.length>2?arguments[2]:void 0)},setUint32:function(e,t){q(this,4,e,z,t,arguments.length>2?arguments[2]:void 0)},setFloat32:function(e,t){q(this,4,e,j,t,arguments.length>2?arguments[2]:void 0)},setFloat64:function(e,t){q(this,8,e,D,t,arguments.length>2?arguments[2]:void 0)}});b(T,k),b(C,A),e.exports={ArrayBuffer:T,DataView:C}},1048:function(e,t,n){"use strict";var r=n(7908),i=n(1400),o=n(7466),a=Math.min;e.exports=[].copyWithin||function(e,t){var n=r(this),u=o(n.length),s=i(e,u),l=i(t,u),c=arguments.length>2?arguments[2]:void 0,f=a((void 0===c?u:i(c,u))-l,u-s),p=1;for(l0;)l in n?n[s]=n[l]:delete n[s],s+=p,l+=p;return n}},1285:function(e,t,n){"use strict";var r=n(7908),i=n(1400),o=n(7466);e.exports=function(e){for(var t=r(this),n=o(t.length),a=arguments.length,u=i(a>1?arguments[1]:void 0,n),s=a>2?arguments[2]:void 0,l=void 0===s?n:i(s,n);l>u;)t[u++]=e;return t}},8533:function(e,t,n){"use strict";var r=n(2092).forEach,i=n(9341)("forEach");e.exports=i?[].forEach:function(e){return r(this,e,arguments.length>1?arguments[1]:void 0)}},8457:function(e,t,n){"use strict";var r=n(9974),i=n(7908),o=n(3411),a=n(7659),u=n(7466),s=n(6135),l=n(1246);e.exports=function(e){var t,n,c,f,p,h,d=i(e),v="function"==typeof this?this:Array,y=arguments.length,g=y>1?arguments[1]:void 0,m=void 0!==g,b=l(d),x=0;if(m&&(g=r(g,y>2?arguments[2]:void 0,2)),null==b||v==Array&&a(b))for(n=new v(t=u(d.length));t>x;x++)h=m?g(d[x],x):d[x],s(n,x,h);else for(p=(f=b.call(d)).next,n=new v;!(c=p.call(f)).done;x++)h=m?o(f,g,[c.value,x],!0):c.value,s(n,x,h);return n.length=x,n}},1318:function(e,t,n){var r=n(5656),i=n(7466),o=n(1400),a=function(e){return function(t,n,a){var u,s=r(t),l=i(s.length),c=o(a,l);if(e&&n!=n){for(;l>c;)if((u=s[c++])!=u)return!0}else for(;l>c;c++)if((e||c in s)&&s[c]===n)return e||c||0;return!e&&-1}};e.exports={includes:a(!0),indexOf:a(!1)}},2092:function(e,t,n){var r=n(9974),i=n(8361),o=n(7908),a=n(7466),u=n(5417),s=[].push,l=function(e){var t=1==e,n=2==e,l=3==e,c=4==e,f=6==e,p=7==e,h=5==e||f;return function(d,v,y,g){for(var m,b,x=o(d),w=i(x),E=r(v,y,3),k=a(w.length),A=0,S=g||u,F=t?S(d,k):n||p?S(d,0):void 0;k>A;A++)if((h||A in w)&&(b=E(m=w[A],A,x),e))if(t)F[A]=b;else if(b)switch(e){case 3:return!0;case 5:return m;case 6:return A;case 2:s.call(F,m)}else switch(e){case 4:return!1;case 7:s.call(F,m)}return f?-1:l||c?c:F}};e.exports={forEach:l(0),map:l(1),filter:l(2),some:l(3),every:l(4),find:l(5),findIndex:l(6),filterOut:l(7)}},6583:function(e,t,n){"use strict";var r=n(5656),i=n(9958),o=n(7466),a=n(9341),u=Math.min,s=[].lastIndexOf,l=!!s&&1/[1].lastIndexOf(1,-0)<0,c=a("lastIndexOf"),f=l||!c;e.exports=f?function(e){if(l)return s.apply(this,arguments)||0;var t=r(this),n=o(t.length),a=n-1;for(arguments.length>1&&(a=u(a,i(arguments[1]))),a<0&&(a=n+a);a>=0;a--)if(a in t&&t[a]===e)return a||0;return-1}:s},1194:function(e,t,n){var r=n(7293),i=n(5112),o=n(7392),a=i("species");e.exports=function(e){return o>=51||!r((function(){var t=[];return(t.constructor={})[a]=function(){return{foo:1}},1!==t[e](Boolean).foo}))}},9341:function(e,t,n){"use strict";var r=n(7293);e.exports=function(e,t){var n=[][e];return!!n&&r((function(){n.call(null,t||function(){throw 1},1)}))}},3671:function(e,t,n){var r=n(3099),i=n(7908),o=n(8361),a=n(7466),u=function(e){return function(t,n,u,s){r(n);var l=i(t),c=o(l),f=a(l.length),p=e?f-1:0,h=e?-1:1;if(u<2)for(;;){if(p in c){s=c[p],p+=h;break}if(p+=h,e?p<0:f<=p)throw TypeError("Reduce of empty array with no initial value")}for(;e?p>=0:f>p;p+=h)p in c&&(s=n(s,c[p],p,l));return s}};e.exports={left:u(!1),right:u(!0)}},5417:function(e,t,n){var r=n(111),i=n(3157),o=n(5112)("species");e.exports=function(e,t){var n;return i(e)&&("function"!=typeof(n=e.constructor)||n!==Array&&!i(n.prototype)?r(n)&&null===(n=n[o])&&(n=void 0):n=void 0),new(void 0===n?Array:n)(0===t?0:t)}},3411:function(e,t,n){var r=n(9670),i=n(9212);e.exports=function(e,t,n,o){try{return o?t(r(n)[0],n[1]):t(n)}catch(t){throw i(e),t}}},7072:function(e,t,n){var r=n(5112)("iterator"),i=!1;try{var o=0,a={next:function(){return{done:!!o++}},return:function(){i=!0}};a[r]=function(){return this},Array.from(a,(function(){throw 2}))}catch(e){}e.exports=function(e,t){if(!t&&!i)return!1;var n=!1;try{var o={};o[r]=function(){return{next:function(){return{done:n=!0}}}},e(o)}catch(e){}return n}},4326:function(e){var t={}.toString;e.exports=function(e){return t.call(e).slice(8,-1)}},648:function(e,t,n){var r=n(1694),i=n(4326),o=n(5112)("toStringTag"),a="Arguments"==i(function(){return arguments}());e.exports=r?i:function(e){var t,n,r;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(n=function(e,t){try{return e[t]}catch(e){}}(t=Object(e),o))?n:a?i(t):"Object"==(r=i(t))&&"function"==typeof t.callee?"Arguments":r}},9920:function(e,t,n){var r=n(6656),i=n(3887),o=n(1236),a=n(3070);e.exports=function(e,t){for(var n=i(t),u=a.f,s=o.f,l=0;l=74)&&(r=a.match(/Chrome\/(\d+)/))&&(i=r[1]),e.exports=i&&+i},748:function(e){e.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},2109:function(e,t,n){var r=n(7854),i=n(1236).f,o=n(8880),a=n(1320),u=n(3505),s=n(9920),l=n(4705);e.exports=function(e,t){var n,c,f,p,h,d=e.target,v=e.global,y=e.stat;if(n=v?r:y?r[d]||u(d,{}):(r[d]||{}).prototype)for(c in t){if(p=t[c],f=e.noTargetGet?(h=i(n,c))&&h.value:n[c],!l(v?c:d+(y?".":"#")+c,e.forced)&&void 0!==f){if(typeof p==typeof f)continue;s(p,f)}(e.sham||f&&f.sham)&&o(p,"sham",!0),a(n,c,p,e)}}},7293:function(e){e.exports=function(e){try{return!!e()}catch(e){return!0}}},7007:function(e,t,n){"use strict";n(4916);var r=n(1320),i=n(7293),o=n(5112),a=n(2261),u=n(8880),s=o("species"),l=!i((function(){var e=/./;return e.exec=function(){var e=[];return e.groups={a:"7"},e},"7"!=="".replace(e,"$")})),c="$0"==="a".replace(/./,"$0"),f=o("replace"),p=!!/./[f]&&""===/./[f]("a","$0"),h=!i((function(){var e=/(?:)/,t=e.exec;e.exec=function(){return t.apply(this,arguments)};var n="ab".split(e);return 2!==n.length||"a"!==n[0]||"b"!==n[1]}));e.exports=function(e,t,n,f){var d=o(e),v=!i((function(){var t={};return t[d]=function(){return 7},7!=""[e](t)})),y=v&&!i((function(){var t=!1,n=/a/;return"split"===e&&((n={}).constructor={},n.constructor[s]=function(){return n},n.flags="",n[d]=/./[d]),n.exec=function(){return t=!0,null},n[d](""),!t}));if(!v||!y||"replace"===e&&(!l||!c||p)||"split"===e&&!h){var g=/./[d],m=n(d,""[e],(function(e,t,n,r,i){return t.exec===a?v&&!i?{done:!0,value:g.call(t,n,r)}:{done:!0,value:e.call(n,t,r)}:{done:!1}}),{REPLACE_KEEPS_$0:c,REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE:p}),b=m[0],x=m[1];r(String.prototype,e,b),r(RegExp.prototype,d,2==t?function(e,t){return x.call(e,this,t)}:function(e){return x.call(e,this)})}f&&u(RegExp.prototype[d],"sham",!0)}},9974:function(e,t,n){var r=n(3099);e.exports=function(e,t,n){if(r(e),void 0===t)return e;switch(n){case 0:return function(){return e.call(t)};case 1:return function(n){return e.call(t,n)};case 2:return function(n,r){return e.call(t,n,r)};case 3:return function(n,r,i){return e.call(t,n,r,i)}}return function(){return e.apply(t,arguments)}}},5005:function(e,t,n){var r=n(857),i=n(7854),o=function(e){return"function"==typeof e?e:void 0};e.exports=function(e,t){return arguments.length<2?o(r[e])||o(i[e]):r[e]&&r[e][t]||i[e]&&i[e][t]}},1246:function(e,t,n){var r=n(648),i=n(7497),o=n(5112)("iterator");e.exports=function(e){if(null!=e)return e[o]||e["@@iterator"]||i[r(e)]}},8554:function(e,t,n){var r=n(9670),i=n(1246);e.exports=function(e){var t=i(e);if("function"!=typeof t)throw TypeError(String(e)+" is not iterable");return r(t.call(e))}},647:function(e,t,n){var r=n(7908),i=Math.floor,o="".replace,a=/\$([$&'`]|\d\d?|<[^>]*>)/g,u=/\$([$&'`]|\d\d?)/g;e.exports=function(e,t,n,s,l,c){var f=n+e.length,p=s.length,h=u;return void 0!==l&&(l=r(l),h=a),o.call(c,h,(function(r,o){var a;switch(o.charAt(0)){case"$":return"$";case"&":return e;case"`":return t.slice(0,n);case"'":return t.slice(f);case"<":a=l[o.slice(1,-1)];break;default:var u=+o;if(0===u)return r;if(u>p){var c=i(u/10);return 0===c?r:c<=p?void 0===s[c-1]?o.charAt(1):s[c-1]+o.charAt(1):r}a=s[u-1]}return void 0===a?"":a}))}},7854:function(e,t,n){var r=function(e){return e&&e.Math==Math&&e};e.exports=r("object"==typeof globalThis&&globalThis)||r("object"==typeof window&&window)||r("object"==typeof self&&self)||r("object"==typeof n.g&&n.g)||function(){return this}()||Function("return this")()},6656:function(e){var t={}.hasOwnProperty;e.exports=function(e,n){return t.call(e,n)}},3501:function(e){e.exports={}},490:function(e,t,n){var r=n(5005);e.exports=r("document","documentElement")},4664:function(e,t,n){var r=n(9781),i=n(7293),o=n(317);e.exports=!r&&!i((function(){return 7!=Object.defineProperty(o("div"),"a",{get:function(){return 7}}).a}))},1179:function(e){var t=Math.abs,n=Math.pow,r=Math.floor,i=Math.log,o=Math.LN2;e.exports={pack:function(e,a,u){var s,l,c,f=new Array(u),p=8*u-a-1,h=(1<>1,v=23===a?n(2,-24)-n(2,-77):0,y=e<0||0===e&&1/e<0?1:0,g=0;for((e=t(e))!=e||e===1/0?(l=e!=e?1:0,s=h):(s=r(i(e)/o),e*(c=n(2,-s))<1&&(s--,c*=2),(e+=s+d>=1?v/c:v*n(2,1-d))*c>=2&&(s++,c/=2),s+d>=h?(l=0,s=h):s+d>=1?(l=(e*c-1)*n(2,a),s+=d):(l=e*n(2,d-1)*n(2,a),s=0));a>=8;f[g++]=255&l,l/=256,a-=8);for(s=s<0;f[g++]=255&s,s/=256,p-=8);return f[--g]|=128*y,f},unpack:function(e,t){var r,i=e.length,o=8*i-t-1,a=(1<>1,s=o-7,l=i-1,c=e[l--],f=127&c;for(c>>=7;s>0;f=256*f+e[l],l--,s-=8);for(r=f&(1<<-s)-1,f>>=-s,s+=t;s>0;r=256*r+e[l],l--,s-=8);if(0===f)f=1-u;else{if(f===a)return r?NaN:c?-1/0:1/0;r+=n(2,t),f-=u}return(c?-1:1)*r*n(2,f-t)}}},8361:function(e,t,n){var r=n(7293),i=n(4326),o="".split;e.exports=r((function(){return!Object("z").propertyIsEnumerable(0)}))?function(e){return"String"==i(e)?o.call(e,""):Object(e)}:Object},9587:function(e,t,n){var r=n(111),i=n(7674);e.exports=function(e,t,n){var o,a;return i&&"function"==typeof(o=t.constructor)&&o!==n&&r(a=o.prototype)&&a!==n.prototype&&i(e,a),e}},2788:function(e,t,n){var r=n(5465),i=Function.toString;"function"!=typeof r.inspectSource&&(r.inspectSource=function(e){return i.call(e)}),e.exports=r.inspectSource},9909:function(e,t,n){var r,i,o,a=n(8536),u=n(7854),s=n(111),l=n(8880),c=n(6656),f=n(5465),p=n(6200),h=n(3501),d=u.WeakMap;if(a){var v=f.state||(f.state=new d),y=v.get,g=v.has,m=v.set;r=function(e,t){return t.facade=e,m.call(v,e,t),t},i=function(e){return y.call(v,e)||{}},o=function(e){return g.call(v,e)}}else{var b=p("state");h[b]=!0,r=function(e,t){return t.facade=e,l(e,b,t),t},i=function(e){return c(e,b)?e[b]:{}},o=function(e){return c(e,b)}}e.exports={set:r,get:i,has:o,enforce:function(e){return o(e)?i(e):r(e,{})},getterFor:function(e){return function(t){var n;if(!s(t)||(n=i(t)).type!==e)throw TypeError("Incompatible receiver, "+e+" required");return n}}}},7659:function(e,t,n){var r=n(5112),i=n(7497),o=r("iterator"),a=Array.prototype;e.exports=function(e){return void 0!==e&&(i.Array===e||a[o]===e)}},3157:function(e,t,n){var r=n(4326);e.exports=Array.isArray||function(e){return"Array"==r(e)}},4705:function(e,t,n){var r=n(7293),i=/#|\.prototype\./,o=function(e,t){var n=u[a(e)];return n==l||n!=s&&("function"==typeof t?r(t):!!t)},a=o.normalize=function(e){return String(e).replace(i,".").toLowerCase()},u=o.data={},s=o.NATIVE="N",l=o.POLYFILL="P";e.exports=o},111:function(e){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},1913:function(e){e.exports=!1},7850:function(e,t,n){var r=n(111),i=n(4326),o=n(5112)("match");e.exports=function(e){var t;return r(e)&&(void 0!==(t=e[o])?!!t:"RegExp"==i(e))}},9212:function(e,t,n){var r=n(9670);e.exports=function(e){var t=e.return;if(void 0!==t)return r(t.call(e)).value}},3383:function(e,t,n){"use strict";var r,i,o,a=n(7293),u=n(9518),s=n(8880),l=n(6656),c=n(5112),f=n(1913),p=c("iterator"),h=!1;[].keys&&("next"in(o=[].keys())?(i=u(u(o)))!==Object.prototype&&(r=i):h=!0);var d=null==r||a((function(){var e={};return r[p].call(e)!==e}));d&&(r={}),f&&!d||l(r,p)||s(r,p,(function(){return this})),e.exports={IteratorPrototype:r,BUGGY_SAFARI_ITERATORS:h}},7497:function(e){e.exports={}},133:function(e,t,n){var r=n(7293);e.exports=!!Object.getOwnPropertySymbols&&!r((function(){return!String(Symbol())}))},590:function(e,t,n){var r=n(7293),i=n(5112),o=n(1913),a=i("iterator");e.exports=!r((function(){var e=new URL("b?a=1&b=2&c=3","http://a"),t=e.searchParams,n="";return e.pathname="c%20d",t.forEach((function(e,r){t.delete("b"),n+=r+e})),o&&!e.toJSON||!t.sort||"http://a/c%20d?a=1&c=3"!==e.href||"3"!==t.get("c")||"a=1"!==String(new URLSearchParams("?a=1"))||!t[a]||"a"!==new URL("https://a@b").username||"b"!==new URLSearchParams(new URLSearchParams("a=b")).get("a")||"xn--e1aybc"!==new URL("http://тест").host||"#%D0%B1"!==new URL("http://a#б").hash||"a1c3"!==n||"x"!==new URL("http://x",void 0).host}))},8536:function(e,t,n){var r=n(7854),i=n(2788),o=r.WeakMap;e.exports="function"==typeof o&&/native code/.test(i(o))},1574:function(e,t,n){"use strict";var r=n(9781),i=n(7293),o=n(1956),a=n(5181),u=n(5296),s=n(7908),l=n(8361),c=Object.assign,f=Object.defineProperty;e.exports=!c||i((function(){if(r&&1!==c({b:1},c(f({},"a",{enumerable:!0,get:function(){f(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var e={},t={},n=Symbol(),i="abcdefghijklmnopqrst";return e[n]=7,i.split("").forEach((function(e){t[e]=e})),7!=c({},e)[n]||o(c({},t)).join("")!=i}))?function(e,t){for(var n=s(e),i=arguments.length,c=1,f=a.f,p=u.f;i>c;)for(var h,d=l(arguments[c++]),v=f?o(d).concat(f(d)):o(d),y=v.length,g=0;y>g;)h=v[g++],r&&!p.call(d,h)||(n[h]=d[h]);return n}:c},30:function(e,t,n){var r,i=n(9670),o=n(6048),a=n(748),u=n(3501),s=n(490),l=n(317),c=n(6200)("IE_PROTO"),f=function(){},p=function(e){return"-->
+
+
+
+
+ Gavilan Intranet ->
+
+
+
+
+
+
+
+
+
+
+
+
+ Does something need changing? Please email:
+
Your dept chair
+ Your dean or division assistant
+ HR
+
+
+ In that order.
+
+
+
+
+
+
+
+
+
+
+
+ Alert message
+
+
+
+