From d7392ce856fb18715f3d2e6e5700bb7f8425340f Mon Sep 17 00:00:00 2001 From: Maxim Shafirov Date: Wed, 24 Sep 2014 16:02:00 +0400 Subject: [PATCH] Kotlin port --- .idea/.name | 1 + .idea/artifacts/swot_jar.xml | 8 ++ .idea/compiler.xml | 23 ++++ .idea/copyright/profiles_settings.xml | 3 + .idea/encodings.xml | 5 + .idea/libraries/KotlinJavaRuntime.xml | 11 ++ .idea/misc.xml | 13 ++ .idea/modules.xml | 9 ++ .idea/scopes/scope_settings.xml | 5 + .idea/uiDesigner.xml | 125 +++++++++++++++++++ .idea/vcs.xml | 7 ++ lib/domains/blacklist.txt | 4 + lib/domains/tlds.txt | 162 ++++++++++++++++++++++++ lib/swot.rb | 72 ----------- lib/swot/academic_tlds.rb | 169 -------------------------- src/swot/Swot.kt | 58 +++++++++ swot.iml | 14 +++ 17 files changed, 448 insertions(+), 241 deletions(-) create mode 100644 .idea/.name create mode 100644 .idea/artifacts/swot_jar.xml create mode 100644 .idea/compiler.xml create mode 100644 .idea/copyright/profiles_settings.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/libraries/KotlinJavaRuntime.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/scopes/scope_settings.xml create mode 100644 .idea/uiDesigner.xml create mode 100644 .idea/vcs.xml create mode 100644 lib/domains/blacklist.txt create mode 100644 lib/domains/tlds.txt delete mode 100644 lib/swot.rb delete mode 100644 lib/swot/academic_tlds.rb create mode 100644 src/swot/Swot.kt create mode 100644 swot.iml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000000..ed0c9d1de0 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +swot \ No newline at end of file diff --git a/.idea/artifacts/swot_jar.xml b/.idea/artifacts/swot_jar.xml new file mode 100644 index 0000000000..a1a00a80d5 --- /dev/null +++ b/.idea/artifacts/swot_jar.xml @@ -0,0 +1,8 @@ + + + $PROJECT_DIR$/out/artifacts/ + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000000..217af471a9 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000000..e7bedf3377 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000000..e206d70d85 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/libraries/KotlinJavaRuntime.xml b/.idea/libraries/KotlinJavaRuntime.xml new file mode 100644 index 0000000000..0b98ab4814 --- /dev/null +++ b/.idea/libraries/KotlinJavaRuntime.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000000..df290d270c --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,13 @@ + + + + + + + + + + $USER_HOME$/.subversion + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000000..0e533163bf --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000000..922003b843 --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000000..3b00020308 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000..275077f825 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/lib/domains/blacklist.txt b/lib/domains/blacklist.txt new file mode 100644 index 0000000000..d18bcf8d23 --- /dev/null +++ b/lib/domains/blacklist.txt @@ -0,0 +1,4 @@ +si.edu +america.edu +californiacolleges.edu +maricopa.edu diff --git a/lib/domains/tlds.txt b/lib/domains/tlds.txt new file mode 100644 index 0000000000..d983ba0fc4 --- /dev/null +++ b/lib/domains/tlds.txt @@ -0,0 +1,162 @@ +ac.ae +ac.at +ac.bd +ac.be +ac.cn +ac.cr +ac.cy +ac.fj +ac.gg +ac.gn +ac.id +ac.il +ac.in +ac.ir +ac.jp +ac.ke +ac.kr +ac.ma +ac.me +ac.mu +ac.mw +ac.mz +ac.ni +ac.nz +ac.om +ac.pa +ac.pg +ac.pr +ac.rs +ac.ru +ac.rw +ac.sz +ac.th +ac.tz +ac.ug +ac.uk +ac.yu +ac.za +ac.zm +ac.zw +ed.ao +ed.cr +ed.jp +edu +edu.af +edu.al +edu.ar +edu.au +edu.az +edu.ba +edu.bb +edu.bd +edu.bh +edu.bi +edu.bn +edu.bo +edu.br +edu.bs +edu.bt +edu.bz +edu.ck +edu.cn +edu.co +edu.cu +edu.do +edu.dz +edu.ec +edu.ee +edu.eg +edu.er +edu.es +edu.et +edu.ge +edu.gh +edu.gr +edu.gt +edu.hk +edu.hn +edu.ht +edu.in +edu.iq +edu.jm +edu.jo +edu.kg +edu.kh +edu.kn +edu.kw +edu.ky +edu.kz +edu.la +edu.lb +edu.lr +edu.lv +edu.ly +edu.me +edu.mg +edu.mk +edu.ml +edu.mm +edu.mn +edu.mo +edu.mt +edu.mv +edu.mw +edu.mx +edu.my +edu.ni +edu.np +edu.om +edu.pa +edu.pe +edu.ph +edu.pk +edu.pl +edu.pr +edu.ps +edu.pt +edu.pw +edu.py +edu.qa +edu.rs +edu.ru +edu.sa +edu.sc +edu.sd +edu.sg +edu.sh +edu.sl +edu.sv +edu.sy +edu.tr +edu.tt +edu.tw +edu.ua +edu.uy +edu.ve +edu.vn +edu.ws +edu.ye +edu.zm +es.kr +g12.br +hs.kr +ms.kr +sc.kr +sc.ug +sch.ae +sch.gg +sch.id +sch.ir +sch.je +sch.jo +sch.lk +sch.ly +sch.my +sch.om +sch.ps +sch.sa +sch.uk +school.nz +school.za +vic.edu.au diff --git a/lib/swot.rb b/lib/swot.rb deleted file mode 100644 index 6bd44f881e..0000000000 --- a/lib/swot.rb +++ /dev/null @@ -1,72 +0,0 @@ -require "public_suffix" -require "naughty_or_nice" -require_relative "swot/academic_tlds" - -class Swot < NaughtyOrNice - VERSION = "0.3.0" - - # These are domains that snuck into the edu registry, - # but don't pass the education sniff test - # Note: validated domain must not end with the blacklisted string - BLACKLIST = %w( - si.edu - america.edu - ).freeze - - class << self - alias_method :is_academic?, :valid? - alias_method :academic?, :valid? - - def get_institution_name(text) - Swot.new(text).institution_name - end - alias_method :school_name, :get_institution_name - - def domains_path - @domains_path ||= File.expand_path "domains", File.dirname(__FILE__) - end - end - - # Figure out if an email or domain belongs to academic institution. - # - # Returns true if the domain name belongs to an academic institution; - # false otherwise. - def valid? - if domain.nil? - false - elsif BLACKLIST.any? { |d| domain =~ /(\A|\.)#{Regexp.escape(d)}\z/ } - false - elsif ACADEMIC_TLDS.include?(domain_parts.tld) - true - elsif academic_domain? - true - else - false - end - end - - # Figure out the institution name based on the email address/domain. - # - # Returns a string with the institution name; nil if nothing is found. - def institution_name - @institution_name ||= File.read(file_path, :mode => "rb", :external_encoding => "UTF-8").strip - rescue - nil - end - alias_method :school_name, :institution_name - alias_method :name, :institution_name - - # Figure out if a domain name is a know academic institution. - # - # Returns true if the domain name belongs to a known academic institution; - # false otherwise. - def academic_domain? - @academic_domain ||= File.exists?(file_path) - end - - private - - def file_path - @file_path ||= File.join(Swot::domains_path, domain_parts.domain.to_s.split(".").reverse) + ".txt" - end -end diff --git a/lib/swot/academic_tlds.rb b/lib/swot/academic_tlds.rb deleted file mode 100644 index fea0412fb2..0000000000 --- a/lib/swot/academic_tlds.rb +++ /dev/null @@ -1,169 +0,0 @@ -require 'set' - -class Swot < NaughtyOrNice - # These top-level domains are guaranteed to be academic institutions. - ACADEMIC_TLDS = %w( - ac.ae - ac.at - ac.bd - ac.be - ac.cn - ac.cr - ac.cy - ac.fj - ac.gg - ac.gn - ac.id - ac.il - ac.in - ac.ir - ac.jp - ac.ke - ac.kr - ac.ma - ac.me - ac.mu - ac.mw - ac.mz - ac.ni - ac.nz - ac.om - ac.pa - ac.pg - ac.pr - ac.rs - ac.ru - ac.rw - ac.sz - ac.th - ac.tz - ac.ug - ac.uk - ac.yu - ac.za - ac.zm - ac.zw - ed.ao - ed.cr - ed.jp - edu - edu.af - edu.al - edu.ar - edu.au - edu.az - edu.ba - edu.bb - edu.bd - edu.bh - edu.bi - edu.bn - edu.bo - edu.br - edu.bs - edu.bt - edu.bz - edu.ck - edu.cn - edu.co - edu.cu - edu.do - edu.dz - edu.ec - edu.ee - edu.eg - edu.er - edu.es - edu.et - edu.ge - edu.gh - edu.gr - edu.gt - edu.hk - edu.hn - edu.ht - edu.in - edu.iq - edu.jm - edu.jo - edu.kg - edu.kh - edu.kn - edu.kw - edu.ky - edu.kz - edu.la - edu.lb - edu.lr - edu.lv - edu.ly - edu.me - edu.mg - edu.mk - edu.ml - edu.mm - edu.mn - edu.mo - edu.mt - edu.mv - edu.mw - edu.mx - edu.my - edu.ni - edu.np - edu.om - edu.pa - edu.pe - edu.ph - edu.pk - edu.pl - edu.pr - edu.ps - edu.pt - edu.pw - edu.py - edu.qa - edu.rs - edu.ru - edu.sa - edu.sc - edu.sd - edu.sg - edu.sh - edu.sl - edu.sv - edu.sy - edu.tr - edu.tt - edu.tw - edu.ua - edu.uy - edu.ve - edu.vn - edu.ws - edu.ye - edu.zm - es.kr - g12.br - hs.kr - ms.kr - sc.kr - sc.ug - sch.ae - sch.gg - sch.id - sch.ir - sch.je - sch.jo - sch.lk - sch.ly - sch.my - sch.om - sch.ps - sch.sa - sch.uk - school.nz - school.za - vic.edu.au - ).to_set.freeze -end diff --git a/src/swot/Swot.kt b/src/swot/Swot.kt new file mode 100644 index 0000000000..8e6d7ce626 --- /dev/null +++ b/src/swot/Swot.kt @@ -0,0 +1,58 @@ +package swot + +fun isAcademic(emailOrDomain: String): Boolean { + val parts = domainParts(emailOrDomain) + return !isBlacklisted(parts) && (isUnderTLD(parts) || findSchoolNames(parts).isNotEmpty()) +} + +fun findSchoolNames(emailOrDomain: String): List { + return findSchoolNames(domainParts(emailOrDomain)) +} + +fun isUnderTLD(parts: List): Boolean { + return checkSet(Resources.tlds, parts) +} + +fun isBlacklisted(parts: List): Boolean { + return checkSet(Resources.blackList, parts) +} + +private object Resources { + val tlds = readList("/tlds.txt") ?: error("Cannot find /tlds.txt") + val blackList = readList("/blacklist.txt") ?: error("Cannot find /blacklist.txt") + + fun readList(resource: String) : Set? { + return javaClass.getResourceAsStream(resource)?.reader()?.buffered()?.lines()?.toHashSet() + } +} + +private fun findSchoolNames(parts: List): List { + val resourcePath = StringBuilder("") + for (part in parts) { + resourcePath.append('/').append(part) + val school = Resources.readList("${resourcePath}.txt") + if (school != null) { + return school.toList() + } + } + + return arrayListOf() +} + +private fun domainParts(emailOrDomain: String): List { + return emailOrDomain.toLowerCase().substringAfter('@').split('.').reverse() +} + +private fun checkSet(set: Set, parts: List): Boolean { + val subj = StringBuilder() + for (part in parts) { + subj.append(part) + if (set.contains(subj.toString())) return true + subj.append('.') + } + return false +} + +fun main(args: Array) { + println(isAcademic("max@maricopa.edu")) +} diff --git a/swot.iml b/swot.iml new file mode 100644 index 0000000000..51cbd9f489 --- /dev/null +++ b/swot.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + +