Extracting Email Domain in MyPlayground - xcode

I'm developing a chat application. Users will be required to sign up using a university email address.
My app will heavily rely on compartmentalizing users using a UnivID (University ID) which will be the '#' symbol along with the email domain. For example, if a user signs up using any of the following email addresses : jsmith#mail.havard.edu, jsmith#havard.edu, or jsmith#student.havard.edu. The UnivID = '#havard.edu'
I'm new to coding so I hope not to insult your intelligence if this is easy to implement.
Cheers

Here is an algorithm I created to parse the domain and extension from an email address. I used a hardcoded list of the most common domain suffixes to help ensure I don't return just the suffix part of the email if it has a 2 part domain suffix, like "co.uk" or "ca.gov".
You would just need to prepend "#" onto the resulting domain for your use case.
class func parseDomain(fromEmail email: String) -> String? {
let suffixList = ["com", "edu", "gov", "int", "mil", "net", "org", "xyz", "biz", "info", "ai", "io", "co", "ly", "eu", "cn", "ru", "nl", "de", "uk"]
guard let emailDomains = email.components(separatedBy: "#").last else {
return nil
}
let domainParts = emailDomains.components(separatedBy: ".")
guard domainParts.count >= 2 else {
return nil
}
var domain = domainParts[domainParts.count - 2] + "." + domainParts[domainParts.count - 1]
let secondLastComponent = domainParts[domainParts.count - 2]
if suffixList.contains(secondLastComponent) && domainParts.count >= 3 {
// we want to avoid returning things like co.uk, or com.au,
// so if the 2nd last component is a common suffix, return the last 3 parts instead.
domain = domainParts[domainParts.count - 3] + "." + domainParts[domainParts.count - 2] + "." + domainParts[domainParts.count - 1]
}
return domain
}

Latest 2020, Swift 5.2, XCode 11.4.1
Code that works for all inputs
let example = "email_id#gmail.com"
let components = example.components(separatedBy: "#")
if components.count > 1 {
let domain = components[1]
// domain has value gmail.com
}

I assume that you actually want everything after the ampersand. If that is the case then this code will work.
let example = "jsmith#student.harvard.edu"
let univId = "#" + example.componentsSeparatedByString("#")[1]
// "#student.harvard.edu"
If you really only want the last two parts of an extended domain string then this will work.
let example = "jsmith#student.harvard.edu"
let domain = example.componentsSeparatedByString("#")
let parts = domain.componentsSeparatedByString(".")
let univId = "#" + parts[parts.count - 2] + "." + parts[parts.count - 1]
// #harvard.edu

Related

Using Find to find a user property in Outlook/Redemption

I'm trying to return a single calendaritem from Outlook from our C# windows desktop application. It keeps returning this error:
Redemption.RDOItems
Assertion failed: Number of fields == 1.
I use similar code in an Outlook addin I created and it works fine. The main difference is the filterprefix.
In the AddIn I use:
string filterprefix = "[" + OurCustomProperty.OurItemId + "] = '";
var filter1 = filterprefix + parentItem.NeedlesId + "'";
var findItem = folder.Items.Find(filter1);
but this code does not work from our desktop app.
Here is the code from the desktop App which is returning the error:
The appointment.Id contains a valid value which we set when we create the item.
string Filterprefix = "#SQL="+"http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/OurCustomProperty.OurItemId/0x0000001f = '";
RDOSession rdoSession = new RDOSession();
rdoSession.Logon("", "", false, false, null, false);
RDOFolder folderRDO = rdoSession.GetDefaultFolder(rdoDefaultFolders.olFolderCalendar);
var filter1 = filterprefix + appointment.Id + "'";
string ls_find = Filterprefix + appointment.Id + "'" ;
var findItem = folderRDO.Items.Find(ls_find);
I've tried several variations of the syntax but can't seem to get it right.
I also tried using Sort then Restrict but no luck with that either.
Thanks, Rick
RDOItems.Find takes a SQL statement, please do not use the #SQL= prefix - it is OOM specific. Also do not forget to doublequote the DASL property name:
"http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/OurCustomProperty.OurItemId/0x0000001f" = '<some value>'

