<commit_before>SchemaAlignmentDialog.UILink = function(dialog, link, table, options, parentUINode) {
    this._dialog = dialog;
    this._link = link;
    this._options = options;
    this._parentUINode = parentUINode;
    
    this._tr = table.insertRow(table.rows.length);
    this._tdMain = this._tr.insertCell(0);
    this._tdToggle = this._tr.insertCell(1);
    this._tdDetails = this._tr.insertCell(2);
    
    $(this._tdMain).addClass("schema-alignment-link-main").attr("width", "250").addClass("padded");
    $(this._tdToggle).addClass("schema-alignment-link-toggle").attr("width", "1%").addClass("padded");
    $(this._tdDetails).addClass("schema-alignment-link-details").attr("width", "90%");
    
    this._collapsedDetailDiv = $('<div></div>').appendTo(this._tdDetails).addClass("padded").html("...");
    this._expandedDetailDiv = $('<div></div>').appendTo(this._tdDetails).addClass("schema-alignment-detail-container");
    var self = this;
    var show = function() {
        if (self._options.expanded) {
            self._collapsedDetailDiv.hide();
            self._expandedDetailDiv.show();
        } else {
            self._collapsedDetailDiv.show();
            self._expandedDetailDiv.hide();
        }
    };
    show();
    
    $(this._tdToggle).html("&nbsp;");
    $('<img />')
        .attr("src", this._options.expanded ? "images/expanded.png" : "images/collapsed.png")
        .appendTo(this._tdToggle)
        .click(function() {
            self._options.expanded = !self._options.expanded;
            
            $(this).attr("src", self._options.expanded ? "images/expanded.png" : "images/collapsed.png");
            
            show();
        });
    
    this._renderMain();
    this._renderDetails();
};

SchemaAlignmentDialog.UILink.prototype._renderMain = function() {
    $(this._tdMain).empty();
    
    var label = this._link.property !== null ? this._link.property.id : "property?";
    
    var self = this;
    
    $('<img />')
        .attr("title", "remove property")
        .attr("src", "images/close.png")
        .css("cursor", "pointer")
        .prependTo(this._tdMain)
        .click(function() {
            window.setTimeout(function() {
                self._parentUINode.removeLink(self);
                self._tr.parentNode.removeChild(self._tr);
                self._dialog.preview();
            }, 100);
        });
    
    var a = $('<a href="javascript:{}"></a>')
        .addClass("schema-alignment-link-tag")
        .html(label)
        .appendTo(this._tdMain)
        .click(function(evt) {
            self._startEditProperty(this);
        });
        
    $('<img />').attr("src", "images/arrow-start.png").prependTo(a);
    $('<img />').attr("src", "images/arrow-end.png").appendTo(a);
};

SchemaAlignmentDialog.UILink.prototype._renderDetails = function() {
    if (this._targetUI) {
        this._targetUI.dispose();
    }
    if (this._tableDetails) {
        this._tableDetails.remove();
    }
    
    this._tableDetails = $('<table></table>').addClass("schema-alignment-table-layout").appendTo(this._expandedDetailDiv);
    this._targetUI = new SchemaAlignmentDialog.UINode(
        this._dialog,
        this._link.target, 
        this._tableDetails[0], 
        { expanded: "links" in this._link.target && this._link.target.links.length > 0 });
};

SchemaAlignmentDialog.UILink.prototype._startEditProperty = function(elmt) {
    var sourceTypeID = this._parentUINode.getExpectedType();
    var targetTypeID = "type" in this._link.target && this._link.target.type !== null ? this._link.target.type.id : null;
    var targetTypeName = "columnName" in this._link.target ? this._link.target.columnName : null;
    
    if (sourceTypeID !== null) {
        var self = this;
        var dismissBusy = DialogSystem.showBusy();
        
        var instanceCount = 0;
        var outgoing = [];
        var incoming = [];
        
        function onDone(properties) {
            dismissBusy();
            
            self._showPropertySuggestPopup(
                elmt, 
                SchemaAlignmentDialog.UILink._rankProperties(properties, sourceTypeID, targetTypeID, targetTypeName)
            );
        }
        
        SchemaAlignmentDialog.UILink._getPropertiesOfType(
            sourceTypeID,
            onDone
        );
    } else {
        this._showPropertySuggestPopup(elmt, []);
    }
};

