Skip to content

Commit ac1cd15

Browse files
Merge branch 'ServiceNowDevProgram:main' into Branch-3
2 parents 22a222a + b0ff8ee commit ac1cd15

File tree

12 files changed

+272
-15
lines changed

12 files changed

+272
-15
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
(function() {
2+
var priorities = {};
3+
var agg = new GlideAggregate('incident');
4+
agg.addAggregate('COUNT');
5+
agg.groupBy('priority');
6+
agg.query();
7+
while (agg.next()) {
8+
var priority = agg.getDisplayValue('priority') || 'No Priority Set';
9+
var count = agg.getAggregate('COUNT');
10+
priorities[priority] = parseInt(count, 10);
11+
}
12+
for (var priority in priorities) {
13+
gs.info('Priority: ' + priority + ' | Count: ' + priorities[priority]);
14+
}
15+
})();
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//To get the incident count based on priority.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
How often we come across cases where reports are created with same name by different users. Well to maintain some uniquenss across why not have some controls to get it unified. Below script can be used to suffix 'Created by' to the report to help uniquely identify report.
2+
Execute it as a background script to update it in bulk.
3+
For example Report named ABC will becom ABC - [PQR]v1 and ABC - [XYZ]v2 where PQR and XYZ are created by users
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
var ar = [];
2+
var dupCheck = new GlideAggregate('sys_report');
3+
dupCheck.addEncodedQuery('titleISNOTEMPTY');
4+
dupCheck.addNotNullQuery('title');
5+
dupCheck.groupBy('title');
6+
dupCheck.addAggregate('COUNT', 'title');
7+
dupCheck.addHaving('COUNT', '>', 1);
8+
dupCheck.query();
9+
while (dupCheck.next()) {
10+
ar.push(dupCheck.getValue("title"));
11+
}
12+
13+
for(var i = 0 ; i< ar.length; i++){
14+
var report = new GlideRecord("sys_report");
15+
report.addQuery("title",ar[i]);
16+
report.query();
17+
var c= 0;
18+
while(report.next()){
19+
c++;
20+
var user = new GlideRecord("sys_user");
21+
user.addQuery("email",report.sys_created_by.toString());
22+
user.query();
23+
if(user.next()){
24+
var name = user.name;
25+
}
26+
27+
if(name){
28+
report.title = report.title+" "+' - [' + name + ']'+" "+"v"+c; // Report named ABC will now be ABC - [PQR]v1 and ABC - [XYZ]v2 where PQR and XYZ are created by users
29+
report.setWorkflow(false);
30+
report.autoSysFields(false);
31+
report.update();
32+
}
33+
else {
34+
report.title = report.title+" "+"v"+c;
35+
report.setWorkflow(false);
36+
report.autoSysFields(false);
37+
report.update();
38+
39+
}
40+
}
41+
42+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//Scenario: whenever a user submits a ticket (Incident, HR Case, etc.), the system analyzes the tone of the message - like frustrated, urgent, calm, confused
2+
// and automatically adjusts the ticket priority, or routes it to a specific team (like “Empathy Response Desk)
3+
4+
var EmotionAnalyzer = Class.create();
5+
EmotionAnalyzer.prototype = {
6+
initialize: function() {},
7+
8+
detectEmotion: function(text) {
9+
try {
10+
// ---- Mock Sentiment Logic (No external API) ----
11+
text = text.toLowerCase();
12+
var score = 0;
13+
var negativeWords = ['angry', 'frustrated', 'bad', 'urgent', 'hate', 'delay'];
14+
var positiveWords = ['thank', 'happy', 'great', 'awesome', 'love'];
15+
16+
negativeWords.forEach(function(word) {
17+
if (text.includes(word)) score -= 1;
18+
});
19+
positiveWords.forEach(function(word) {
20+
if (text.includes(word)) score += 1;
21+
});
22+
23+
var sentiment = (score > 0) ? 'positive' : (score < 0) ? 'negative' : 'neutral';
24+
return { sentiment: sentiment, score: Math.abs(score / 3) };
25+
} catch (e) {
26+
gs.error("EmotionAnalyzer error: " + e.message);
27+
return { sentiment: 'neutral', score: 0 };
28+
}
29+
},
30+
31+
type: 'EmotionAnalyzer'
32+
};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
### Overview
2+
The **Emotion-Aware Ticket Prioritizer** is an AI-driven innovation for ServiceNow that automatically analyzes the tone and emotion of user-submitted tickets (Incidents, HR Cases, etc.) to determine the urgency and emotional state of the user.
3+
If frustration or urgency is detected, the system dynamically increases the **priority**, adds contextual **work notes**, and routes the ticket to the right team — ensuring faster resolution and better user experience.
4+
5+
---
6+
7+
## How It Works
8+
1. When a ticket is created, a **Business Rule** triggers a **Script Include** (`EmotionAnalyzer`).
9+
2. The Script Include analyzes the short description and description text.
10+
3. It detects emotional tone — *positive*, *neutral*, or *negative*.
11+
4. Based on sentiment, the system:
12+
- Adjusts **priority** automatically
13+
- Adds a **work note** with detected emotion
14+
- Optionally, notifies the support team for urgent or frustrated cases
15+
16+
---
17+
## How It Trigger Script Include Via Business Rule
18+
1. Create object of Script Include (Accessible from all scopes)
19+
var util = new global.EmotionAnalyzer();
20+
21+
----
22+
## Example line as input and output
23+
| User Input | Detected Emotion | Auto Priority | Output |
24+
| -------------------------------------- | ---------------- | ------------- | --------------------- |
25+
| “Laptop crashed again, no one helps!” | Negative | 1 (Critical) | Escalate to VIP queue |
26+
| “Thank you, system working great now!” | Positive | 4 (Low) | No action |
27+
| “Need help resetting my password.” | Neutral | 3 (Moderate) | Normal SLA |
28+
29+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
## Incident Root-Cause Predictor
2+
3+
### Overview
4+
The **Incident Root-Cause Predictor** automatically classifies incoming Incidents into categories like *Network, Hardware, Application,* or *Security* based on keywords in the description.
5+
This helps in faster triaging and routing tickets to the right support teams.
6+
7+
---
8+
9+
## How It Works
10+
1. A user submits an Incident.
11+
2. A **Business Rule** runs on insert.
12+
3. It calls the **Script Include – `RootCausePredictor`**.
13+
4. The predictor scans the description and returns a probable root-cause category.
14+
15+
---
16+
## Business Rule Script (How to call Script Include on BR)
17+
var util = new global.RootCausePredictor();
18+
19+
(function executeRule(current) {
20+
var util = new global.RootCausePredictor();
21+
var cat = util.predict(current.description);
22+
current.u_root_cause = cat;
23+
current.work_notes = "Auto-classified as: " + cat.toUpperCase();
24+
})(current);
25+
26+
--------------
27+
## Sample Input and Output
28+
Input : A user logs a ticket:
29+
“Wi-Fi keeps disconnecting every few minutes.”
30+
31+
The Script Include scans for the word “Wi-Fi”, which matches the Network keyword list.
32+
OutPut:
33+
34+
System automatically sets field u_root_cause = "Network"
35+
Work note added: “Auto-classified as: NETWORK”
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//Scenario : Automatically detect the root cause category of an Incident based on keywords in the short description or description.
2+
3+
// Script Include
4+
var RootCausePredictor = Class.create();
5+
RootCausePredictor.prototype = {
6+
predict: function(text) {
7+
var data = {
8+
network: ['router', 'switch', 'wifi', 'dns'],
9+
hardware: ['laptop', 'keyboard', 'printer', 'battery'],
10+
application: ['login', 'error', 'bug', 'page'],
11+
security: ['virus', 'attack', 'unauthorized']
12+
};
13+
text = text.toLowerCase();
14+
for (var cat in data) {
15+
for (var i = 0; i < data[cat].length; i++) {
16+
if (text.includes(data[cat][i])) return cat;
17+
}
18+
}
19+
return 'general';
20+
},
21+
type: 'RootCausePredictor'
22+
};
Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,48 @@
1-
## Email Address Validation
1+
# Email Address Validation
22

3-
This regular expression checks if the provided string matches the common pattern for email addresses.
3+
This project provides email validation functionality in pure JavaScript. It includes a refactored regex implementation that covers common RFC 5322 patterns and stricter domain rules.
44

5-
**Please note that the code is based on ES2021, and as such, will not work in the global scope or scopes that are not ES2021 compatible.**
5+
---
66

7-
^[a-zA-Z0-9._%+-]+: Matches one or more characters that can be letters (both uppercase and lowercase), digits, dots, underscores, percent signs, or plus or hyphen signs at the start of the string.
8-
@: Matches the "@" symbol.
9-
[a-zA-Z0-9.-]+: Matches one or more characters that can be letters, digits, dots, or hyphens in the domain part of the email address.
10-
\.: Matches a dot.
11-
[a-zA-Z]{2,}$: Matches two or more letters at the end of the string, representing the top-level domain (TLD) of the email address.
7+
## Refactored Email Validation (2025 Update)
8+
9+
The regex has been improved to handle edge cases in the local part, domain, and top-level domain (TLD).
10+
11+
### Key Features
12+
13+
- Supports letters, digits, and allowed special characters in the local part:
14+
`!#$%&'*+/=?^_`{|}~-`
15+
- Supports dots in the local part, but not consecutive dots.
16+
- Supports quoted local parts, e.g., `"john.doe"@example.com`.
17+
- Validates domain labels:
18+
- Letters, digits, and hyphens (`-`)
19+
- Labels cannot start or end with a hyphen
20+
- No consecutive dots
21+
- Restricts TLD length to 2–63 characters.
22+
- Supports IPv4/IPv6 literals in brackets, e.g., `user@[192.168.0.1]`.
23+
24+
### Example Usage
25+
26+
```js
27+
const emailRegex = /^(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:(?:\\[\x00-\x7f]|[^\\"\r\n])*)")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,63}|\[(?:(?:25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})\.){3}(?:25[0-5]|2[0-4][0-9]|1?[0-9]{1,2}|[a-zA-Z0-9-]*[a-zA-Z0-9]:[^\]]+)\])$/;
28+
29+
function validateEmail(email) {
30+
return emailRegex.test(email);
31+
}
32+
33+
const emails = [
34+
"example@email.com",
35+
"user.name+tag@example.co.uk",
36+
'"quoted.user"@example.com',
37+
"user@[192.168.1.1]",
38+
"user@-example.com",
39+
"user@example..com",
40+
"user@example-.com",
41+
"user@.example.com"
42+
];
43+
44+
emails.forEach(email => {
45+
console.log(email, validateEmail(email)
46+
? "is valid"
47+
: "is invalid");
48+
});
Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
1-
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
1+
//const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
22

3-
const email = "example@email.com";
3+
//refactor emailRegex
4+
const emailRegex = /^(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:(?:\\[\x00-\x7f]|[^\\"\r\n])*)")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,63}|\[(?:(?:25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})\.){3}(?:25[0-5]|2[0-4][0-9]|1?[0-9]{1,2}|[a-zA-Z0-9-]*[a-zA-Z0-9]:[^\]]+)\])$/;
45

5-
if (emailRegex.test(email)) {
6-
console.log("Valid email address");
7-
} else {
8-
console.log("Invalid email address");
9-
}
6+
const emails = [
7+
// Valid emails
8+
"example@email.com",
9+
"user.name+tag@example.co.uk",
10+
'"quoted.user"@example.com',
11+
"user@[192.168.1.1]",
12+
13+
// Invalid emails (should fail)
14+
"user@-example.com",
15+
"user@example..com",
16+
"user@example-.com",
17+
"user@.example.com"
18+
];
19+
20+
emails.forEach(email => {
21+
console.log(email, emailRegex.test(email) ? "is valid email addres" : "is invalid email address");
22+
});

0 commit comments

Comments
 (0)