{"id":1883,"date":"2020-05-24T17:44:21","date_gmt":"2020-05-24T17:44:21","guid":{"rendered":"https:\/\/dev95.site\/the-algorithm-powering-iharmony\/"},"modified":"2020-05-24T17:44:21","modified_gmt":"2020-05-24T17:44:21","slug":"the-algorithm-powering-iharmony","status":"publish","type":"post","link":"https:\/\/dev95.site\/ar\/the-algorithm-powering-iharmony\/","title":{"rendered":"The algorithm powering iHarmony"},"content":{"rendered":"<div id=\"dev95-877417391\" class=\"dev95-- dev95-entity-placement\"><script async=\"async\" data-cfasync=\"false\" src=\"https:\/\/pl27862732.profitableratecpmnetwork.com\/2ad7a50e0bbc23ac6801d7b77c501463\/invoke.js\"><\/script>\r\n<div id=\"container-2ad7a50e0bbc23ac6801d7b77c501463\"><\/div><\/div><div>\n<h2 id=\"problem\">Problem<\/h2>\n<p><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/storage.ghost.io\/c\/ae\/f4\/aef4d625-32a2-417b-86f4-22c70a9b47a1\/content\/images\/2025\/09\/slack-imgs.png?w=1280&#038;ssl=1\" alt=\"The algorithm powering iHarmony\"><\/p>\n<p>I wrote the first version of <a href=\"https:\/\/apps.apple.com\/gb\/app\/iharmony\/id292413210?ref=albertodebortoli.com\">iHarmony<\/a> in 2008. It was the very first iOS app I gave birth to, combining my passion for music and programming. I remember buying an iPhone and my first Mac with the precise purpose of jumping on the apps train at a time when it wasn&#8217;t clear if the apps were there to stay or were just a temporary hype. But I did it, dropped my beloved Ubuntu to join a whole new galaxy. iHarmony was also one of the first 2000 apps on the App Store.<\/p>\n<p>Up until the recent rewrite, iHarmony was powered by a manually crafted database containing scales, chords, and harmonization I inputted.<\/p><div id=\"dev95-1866460436\" class=\"dev95- dev95-entity-placement\"><center>\r\n<script>\r\n  atOptions = {\r\n    'key' : '4ba6b6513c00e0ba76511f798ae56401',\r\n    'format' : 'iframe',\r\n    'height' : 50,\r\n    'width' : 320,\r\n    'params' : {}\r\n  };\r\n<\/script>\r\n<script src=\"https:\/\/www.highrevenueformat.com\/4ba6b6513c00e0ba76511f798ae56401\/invoke.js\"><\/script>\r\n\t<\/center><\/div>\n<p>What-a-shame!<\/p>\n<figure class=\"kg-card kg-image-card\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/storage.ghost.io\/c\/ae\/f4\/aef4d625-32a2-417b-86f4-22c70a9b47a1\/content\/images\/2020\/05\/shame.png?resize=497%2C266&#038;ssl=1\" class=\"kg-image\" alt=\"The algorithm powering iHarmony\" loading=\"lazy\" width=\"497\" height=\"266\"><\/figure>\n<p>I guess it made sense, I wanted to learn iOS and not to focus on implementing some core logic independent from the platform. Clearly a much better and less error-prone way to go would be to implement an algorithm to generate all the entries based on some DSL\/spec. It took me almost 12 years to decide to tackle the problem and I&#8217;ve recently realized that writing the algorithm I wanted was <a href=\"https:\/\/twitter.com\/albertodebo\/status\/1258123943573180425?s=20&amp;ref=albertodebortoli.com\">harder than I thought<\/a>. Also thought was a good idea give SwiftUI a try since the UI of iHarmony is extremely simple but&#8230; <a href=\"https:\/\/twitter.com\/albertodebo\/status\/1254096544468553728?s=20&amp;ref=albertodebortoli.com\">nope<\/a>.<\/p>\n<p>Since <a href=\"https:\/\/twitter.com\/SteveBarnegren\/status\/1258391221397053441?ref=albertodebortoli.com\">someone<\/a> on the Internet expressed interest \ud83d\ude09, I wrote this article to explain how I solved the problem of modeling music theory concepts in a way that allows the generation of any sort of scales, chords, and harmonization. I only show the code needed to get a grasp of the overall structure.<\/p>\n<p>I know there are other solutions ready to be used on GitHub but, while I don&#8217;t particularly like any of them, the point of rewriting iHarmony from scratch was to challenge myself, not to reuse code someone else wrote. Surprisingly to me, getting to the solution described here took me 3 rewrites and 2 weeks.<\/p>\n<h2 id=\"solution\">Solution<\/h2>\n<p>The first fundamental building blocks to model are surely the musical notes, which are made up of a natural note and an accidental.<\/p>\n<pre><code class=\"language-swift\">enum NaturalNote: String {\n    case C, D, E, F, G, A, B\n}\n\nenum Accidental: String {\n    case flatFlatFlat = \"bbb\"\n    case flatFlat = \"bb\"\n    case flat = \"b\"\n    case natural = \"\"\n    case sharp = \"#\"\n    case sharpSharp = \"##\"\n    case sharpSharpSharp = \"###\"\n    \n    func applyAccidental(_ accidental: Accidental) throws -&gt; Accidental {...}\n}\n\nstruct Note: Hashable, Equatable {\n    \n    let naturalNote: NaturalNote\n    let accidental: Accidental\n    \n    ...\n    \n    static let Dff = Note(naturalNote: .D, accidental: .flatFlat)\n    static let Df = Note(naturalNote: .D, accidental: .flat)\n    static let D = Note(naturalNote: .D, accidental: .natural)\n    static let Ds = Note(naturalNote: .D, accidental: .sharp)\n    static let Dss = Note(naturalNote: .D, accidental: .sharpSharp)\n    \n    ...\n    \n    func noteByApplyingAccidental(_ accidental: Accidental) throws -&gt; Note {...}\n}<\/code><\/pre>\n<p>Combinations of notes make up scales and chords and they are&#8230; many. What&#8217;s fixed instead in music theory, and therefore can be hard-coded, are the keys (both major and minor) such as:<\/p>\n<ul>\n<li>C major: C, D, E, F, G, A, B<\/li>\n<li>A minor: A, B, C, D, E, F, G<\/li>\n<li>D major: D, E, F#, G, A, B, C#<\/li>\n<\/ul>\n<p>We&#8217;ll get back to the keys later, but we can surely implement the note sequence for each musical key.<\/p>\n<pre><code class=\"language-swift\">typealias NoteSequence = [Note]\n\nextension NoteSequence {\n    static let C = [Note.C, Note.D, Note.E, Note.F, Note.G, Note.A, Note.B]\n    static let A_min = [Note.A, Note.B, Note.C, Note.D, Note.E, Note.F, Note.G]\n    \n    static let G = [Note.G, Note.A, Note.B, Note.C, Note.D, Note.E, Note.Fs]\n    static let E_min = [Note.E, Note.Fs, Note.G, Note.A, Note.B, Note.C, Note.D]\n    \n    ...\n}<\/code><\/pre>\n<p>Next stop: intervals. They are a bit more interesting as not every degree has the same types. Let&#8217;s split into 2 sets:<\/p>\n<ol>\n<li><em>2nd<\/em>, <em>3rd<\/em>, <em>6th<\/em> and <em>7th<\/em> degrees can be <em>minor<\/em>, <em>major<\/em>, <em>diminished<\/em> and <em>augmented<\/em><\/li>\n<li><em>1st<\/em> (and <em>8th<\/em>), <em>4th<\/em> and <em>5th<\/em> degrees can be <em>perfect<\/em>, <em>diminished<\/em> and <em>augmented<\/em>.<\/li>\n<\/ol>\n<p>We need to use different kinds of &#8220;diminished&#8221; and &#8220;augmented&#8221; for the 2 sets as later on we&#8217;ll have to calculate the accidentals needed to turn an interval into another.<\/p>\n<p>Some examples:<\/p>\n<ul>\n<li>to get from <em>2nd augmented<\/em> to <em>2nd diminished<\/em>, we need a <em>triple flat<\/em> accidental (e.g. in C major scale, from D\u266f to D\u266d\u266d there are 3 semitones)<\/li>\n<li>to get from <em>5th augmented<\/em> to <em>5th diminished<\/em>, we need a <em>double flat<\/em> accidental (e.g. in C major scale, from G\u266f to G\u266dthere are 2 semitones)<\/li>\n<\/ul>\n<p>We proceed to hard-code the allowed intervals in music, leaving out the invalid ones (e.g. <code>Interval(degree: ._2, type: .augmented)<\/code>)<\/p>\n<pre><code class=\"language-swift\">enum Degree: Int, CaseIterable {\n    case _1, _2, _3, _4, _5, _6, _7, _8\n}\n\nenum IntervalType: Int, RawRepresentable {\n    case perfect\n    case minor\n    case major\n    case diminished\n    case augmented\n    case minorMajorDiminished\n    case minorMajorAugmented\n}\n\nstruct Interval: Hashable, Equatable {\n    let degree: Degree\n    let type: IntervalType\n    \n    static let _1dim = Interval(degree: ._1, type: .diminished)\n    static let _1    = Interval(degree: ._1, type: .perfect)\n    static let _1aug = Interval(degree: ._1, type: .augmented)\n    \n    static let _2dim = Interval(degree: ._2, type: .minorMajorDiminished)\n    static let _2min = Interval(degree: ._2, type: .minor)\n    static let _2maj = Interval(degree: ._2, type: .major)\n    static let _2aug = Interval(degree: ._2, type: .minorMajorAugmented)\n    \n    ...\n    \n    static let _4dim = Interval(degree: ._4, type: .diminished)\n    static let _4    = Interval(degree: ._4, type: .perfect)\n    static let _4aug = Interval(degree: ._4, type: .augmented)\n    \n    ...\n    \n    static let _7dim = Interval(degree: ._7, type: .minorMajorDiminished)\n    static let _7min = Interval(degree: ._7, type: .minor)\n    static let _7maj = Interval(degree: ._7, type: .major)\n    static let _7aug = Interval(degree: ._7, type: .minorMajorAugmented)\n}<\/code><\/pre>\n<p>Now it&#8217;s time to model the keys (we touched on them above already). What&#8217;s important is to define the intervals for all of them (major and minor ones).<\/p>\n<pre><code class=\"language-swift\">enum Key {\n    \/\/ natural\n    case C, A_min\n    \n    \/\/ sharp\n    case G, E_min\n    case D, B_min\n    case A, Fs_min\n    case E, Cs_min\n    case B, Gs_min\n    case Fs, Ds_min\n    case Cs, As_min\n    \n    \/\/ flat\n    case F, D_min\n    case Bf, G_min\n    case Ef, C_min\n    case Af, F_min\n    case Df, Bf_min\n    case Gf, Ef_min\n    case Cf, Af_min\n    \n    ...\n    \n    enum KeyType {\n        case naturalMajor\n        case naturalMinor\n        case flatMajor\n        case flatMinor\n        case sharpMajor\n        case sharpMinor\n    }\n    \n    var type: KeyType {\n        switch self {\n        case .C: return .naturalMajor\n        case .A_min: return .naturalMinor\n        case .G, .D, .A, .E, .B, .Fs, .Cs: return .sharpMajor\n        case .E_min, .B_min, .Fs_min, .Cs_min, .Gs_min, .Ds_min, .As_min: return .sharpMinor\n        case .F, .Bf, .Ef, .Af, .Df, .Gf, .Cf: return .flatMajor\n        case .D_min, .G_min, .C_min, .F_min, .Bf_min, .Ef_min, .Af_min: return .flatMinor\n        }\n    }\n    \n    var intervals: [Interval] {\n        switch type {\n        case .naturalMajor, .flatMajor, .sharpMajor:\n            return [\n                ._1, ._2maj, ._3maj, ._4, ._5, ._6maj, ._7maj\n            ]\n        case .naturalMinor, .flatMinor, .sharpMinor:\n            return [\n                ._1, ._2maj, ._3min, ._4, ._5, ._6min, ._7min\n            ]\n        }\n    }\n    \n    var notes: NoteSequence {\n        switch self {\n        case .C: return .C\n        case .A_min: return .A_min\n    \t...\n    }\n}<\/code><\/pre>\n<p>At this point we have all the fundamental building blocks and we can proceed with the implementation of the algorithm.<\/p>\n<p>The idea is to have a function that given<\/p>\n<ul>\n<li>a key<\/li>\n<li>a root interval<\/li>\n<li>a list of intervals<\/li>\n<\/ul>\n<p>it works out the list of notes. In terms of inputs, it seems the above is all we need to correctly work out scales, chords, and &#8211; by extension &#8211; also harmonizations. Mind that the root interval doesn&#8217;t have to be part of the list of intervals, that is simply the interval to start from based on the given key.<\/p>\n<p>Giving a note as a starting point is not good enough since some scales simply don&#8217;t exist for some notes (e.g. G\u266f major scale doesn&#8217;t exist in the major key, and G\u266dminor scale doesn&#8217;t exist in any minor key).<\/p>\n<p>Before progressing to the implementation, please consider the following unit tests that should make sense to you:<\/p>\n<pre><code class=\"language-swift\">func test_noteSequence_C_1() {\n    let key: Key = .C\n    let noteSequence = try! engine.noteSequence(customKey: key.associatedCustomKey,\n                                                intervals: [._1, ._2maj, ._3maj, ._4, ._5, ._6maj, ._7maj])\n    let expectedValue: NoteSequence = [.C, .D, .E, .F, .G, .A, .B]\n    XCTAssertEqual(noteSequence, expectedValue)\n}\n    \nfunc test_noteSequence_withRoot_C_3maj_majorScaleIntervals() {\n    let key = Key.C\n    let noteSequence = try! engine.noteSequence(customKey: key.associatedCustomKey,\n                                                rootInterval: ._3maj,\n                                                intervals: [._1, ._2maj, ._3maj, ._4, ._5, ._6maj, ._7maj])\n    let expectedValue: NoteSequence = [.E, .Fs, .Gs, .A, .B, .Cs, .Ds]\n    XCTAssertEqual(noteSequence, expectedValue)\n}\n    \nfunc test_noteSequence_withRoot_Gsmin_3maj_alteredScaleIntervals() {\n    let key = Key.Gs_min\n    let noteSequence = try! engine.noteSequence(customKey: key.associatedCustomKey,\n                                                rootInterval: ._3maj,\n                                                intervals: [._1aug, ._2maj, ._3dim, ._4dim, ._5aug, ._6dim, ._7dim])\n    let expectedValue: NoteSequence = [.Bs, .Cs, .Df, .Ef, .Fss, .Gf, .Af]\n    XCTAssertEqual(noteSequence, expectedValue)\n}<\/code><\/pre>\n<p>and here is the implementation. Let&#8217;s consider a simple case, so it&#8217;s easier to follow:<\/p>\n<ul>\n<li>key = C major<\/li>\n<li>root interval = 3maj<\/li>\n<li>interval = major scale interval (1, 2maj, 3min, 4, 5, 6maj, 7min)<\/li>\n<\/ul>\n<p>if you music theory allowed you to understand the above unit tests, you would expect the output to be: E, F\u266f, G, A, B, C\u266f, D (which is a Dorian scale).<\/p>\n<p>Steps:<\/p>\n<ol>\n<li>we start by shifting the notes of the C key to position the 3rd degree (based on the 3maj) as the first element of the array, getting the note sequence E, F, G, A, B, C, D;<\/li>\n<li>here&#8217;s the first interesting bit: we then get the list of intervals by calculating the number of semitones from the root to any other note in the sequence and working out the corresponding <code>Interval<\/code>:<br \/><em>1_perfect, 2_minor, 3_minor, 4_perfect, 5_perfect, 6_minor, 7_minor;<\/em><\/li>\n<li>we now have all we need to create a <code>CustomKey<\/code> which is pretty much a <code>Key<\/code> (with notes and intervals) but instead of being an enum with pre-defined values, is a struct;<\/li>\n<li>here&#8217;s the second tricky part: return the notes by mapping the input intervals. Applying to each note in the custom key the accidental needed to match the desired interval. In our case, the only 2 intervals to &#8216;adjust&#8217; are the 2nd and the 6th intervals, both minor in the custom key but major in the list of intervals. So we have to apply a sharp accidental to &#8216;correct&#8217; them.<\/li>\n<\/ol>\n<p>\ud83d\udc40 I&#8217;ve used force unwraps in these examples for simplicity, the code might already look complex by itself.<\/p>\n<pre><code class=\"language-swift\">class CoreEngine {\n\n    func noteSequence(customKey: CustomKey,\n                      rootInterval: Interval = ._1,\n                      intervals: [Interval]) throws -&gt; NoteSequence {\n        \/\/ 1.\n        let noteSequence = customKey.shiftedNotes(by: rootInterval.degree)\n        let firstNoteInShiftedSequence = noteSequence.first!\n        \n        \/\/ 2.\n        let adjustedIntervals = try noteSequence.enumerated().map {\n            try interval(from: firstNoteInShiftedSequence,\n                         to: $1,\n                         targetDegree: Degree(rawValue: $0)!)\n        }\n        \n        \/\/ 3.\n        let customKey = CustomKey(notes: noteSequence,\n                                  intervals: adjustedIntervals)\n        \n        \/\/ 4.\n        return try intervals.map {\n            let referenceInterval = customKey.firstIntervalWithDegree($0.degree)!\n            let note = customKey.notes[$0.degree.rawValue]\n            let accidental = try referenceInterval.type.accidental(to: $0.type)\n            return try note.noteByApplyingAccidental(accidental)\n        }\n    }\n}<\/code><\/pre>\n<p>It&#8217;s worth showing the implementation of the methods used above:<\/p>\n<pre><code class=\"language-swift\">private func numberOfSemitones(from sourceNote: Note,\n                               to targetNote: Note) -&gt; Int {\n    let notesGroupedBySameTone: [[Note]] = [\n        [.C, .Bs, .Dff],\n        [.Cs, .Df, .Bss],\n        [.D, .Eff, .Css],\n        [.Ds, .Ef, .Fff],\n        [.E, .Dss, .Ff],\n        [.F, .Es, .Gff],\n        [.Fs, .Ess, .Gf],\n        [.G, .Fss, .Aff],\n        [.Gs, .Af],\n        [.A, .Gss, .Bff],\n        [.As, .Bf, .Cff],\n        [.B, .Cf, .Ass]\n    ]\n        \n    let startIndex = notesGroupedBySameTone.firstIndex { $0.contains(sourceNote)}!\n    let endIndex = notesGroupedBySameTone.firstIndex { $0.contains(targetNote)}!\n        \n    return endIndex &gt;= startIndex ? endIndex - startIndex : (notesGroupedBySameTone.count - startIndex) + endIndex\n}\n    \nprivate func interval(from sourceNote: Note,\n                      to targetNote: Note,\n                      targetDegree: Degree) throws -&gt; Interval {\n    let semitones = numberOfSemitones(from: sourceNote, to: targetNote)\n        \n    let targetType: IntervalType = try {\n        switch targetDegree {\n        case ._1, ._8:\n            return .perfect\n        ...\n        case ._4:\n            switch semitones {\n            case 4:\n                return .diminished\n            case 5:\n                return .perfect\n            case 6:\n                return .augmented\n            default:\n                throw CustomError.invalidConfiguration\n        ...\n        case ._7:\n            switch semitones {\n            case 9:\n                return .minorMajorDiminished\n            case 10:\n                return .minor\n            case 11:\n                return .major\n            case 0:\n                return .minorMajorAugmented\n            default:\n                throw CustomError.invalidConfiguration\n            }\n        }\n    }()\n    return Interval(degree: targetDegree, type: targetType)\n}<\/code><\/pre>\n<p>the <code>Note<\/code>&#8216;s <code>noteByApplyingAccidental<\/code> method:<\/p>\n<pre><code class=\"language-swift\">func noteByApplyingAccidental(_ accidental: Accidental) throws -&gt; Note {\n    let newAccidental = try self.accidental.apply(accidental)\n    return Note(naturalNote: naturalNote, accidental: newAccidental)\n}<\/code><\/pre>\n<p>and the <code>Accidental<\/code>&#8216;s <code>apply<\/code> method:<\/p>\n<pre><code class=\"language-swift\">func apply(_ accidental: Accidental) throws -&gt; Accidental {\n    switch (self, accidental) {\n    ...\n    case (.flat, .flatFlatFlat):\n        throw CustomError.invalidApplicationOfAccidental\n    case (.flat, .flatFlat):\n        return .flatFlatFlat\n    case (.flat, .flat):\n        return .flatFlat\n    case (.flat, .natural):\n        return .flat\n    case (.flat, .sharp):\n        return .natural\n    case (.flat, .sharpSharp):\n        return .sharp\n    case (.flat, .sharpSharpSharp):\n        return .sharpSharp\n            \n    case (.natural, .flatFlatFlat):\n        return .flatFlatFlat\n    case (.natural, .flatFlat):\n        return .flatFlat\n    case (.natural, .flat):\n        return .flat\n    case (.natural, .natural):\n        return .natural\n    case (.natural, .sharp):\n        return .sharp\n    case (.natural, .sharpSharp):\n        return .sharpSharp\n    case (.natural, .sharpSharpSharp):\n        return .sharpSharpSharp   \n    ...\n}<\/code><\/pre>\n<p>With the above engine ready (and \ud83d\udcaf\ufe6a unit tested!), we can now proceed to use it to work out what we ultimately need (scales, chords, and harmonizations).<\/p>\n<pre><code>extension CoreEngine {\n    func scale(note: Note, scaleIdentifier: Identifier) throws -&gt; NoteSequence {...}\n    func chord(note: Note, chordIdentifier: Identifier) throws -&gt; NoteSequence {...}\n    func harmonization(key: Key, harmonizationIdentifier: Identifier) throws -&gt; NoteSequence {...}\n    func chordSignatures(note: Note, scaleHarmonizationIdentifier: Identifier) throws -&gt; [ChordSignature] {...}\n    func harmonizations(note: Note, scaleHarmonizationIdentifier: Identifier) throws -&gt; [NoteSequence] {...}\n}<\/code><\/pre>\n<h2 id=\"conclusions\">Conclusions<\/h2>\n<p>There&#8217;s more to it but with this post I only wanted to outline the overall idea. <\/p>\n<p>The default database is available on GitHub at <a href=\"https:\/\/github.com\/albertodebortoli\/iHarmonyDB?ref=albertodebortoli.com\">albertodebortoli\/iHarmonyDB<\/a>. The format used is JSON and the community can now easily suggest additions.<\/p>\n<p>Here is how the definition of a scale looks:<\/p>\n<pre><code class=\"language-swift\">\"scale_dorian\": {\n    \"group\": \"group_scales_majorModes\",\n    \"isMode\": true,\n    \"degreeRelativeToMain\": 2,\n    \"inclination\": \"minor\",\n    \"intervals\": [\n        \"1\",\n        \"2maj\",\n        \"3min\",\n        \"4\",\n        \"5\",\n        \"6maj\",\n        \"7min\"\n    ]\n}<\/code><\/pre>\n<p>and a chord:<\/p>\n<pre><code class=\"language-swift\">\"chord_diminished\": {\n    \"group\": \"group_chords_diminished\",\n    \"abbreviation\": \"dim\",\n    \"intervals\": [\n        \"1\",\n        \"3min\",\n        \"5dim\"\n    ]\n}<\/code><\/pre>\n<p>and a harmonization:<\/p>\n<pre><code class=\"language-swift\">\"scaleHarmonization_harmonicMajorScale4Tones\": {\n    \"group\": \"group_harmonization_harmonic_major\",\n    \"inclination\": \"major\",\n    \"harmonizations\": [\n        \"harmonization_1_major7plus\",\n        \"harmonization_2maj_minor7dim5\",\n        \"harmonization_3maj_minor7\",\n        \"harmonization_4_minor7plus\",\n        \"harmonization_5_major7\",\n        \"harmonization_6min_major7plus5sharp\",\n        \"harmonization_7maj_diminished7\"\n    ]\n}<\/code><\/pre>\n<p>Have to say, I&#8217;m pretty satisfied with how extensible this turned out to be. <\/p>\n<p>Thanks for reading \ud83c\udfb6<\/p>\n<\/div>\n<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_1883\" class=\"pvc_stats total_only  \" data-element-id=\"1883\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" version=\"1.0\" viewBox=\"0 0 502 315\" preserveAspectRatio=\"xMidYMid meet\"><g transform=\"translate(0,332) scale(0.1,-0.1)\" fill=\"\" stroke=\"none\"><path d=\"M2394 3279 l-29 -30 -3 -207 c-2 -182 0 -211 15 -242 39 -76 157 -76 196 0 15 31 17 60 15 243 l-3 209 -33 29 c-26 23 -41 29 -80 29 -41 0 -53 -5 -78 -31z\"\/><path d=\"M3085 3251 c-45 -19 -58 -50 -96 -229 -47 -217 -49 -260 -13 -295 52 -53 146 -42 177 20 16 31 87 366 87 410 0 70 -86 122 -155 94z\"\/><path d=\"M1751 3234 c-13 -9 -29 -31 -37 -50 -12 -29 -10 -49 21 -204 19 -94 39 -189 45 -210 14 -50 54 -80 110 -80 34 0 48 6 76 34 21 21 34 44 34 59 0 14 -18 113 -40 219 -37 178 -43 195 -70 221 -36 32 -101 37 -139 11z\"\/><path d=\"M1163 3073 c-36 -7 -73 -59 -73 -102 0 -56 133 -378 171 -413 34 -32 83 -37 129 -13 70 36 67 87 -16 290 -86 209 -89 214 -129 231 -35 14 -42 15 -82 7z\"\/><path d=\"M3689 3066 c-15 -9 -33 -30 -42 -48 -48 -103 -147 -355 -147 -375 0 -98 131 -148 192 -74 13 15 57 108 97 206 80 196 84 226 37 273 -30 30 -99 39 -137 18z\"\/><path d=\"M583 2784 c-38 -19 -67 -74 -58 -113 9 -42 211 -354 242 -373 16 -10 45 -18 66 -18 51 0 107 52 107 100 0 39 -1 41 -124 234 -80 126 -108 162 -133 173 -41 17 -61 16 -100 -3z\"\/><path d=\"M4250 2784 c-14 -9 -74 -91 -133 -183 -95 -150 -107 -173 -107 -213 0 -55 33 -94 87 -104 67 -13 90 8 211 198 130 202 137 225 78 284 -27 27 -42 34 -72 34 -22 0 -50 -8 -64 -16z\"\/><path d=\"M2275 2693 c-553 -48 -1095 -270 -1585 -649 -135 -104 -459 -423 -483 -476 -23 -49 -22 -139 2 -186 73 -142 361 -457 571 -626 285 -228 642 -407 990 -497 242 -63 336 -73 660 -74 310 0 370 5 595 52 535 111 1045 392 1455 803 122 121 250 273 275 326 19 41 19 137 0 174 -41 79 -309 363 -465 492 -447 370 -946 591 -1479 653 -113 14 -422 18 -536 8z m395 -428 c171 -34 330 -124 456 -258 112 -119 167 -219 211 -378 27 -96 24 -300 -5 -401 -72 -255 -236 -447 -474 -557 -132 -62 -201 -76 -368 -76 -167 0 -236 14 -368 76 -213 98 -373 271 -451 485 -162 444 86 934 547 1084 153 49 292 57 452 25z m909 -232 c222 -123 408 -262 593 -441 76 -74 138 -139 138 -144 0 -16 -233 -242 -330 -319 -155 -123 -309 -223 -461 -299 l-81 -41 32 46 c18 26 49 83 70 128 143 306 141 649 -6 957 -25 52 -61 116 -79 142 l-34 47 45 -20 c26 -10 76 -36 113 -56z m-2057 25 c-40 -58 -105 -190 -130 -263 -110 -324 -59 -707 132 -981 25 -35 42 -64 37 -64 -19 0 -241 119 -326 174 -188 122 -406 314 -532 468 l-58 71 108 103 c185 178 428 349 672 473 66 33 121 60 123 61 2 0 -10 -19 -26 -42z\"\/><path d=\"M2375 1950 c-198 -44 -350 -190 -395 -379 -18 -76 -8 -221 19 -290 114 -284 457 -406 731 -260 98 52 188 154 231 260 27 69 37 214 19 290 -38 163 -166 304 -326 360 -67 23 -215 33 -279 19z\"\/><\/g><\/svg><\/i> <img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/i0.wp.com\/dev95.site\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif?resize=16%2C16&#038;ssl=1\" border=0 \/><\/p>\n<div class=\"pvc_clear\"><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Problem I wrote the first version of iHarmony in 2008. It was the very first iOS app I gave birth to, combining my passion for music and programming. I remember buying an iPhone and my first Mac with the precise<\/p>\n<div class=\"hosteria-entry-more\"><a href=\"https:\/\/dev95.site\/ar\/the-algorithm-powering-iharmony\/\" class=\"no-underline font-light  group-hover:text-primary-800 dark:group-hover:text-primary-300 py-1\">Read more &gt;&gt;&gt;<\/a><\/div>\n<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_1883\" class=\"pvc_stats total_only\" data-element-id=\"1883\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" version=\"1.0\" viewbox=\"0 0 502 315\" preserveaspectratio=\"xMidYMid meet\"><g transform=\"translate(0,332) scale(0.1,-0.1)\" fill=\"\" stroke=\"none\"><path d=\"M2394 3279 l-29 -30 -3 -207 c-2 -182 0 -211 15 -242 39 -76 157 -76 196 0 15 31 17 60 15 243 l-3 209 -33 29 c-26 23 -41 29 -80 29 -41 0 -53 -5 -78 -31z\"\/><path d=\"M3085 3251 c-45 -19 -58 -50 -96 -229 -47 -217 -49 -260 -13 -295 52 -53 146 -42 177 20 16 31 87 366 87 410 0 70 -86 122 -155 94z\"\/><path d=\"M1751 3234 c-13 -9 -29 -31 -37 -50 -12 -29 -10 -49 21 -204 19 -94 39 -189 45 -210 14 -50 54 -80 110 -80 34 0 48 6 76 34 21 21 34 44 34 59 0 14 -18 113 -40 219 -37 178 -43 195 -70 221 -36 32 -101 37 -139 11z\"\/><path d=\"M1163 3073 c-36 -7 -73 -59 -73 -102 0 -56 133 -378 171 -413 34 -32 83 -37 129 -13 70 36 67 87 -16 290 -86 209 -89 214 -129 231 -35 14 -42 15 -82 7z\"\/><path d=\"M3689 3066 c-15 -9 -33 -30 -42 -48 -48 -103 -147 -355 -147 -375 0 -98 131 -148 192 -74 13 15 57 108 97 206 80 196 84 226 37 273 -30 30 -99 39 -137 18z\"\/><path d=\"M583 2784 c-38 -19 -67 -74 -58 -113 9 -42 211 -354 242 -373 16 -10 45 -18 66 -18 51 0 107 52 107 100 0 39 -1 41 -124 234 -80 126 -108 162 -133 173 -41 17 -61 16 -100 -3z\"\/><path d=\"M4250 2784 c-14 -9 -74 -91 -133 -183 -95 -150 -107 -173 -107 -213 0 -55 33 -94 87 -104 67 -13 90 8 211 198 130 202 137 225 78 284 -27 27 -42 34 -72 34 -22 0 -50 -8 -64 -16z\"\/><path d=\"M2275 2693 c-553 -48 -1095 -270 -1585 -649 -135 -104 -459 -423 -483 -476 -23 -49 -22 -139 2 -186 73 -142 361 -457 571 -626 285 -228 642 -407 990 -497 242 -63 336 -73 660 -74 310 0 370 5 595 52 535 111 1045 392 1455 803 122 121 250 273 275 326 19 41 19 137 0 174 -41 79 -309 363 -465 492 -447 370 -946 591 -1479 653 -113 14 -422 18 -536 8z m395 -428 c171 -34 330 -124 456 -258 112 -119 167 -219 211 -378 27 -96 24 -300 -5 -401 -72 -255 -236 -447 -474 -557 -132 -62 -201 -76 -368 -76 -167 0 -236 14 -368 76 -213 98 -373 271 -451 485 -162 444 86 934 547 1084 153 49 292 57 452 25z m909 -232 c222 -123 408 -262 593 -441 76 -74 138 -139 138 -144 0 -16 -233 -242 -330 -319 -155 -123 -309 -223 -461 -299 l-81 -41 32 46 c18 26 49 83 70 128 143 306 141 649 -6 957 -25 52 -61 116 -79 142 l-34 47 45 -20 c26 -10 76 -36 113 -56z m-2057 25 c-40 -58 -105 -190 -130 -263 -110 -324 -59 -707 132 -981 25 -35 42 -64 37 -64 -19 0 -241 119 -326 174 -188 122 -406 314 -532 468 l-58 71 108 103 c185 178 428 349 672 473 66 33 121 60 123 61 2 0 -10 -19 -26 -42z\"\/><path d=\"M2375 1950 c-198 -44 -350 -190 -395 -379 -18 -76 -8 -221 19 -290 114 -284 457 -406 731 -260 98 52 188 154 231 260 27 69 37 214 19 290 -38 163 -166 304 -326 360 -67 23 -215 33 -279 19z\"\/><\/g><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/dev95.site\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=\"0\" \/><\/p>\n<div class=\"pvc_clear\"><\/div>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"fp_fajr_begins":"","fp_fajr_iqamah":"","fp_dhuhr_begins":"","fp_dhuhr_iqamah":"","fp_asr_begins":"","fp_asr_iqamah":"","fp_maghrib_begins":"","fp_maghrib_iqamah":"","fp_isha_begins":"","fp_isha_iqamah":"","fp_midnight":"","fp_midnight_name":"","fp_sunrise":"","fp_single_prayer_begins_title":"","fp_single_prayer_iqamah_title":"","fp_prayer_times_for_today":"","fp_hijra_date":"","fp_fajr_name":"","fp_dhuhr_name":"","fp_asr_name":"","fp_maghrib_name":"","fp_isha_name":"","fp_sunrise_name":"","fp_currentDate":"","fp_current_time":"","fp_current_title":"","fp_current_location":"","fp_masjid_name":"","fp_prayer_title":"","fp_next_prayer_iqamah_time":"","fp_next_prayer_iqamah_title":"","fp_next_prayer_begins_time":"","fp_next_prayer_begins_title":"","fp_next_prayer_title":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[37],"tags":[],"class_list":["post-1883","post","type-post","status-publish","format-standard","hentry","category-posts"],"a3_pvc":{"activated":true,"total_views":1,"today_views":0},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>The algorithm powering iHarmony - Dev95<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/dev95.site\/ar\/the-algorithm-powering-iharmony\/\" \/>\n<meta property=\"og:locale\" content=\"ar_AR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"The algorithm powering iHarmony - Dev95\" \/>\n<meta property=\"og:description\" content=\"Problem I wrote the first version of iHarmony in 2008. It was the very first iOS app I gave birth to, combining my passion for music and programming. I remember buying an iPhone and my first Mac with the preciseRead more &gt;&gt;&gt;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/dev95.site\/ar\/the-algorithm-powering-iharmony\/\" \/>\n<meta property=\"og:site_name\" content=\"Dev95\" \/>\n<meta property=\"article:published_time\" content=\"2020-05-24T17:44:21+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/storage.ghost.io\/c\/ae\/f4\/aef4d625-32a2-417b-86f4-22c70a9b47a1\/content\/images\/2025\/09\/slack-imgs.png\" \/>\n<meta name=\"author\" content=\"dev95\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u0643\u064f\u062a\u0628 \u0628\u0648\u0627\u0633\u0637\u0629\" \/>\n\t<meta name=\"twitter:data1\" content=\"dev95\" \/>\n\t<meta name=\"twitter:label2\" content=\"\u0648\u0642\u062a \u0627\u0644\u0642\u0631\u0627\u0621\u0629 \u0627\u0644\u0645\u064f\u0642\u062f\u0651\u0631\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 \u062f\u0642\u064a\u0642\u0629\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/dev95.site\\\/the-algorithm-powering-iharmony\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/the-algorithm-powering-iharmony\\\/\"},\"author\":{\"name\":\"dev95\",\"@id\":\"https:\\\/\\\/dev95.site\\\/#\\\/schema\\\/person\\\/b807805ffe2916206b04d0938bce0298\"},\"headline\":\"The algorithm powering iHarmony\",\"datePublished\":\"2020-05-24T17:44:21+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/the-algorithm-powering-iharmony\\\/\"},\"wordCount\":1140,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/the-algorithm-powering-iharmony\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/storage.ghost.io\\\/c\\\/ae\\\/f4\\\/aef4d625-32a2-417b-86f4-22c70a9b47a1\\\/content\\\/images\\\/2025\\\/09\\\/slack-imgs.png\",\"articleSection\":[\"Posts\"],\"inLanguage\":\"ar\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/dev95.site\\\/the-algorithm-powering-iharmony\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/dev95.site\\\/the-algorithm-powering-iharmony\\\/\",\"url\":\"https:\\\/\\\/dev95.site\\\/the-algorithm-powering-iharmony\\\/\",\"name\":\"The algorithm powering iHarmony - Dev95\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/the-algorithm-powering-iharmony\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/the-algorithm-powering-iharmony\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/storage.ghost.io\\\/c\\\/ae\\\/f4\\\/aef4d625-32a2-417b-86f4-22c70a9b47a1\\\/content\\\/images\\\/2025\\\/09\\\/slack-imgs.png\",\"datePublished\":\"2020-05-24T17:44:21+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/the-algorithm-powering-iharmony\\\/#breadcrumb\"},\"inLanguage\":\"ar\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/dev95.site\\\/the-algorithm-powering-iharmony\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"ar\",\"@id\":\"https:\\\/\\\/dev95.site\\\/the-algorithm-powering-iharmony\\\/#primaryimage\",\"url\":\"https:\\\/\\\/storage.ghost.io\\\/c\\\/ae\\\/f4\\\/aef4d625-32a2-417b-86f4-22c70a9b47a1\\\/content\\\/images\\\/2025\\\/09\\\/slack-imgs.png\",\"contentUrl\":\"https:\\\/\\\/storage.ghost.io\\\/c\\\/ae\\\/f4\\\/aef4d625-32a2-417b-86f4-22c70a9b47a1\\\/content\\\/images\\\/2025\\\/09\\\/slack-imgs.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/dev95.site\\\/the-algorithm-powering-iharmony\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/dev95.site\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"The algorithm powering iHarmony\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/dev95.site\\\/#website\",\"url\":\"https:\\\/\\\/dev95.site\\\/\",\"name\":\"Dev95\",\"description\":\"A comprehensive platform for data and knowledge, delivering reliable content that meets the aspirations of readers and enthusiasts.\",\"publisher\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/dev95.site\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"ar\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/dev95.site\\\/#organization\",\"name\":\"Dev95\",\"url\":\"https:\\\/\\\/dev95.site\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ar\",\"@id\":\"https:\\\/\\\/dev95.site\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/dev95.site\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/rbrrbr-6.png?fit=512%2C512&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/dev95.site\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/rbrrbr-6.png?fit=512%2C512&ssl=1\",\"width\":512,\"height\":512,\"caption\":\"Dev95\"},\"image\":{\"@id\":\"https:\\\/\\\/dev95.site\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/dev95.site\\\/#\\\/schema\\\/person\\\/b807805ffe2916206b04d0938bce0298\",\"name\":\"dev95\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ar\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/a70a73d950838b20cd80d7ebdc955737e802e8cd896044c5473b32b946c0662a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/a70a73d950838b20cd80d7ebdc955737e802e8cd896044c5473b32b946c0662a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/a70a73d950838b20cd80d7ebdc955737e802e8cd896044c5473b32b946c0662a?s=96&d=mm&r=g\",\"caption\":\"dev95\"},\"url\":\"https:\\\/\\\/dev95.site\\\/ar\\\/author\\\/mohammad\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"The algorithm powering iHarmony - Dev95","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/dev95.site\/ar\/the-algorithm-powering-iharmony\/","og_locale":"ar_AR","og_type":"article","og_title":"The algorithm powering iHarmony - Dev95","og_description":"Problem I wrote the first version of iHarmony in 2008. It was the very first iOS app I gave birth to, combining my passion for music and programming. I remember buying an iPhone and my first Mac with the preciseRead more &gt;&gt;&gt;","og_url":"https:\/\/dev95.site\/ar\/the-algorithm-powering-iharmony\/","og_site_name":"Dev95","article_published_time":"2020-05-24T17:44:21+00:00","og_image":[{"url":"https:\/\/storage.ghost.io\/c\/ae\/f4\/aef4d625-32a2-417b-86f4-22c70a9b47a1\/content\/images\/2025\/09\/slack-imgs.png","type":"","width":"","height":""}],"author":"dev95","twitter_card":"summary_large_image","twitter_misc":{"\u0643\u064f\u062a\u0628 \u0628\u0648\u0627\u0633\u0637\u0629":"dev95","\u0648\u0642\u062a \u0627\u0644\u0642\u0631\u0627\u0621\u0629 \u0627\u0644\u0645\u064f\u0642\u062f\u0651\u0631":"11 \u062f\u0642\u064a\u0642\u0629"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/dev95.site\/the-algorithm-powering-iharmony\/#article","isPartOf":{"@id":"https:\/\/dev95.site\/the-algorithm-powering-iharmony\/"},"author":{"name":"dev95","@id":"https:\/\/dev95.site\/#\/schema\/person\/b807805ffe2916206b04d0938bce0298"},"headline":"The algorithm powering iHarmony","datePublished":"2020-05-24T17:44:21+00:00","mainEntityOfPage":{"@id":"https:\/\/dev95.site\/the-algorithm-powering-iharmony\/"},"wordCount":1140,"commentCount":0,"publisher":{"@id":"https:\/\/dev95.site\/#organization"},"image":{"@id":"https:\/\/dev95.site\/the-algorithm-powering-iharmony\/#primaryimage"},"thumbnailUrl":"https:\/\/storage.ghost.io\/c\/ae\/f4\/aef4d625-32a2-417b-86f4-22c70a9b47a1\/content\/images\/2025\/09\/slack-imgs.png","articleSection":["Posts"],"inLanguage":"ar","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/dev95.site\/the-algorithm-powering-iharmony\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/dev95.site\/the-algorithm-powering-iharmony\/","url":"https:\/\/dev95.site\/the-algorithm-powering-iharmony\/","name":"The algorithm powering iHarmony - Dev95","isPartOf":{"@id":"https:\/\/dev95.site\/#website"},"primaryImageOfPage":{"@id":"https:\/\/dev95.site\/the-algorithm-powering-iharmony\/#primaryimage"},"image":{"@id":"https:\/\/dev95.site\/the-algorithm-powering-iharmony\/#primaryimage"},"thumbnailUrl":"https:\/\/storage.ghost.io\/c\/ae\/f4\/aef4d625-32a2-417b-86f4-22c70a9b47a1\/content\/images\/2025\/09\/slack-imgs.png","datePublished":"2020-05-24T17:44:21+00:00","breadcrumb":{"@id":"https:\/\/dev95.site\/the-algorithm-powering-iharmony\/#breadcrumb"},"inLanguage":"ar","potentialAction":[{"@type":"ReadAction","target":["https:\/\/dev95.site\/the-algorithm-powering-iharmony\/"]}]},{"@type":"ImageObject","inLanguage":"ar","@id":"https:\/\/dev95.site\/the-algorithm-powering-iharmony\/#primaryimage","url":"https:\/\/storage.ghost.io\/c\/ae\/f4\/aef4d625-32a2-417b-86f4-22c70a9b47a1\/content\/images\/2025\/09\/slack-imgs.png","contentUrl":"https:\/\/storage.ghost.io\/c\/ae\/f4\/aef4d625-32a2-417b-86f4-22c70a9b47a1\/content\/images\/2025\/09\/slack-imgs.png"},{"@type":"BreadcrumbList","@id":"https:\/\/dev95.site\/the-algorithm-powering-iharmony\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/dev95.site\/"},{"@type":"ListItem","position":2,"name":"The algorithm powering iHarmony"}]},{"@type":"WebSite","@id":"https:\/\/dev95.site\/#website","url":"https:\/\/dev95.site\/","name":"Dev95","description":"A comprehensive platform for data and knowledge, delivering reliable content that meets the aspirations of readers and enthusiasts.","publisher":{"@id":"https:\/\/dev95.site\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/dev95.site\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"ar"},{"@type":"Organization","@id":"https:\/\/dev95.site\/#organization","name":"Dev95","url":"https:\/\/dev95.site\/","logo":{"@type":"ImageObject","inLanguage":"ar","@id":"https:\/\/dev95.site\/#\/schema\/logo\/image\/","url":"https:\/\/i0.wp.com\/dev95.site\/wp-content\/uploads\/2026\/07\/rbrrbr-6.png?fit=512%2C512&ssl=1","contentUrl":"https:\/\/i0.wp.com\/dev95.site\/wp-content\/uploads\/2026\/07\/rbrrbr-6.png?fit=512%2C512&ssl=1","width":512,"height":512,"caption":"Dev95"},"image":{"@id":"https:\/\/dev95.site\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/dev95.site\/#\/schema\/person\/b807805ffe2916206b04d0938bce0298","name":"dev95","image":{"@type":"ImageObject","inLanguage":"ar","@id":"https:\/\/secure.gravatar.com\/avatar\/a70a73d950838b20cd80d7ebdc955737e802e8cd896044c5473b32b946c0662a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/a70a73d950838b20cd80d7ebdc955737e802e8cd896044c5473b32b946c0662a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/a70a73d950838b20cd80d7ebdc955737e802e8cd896044c5473b32b946c0662a?s=96&d=mm&r=g","caption":"dev95"},"url":"https:\/\/dev95.site\/ar\/author\/mohammad\/"}]}},"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/dev95.site\/ar\/wp-json\/wp\/v2\/posts\/1883","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dev95.site\/ar\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dev95.site\/ar\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dev95.site\/ar\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dev95.site\/ar\/wp-json\/wp\/v2\/comments?post=1883"}],"version-history":[{"count":0,"href":"https:\/\/dev95.site\/ar\/wp-json\/wp\/v2\/posts\/1883\/revisions"}],"wp:attachment":[{"href":"https:\/\/dev95.site\/ar\/wp-json\/wp\/v2\/media?parent=1883"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dev95.site\/ar\/wp-json\/wp\/v2\/categories?post=1883"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dev95.site\/ar\/wp-json\/wp\/v2\/tags?post=1883"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}