SchemaAlignmentDialog.UILink._rankProperties = function(properties, sourceTypeID, targetTypeID, targetTypeName) {
    var nameScorer;
    if (targetTypeName === null) {
        nameScorer = function() { return 1; };
    } else {
        var nameWords = targetTypeName.toLowerCase().replace(/\W/g, ' ').replace(/\s+/g, ' ').split(" ");
        var nameScoreString = function(score, s) {
            s = s.toLowerCase().replace(/\W/g, ' ');
            
            var n = 0;
            for (var i = 0; i < nameWords.length; i++) {
                if (s.indexOf(nameWords[i]) >= 0) {
                    n++;
                }
            }
            return Math.max(score, n / nameWords.length);
        };
        var nameScoreStrings = function(score, a) {
            $.each(a, function() { score = nameScoreString(score, this); });
            return score;
        };
        
        nameScorer = function(p) {
            var score = nameScoreString(0, p.name);
            score = nameScoreStrings(score, p.alias);
            
            if ("name2" in p) {
                score = nameScoreString(score, p.name2);
                score = nameScoreStrings(score, p.alias2);
            }
            
            if ("expects" in p && p.expects !== null) {
                score = nameScoreString(score, p.expects.name);
                score = nameScoreStrings(score, p.expects.alias);
            }
            if ("expects2" in p && p.expects2 !== null) {
                score = nameScoreString(score, p.expects2.name);
                score = nameScoreStrings(score, p.expects2.alias);
            }
            
            return score;
        };
    }
    
    var typeScorer;
    if (targetTypeID === null) {
        typeScorer = function(p) { return p.weight; };
    } else {
        typeScorer = function(p) {
            return p.expects.id == targetTypeID ? 1 : p.weight;
        };
    }
    
    var suggestions = [];
    for (var i = 0; i < properties.length; i++) {
        var p = properties[i];
        p.score = p.weight * (0.5 * nameScorer(p) + 0.5 * typeScorer(p));
        
        suggestions.push(p);
    }
    
    suggestions.sort(function(a, b) { return b.score - a.score; });
    suggestions = suggestions.slice(0, 7);
    
    return suggestions;
};

SchemaAlignmentDialog.UILink._getPropertiesOfType = function(typeID, onDone) {
    var done = false;
    
    $.getJSON(
        "http://gridworks-helper.freebaseapps.com/get_properties_of_type?type=" + typeID + "&callback=?",
        null,
        function(data) {
            if (done) return;
            
            onDone(data.properties || []);
        }
    );
    
    window.setTimeout(function() {
        if (done) return;
        
        done = true;
        onDone([]);
    }, 7000); // time to give up?
};