Servicenow script infinite recursion

I have the following ServiceNow script which inserts the record into live_message table.
(function executeRule(current, previous/*null when async*/) {
var requestBody;
var responseBody;
var status;
var request;
var response;
try {
request = new sn_ws.RESTMessageV2("LiveMessageWebhook", "post");
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
var parameters = "&chat_message=" + current.chat_message.toString();
parameters = parameters + "&context=" + current.context.toString();
parameters = parameters + "&formatted_message=" + current.formatted_message.toString();
parameters = parameters + "&has_attachments=" + current.has_attachments.toString();
parameters = parameters + "&has_links=" + current.has_links.toString();
parameters = parameters + "&has_tags=" + current.has_tags.toString();
parameters = parameters + "&ID=" + current.id.toString();
parameters = parameters + "&in_reply_to=" + current.in_reply_to.toString();
parameters = parameters + "&isLiked=" + current.is_liked.toString();
parameters = parameters + "&lastActivity=" + current.last_activity.toString();
parameters = parameters + "&lastMessage=" + current.last_message.toString();
parameters = parameters + "&likeCount=" + current.like_count.toString();
parameters = parameters + "&message=" + current.message.toString();
parameters = parameters + "&next_reply_order_chunk=" + current.next_reply_order_chunk.toString();
parameters = parameters + "&order=" + current.order.toString();
parameters = parameters + "&poll=" + current.poll.toString();
parameters = parameters + "&private=" + current.private_message.toString();
parameters = parameters + "&profile=" + current.profile.toString();
parameters = parameters + "&reflected_field=" + current.reflected_field.toString();
parameters = parameters + "&reply_to=" + current.reply_to.toString();
parameters = parameters + "&state=" + current.state.toString();
parameters = parameters + "&group_type=" + current.sys_class_name.toString();
parameters = parameters + "&created_by=" + current.sys_created_by.toString();
parameters = parameters + "&created_on=" + current.sys_created_on.toString();
parameters = parameters + "&domain=" + current.sys_domain.toString();
parameters = parameters + "&domain_path=" + current.sys_domain_path.toString();
parameters = parameters + "&sys_ID=" + current.sys_id.toString();
parameters = parameters + "&to_profile=" + current.sys_domain.toString();
parameters = parameters + "&updates=" + current.sys_mod_count.toString();
parameters = parameters + "&updated_by=" + current.sys_updated_by.toString();
parameters = parameters + "&updated_on=" + current.sys_updated_on.toString();
request.setRequestBody(encodeURI(parameters));
var l = request.getRequestBody();
response = request.execute();
responseBody = response.haveError()
? response.getErrorMessage()
: response.getBody();
status = response.getStatusCode();
{
var gr = new GlideRecord('live_message');
gr.initialize();
gr.chat_message = current.chat_message;
gr.context = current.context.toString();
gr.formatted_message = "abc";
gr.group = current.group;
gr.has_attachments = current.has_attachments;
gr.has_links = current.has_links;
gr.has_tags = current.has_tags;
gr.id = current.id;
gr.in_reply_to = "admin";
gr.is_liked = current.is_liked;
gr.last_activity = current.last_activity;
gr.last_message = current.last_message;
gr.like_count = current.like_count;
gr.message = "abc";
gr.next_reply_order_chunk = current.next_reply_order_chunk;
gr.order = current.order;
gr.poll = current.poll;
gr.private_message = current.private_message;
gr.profile = current.profile;
gr.reflected_field = current.reflected_field;
gr.reply_to = current.reply_to;
gr.state = current.state;
gr.sys_class_name = current.sys_class_name;
gr.sys_created_by = current.sys_created_by;
gr.sys_created_on = current.sys_created_on;
gr.sys_domain = current.sys_domain;
gr.sys_domain_path = current.sys_domain_path;
gr.sys_mod_count = current.sys_mod_count;
gr.sys_updated_by = current.sys_updated_by;
gr.sys_updated_on = current.sys_updated_on;
gr.to_profile = current.to_profile;
gr.insertWithReferences();
}
} catch (ex) {
responseBody = 'Exception: ' + ex;
status = '900';
requestBody = request
? request.getRequestBody()
: null;
} finally {
gs.info("Final: Request Body: " + requestBody);
gs.info("Final: Response: " + responseBody);
gs.info("Final: HTTP Status: " + status);
gs.addInfoMessage('Final: Finished');
}
})(current, previous);
But after inserting the record it again goes back to the try block again and does the whole thing again and now with the inserted record
How is this business rule configured?
Is it possible that the changes made by this script, could also trigger the script to run?
Here's an example of what I mean:
Imagine I have a business rule that executes whenever a record in the table "u_arbitrary_counter" is updated.
Imagine that the function of this business rule is that whenever such a record is updated, we increase the value of the "u_counter" field by one, like so:
current.setValue('u_counter', parseInt(current.getValue('u_counter')) + 1);
current.update();
By using .update(), I'm forcing an update to the database, EVEN if this is a "before" business rule.
Pro Tip: Note that "before" business rules run on the data that's about to be
saved to the database, BEFORE the actual database operation has taken
place. Any changes to the "current" object in a "before" business rule
will be saved even without using current.update, because you're
modifying the data that's about to be sent to the database anyway, in
the natural course of this operation.
So using current.update() in a BEFORE business rule isn't a great idea. For the same reason though, performing any other operation which necessarily leads to a database update which could trigger this same business rule is a bad idea. It doesn't have to be current.update() -- Instead, imagine if rather than updating the current record, I did something like...
var gr = new GlideRecord('u_arbitrary_counter'); //the same table this BR is running on
gr.initialize();
gr.setValue('u_counter', parseInt(current.getValue('u_counter')) + 1);
gr.insert(); //This triggers a database action!
This is no good for the same reason.
Ditto for any REST calls which would trigger a DB action on this table which may trigger this business rule.
The solution
If this is indeed the cause of your issue (and without knowing the configuration of your business rule, I can't be sure if it is or not), there is actually a way to tell the system not to run any further business rules as a result of the operation your script performs. Right before your gr.insertWithReferences(); line (line 91), IF that block of code is the issue (which I'm fairly confident it is), add:
gr.setWorkflow(false);
This prevents business rules from running.
Unfortunately, since you're placing the record into the live_message table, that may not be a good idea either, since the messenger may require some business rule to propagate or present that information once inserted; I'm not sure.
If that is the case, I would recommend adding a condition to your business rule so that it only runs under certain circumstances, and then craft your inserted record to not meet those criteria.
Pro Tip: PS - I notice you access a table field using current.field_name.toString() in some places, and directly access
current.field_name in others. While the former is acceptable (not
that I recommend it in most cases), the latter should almost never be
used -- except in the case of journal fields. Instead, I strongly
recommend using the appropriate getter/setter methods, to avoid
pass-by-reference issues and confusion, and to ensure you're not
relying on JavaScript's coersion, which doesn't always play nice with
Mozilla Rhino, which ServiceNow runs on the back-end. Example issue
here. For more info, please see my article on using getValue()
and setValue() in ServiceNow.

Count number of dictionarys in dictionary in swift

I have a buch of accounts stored in a string dictionary and i would like to count the number of accounts existing, so basicly a ".count" but to find the number of dictionaries created.
var dictionary: [String : [ String ]] = ["" : []]
let storeString = "StoreString"
func addUpdateArray(strings: [String], index: Int) {
let locator = storeString + index.description
dictionary[locator] = strings
}
addUpdateArray(["Account1", "Hy"], 1)
addUpdateArray(["Account2", "Hey"], 3)
and now I would like to see how many accounts are have created of the kind dictionary, is ther a way?
Something like this?
var accounts = [String:[String:String]]() // or whatever your structure is
accounts["Edmund"] = [
"amount": "23.87",
"curreny": "dollars"
]
accounts["Baldrick"] = [
"amount": "23.87",
"curreny": "dollars"
]
accounts["Percy"] = [
"amount": "87.00",
"curreny": "peso"
]
println(accounts.keys.array.count) // 3
If you have dictionary of dictionaries and you want to count the number of actual values inside, you can do it like this:
var accounts = [
"accountsGroup1" : ["account1", "account2", "account3", "account4"],
"accountsGroup2" : ["account1", "account2"],
"accountsGroup3" : ["account1", "account2", "account3", "account4"]
]
let accountsCount = accounts.values.map { $0.count }
let numberOfAllAccounts = reduce(accountsCount, 0) { $0 + $1 }
println(numberOfAllAccounts)

