From fed9789dee91a71d76fa50688f45eaaf904a751c Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Sun, 23 Jan 2022 19:00:49 +0000 Subject: [PATCH 01/26] Add services to client routes --- client_routes.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client_routes.php b/client_routes.php index 0b5ac1ce..831e6b2a 100644 --- a/client_routes.php +++ b/client_routes.php @@ -58,6 +58,9 @@ if(isset($_GET['tab'])){ elseif($_GET['tab'] == "documents"){ include("client_documents.php"); } + elseif($_GET['tab'] == "services"){ + include("client_services.php"); + } } else{ include("client_overview.php"); From d85b11fae8d9c537fab6fbdbaa70162039a4f2b8 Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Sun, 23 Jan 2022 21:11:19 +0000 Subject: [PATCH 02/26] Initial work for services module --- client_services.php | 116 +++++++++++++++++++++++++ client_side_nav.php | 13 +++ service_view_modal.php | 192 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 321 insertions(+) create mode 100644 client_services.php create mode 100644 service_view_modal.php diff --git a/client_services.php b/client_services.php new file mode 100644 index 00000000..3e05ec55 --- /dev/null +++ b/client_services.php @@ -0,0 +1,116 @@ + +
+
+

Services

+
+ +
+
+ +
+
+ + "> + + + + + + + + + + + $service_importance"; + }elseif($service_importance == "Medium"){ + $service_importance_display = "$service_importance"; + }elseif($service_importance == "Low"){ + $service_importance_display = "$service_importance"; + }else{ + $service_importance_display = "-"; + } + + + ?> + + + + + + + + + + + + + + + +
NameCategoryUpdatedImportanceAction
+ +
+
+
+
diff --git a/client_side_nav.php b/client_side_nav.php index e218e53f..db8632d9 100644 --- a/client_side_nav.php +++ b/client_side_nav.php @@ -140,6 +140,19 @@ + + "; +// } +// } +// +// // Showing explicitly linked URLs +// while($row = mysqli_fetch_array($sql_urls)){ +// if(!empty($row['service_uri'])){ +// echo "
  • $row[service_uri]
  • "; +// } +// } +// ?> + + From 301e6d94cd6453ec3c3351b1afb13c9f15ba8382 Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Thu, 27 Jan 2022 21:48:26 +0000 Subject: [PATCH 16/26] Add service logic. Removing URLs for now --- client_services.php | 2 +- post.php | 73 +++++++++++++++++++++++++++++++++++++++++++ service_add_modal.php | 6 ++-- 3 files changed, 77 insertions(+), 4 deletions(-) diff --git a/client_services.php b/client_services.php index 8747989f..773a3852 100644 --- a/client_services.php +++ b/client_services.php @@ -77,7 +77,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli,"SELECT FOUND_ROWS()")); insert_id; + + $service_contact_ids = $_POST['contacts']; + foreach($service_contact_ids as $contact_id){ + if(intval($contact_id)){ + mysqli_query($mysqli, "INSERT INTO service_contacts SET service_id = '$service_id', contact_id = '$contact_id'"); + } + } + + $service_vendor_ids = $_POST['vendors']; + foreach($service_vendor_ids as $vendor_id){ + if(intval($vendor_id)){ + mysqli_query($mysqli, "INSERT INTO service_vendors SET service_id = '$service_id', vendor_id = '$vendor_id'"); + } + } + + $service_document_ids = $_POST['documents']; + foreach($service_document_ids as $document_id){ + if(intval($document_id)){ + mysqli_query($mysqli, "INSERT INTO service_documents SET service_id = '$service_id', document_id = '$document_id'"); + } + } + + $service_asset_ids = $_POST['assets']; + foreach($service_asset_ids as $asset_id){ + if(intval($asset_id)){ + mysqli_query($mysqli, "INSERT INTO service_assets SET service_id = '$service_id', asset_id = '$asset_id'"); + } + } + + $service_login_ids = $_POST['logins']; + foreach($service_login_ids as $login_id){ + if(intval($login_id)){ + mysqli_query($mysqli, "INSERT INTO service_logins SET service_id = '$service_id', login_id = '$login_id'"); + } + } + + $service_domain_ids = $_POST['domains']; + foreach($service_domain_ids as $domain_id){ + if(intval($domain_id)){ + mysqli_query($mysqli, "INSERT INTO service_domains SET service_id = '$service_id', domain_id = '$domain_id'"); + } + } + + $_SESSION['alert_message'] = "Service added"; + header("Location: " . $_SERVER["HTTP_REFERER"]); + + } + else{ + $_SESSION['alert_message'] = "Something went wrong (SQL)"; + header("Location: " . $_SERVER["HTTP_REFERER"]); + } + + + + } if(isset($_POST['add_file'])){ diff --git a/service_add_modal.php b/service_add_modal.php index f335e517..37dc114e 100644 --- a/service_add_modal.php +++ b/service_add_modal.php @@ -60,7 +60,7 @@
    - + @@ -79,7 +79,7 @@ -
    +
    From 49d785259ba5a696a84c758da1f1244a0cebc9ad Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Thu, 27 Jan 2022 21:59:33 +0000 Subject: [PATCH 17/26] Add search --- client_services.php | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/client_services.php b/client_services.php index 773a3852..8fe658c2 100644 --- a/client_services.php +++ b/client_services.php @@ -1,7 +1,17 @@ @@ -14,6 +24,19 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli,"SELECT FOUND_ROWS()"));
    + +
    + + +
    + +
    + +
    +
    +
    +
    +
    "> From d2da0545e1fb0d12ed4c03925840df4f963dc59f Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Thu, 27 Jan 2022 22:03:43 +0000 Subject: [PATCH 18/26] Initial add service functionaliy complete --- client_services.php | 1 - service_add_modal.php | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/client_services.php b/client_services.php index 8fe658c2..d609e685 100644 --- a/client_services.php +++ b/client_services.php @@ -73,7 +73,6 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli,"SELECT FOUND_ROWS()")); $service_importance_display = "-"; } - ?> diff --git a/service_add_modal.php b/service_add_modal.php index 37dc114e..e7171277 100644 --- a/service_add_modal.php +++ b/service_add_modal.php @@ -95,7 +95,6 @@ -
    @@ -144,6 +143,9 @@ ?>
    + + +
    From e509cc5719bf3b21ce92b854273c4e86db91313e Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Thu, 27 Jan 2022 22:21:58 +0000 Subject: [PATCH 19/26] Add functionality to delete service --- client_services.php | 2 +- post.php | 21 +++++++++++++++++++++ service_add_modal.php | 2 +- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/client_services.php b/client_services.php index d609e685..9aeb6136 100644 --- a/client_services.php +++ b/client_services.php @@ -91,7 +91,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli,"SELECT FOUND_ROWS()")); diff --git a/post.php b/post.php index 0426ffac..16735899 100644 --- a/post.php +++ b/post.php @@ -5539,10 +5539,31 @@ if(isset($_POST['add_service'])){ $_SESSION['alert_message'] = "Something went wrong (SQL)"; header("Location: " . $_SERVER["HTTP_REFERER"]); } +} +if(isset($_GET['delete_service'])){ + $service_id = intval($_GET['delete_service']); + // Delete service + $delete_sql = mysqli_query($mysqli, "DELETE FROM services WHERE service_id = '$service_id' AND company_id = '$session_company_id'"); + // Delete relations + // TODO: Convert this to a join delete + if($delete_sql){ + mysqli_query($mysqli, "DELETE FROM service_contacts WHERE service_id = '$service_id'"); + mysqli_query($mysqli, "DELETE FROM service_vendors WHERE service_id = '$service_id'"); + mysqli_query($mysqli, "DELETE FROM service_documents WHERE service_id = '$service_id'"); + mysqli_query($mysqli, "DELETE FROM service_assets WHERE service_id = '$service_id'"); + mysqli_query($mysqli, "DELETE FROM service_logins WHERE service_id = '$service_id'"); + mysqli_query($mysqli, "DELETE FROM service_domains WHERE service_id = '$service_id'"); + $_SESSION['alert_message'] = "Service deleted"; + header("Location: " . $_SERVER["HTTP_REFERER"]); + } + else{ + $_SESSION['alert_message'] = "Something went wrong (SQL)"; + header("Location: " . $_SERVER["HTTP_REFERER"]); + } } if(isset($_POST['add_file'])){ diff --git a/service_add_modal.php b/service_add_modal.php index e7171277..02d20a83 100644 --- a/service_add_modal.php +++ b/service_add_modal.php @@ -2,7 +2,7 @@ - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/service_edit_modal.php b/service_edit_modal.php index 5e6d3dac..29e80173 100644 --- a/service_edit_modal.php +++ b/service_edit_modal.php @@ -1,7 +1,262 @@ -" tabindex="-1"> + + From ae6758346d4017bfd4fd1656cd623e712cbf6666 Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Fri, 28 Jan 2022 21:41:56 +0000 Subject: [PATCH 22/26] Adding edit functionaliy - WIP --- service_view_modal.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/service_view_modal.php b/service_view_modal.php index 9d686f53..23a118ee 100644 --- a/service_view_modal.php +++ b/service_view_modal.php @@ -27,6 +27,9 @@
    Assets
      $row[asset_name]"; } @@ -43,7 +46,7 @@ $network_names = []; $network_vlans = []; - // Reset the $sql_assets pointer to the start - as we've already cycled through once + // Reset the $sql_assets pointer to the start mysqli_data_seek($sql_assets, 0); // Get networks linked to assets - push their name and vlan to arrays @@ -118,6 +121,9 @@
      Domains
        0){ ?>
        Vendors
          @@ -161,6 +170,9 @@
          Contacts
            $row[contact_name]"; } @@ -176,7 +188,7 @@
            Logins
              Documents
                $row[document_name]"; } From 780e8354c7a577e4e9d0164c323ffcf8de9f8e84 Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Fri, 28 Jan 2022 22:10:34 +0000 Subject: [PATCH 23/26] Better handling of empty linked assets --- post.php | 60 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/post.php b/post.php index 16735899..d1d037fa 100644 --- a/post.php +++ b/post.php @@ -5489,45 +5489,57 @@ if(isset($_POST['add_service'])){ if($service_sql){ $service_id = $mysqli->insert_id; - $service_contact_ids = $_POST['contacts']; - foreach($service_contact_ids as $contact_id){ - if(intval($contact_id)){ - mysqli_query($mysqli, "INSERT INTO service_contacts SET service_id = '$service_id', contact_id = '$contact_id'"); + if(!empty($_POST['contacts'])){ + $service_contact_ids = $_POST['contacts']; + foreach($service_contact_ids as $contact_id){ + if(intval($contact_id)){ + mysqli_query($mysqli, "INSERT INTO service_contacts SET service_id = '$service_id', contact_id = '$contact_id'"); + } } } - $service_vendor_ids = $_POST['vendors']; - foreach($service_vendor_ids as $vendor_id){ - if(intval($vendor_id)){ - mysqli_query($mysqli, "INSERT INTO service_vendors SET service_id = '$service_id', vendor_id = '$vendor_id'"); + if(!empty($_POST['vendors'])){ + $service_vendor_ids = $_POST['vendors']; + foreach($service_vendor_ids as $vendor_id){ + if(intval($vendor_id)){ + mysqli_query($mysqli, "INSERT INTO service_vendors SET service_id = '$service_id', vendor_id = '$vendor_id'"); + } } } - $service_document_ids = $_POST['documents']; - foreach($service_document_ids as $document_id){ - if(intval($document_id)){ - mysqli_query($mysqli, "INSERT INTO service_documents SET service_id = '$service_id', document_id = '$document_id'"); + if(!empty($_POST['documents'])){ + $service_document_ids = $_POST['documents']; + foreach($service_document_ids as $document_id){ + if(intval($document_id)){ + mysqli_query($mysqli, "INSERT INTO service_documents SET service_id = '$service_id', document_id = '$document_id'"); + } } } - $service_asset_ids = $_POST['assets']; - foreach($service_asset_ids as $asset_id){ - if(intval($asset_id)){ - mysqli_query($mysqli, "INSERT INTO service_assets SET service_id = '$service_id', asset_id = '$asset_id'"); + if(!empty($_POST['assets'])){ + $service_asset_ids = $_POST['assets']; + foreach($service_asset_ids as $asset_id){ + if(intval($asset_id)){ + mysqli_query($mysqli, "INSERT INTO service_assets SET service_id = '$service_id', asset_id = '$asset_id'"); + } } } - $service_login_ids = $_POST['logins']; - foreach($service_login_ids as $login_id){ - if(intval($login_id)){ - mysqli_query($mysqli, "INSERT INTO service_logins SET service_id = '$service_id', login_id = '$login_id'"); + if(!empty($_POST['logins'])){ + $service_login_ids = $_POST['logins']; + foreach($service_login_ids as $login_id){ + if(intval($login_id)){ + mysqli_query($mysqli, "INSERT INTO service_logins SET service_id = '$service_id', login_id = '$login_id'"); + } } } - $service_domain_ids = $_POST['domains']; - foreach($service_domain_ids as $domain_id){ - if(intval($domain_id)){ - mysqli_query($mysqli, "INSERT INTO service_domains SET service_id = '$service_id', domain_id = '$domain_id'"); + if(!empty($_POST['logins'])){ + $service_domain_ids = $_POST['domains']; + foreach($service_domain_ids as $domain_id){ + if(intval($domain_id)){ + mysqli_query($mysqli, "INSERT INTO service_domains SET service_id = '$service_id', domain_id = '$domain_id'"); + } } } From f92dc13311142b41ad0b2233e4a64efd47f61049 Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Fri, 28 Jan 2022 22:20:40 +0000 Subject: [PATCH 24/26] Add service edit functionality --- client_services.php | 100 ++++++++++++++++++++--------------------- post.php | 80 +++++++++++++++++++++++++++++++++ service_edit_modal.php | 72 +++++++++++++++-------------- service_view_modal.php | 3 +- 4 files changed, 170 insertions(+), 85 deletions(-) diff --git a/client_services.php b/client_services.php index 6eb1ec6a..afd6e7a0 100644 --- a/client_services.php +++ b/client_services.php @@ -73,56 +73,6 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli,"SELECT FOUND_ROWS()")); $service_importance_display = "-"; } - - // Associated Assets (and their logins/networks/locations) - $sql_assets = mysqli_query($mysqli, "SELECT * FROM service_assets - LEFT JOIN assets - ON service_assets.asset_id = assets.asset_id - LEFT JOIN logins - ON service_assets.asset_id = logins.login_asset_id - LEFT JOIN networks - ON assets.asset_network_id = networks.network_id - LEFT JOIN locations - ON assets.asset_location_id = locations.location_id - WHERE service_id = '$service_id'"); - - // Associated logins - $sql_logins = mysqli_query($mysqli, "SELECT * FROM service_logins - LEFT JOIN logins - ON service_logins.login_id = logins.login_id - WHERE service_id = '$service_id'"); - - // Associated Domains - $sql_domains = mysqli_query($mysqli, "SELECT * FROM service_domains - LEFT JOIN domains - ON service_domains.domain_id = domains.domain_id - WHERE service_id = '$service_id'"); - - // Associated URLs - $sql_urls = mysqli_query($mysqli, "SELECT * FROM service_urls - WHERE service_id = '$service_id'"); - - // Associated Vendors - $sql_vendors = mysqli_query($mysqli, "SELECT * FROM service_vendors - LEFT JOIN vendors - ON service_vendors.vendor_id = vendors.vendor_id - WHERE service_id = '$service_id'"); - - // Associated Contacts - $sql_contacts = mysqli_query($mysqli, "SELECT * FROM service_contacts - LEFT JOIN contacts - ON service_contacts.contact_id = contacts.contact_id - WHERE service_id = '$service_id'"); - - // Associated Documents - $sql_docs = mysqli_query($mysqli, "SELECT * FROM service_documents - LEFT JOIN documents - ON service_documents.document_id = documents.document_id - WHERE service_id = '$service_id'"); - - include("service_edit_modal.php"); - include("service_view_modal.php"); - ?>
    @@ -148,6 +98,56 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli,"SELECT FOUND_ROWS()")); diff --git a/post.php b/post.php index d1d037fa..604691c6 100644 --- a/post.php +++ b/post.php @@ -5553,6 +5553,86 @@ if(isset($_POST['add_service'])){ } } +if(isset($_POST['edit_service'])){ + $client_id = intval($_POST['client_id']); + $service_id = intval($_POST['service_id']); + $service_name = trim(strip_tags(mysqli_real_escape_string($mysqli,$_POST['name']))); + $service_description = trim(strip_tags(mysqli_real_escape_string($mysqli,$_POST['description']))); + $service_category = trim(strip_tags(mysqli_real_escape_string($mysqli,$_POST['category']))); //TODO: Needs integration with company categories + $service_importance = trim(strip_tags(mysqli_real_escape_string($mysqli,$_POST['importance']))); + $service_notes = trim(strip_tags(mysqli_real_escape_string($mysqli,$_POST['note']))); + + // Update main service details + mysqli_query($mysqli, "UPDATE services SET service_name = '$service_name', service_description = '$service_description', service_category = '$service_category', service_importance = '$service_importance', service_notes = '$service_notes', service_updated_at = NOW() WHERE service_id = '$service_id' AND company_id = '$session_company_id'"); + + // Unlink existing relations/assets + mysqli_query($mysqli, "DELETE FROM service_contacts WHERE service_id = '$service_id'"); + mysqli_query($mysqli, "DELETE FROM service_vendors WHERE service_id = '$service_id'"); + mysqli_query($mysqli, "DELETE FROM service_documents WHERE service_id = '$service_id'"); + mysqli_query($mysqli, "DELETE FROM service_assets WHERE service_id = '$service_id'"); + mysqli_query($mysqli, "DELETE FROM service_logins WHERE service_id = '$service_id'"); + mysqli_query($mysqli, "DELETE FROM service_domains WHERE service_id = '$service_id'"); + + // Relink + if(!empty($_POST['contacts'])){ + $service_contact_ids = $_POST['contacts']; + foreach($service_contact_ids as $contact_id){ + if(intval($contact_id)){ + mysqli_query($mysqli, "INSERT INTO service_contacts SET service_id = '$service_id', contact_id = '$contact_id'"); + } + } + } + + if(!empty($_POST['vendors'])){ + $service_vendor_ids = $_POST['vendors']; + foreach($service_vendor_ids as $vendor_id){ + if(intval($vendor_id)){ + mysqli_query($mysqli, "INSERT INTO service_vendors SET service_id = '$service_id', vendor_id = '$vendor_id'"); + } + } + } + + if(!empty($_POST['documents'])){ + $service_document_ids = $_POST['documents']; + foreach($service_document_ids as $document_id){ + if(intval($document_id)){ + mysqli_query($mysqli, "INSERT INTO service_documents SET service_id = '$service_id', document_id = '$document_id'"); + } + } + } + + if(!empty($_POST['assets'])){ + $service_asset_ids = $_POST['assets']; + foreach($service_asset_ids as $asset_id){ + if(intval($asset_id)){ + mysqli_query($mysqli, "INSERT INTO service_assets SET service_id = '$service_id', asset_id = '$asset_id'"); + } + } + } + + if(!empty($_POST['logins'])){ + $service_login_ids = $_POST['logins']; + foreach($service_login_ids as $login_id){ + if(intval($login_id)){ + mysqli_query($mysqli, "INSERT INTO service_logins SET service_id = '$service_id', login_id = '$login_id'"); + } + } + } + + if(!empty($_POST['logins'])){ + $service_domain_ids = $_POST['domains']; + foreach($service_domain_ids as $domain_id){ + if(intval($domain_id)){ + mysqli_query($mysqli, "INSERT INTO service_domains SET service_id = '$service_id', domain_id = '$domain_id'"); + } + } + } + + $_SESSION['alert_message'] = "Service updated"; + header("Location: " . $_SERVER["HTTP_REFERER"]); + +} + if(isset($_GET['delete_service'])){ $service_id = intval($_GET['delete_service']); diff --git a/service_edit_modal.php b/service_edit_modal.php index 29e80173..89d1e8f1 100644 --- a/service_edit_modal.php +++ b/service_edit_modal.php @@ -10,6 +10,7 @@ +
    @@ -239,11 +235,19 @@ diff --git a/service_view_modal.php b/service_view_modal.php index 23a118ee..78335eec 100644 --- a/service_view_modal.php +++ b/service_view_modal.php @@ -188,8 +188,9 @@
    Logins
      Date: Fri, 28 Jan 2022 22:34:27 +0000 Subject: [PATCH 25/26] Add logging --- post.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/post.php b/post.php index 604691c6..0aa87eaf 100644 --- a/post.php +++ b/post.php @@ -5543,6 +5543,9 @@ if(isset($_POST['add_service'])){ } } + //Logging + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Service', log_action = 'Create', log_description = '$session_name created service $service_name', log_created_at = NOW(), log_client_id = $client_id, company_id = $session_company_id, log_user_id = $session_user_id"); + $_SESSION['alert_message'] = "Service added"; header("Location: " . $_SERVER["HTTP_REFERER"]); @@ -5628,6 +5631,9 @@ if(isset($_POST['edit_service'])){ } } + //Logging + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Service', log_action = 'Modified', log_description = '$session_name modified service $service_name', log_created_at = NOW(), company_id = $session_company_id, log_user_id = $session_user_id"); + $_SESSION['alert_message'] = "Service updated"; header("Location: " . $_SERVER["HTTP_REFERER"]); @@ -5649,6 +5655,9 @@ if(isset($_GET['delete_service'])){ mysqli_query($mysqli, "DELETE FROM service_logins WHERE service_id = '$service_id'"); mysqli_query($mysqli, "DELETE FROM service_domains WHERE service_id = '$service_id'"); + //Logging + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Service', log_action = 'Deleted', log_description = '$session_name deleted service $service_id', log_created_at = NOW(), company_id = $session_company_id, log_user_id = $session_user_id"); + $_SESSION['alert_message'] = "Service deleted"; header("Location: " . $_SERVER["HTTP_REFERER"]); } From e4db4808555a790df52a79ed761623a9afc52346 Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Fri, 28 Jan 2022 22:46:19 +0000 Subject: [PATCH 26/26] Fix network vlan duplicating --- service_view_modal.php | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/service_view_modal.php b/service_view_modal.php index 78335eec..1f3bd2bf 100644 --- a/service_view_modal.php +++ b/service_view_modal.php @@ -43,34 +43,31 @@ + if(!empty($networks)){ ?>
      Networks
        $network (VLAN: $vlan)"; - } + foreach($networks as $network){ + $network = explode(":", $network); + echo "
      • $network[0] (VLAN $network[1])
      • "; } // Not showing/haven't added explicitly linked networks - can't see a need for a network that doesn't have an asset on it?
    - -
    + +