SchemaAlignmentDialog.UILink.prototype._showPropertySuggestPopup = function(elmt, suggestions) {
    self = this;
    
    var menu = MenuSystem.createMenu().width("350px");
    
    var commitProperty = function(p) {
        window.setTimeout(function() { MenuSystem.dismissAll(); }, 100);
        <commit_msg>Put more of the logic of suggesting properties for protograph links over to the gridworks-helper acre app.<commit_after>SchemaAlignmentDialog.UILink = function(dialog, link, table, options, parentUINode) {
    this._dialog = dialog;
    this._link = link;
    this._options = options;
    this._parentUINode = parentUINode;
    
    this._tr = table.insertRow(table.rows.length);
    this._tdMain = this._tr.insertCell(0);
    this._tdToggle = this._tr.insertCell(1);
    this._tdDetails = this._tr.insertCell(2);
    
    $(this._tdMain).addClass("schema-alignment-link-main").attr("width", "250").addClass("padded");
    $(this._tdToggle).addClass("schema-alignment-link-toggle").attr("width", "1%").addClass("padded");
    $(this._tdDetails).addClass("schema-alignment-link-details").attr("width", "90%");
    
    this._collapsedDetailDiv = $('<div></div>').appendTo(this._tdDetails).addClass("padded").html("...");
    this._expandedDetailDiv = $('<div></div>').appendTo(this._tdDetails).addClass("schema-alignment-detail-container");
    var self = this;
    var show = function() {
        if (self._options.expanded) {
            self._collapsedDetailDiv.hide();
            self._expandedDetailDiv.show();
        } else {
            self._collapsedDetailDiv.show();
            self._expandedDetailDiv.hide();
        }
    };
    show();
    
    $(this._tdToggle).html("&nbsp;");
    $('<img />')
        .attr("src", this._options.expanded ? "images/expanded.png" : "images/collapsed.png")
        .appendTo(this._tdToggle)
        .click(function() {
            self._options.expanded = !self._options.expanded;
            
            $(this).attr("src", self._options.expanded ? "images/expanded.png" : "images/collapsed.png");
            
            show();
        });
    
    this._renderMain();
    this._renderDetails();
};

SchemaAlignmentDialog.UILink.prototype._renderMain = function() {
    $(this._tdMain).empty();
    
    var label = this._link.property !== null ? this._link.property.id : "property?";
    
    var self = this;
    
    $('<img />')
        .attr("title", "remove property")
        .attr("src", "images/close.png")
        .css("cursor", "pointer")
        .prependTo(this._tdMain)
        .click(function() {
            window.setTimeout(function() {
                self._parentUINode.removeLink(self);
                self._tr.parentNode.removeChild(self._tr);
                self._dialog.preview();
            }, 100);
        });
    
    var a = $('<a href="javascript:{}"></a>')
        .addClass("schema-alignment-link-tag")
        .html(label)
        .appendTo(this._tdMain)
        .click(function(evt) {
            self._startEditProperty(this);
        });
        
    $('<img />').attr("src", "images/arrow-start.png").prependTo(a);
    $('<img />').attr("src", "images/arrow-end.png").appendTo(a);
};

SchemaAlignmentDialog.UILink.prototype._renderDetails = function() {
    if (this._targetUI) {
        this._targetUI.dispose();
    }
    if (this._tableDetails) {
        this._tableDetails.remove();
    }
    
    this._tableDetails = $('<table></table>').addClass("schema-alignment-table-layout").appendTo(this._expandedDetailDiv);
    this._targetUI = new SchemaAlignmentDialog.UINode(
        this._dialog,
        this._link.target, 
        this._tableDetails[0], 
        { expanded: "links" in this._link.target && this._link.target.links.length > 0 });
};

SchemaAlignmentDialog.UILink.prototype._startEditProperty = function(elmt) {
    var sourceTypeID = this._parentUINode.getExpectedType();
    var targetNode = this._targetUI._node;
    var targetTypeID = "type" in targetNode && targetNode.type !== null ? targetNode.type.id : null;
    var targetTypeName = "columnName" in targetNode ? targetNode.columnName : null;
    
    if (sourceTypeID !== null) {
        var self = this;
        var dismissBusy = DialogSystem.showBusy();
        
        var instanceCount = 0;
        var outgoing = [];
        var incoming = [];
        
        function onDone(properties) {
            dismissBusy();
            
            self._showPropertySuggestPopup(
                elmt, 
                properties
            );
        }
        
        SchemaAlignmentDialog.UILink._getPropertiesOfType(
            sourceTypeID,
            targetTypeID,
            targetTypeName,
            onDone
        );
    } else {
        this._showPropertySuggestPopup(elmt, []);
    }
};

SchemaAlignmentDialog.UILink._getPropertiesOfType = function(typeID, targetTypeID, targetTypeName, onDone) {
    var done = false;
    
    var params = {
        "type" : typeID
    };
    if (targetTypeID != null) {
        params.expects = targetTypeID;
    } else if (targetTypeName != null) {
        params.expects = targetTypeName;
    }
    
    $.getJSON(
        "http://gridworks-helper.freebaseapps.com/get_properties_of_type?" + $.param(params) + "&callback=?",
        null,
        function(data) {
            if (done) return;
            
            onDone(data.properties || []);
        }
    );
    
    window.setTimeout(function() {
        if (done) return;
        
        done = true;
        onDone([]);
    }, 7000); // time to give up?
};

SchemaAlignmentDialog.UILink.prototype._showPropertySuggestPopup = function(elmt, suggestions) {
    self = this;
    
    var menu = MenuSystem.createMenu().width("350px");
    
    var commitProperty = function(p) {
        window.setTimeout(function() { MenuSystem.dismissAll(); }, 100);
        
{'fraction_non_alphanumeric': 0.14915098669114274, 'fraction_numerical': 0.00535413798378461, 'mean_word_length': 2.18203942565101, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 30, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4891904', 'n_tokens_mistral': 3927, 'n_tokens_neox': 3848, 'n_words': 621}