How to query from URL "Line" Format to VBA variable

I'm trying to make an application that will display user data through api on command... I have assembled the URL generator and everything. it's just beyond me to find a simple way to assign THIS: "http://api.bf4stats.com/api/playerInfo?plat=xbox&name=charlie%20is%20tftc&output=lines" data to specific variables with my parameters. (Lines / Text format)
This is my code so far, I just want to be able to assign data like 'player.id' to playerid and display it. (Player.id is the first value in the data linked above)
//the code below will be changed to user input, I don't need help with that this was just for theory
Public Class Form1
Public Sub URL_Player_Info(ByVal Address As String)
'Assign all data figures for constructing the "URL"...
Dim url, plat, player, webprefix, domain, paramsym, ext, preplat, preplayer, andsym, lineparam, format As String
'Variables for "Plat"
plat = "xbox"
'Input for "Player"
player = "Charlie Is TFTC"
'Structure for "URL"
webprefix = "http://"
domain = "api.bf4stats"
ext = ".com/api/playerInfo"
paramsym = "?"
preplat = "plat="
andsym = "&"
preplayer = "name="
format = "output="
lineparam = "lines"
'Generate Final "URL"
url = webprefix + domain + ext + paramsym + preplat + plat + andsym + preplayer + player + andsym + format + lineparam
'Getting Data / Assigning Data for "Plat. Player: Params"
End Sub
Thanks in advanced!

Dynamic Expression API (Dynamic.cs) Not properly parsing expression in .net 3.5

I'm having trouble getting this API working in .net 3.5 (works fine in 4.0). Basically I have following code
List<ParameterExpression> parameters = new List<ParameterExpression>();
parameters.Add(Expression.Parameter(typeof(double), "R0C6"));
parameters.Add(Expression.Parameter(typeof(double), "R0C7"));
parameters.Add(Expression.Parameter(typeof(double), "R0C8"));
parameters.Add(Expression.Parameter(typeof(double), "R0C9"));
parameters.Add(Expression.Parameter(typeof(double), "R0C10"));
parameters.Add(Expression.Parameter(typeof(double), "R0C11"));
parameters.Add(Expression.Parameter(typeof(double), "R0C12"));
LambdaExpression e = DynamicExpressionBuilder.ParseLambda(
parameters.ToArray(), typeof(double), "R0C6 + R0C7 + R0C8 + R0C9 + R0C10 + R0C11 + R0C12");
var result = e.Compile().DynamicInvoke(1, 1, 1, 1, 1, 1, 1);
Console.WriteLine(result);
When running this code I get ArgumentException. The reason being .NET 3.5 does not have Func delegate which takes more than 4 parameters. Can someone suggest me change in Dynamic.cs so that I can get able code working in 3.5?
Yes thats one alternative. Here is the code that worked for me
List<ParameterExpression> parameters = new List<ParameterExpression>();
parameters.Add(Expression.Parameter(typeof(Holder), "H"));
LambdaExpression e = DynamicExpressionBuilder.ParseLambda(parameters.ToArray(), typeof(double), "H.R0C6 + H.R0C7 + H.R0C8 + H.R0C9 + H.R0C10 + H.R0C11 + H.R0C12");
var result = e.Compile().DynamicInvoke(new Holder { R0C6 = 1, R0C7 = 1, R0C8 = 1, R0C9 = 1, R0C10 = 1, R0C11 = 1, R0C12 = 1 });
Console.WriteLine(result);
But surely there should be better way of achieving my original implementation.
Is there a reason that you can't combine all the doubles into a single parameter object that contains fields or properties for the values? Then you'd only need one parameter in your Func for the expression.

Resources