Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@realgenekim
Last active October 6, 2022 03:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save realgenekim/a1df9d0f7dc6bfce43e198666fec0348 to your computer and use it in GitHub Desktop.
Save realgenekim/a1df9d0f7dc6bfce43e198666fec0348 to your computer and use it in GitHub Desktop.
These are selected portions of the code to do the analysis presented here: Analysis Of DevOps Enterprise Summit Speaker Titles (2014-2022): http://itrevolution.com/speaker-titles
; I'll post entire repo of how to use this analysis code, but I wanted to get something
; up right away
;
(ns does-titles.titles
(:require
[better-cond.core :as b]
[clojure.string :as str]
[clojure.test :refer :all]
[com.fulcrologic.guardrails.core :refer [>defn >defn- >def | ? =>]]))
;; ## Transform titles
(>defn xform-titles
" transform/normalize job titles
assumed already lowercase "
[s] [string? => string?]
(let [s ((fnil clojure.string/lower-case "") s)]
(cond
; E1 engineers
;(re-matches #"software engineer.*" s) "engineer"
(re-matches #"software engineer.*" s) "engineer"
(re-matches #"cloud engineer.*" s) "engineer"
;(re-matches #".* engineer" s) "engineer"
(re-matches #"developer" s) "engineer"
;(re-matches #".* developer" s) "engineer"
; E3 engineers
(re-matches #"solution.* architect" s) "architect"
(re-matches #"enterprise architect" s) "architect"
(re-matches #"devops architect" s) "architect"
(re-matches #"cloud architect" s) "architect"
(re-matches #"system architect" s) "architect"
(re-matches #"security architect" s) "architect"
(re-matches #"coach" s) "coach"
(re-matches #"agile coach" s) "coach"
; E4
(re-matches #"principal engineer" s) "principal engineer"
(re-matches #"principal architect" s) "principal architect"
(re-matches #"devops lead" s) "lead engineer"
(re-matches #"technical lead" s) "lead engineer"
(re-matches #"tech lead" s) "lead engineer"
(re-matches #"engineering lead" s) "lead engineer"
(re-matches #"senior .*architect" s) "lead engineer"
; E5
(re-matches #"chief architect" s) "chief architect"
; M1 managers
(re-matches #"it manager" s) "manager"
(re-matches #".* manager" s) "manager"
(re-matches #"team lead.*" s) "manager"
; M2
; M3
(re-matches #"director.*" s) "director"
(re-matches #"head.*" s) "director"
; M4
(re-matches #"sr director" s) "senior director"
(re-matches #"sr. director" s) "senior director"
(re-matches #"sdr" s) "senior director"
; M5
(re-matches #"vp .*" s) "vp"
; M6
(re-matches #"cio" s) "cio"
(re-matches #"chief tech.*" s) "cto"
; B1
(re-matches #"managing director" s) "managing director"
(re-matches #"ceo" s) "ceo"
; Consultants
(re-matches #".*consultant.*" s) "consultant"
(re-matches #".*flow.*" s) "consultant"
; sales
(re-matches #".*sales.*" s) "sales"
(re-matches #".*account exec.*" s) "sales"
(re-matches #".*business development.*" s) "sales"
:else s)))
;; ## Preserve Titles
;; before refactor: add assoc :final {:rank :old-title}
(def rank-names
{:e1 "e1: developer, engineer"
:e2 "e2: senior engineer, sre"
:e3 "e3: staff engineer, arch, coach"
:e4 "e4: principal engr, solution arch, chief arch"
:e5 "e5: distinguished engr, fellow"
:m1 "m1: manager, lead"
:m2 "m2: senior manager, product owner"
:m3 "m3: director"
:m4 "m4: senior director"
:m5 "m5: vp, head"
:m6 "m6: svp, exec dir, cio, cso"
:m7 "m7: evp, cto, md"
:m8 "m8: ceo/cfo"
:sales "vendor sales, marketing"})
(>defn e1?
" input: map {:title}
output: {:title _, :final-title {:rank, :old-title} "
[m] [map? => map?]
(let [s (:title m)]
(if (or
(re-matches #"software engineer.*" s)
(re-matches #"software engineer.*" s)
(re-matches #"cloud engineer.*" s)
(re-matches #"developer" s)
(re-matches #"devops engineer" s)
(re-matches #"engineer" s)
(re-matches #"software developer" s)
(re-matches #"solutions engineer" s)
(re-matches #"systems engineer" s)
(re-matches #"sales engineer" s)
(re-matches #".*engineer" s)
(re-matches #"devops" s)
(re-matches #".*specialist" s)
(re-matches #".*analyst" s)
(re-matches #".*programmer" s)
(re-matches #".*associate" s)
(re-matches #".*administrator.*" s)
#_0)
{:final-title {:rank :e1
:title "e1: developer, engineer"
:old-title s}}
; else
{})))
(>defn e2?
" input: map {:title}
output: {:title _, :final-title {:rank, :old-title} "
[m] [map? => map?]
(let [s (:title m)]
(if (or
(re-matches #"senior.*engineer.*" s)
(re-matches #"senior.*developer.*" s)
(re-matches #"senior.*associate.*" s)
(re-matches #"sre" s)
(re-matches #".*sre" s)
(re-matches #"site reliability engineer" s)
(re-matches #"sr[\.]* .*engineer" s)
(re-matches #"sr[\.]* .*dev.*" s)
(re-matches #"platform engineer" s)
(re-matches #".*engineer ii" s)
(re-matches #".*supervisor.*" s)
(re-matches #".*advocate" s)
(re-matches #"senior.*" s)
#_0)
{:final-title {:rank :e2
:title "e2: senior engineer, sre"
:old-title s}}
; else
{})))
(>defn e3?
" input: map {:title}
output: {:title _, :final-title {:rank, :old-title} "
[m] [map? => map?]
(let [s (:title m)]
(if (or
(re-matches #".*staff.*engineer.*" s)
(re-matches #".*staff.*developer.*" s)
(re-matches #"lead software engineer" s)
(re-matches #"architect" s)
(re-matches #"solution.*architect" s)
(re-matches #"technical.*architect" s)
(re-matches #"enterprise.*architect" s)
(re-matches #"software architect" s)
(re-matches #"system architect" s)
(re-matches #"it architect" s)
(re-matches #"devops architect" s)
(re-matches #".*architect" s)
(re-matches #".*coach" s)
(re-matches #"devops lead" s)
(re-matches #"lead .*engineer" s)
(re-matches #".*lead" s)
(re-matches #".*engineer 3" s)
(re-matches #".*engineer iii" s)
(re-matches #".*engineer iii" s)
(re-matches #"lead.*" s)
#_0)
{:final-title {:rank :e3
:title "e3: staff engineer, arch, coach"
:old-title s}}
; else
{})))
(>defn e4?
" input: map {:title}
output: {:title _, :final-title {:rank, :old-title} "
[m] [map? => map?]
(let [s (:title m)]
(if (or
(re-matches #".*principal.*engineer.*" s)
(re-matches #".*principal.*developer.*" s)
(re-matches #".*chief architect.*" s)
(re-matches #".*principal architect.*" s)
(re-matches #".*principal.*architect.*" s)
(re-matches #".*principal.*" s)
(re-matches #".*principle.*architect.*" s)
(re-matches #"senior solution.*" s)
(re-matches #"senior .*architect" s)
#_0)
{:final-title {:rank :e4
:title "e4: principal engr, solution arch, chief arch"
:old-title s}}
; else
{})))
(>defn e5?
" input: map {:title}
output: {:title _, :final-title {:rank, :old-title} "
[m] [map? => map?]
(let [s (:title m)]
(if (or
(re-matches #"distinguished.*engineer.*" s)
(re-matches #"distinguish.*engineer.*" s)
(re-matches #".*fellow.*" s)
#_0)
{:final-title {:rank :e5
:title "e5: distinguished engr, fellow"
:old-title s}}
; else
{})))
(>defn m1?
" input: map {:title}
output: {:title _, :final-title {:rank, :old-title} "
[m] [map? => map?]
(let [s (:title m)]
(if (or
(re-matches #".*manager.*" s)
(re-matches #".*team lead.*" s)
#_0)
{:final-title {:rank :m1
:title "m1: manager, lead"
:old-title s}}
; else
{})))
(>defn m2?
" input: map {:title}
output: {:title _, :final-title {:rank, :old-title} "
[m] [map? => map?]
(let [s (:title m)]
(if (or
; senior manager - software engineering
(re-matches #"senior .*manager.*" s)
(re-matches #"sr .*manager.*" s)
(re-matches #"sr\. .*manager.*" s)
(re-matches #".*scrum master.*" s)
(re-matches #".*product owner.*" s)
(re-matches #".*leader" s)
#_0)
{:final-title {:rank :m2
:title "m2: senior manager, product owner"
:old-title s}}
; else
{})))
(>defn m3?
" input: map {:title}
output: {:title _, :final-title {:rank, :old-title} "
[m] [map? => map?]
(let [s (:title m)]
(if (or
(re-matches #".*director.*" s)
(re-matches #".*dir .*" s)
;(re-matches #".*team lead.*" s)
#_0)
{:final-title {:rank :m3
:title "m3: director"
:old-title s}}
; else
{})))
(>defn m4?
" input: map {:title}
output: {:title _, :final-title {:rank, :old-title} "
[m] [map? => map?]
(let [s (:title m)]
(if (or
(re-matches #"senior.*director.*" s)
(re-matches #"sr .*director.*" s)
(re-matches #"sr\. .*director.*" s)
(re-matches #"sdr.*" s)
;sr.engg director
;snr. director
(re-matches #"snr.* director" s)
(re-matches #"sr.* director" s)
#_0)
{:final-title {:rank :m4
:title "m4: senior director"
:old-title s}}
; else
{})))
(>defn m5?
" input: map {:title}
output: {:title _, :final-title {:rank, :old-title} "
[m] [map? => map?]
(let [s (:title m)]
(if (or
(re-matches #"vice president.*" s)
(re-matches #"vp.*" s)
(re-matches #"avp.*" s)
(re-matches #"associate vice president.*" s)
(re-matches #".*head .*" s)
(re-matches #".*chief of staff.*" s)
#_0)
{:final-title {:rank :m5
:title "m5: vp, head"
:old-title s}}
; else
{})))
(>defn m6?
" input: map {:title}
output: {:title _, :final-title {:rank, :old-title} "
[m] [map? => map?]
(let [s (:title m)]
(if (or
(re-matches #"svp.*" s)
(re-matches #"senior vice president.*" s)
(re-matches #".*executive director.*" s)
(re-matches #".*cio.*" s)
(re-matches #".*cso.*" s)
(re-matches #".*ctio.*" s)
#_0)
{:final-title {:rank :m6
:title "m6: svp, exec dir, cio, cso"
:old-title s}}
; else
{})))
(comment
(m7? {:title "executive director"})
(m7? {:title "director"})
(re-matches #".*managing director.*" "director")
(m6? {:title "executive director"})
(def s "director")
(re-matches #".*managing director.*" s)
(re-matches #"evp.*" s)
(re-matches #"executive vice president.*" s)
(re-matches #".*cto[^r].*" s)
9)
(>defn m7?
" input: map {:title}
output: {:title _, :final-title {:rank, :old-title} "
[m] [map? => map?]
(let [s (:title m)]
(if (or
(re-matches #".*managing director.*" s)
(re-matches #"evp.*" s)
(re-matches #"executive vice president.*" s)
(re-matches #".*cto[^r].*" s)
(re-matches #"cto" s)
(re-matches #"chief technology officer" s)
(re-matches #"chief marketing officer" s)
(re-matches #".*coo*" s)
(re-matches #"chief operating officer" s)
(re-matches #"cmo" s)
;(re-matches #"sr\. .*director" s)
#_0)
{:final-title {:rank :m7
:title "m7: evp, cto, md"
:old-title s}}
; else
{})))
(>defn m8?
" input: map {:title}
output: {:title _, :final-title {:rank, :old-title} "
[m] [map? => map?]
(let [s (:title m)]
(if (or
(re-matches #".*ceo.*" s)
(re-matches #".*cfo.*" s)
(re-matches #"president" s)
#_0)
{:final-title {:rank :m8
:title "m8: ceo/cfo"
:old-title s}}
; else
{})))
(>defn sales?
" input: map {:title}
output: {:title _, :final-title {:rank, :old-title} "
[m] [map? => map?]
(let [s (:title m)]
(if (or
(re-matches #".*sales.*" s)
(re-matches #".*business dev.*" s)
(re-matches #".*account exec.*" s)
(re-matches #".*marketing.*" s)
(re-matches #".*demand gen.*" s)
#_0)
{:final-title {:rank :sales
:title "sales"
:old-title s}}
; else
{})))
(>defn consultant?
" input: map {:title}
output: {:title _, :final-title {:rank, :old-title} "
[m] [map? => map?]
(let [s (:title m)]
(if (or
(re-matches #".*consultant.*" s)
(re-matches #".*partner.*" s)
(re-matches #".*flow advisor.*" s)
#_0)
{:final-title {:rank :consultant
:title "consultant"
:old-title s}}
; else
{})))
(>defn none?
" input: map {:title}
output: {:title _, :final-title {:rank, :old-title} "
[m] [map? => map?]
(let [s (:title m)]
(if (or
(re-matches #"" s)
(re-matches #"mr" s)
(re-matches #"mrs" s)
(re-matches #"mr\." s)
(re-matches #"mrs\." s)
(re-matches #"student" s)
(re-matches #"-" s)
#_0)
{:final-title {:rank :none
:title "none"
:old-title s}}
; else
{})))
(>defn xform-map
" transform/normalize job titles
assumed already lowercase
input: {:title ...} "
[m] [map? => map?]
(b/cond
:let [m8 (m8? m)]
(not-empty m8)
(merge m m8)
; senior manager first
:let [m2 (m2? m)]
(not-empty m2)
(merge m m2)
; then manager
:let [m1 (m1? m)]
(not-empty m1)
(merge m m1)
; senior director first
:let [m4 (m4? m)]
(not-empty m4)
(merge m m4)
; evp / managing director
:let [m7 (m7? m)]
(not-empty m7)
(merge m m7)
; svp / executive director
:let [m6 (m6? m)]
(not-empty m6)
(merge m m6)
; then vp
:let [m5 (m5? m)]
(not-empty m5)
(merge m m5)
; then director
:let [m3 (m3? m)]
(not-empty m3)
(merge m m3)
:let [e5 (e5? m)]
(not-empty e5)
(merge m e5)
:let [e4 (e4? m)]
(not-empty e4)
(merge m e4)
:let [e3 (e3? m)]
(not-empty e3)
(merge m e3)
:let [e2 (e2? m)]
(not-empty e2)
(merge m e2)
:let [e1 (e1? m)]
(not-empty e1)
(merge m e1)
; sales
:let [s1 (sales? m)]
(not-empty s1)
(merge m s1)
; consultant
:let [c1 (consultant? m)]
(not-empty c1)
(merge m c1)
(not-empty (none? m))
(merge m (none? m))
:else
m))
(comment
(xform-map {:title "senior engineer"})
(xform-map {:title "senior cloud engineer"})
(xform-map {:title "cloud engineer"})
(xform-map {:title "director"})
0)
(defn get-rank
[m]
(-> m :final-title :rank))
(deftest test-ranks
(is (= :e5 (get-rank (xform-map {:title "distinguished engineer"}))))
(is (= :e5 (get-rank (xform-map {:title "fellow"}))))
(is (= :e5 (get-rank (xform-map {:title "technical fellow"}))))
(is (= :e4 (get-rank (xform-map {:title "chief architect"}))))
(is (= :e4 (get-rank (xform-map {:title "principal architect"}))))
(is (= :e4 (get-rank (xform-map {:title "software principal engineer"}))))
(is (= :e4 (get-rank (xform-map {:title "senior principal/architect & devops advisor"}))))
(is (= :e3 (get-rank (xform-map {:title "architect"}))))
(is (= :e3 (get-rank (xform-map {:title "solution architect"}))))
(is (= :e3 (get-rank (xform-map {:title "solutions architect"}))))
(is (= :e3 (get-rank (xform-map {:title "enterprise architect"}))))
(is (= :e3 (get-rank (xform-map {:title "software architect"}))))
(is (= :e3 (get-rank (xform-map {:title "cloud architect"}))))
(is (= :e3 (get-rank (xform-map {:title "staff developer"}))))
(is (= :e3 (get-rank (xform-map {:title "lead engineer"}))))
(is (= :e3 (get-rank (xform-map {:title "devops lead"}))))
(is (= :e3 (get-rank (xform-map {:title "coach"}))))
(is (= :e3 (get-rank (xform-map {:title "agile coach"}))))
(is (= :e3 (get-rank (xform-map {:title "technical lead"}))))
(is (= :e3 (get-rank (xform-map {:title "lead automation engineer"}))))
(is (= :e3 (get-rank (xform-map {:title "lead devops engineer"}))))
(is (= :e3 (get-rank (xform-map {:title "senior staff engineer"}))))
(is (= :e3 (get-rank (xform-map {:title "lead, automation solutions"}))))
(is (= :e2 (get-rank (xform-map {:title "senior engineer"}))))
(is (= :e2 (get-rank (xform-map {:title "senior cloud engineer"}))))
(is (= :e2 (get-rank (xform-map {:title "senior developer"}))))
(is (= :e2 (get-rank (xform-map {:title "sr observability engineer"}))))
(is (= :e2 (get-rank (xform-map {:title "senior developer"}))))
(is (= :e2 (get-rank (xform-map {:title "supervisor"}))))
(is (= :e2 (get-rank (xform-map {:title "sr developer"}))))
(is (= :e1 (get-rank (xform-map {:title "cloud engineer"}))))
(is (= :e1 (get-rank (xform-map {:title "engineer"}))))
(is (= :e1 (get-rank (xform-map {:title "developer"}))))
(is (= :e1 (get-rank (xform-map {:title "devops engineer"}))))
(is (= :e1 (get-rank (xform-map {:title "software developer"}))))
(is (= :e1 (get-rank (xform-map {:title "security engineer"}))))
(is (= :e1 (get-rank (xform-map {:title "associate"}))))
(is (= :e1 (get-rank (xform-map {:title "programmer"}))))
(is (= :e1 (get-rank (xform-map {:title "system administrator"}))))
(is (= :e1 (get-rank (xform-map {:title "database administrator"}))))
(is (= :m8 (get-rank (xform-map {:title "ceo"}))))
(is (= :m8 (get-rank (xform-map {:title "cfo"}))))
(is (= :m8 (get-rank (xform-map {:title "ceo in general & administration"}))))
(is (= :m7 (get-rank (xform-map {:title "evp"}))))
(is (= :m7 (get-rank (xform-map {:title "executive vice president"}))))
(is (= :m7 (get-rank (xform-map {:title "managing director"}))))
(is (= :m7 (get-rank (xform-map {:title "cto"}))))
(is (= :m7 (get-rank (xform-map {:title "chief technology officer"}))))
(is (= :m7 (get-rank (xform-map {:title "coo"}))))
(is (= :m7 (get-rank (xform-map {:title "chief operating officer"}))))
(is (= :m7 (get-rank (xform-map {:title "coo"}))))
(is (= :m6 (get-rank (xform-map {:title "svp"}))))
(is (= :m6 (get-rank (xform-map {:title "senior vice president"}))))
(is (= :m6 (get-rank (xform-map {:title "executive director"}))))
(is (= :m6 (get-rank (xform-map {:title "cio"}))))
(is (= :m6 (get-rank (xform-map {:title "cso"}))))
(is (= :m5 (get-rank (xform-map {:title "vice president"}))))
(is (= :m5 (get-rank (xform-map {:title "vp of dev"}))))
(is (= :m5 (get-rank (xform-map {:title "global head of middle office product delivery"}))))
(is (= :m5 (get-rank (xform-map {:title "group head of architecture"}))))
(is (= :m5 (get-rank (xform-map {:title "chief of staff"}))))
(is (= :m4 (get-rank (xform-map {:title "senior director"}))))
(is (= :m4 (get-rank (xform-map {:title "sr director"}))))
(is (= :m4 (get-rank (xform-map {:title "sr. director"}))))
(is (= :m4 (get-rank (xform-map {:title "senior director application security"}))))
(is (= :m4 (get-rank (xform-map {:title "snr. director"}))))
(is (= :m4 (get-rank (xform-map {:title "sr.engg director"}))))
(is (= :m3 (get-rank (xform-map {:title "director"}))))
(is (= :m3 (get-rank (xform-map {:title "dir of architecture"}))))
(is (= :m2 (get-rank (xform-map {:title "senior developer manager"}))))
(is (= :m2 (get-rank (xform-map {:title "senior field marketing manager"}))))
(is (= :m2 (get-rank (xform-map {:title "sr. marketing manager"}))))
(is (= :m2 (get-rank (xform-map {:title "sr marketing manager"}))))
(is (= :m2 (get-rank (xform-map {:title "senior manager - software engineering"}))))
(is (= :m1 (get-rank (xform-map {:title "developer manager"}))))
(is (= :m1 (get-rank (xform-map {:title "team lead"}))))
; trick
(is (= :m1 (get-rank (xform-map {:title "sre manager"}))))
; sales
(is (= :sales (get-rank (xform-map {:title "account executive"}))))
; consultants
(is (= :consultant (get-rank (xform-map {:title "consultant"}))))
(is (= :consultant (get-rank (xform-map {:title "technical consultant"}))))
(is (= :consultant (get-rank (xform-map {:title "partner"}))))
(is (= :consultant (get-rank (xform-map {:title "flow advisor"}))))
(is (= :consultatnt (get-rank (xform-map {:title "Chief of Platform"}))))
; none
(is (= :none (get-rank (xform-map {:title "mr."}))))
(is (= :none (get-rank (xform-map {:title "mr"}))))
(is (= :none (get-rank (xform-map {:title "mrs."}))))
(is (= :none (get-rank (xform-map {:title ""}))))
0)
#_(def rank-names
{:e1 "e1: developer, engineer"
:e2 "e2: senior engineer, sre"
:e3 "e3: staff engineer, arch, coach"
:e4 "e4: principal engr, solution arch, chief arch"
:e5 "e5: distinguished engr, fellow"
:m1 "m1: manager, lead"
:m2 "m2: senior manager, product owner"
:m3 "m3: director"
:m4 "m4: senior director"
:m5 "m5: vp, head"
:m6 "m6: svp, exec dir, cio, cso"
:m7 "m7: evp, cto, md"
:m8 "m8: ceo/cfo"
:sales "vendor sales, marketing"})
(def group-ranks-table
{:e01 {:ranks [:e1]}
:e02 {:ranks [:e2 :e3]}
:e03 {:ranks [:e4 :e5]}
:m01 {:ranks [:m1]}
:m02 {:ranks [:m2 :m3 :m4]}
:m03 {:ranks [:m5 :m6]}
:m04 {:ranks [:m7 :m8]}})
(def rank->newrank
(->> (for [[newrank v] group-ranks-table]
(let [ranks (-> v :ranks)]
(for [r ranks]
; map rank -> new rank
{r newrank})))
flatten
(apply merge)))
(comment
; results in this
{:m5 :m03,
:e1 :e01,
:m3 :m02,
:e2 :e02,
:e3 :e02,
:e4 :e03,
:m4 :m02,
:e5 :e03,
:m8 :m03,
:m6 :m03,
:m2 :m02,
:m1 :m01,
:m7 :m03}
(get rank->newrank :m8)
0)
(def group-rank-names
(->> (for [g group-ranks-table]
(let [[newrank v] g
ranks (-> v :ranks)]
(->> (for [r ranks]
(let [nm (get rank-names r)]
;nm
(->> (clojure.string/replace nm #"^..: " ""))))
(clojure.string/join ", ")
((fn [s]
{newrank (format "%s: %s" newrank s)})))))
(apply merge)))
(comment
; generates this
{:e01 ":e01: developer, engineer",
:e02 ":e02: senior engineer, sre, staff engineer, arch, coach",
:e03 ":e03: principal engr, solution arch, chief arch, distinguished engr, fellow",
:m01 ":m01: manager, lead",
:m02 ":m02: senior manager, product owner, director, senior director",
:m03 ":m03: vp, head, svp, exec dir, cio, cso, evp, cto, md, ceo/cfo"}
0)
(defn group-ranks
" quanitze the ranks
input: {:rank ... } "
[m]
(let [r (-> m :rank)
newrank (get rank->newrank r)
newrankname (get group-rank-names newrank)]
(assoc m :newrank newrank
:newrankname newrankname)))
(defn generate-group-rank-names []
(->> (for [[g gs] group-rank-names]
(clojure.string/replace gs #"^." ""))
sort))
(comment
0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment