<commit_before>var activeTime, pomodoro
var breakTimeSec = 360 // 360 sec = 6 min
var workTimeSec = 1440 // 1440 sec = 24 min

function renderTime (time) {
  var minutes = Math.floor(time / 60)
  var seconds = time % 60
  if (seconds.toString().length === 1) seconds = '0' + seconds
  window.time.innerHTML = minutes + ':' + seconds
}

function toggleStatusIcon (pause) {
  if (pause) window.statusIcon.innerHTML = '▮▮'
  else window.statusIcon.innerHTML = '▶'
}

function soundAlarm () {
  window.alarm.play()

  if (window.Notification.permission === 'granted') {
    var notify = new window.Notification('Pomodoro', { body: 'Time to switch!' })
  }

  console.log(notify)
}

function toggleType (type) {
  if (type === 'Work') {
    activeTime = breakTimeSec
    window.tomato.innerHTML = 'Break'
  } else {
    activeTime = workTimeSec
    window.tomato.innerHTML = 'Work'
  }
}

function clearPomodoro () {
  window.clearInterval(pomodoro)
  pomodoro = null
}

function toggleActive () {
  toggleStatusIcon(!pomodoro)

  if (!pomodoro) {
    pomodoro = window.setInterval(() => {
      activeTime--

      if (activeTime === 0) soundAlarm()
      if (activeTime < 0) toggleType(window.tomato.innerHTML)

      renderTime(activeTime)
    }, 1000)
  } else {
    clearPomodoro()
  }

}

function resetTimer () {
  activeTime = workTimeSec

  if (pomodoro) clearPomodoro()

  toggleType('hamburgers')
  toggleStatusIcon(false)
  renderTime(activeTime)
}

function timeIncDec (click) {
  // Exit if clock is running
  if (pomodoro) return

  var id = click.target.innerHTML
  var x = click.target.className

  if (id === '+') {
    window[x + 'Sec'] += 60
  } else if (id === '-' && window[x + 'Sec'] > 60) {
    window[x + 'Sec'] -= 60
  } else {
    return
  }

  window[x].innerHTML = Math.floor(window[x + 'Sec'] / 60)

  activeTime = workTimeSec
  renderTime(activeTime)
}

if (window.Notification.permission !== 'granted' &&
    window.Notification.permission !== 'denied') {
  window.Notification.requestPermission()
}

document.addEventListener('DOMContentLoaded', () => {
  resetTimer()
  renderTime(activeTime)
  window.timer.addEventListener('click', toggleActive)
  window.reset.addEventListener('click', resetTimer)

  // Add in-/decrement click listeners
  Array.from(document.getElementsByClassName('timeControl'))
       .forEach((x) => x.addEventListener('click', timeIncDec))
})
<commit_msg>Improved notifications<commit_after>var activeTime, pomodoro
var breakTimeSec = 360 // 360 sec = 6 min
var workTimeSec = 1440 // 1440 sec = 24 min

function renderTime (time) {
  var minutes = Math.floor(time / 60)
  var seconds = time % 60
  if (seconds.toString().length === 1) seconds = '0' + seconds
  window.time.innerHTML = minutes + ':' + seconds
}

function toggleStatusIcon (pause) {
  if (pause) window.statusIcon.innerHTML = '▮▮'
  else window.statusIcon.innerHTML = '▶'
}

function working () {
  return window.tomato.innerHTML === 'Work'
}

function soundAlarm () {
  window.alarm.play()

  var body

  if (working()) body = "Good job!\nIt's time for a break."
  else body = "Break's over!\nTime to get back to work."

  if (window.Notification.permission === 'granted') {
    var notify = new window.Notification('Pomodoro', { body: body })
  }

  console.log(notify)
}

function toggleType (type) {
  if (working()) {
    activeTime = breakTimeSec
    window.tomato.innerHTML = 'Break'
  } else {
    activeTime = workTimeSec
    window.tomato.innerHTML = 'Work'
  }
}

function clearPomodoro () {
  window.clearInterval(pomodoro)
  pomodoro = null
}

function toggleActive () {
  toggleStatusIcon(!pomodoro)

  if (!pomodoro) {
    pomodoro = window.setInterval(() => {
      activeTime--

      if (activeTime === 0) soundAlarm()
      if (activeTime < 0) toggleType()

      renderTime(activeTime)
    }, 1000)
  } else {
    clearPomodoro()
  }

}

function resetTimer () {
  activeTime = workTimeSec

  if (pomodoro) clearPomodoro()

  if (!working()) toggleType()
  toggleStatusIcon(false)
  renderTime(activeTime)
}

function timeIncDec (click) {
  // Exit if clock is running
  if (pomodoro) return

  var id = click.target.innerHTML
  var x = click.target.className

  if (id === '+') {
    window[x + 'Sec'] += 60
  } else if (id === '-' && window[x + 'Sec'] > 60) {
    window[x + 'Sec'] -= 60
  } else {
    return
  }

  window[x].innerHTML = Math.floor(window[x + 'Sec'] / 60)

  activeTime = workTimeSec
  renderTime(activeTime)
}

if (window.Notification.permission !== 'granted' &&
    window.Notification.permission !== 'denied') {
  window.Notification.requestPermission()
}

document.addEventListener('DOMContentLoaded', () => {
  resetTimer()
  renderTime(activeTime)
  window.timer.addEventListener('click', toggleActive)
  window.reset.addEventListener('click', resetTimer)

  // Add in-/decrement click listeners
  Array.from(document.getElementsByClassName('timeControl'))
       .forEach((x) => x.addEventListener('click', timeIncDec))
})
<|endoftext|>


<commit_before>var todos = {
  todos: [],
  add: function(text) {
    this.todos.push({
      text: text,
      completed: false
    });
  },
  edit: function(position, text) {
    this.todos[position].text = text;
  },
  destroy: function(position) {
    this.todos.splice(position, 1);
  },
  toggle: function(position) {
    var todo = this.todos[position];
    todo.completed = !todo.completed;
  },
  toggleAll: function() {
    var completed = this.completed().length;

    this.todos.forEach((t) => {
      t.completed = !(completed === this.size());
    }, this);
  },
  size: function() {
    return this.todos.length;
  },
  completed: function() {
    return this.todos.filter((t) => {
      return t.completed;
    });
  }
};

var handlers = {
  add: function() {
    var input = document.getElementsByClassName('new-todo')[0];
    if (input.value.replace(/\s+/g, ''))
      todos.add(input.value);
    input.value = '';
    view.displayTodos();
  },
  edit: function(position, val) {
    if (val.replace(/\s+/g, ''))
      todos.edit(position, val);
    view.displayTodos();
  },
  destroy: function(position) {
    todos.destroy(position);
    view.displayTodos();
  },
  toggle: function(position) {
    todos.toggle(position);
    view.displayTodos();
  },
  toggleAll: function() {
    todos.toggleAll();
    view.displayTodos();
  },
};

var view = {
  displayTodos: function() {
    var ul = document.querySelector('ul');
    ul.innerHTML = '';

    todos.todos.forEach(function(todo, i) {
      var li = document.createElement('li');
      li.id = i;
      li.className = todo.completed ? 'completed' : '';
      li.appendChild(view.createTodoItem(todo));
      ul.appendChild(li);
    }, this);
  },
  createDeleteButton: function() {
    var deleteButton = document.createElement('button');
    deleteButton.className = 'destroy';
    return deleteButton;
  },
  createEditInput: function() {
    var edit = document.createElement('input');
    edit.className = 'edit';

    edit.addEventListener('keyup', (e) => {
      if (e.keyCode == 13) {
        handlers.edit(Number(e.target.parentElement.id), e.target.value);
        edit.parentNode.removeChild(edit);
      }
    });

    return edit;
  },
  createToggle: function() {
    var toggle = document.createElement('input');
    toggle.className = 'toggle';
    toggle.type = 'checkbox';

    toggle.addEventListener('click', function(e) {
      var parent = e.target.parentNode.parentNode;
      var id = parent.id;
      parent.className = parent.className === 'completed' ? '' : 'completed';
      handlers.toggle(Number(id));
    });

    return toggle;
  },
  createTodoItem: function(todo) {
    var div = document.createElement('div');
    div.className = 'view';

    var toggle = this.createToggle();
    toggle.checked = todo.completed;

    var label = document.createElement('label');
    label.textContent = todo.text;

    var edit = this.createEditInput();

    label.addEventListener('dblclick', (e) => {
      var val = e.target.textContent;
      e.target.parentNode.insertAdjacentElement('afterend', edit);
      e.target.parentNode.parentNode.className = 'editing';
      edit.value = val;
      edit.focus();
    });

    div.appendChild(toggle);
    div.appendChild(label);

    div.appendChild(view.createDeleteButton());

    return div;
  },
  setUpEventListeners: function() {
    var todosUl = document.querySelector('ul');
    var newTodo = document.getElementsByClassName('new-todo')[0];

    todosUl.addEventListener('click', (e) => {
      var clickedElement = e.target;
      if (clickedElement.className === 'destroy') {
        handlers.destroy(parseInt(clickedElement.parentNode.id));
      }
    });

    newTodo.addEventListener('keyup', (e) => {
      if (e.keyCode == 13) {
        handlers.add();
      }
    });

    document.addEventListener('click', function(e) {
      var edit = document.getElementsByClassName('edit')[0];
      if (edit && e.target.className !== 'edit') {
        handlers.edit(Number(edit.parentElement.id), edit.value);
        edit.parentNode.removeChild(edit);
      }
    });
  }
};

view.setUpEventListeners();
<commit_msg>Refactor handlers<commit_after>var todos = {
  todos: [],
  add: function(text) {
    if (this.valid(text))
      this.todos.push({
        text: text,
        completed: false
      });
  },
  edit: function(position, text) {
    if (this.valid(text))
      this.todos[position].text = text;
  },
  destroy: function(position) {
    this.todos.splice(position, 1);
  },
  toggle: function(position) {
    var todo = this.todos[position];
    todo.completed = !todo.completed;
  },
  toggleAll: function() {
    var completed = this.completed().length;

    this.todos.forEach((t) => {
      t.completed = !(completed === this.size());
    }, this);
  },
  size: function() {
    return this.todos.length;
  },
  completed: function() {
    return this.todos.filter((t) => {
      return t.completed;
    });
  },
  valid: function(text) {
    return text.replace(/\s+/g, '');
  }
};

var handlers = {
  add: function() {
    var input = document.getElementsByClassName('new-todo')[0];
    todos.add(input.value);
    input.value = '';
    view.displayTodos();
  },
  edit: function(position, text) {
    todos.edit(position, text);
    view.displayTodos();
  },
  destroy: function(position) {
    todos.destroy(position);
    view.displayTodos();
  },
  toggle: function(position) {
    todos.toggle(position);
    view.displayTodos();
  },
  toggleAll: function() {
    todos.toggleAll();
    view.displayTodos();
  },
};

var view = {
  displayTodos: function() {
    var ul = document.querySelector('ul');
    ul.innerHTML = '';

    todos.todos.forEach(function(todo, i) {
      ul.appendChild(this.createListItem(todo, i));
    }, this);
  },
  createListItem: function(todo, i) {
    var li = document.createElement('li');
    li.id = i;
    li.className = todo.completed ? 'completed' : '';
    li.appendChild(this.createTodoItem(todo));
    return li;
  },
  createDeleteButton: function() {
    var deleteButton = document.createElement('button');
    deleteButton.className = 'destroy';
    return deleteButton;
  },
  createEditInput: function() {
    var edit = document.createElement('input');
    edit.className = 'edit';

    edit.addEventListener('keyup', (e) => {
      if (e.keyCode == 13) {
        handlers.edit(Number(e.target.parentElement.id), e.target.value);
        edit.parentNode.removeChild(edit);
      }
    });

    return edit;
  },
  createToggle: function() {
    var toggle = document.createElement('input');
    toggle.className = 'toggle';
    toggle.type = 'checkbox';

    toggle.addEventListener('click', function(e) {
      var parent = e.target.parentNode.parentNode;
      var id = parent.id;
      parent.className = parent.className === 'completed' ? '' : 'completed';
      handlers.toggle(Number(id));
    });

    return toggle;
  },
  createTodoItem: function(todo) {
    var div = document.createElement('div');
    div.className = 'view';

    var toggle = this.createToggle();
    toggle.checked = todo.completed;

    var label = document.createElement('label');
    label.textContent = todo.text;

    var edit = this.createEditInput();

    label.addEventListener('dblclick', (e) => {
      var val = e.target.textContent;
      e.target.parentNode.insertAdjacentElement('afterend', edit);
      e.target.parentNode.parentNode.className = 'editing';
      edit.value = val;
      edit.focus();
    });

    div.appendChild(toggle);
    div.appendChild(label);

    div.appendChild(this.createDeleteButton());

    return div;
  },
  setUpEventListeners: function() {
    var todosUl = document.querySelector('ul');
    todosUl.addEventListener('click', (e) => {
      var clickedElement = e.target;
      if (clickedElement.className === 'destroy') {
        handlers.destroy(parseInt(clickedElement.parentNode.id));
      }
    });

    var newTodo = document.getElementsByClassName('new-todo')[0];
    newTodo.addEventListener('keyup', (e) => {
      if (e.keyCode == 13) {
        handlers.add();
      }
    });

    document.addEventListener('click', function(e) {
      var edit = document.getElementsByClassName('edit')[0];
      if (edit && e.target.className !== 'edit') {
        handlers.edit(Number(edit.parentElement.id), edit.value);
        edit.parentNode.removeChild(edit);
      }
    });
  }
};

view.setUpEventListeners();
<|endoftext|>


<commit_before>var whereIsMyBuild = function ($, d3) {
    var my = {
        width: 960,
        height: 2000,
        jenkinsUrl: "http://localhost:8080",
        startJob: "chain-start",
        updateInterval: 2000,
        commitUpdateInterval: 20000,
        bulkUpdateSize: 10
    };

    var data;
    var needsUpdate = true;

    var updateLinks = function() {
        var jobRequest = $.getJSON(
            my.jenkinsUrl + "/job/" + my.startJob + "/api/json?tree=allBuilds[changeSet[*[*]]]"
        );
        jobRequest.then(function(job) {
            var builds = job.allBuilds,
                revs = $("#revs");

            revs.empty();
            builds.map(function(build) {
                return build.changeSet.items;
            }).reduce(function(a, b) {
                return a.concat(b);
            }).forEach(function(el) {
                revs.append("
" + el.commitId + " - " + el.user + "
" + el.msg.replace("\n", "
") + "
");
            });
        });
    };

    var getQueryVariable = function (variable) {
        var query = window.location.search.substring(1),
            results = query.split("&").map(function (el) {
                return el.split("=")
            }).filter(function (el) {
                return (el[0] === variable);
            }).map(function (el) {
                return el[1];
            });
        return results.length === 0 ? false : results[0];
    };

    var baseBuildNode = {
        getNewFailCount: function () {
            if (this.newFailCount) {
                return this.newFailCount;
            }
            return 0;
        }

    };

    var buildNode = function (jobName, revision, url) {
        var n = Object.create(baseBuildNode);
        n.jobName = jobName;
        n.revision = revision;
        n.url = url;
        n.status = "pending";
        n.downstreamProjects = [];

        return n;
    };

    var toUpdate = [];

    var renderer = function (conf, data) {
        var my = {};

        var cluster = d3.layout.tree().nodeSize([200, 200]);
        var diagonal = d3.svg.diagonal()
            .projection(function (d) {
                return [d.x, d.y];
            });

        var canvas = d3.select("body").append("svg")
            .attr("width", conf.width)
            .attr("height", conf.height);

        var svg = canvas
            .append("g")
            .attr("transform", "translate(" + (conf.width/2) + ",200)");

        d3.select(self.frameElement).style("height", conf.height + "px");

        var jobName = function (job) {
            return job.jobName;
        };

        var jobUrl = function (job) {
            return job.url;
        };

        var addBuildNode = function(node, radius, cssClass) {
            var arc = d3.svg.arc()
                .innerRadius(radius / 2)
                .outerRadius(radius)
                .startAngle(0)
                .endAngle(Math.PI * 2);

            node.append("circle")
                .attr("r", radius);
            node.append("path")
                .attr("class", cssClass)
                .attr("d", arc);
            node.append("text")
                .style("text-anchor", "middle")
                .attr("dy", "0.3em")
                .attr("class", "testcount");
        };

        my.renderData = function () {
            var nodes = cluster.nodes(data);

            var maxY = nodes.reduce(function (acc, current) {
                return Math.max(acc, current.y);
            }, 400);

            canvas.attr("height", (maxY + 400) + "px");

            var links = cluster.links(nodes);

            var link = svg.selectAll(".link")
                .data(links, function (d) {
                    return d.source.jobName + "->" +d.target.jobName;
                });

            link.enter().insert("path", ".node")
                .attr("class", "link");

            link.transition().attr("d", diagonal);

            link.exit().remove();

            var node = svg.selectAll(".node")
                .data(nodes, jobName);

            var parentNode = node.enter().append("g")
                .attr("class", "node");

            var coreNode = parentNode
                .append("a");

            var textNode = coreNode
                .append("text")
                .attr("transform", "rotate(10)")
                .attr("class", "core");

            addBuildNode(coreNode, 20, "core");
            var dxChildren = function () {
                return 40;
            };

            textNode
                .append("tspan")
                .text(jobName);

            textNode
                .append("tspan")
                .attr("class", "revision")
                .attr("dy", "1.2em")
                .text(function (d) {
                    return d.revision
                });

            var downstreamNodes = node.selectAll(".downstream").data(function (coreNode) {
                return coreNode.downstreamProjects;
            }, jobName);

            var downstreamContainer = downstreamNodes.enter()
                .append("a")
                .attr("class", "downstream")
                .attr("transform", function (d, i) {
                    return "rotate(" + (-10 + 35 * i) + ")translate(-40,0)";
                });

            addBuildNode(downstreamContainer, 10, "downstream");

            downstreamContainer
                .append("text")
                .text(function (d) {
                    var parentData = d3.select(this.parentNode.parentNode).datum();
                    return d.jobName.replace(new RegExp(parentData.jobName + '(-|~~)*'), '')
                        .split('-')
                        .map(function (s) {
                            return s[0]
                        })
                        .join('');
                })
                .attr("text-anchor", "end")
                .attr("dx", "-15")
                .attr("dy", "0.3em");

            downstreamNodes.exit().remove();

            node.selectAll("a")
                .attr("xlink:href", jobUrl);

            node.selectAll("a text tspan")
                .attr("x", "0")
                .attr("dx", dxChildren);

            node.selectAll("text.testcount")
                .text(function (d) {
                    var newFailCount = d.getNewFailCount();
                    return newFailCount === 0 ? undefined : (newFailCount > 0 ? '+' + newFailCount : newFailCount);
                })
                .classed('worse', function (d) {
                    return d.getNewFailCount() > 0;
                })
                .classed('better', function (d) {
                    return d.getNewFailCount() < 0;
                });

            node.selectAll("path")
                .attr("class", function (d) {
                    return d.status;
                });

            node.selectAll("a text.core").transition()
                .attr("dy", 0);

            node.selectAll("a text tspan.revision").transition()
                .text(function (d) {
                    return d.revision;
                });

            node.transition().attr("transform", function (d) {
                return "translate(" + d.x + "," + d.y + ")";
            });

            node.exit().remove();
        };

        return my;
    };

    var buildData = function (nodeToUpdate) {
        var jobName = nodeToUpdate.jobName;
        var resultDef = $.Deferred();
        var findRevision = function (envVars) {
            for (var i = 0; i < envVars.length; i++) {
                var env = envVars[i];
                if (env.name === "REV") {
                    return parseInt(env.value, 10);
                }
            }
        };

        var nodeFromProject = function(project) {
            return buildNode(project.name, nodeToUpdate.revision, project.url);
        };

        var buildKeys =
            "number,url,result,actions[triggeredProjects[name,url,downstreamProjects[url,name]],failCount,skipCount,totalCount,urlName],changeSet[items[commitId,author,msg]]";

        var jobRequest = $.getJSON(
            my.jenkinsUrl + "/job/" + jobName +
            "/api/json?tree=url,downstreamProjects[url,name],lastCompletedBuild[" + buildKeys + "]"
        ).then(function (job) {
                return job;
            });

        var buildDef = jobRequest.then(function (job) {
            if (nodeToUpdate.url === undefined) {
                nodeToUpdate.url = job.url;
                $(data).trigger("change");
            }
            return job.lastCompletedBuild;
        });

        var getEnvVars = function (build) {
            return build === undefined ? undefined : $.getJSON(build.url +
                "injectedEnvVars/export");
        };
        var getRevision = function (build) {
            if (build === undefined) {
                return undefined;
            }
            return getEnvVars(build).then(function (envVars) {
                return findRevision(envVars.envVars.envVar)
            })
        };

        var buildUrl = function (buildNumber) {
            return my.jenkinsUrl + "/job/" + nodeToUpdate.jobName + "/" + buildNumber +
                                "/api/json?tree=" + buildKeys;
        };

        var getBuildDef = function (buildNumber) {
            return $.getJSON(buildUrl(buildNumber)).then(function (build) {
                return build;
            });
        };

        var buildForRevision = function (buildDef) {
            return $.when(buildDef, buildDef.then(getRevision)).then(
                function (build, revision) {
                    if (build === undefined) {
                        return undefined;
                    }
                    build.revision = revision;
                    if (revision < nodeToUpdate.revision) {
                        return undefined;
                    } else if (revision === nodeToUpdate.revision) {
                        return build;
                    } else {
                        return buildForRevision(getBuildDef(build.number - 1))
                            .then(function (previousBuild) {
                            if (previousBuild === undefined) {
                                return build;
                            } else {
                                return previousBuild;
                            }
                        })
                    }
                })
        };

        var getTriggeredProjects = function (build) {
            return build.actions.filter(function (el) {
                return el.triggeredProjects;
            }).map(function (el) {
                return el.triggeredProjects;
            }).reduce(function (a, b) {
                return a.concat(b);
            }, []);
        };

        var getTestResult = function (build) {
            var actions = build.actions;

            var testReports = actions.filter(function (action) {
                return action.urlName === "testReport";
            });

            if (testReports.length > 0) {
                return testReports[0];
            }
            return {
                failCount: 0,
                skipCount: 0,
                totalCount: 0
            };
        };

        var foundBuildDef = buildForRevision(buildDef);

        var previousBuildDef = foundBuildDef.then(function (build) {
            return build ? (build.number > 1 ? getBuildDef(build.number - 1) : undefined) : undefined;
        });

        $.when(foundBuildDef, previousBuildDef).then(function (build, previousBuild) {
            if (build === undefined) {
                toUpdate.push(nodeToUpdate);
                resultDef.resolve(nodeToUpdate);
            } else {
                nodeToUpdate.status = build.result.toLowerCase();
                nodeToUpdate.revision = build.revision;
                nodeToUpdate.url = build.url;
                nodeToUpdate.testResult = getTestResult(build);
                if (previousBuild !== undefined) {
                    var previousTestResult = getTestResult(previousBuild);
                    nodeToUpdate.newFailCount = nodeToUpdate.testResult.failCount - previousTestResult.failCount;
                }

                var triggeredProjects = getTriggeredProjects(build);
                var children = triggeredProjects.map(function (project) {
                    var node = nodeFromProject(project);
                    node.downstreamProjects = project.downstreamProjects.map(nodeFromProject);
                    return node;
                });

                children.map(buildData);
                nodeToUpdate.downstreamProjects.map(buildData);

                nodeToUpdate.children = children;

                $(data).trigger("change");

                resultDef.resolve(nodeToUpdate);
            }
        }, function () {
            toUpdate.push(nodeToUpdate);
        });

        return resultDef;
    };

    var updateNext = function () {
        if (toUpdate.length > 0) {
            var toUpdateNow = toUpdate.slice(0, my.bulkUpdateSize);
            toUpdate = toUpdate.slice(my.bulkUpdateSize);
            toUpdateNow.map(buildData);
        }
    };

    my.init = function () {
        data = buildNode(my.startJob, parseInt(getQueryVariable("revision"), 10));
        toUpdate.push(data);

        var r = renderer(this, data);

        $(data).bind("change", function () {
            needsUpdate = true;
            setTimeout(function () {
                if (needsUpdate) {
                    r.renderData();
                    needsUpdate = false;
                }
            }, 0);
        });
        $(data).trigger("change");

        updateNext();
        updateLinks();

        setInterval(updateLinks, my.commitUpdateInterval);
        setInterval(updateNext, my.updateInterval);
    };

    return my;

}($, d3);
<commit_msg>Fix backslashes in returned JSON<commit_after>var whereIsMyBuild = function ($, d3) {
    var my = {
        width: 960,
        height: 2000,
        jenkinsUrl: "http://localhost:8080",
        startJob: "chain-start",
        updateInterval: 2000,
        commitUpdateInterval: 20000,
        bulkUpdateSize: 10
    };

    var data;
    var needsUpdate = true;

    var getJSON = function(url) {
        return $.ajax({
            dataType: "json",
            dataFilter: function (data) {
                return data.replace(/\\/g, '\\\\');
            },
            url: url
        });
    };

    var updateLinks = function() {
        var jobRequest = getJSON(
            my.jenkinsUrl + "/job/" + my.startJob + "/api/json?tree=allBuilds[changeSet[*[*]]]"
        );
        jobRequest.then(function(job) {
            var builds = job.allBuilds,
                revs = $("#revs");

            revs.empty();
            builds.map(function(build) {
                return build.changeSet.items;
            }).reduce(function(a, b) {
                return a.concat(b);
            }).forEach(function(el) {
                revs.append("
" + el.commitId + " - " + el.user + "
" + el.msg.replace("\n", "
") + "
");
            });
        });
    };

    var getQueryVariable = function (variable) {
        var query = window.location.search.substring(1),
            results = query.split("&").map(function (el) {
                return el.split("=")
            }).filter(function (el) {
                return (el[0] === variable);
            }).map(function (el) {
                return el[1];
            });
        return results.length === 0 ? false : results[0];
    };

    var baseBuildNode = {
        getNewFailCount: function () {
            if (this.newFailCount) {
                return this.newFailCount;
            }
            return 0;
        }

    };

    var buildNode = function (jobName, revision, url) {
        var n = Object.create(baseBuildNode);
        n.jobName = jobName;
        n.revision = revision;
        n.url = url;
        n.status = "pending";
        n.downstreamProjects = [];

        return n;
    };

    var toUpdate = [];

    var renderer = function (conf, data) {
        var my = {};

        var cluster = d3.layout.tree().nodeSize([200, 200]);
        var diagonal = d3.svg.diagonal()
            .projection(function (d) {
                return [d.x, d.y];
            });

        var canvas = d3.select("body").append("svg")
            .attr("width", conf.width)
            .attr("height", conf.height);

        var svg = canvas
            .append("g")
            .attr("transform", "translate(" + (conf.width/2) + ",200)");

        d3.select(self.frameElement).style("height", conf.height + "px");

        var jobName = function (job) {
            return job.jobName;
        };

        var jobUrl = function (job) {
            return job.url;
        };

        var addBuildNode = function(node, radius, cssClass) {
            var arc = d3.svg.arc()
                .innerRadius(radius / 2)
                .outerRadius(radius)
                .startAngle(0)
                .endAngle(Math.PI * 2);

            node.append("circle")
                .attr("r", radius);
            node.append("path")
                .attr("class", cssClass)
                .attr("d", arc);
            node.append("text")
                .style("text-anchor", "middle")
                .attr("dy", "0.3em")
                .attr("class", "testcount");
        };

        my.renderData = function () {
            var nodes = cluster.nodes(data);

            var maxY = nodes.reduce(function (acc, current) {
                return Math.max(acc, current.y);
            }, 400);

            canvas.attr("height", (maxY + 400) + "px");

            var links = cluster.links(nodes);

            var link = svg.selectAll(".link")
                .data(links, function (d) {
                    return d.source.jobName + "->" +d.target.jobName;
                });

            link.enter().insert("path", ".node")
                .attr("class", "link");

            link.transition().attr("d", diagonal);

            link.exit().remove();

            var node = svg.selectAll(".node")
                .data(nodes, jobName);

            var parentNode = node.enter().append("g")
                .attr("class", "node");

            var coreNode = parentNode
                .append("a");

            var textNode = coreNode
                .append("text")
                .attr("transform", "rotate(10)")
                .attr("class", "core");

            addBuildNode(coreNode, 20, "core");
            var dxChildren = function () {
                return 40;
            };

            textNode
                .append("tspan")
                .text(jobName);

            textNode
                .append("tspan")
                .attr("class", "revision")
                .attr("dy", "1.2em")
                .text(function (d) {
                    return d.revision
                });

            var downstreamNodes = node.selectAll(".downstream").data(function (coreNode) {
                return coreNode.downstreamProjects;
            }, jobName);

            var downstreamContainer = downstreamNodes.enter()
                .append("a")
                .attr("class", "downstream")
                .attr("transform", function (d, i) {
                    return "rotate(" + (-10 + 35 * i) + ")translate(-40,0)";
                });

            addBuildNode(downstreamContainer, 10, "downstream");

            downstreamContainer
                .append("text")
                .text(function (d) {
                    var parentData = d3.select(this.parentNode.parentNode).datum();
                    return d.jobName.replace(new RegExp(parentData.jobName + '(-|~~)*'), '')
                        .split('-')
                        .map(function (s) {
                            return s[0]
                        })
                        .join('');
                })
                .attr("text-anchor", "end")
                .attr("dx", "-15")
                .attr("dy", "0.3em");

            downstreamNodes.exit().remove();

            node.selectAll("a")
                .attr("xlink:href", jobUrl);

            node.selectAll("a text tspan")
                .attr("x", "0")
                .attr("dx", dxChildren);

            node.selectAll("text.testcount")
                .text(function (d) {
                    var newFailCount = d.getNewFailCount();
                    return newFailCount === 0 ? undefined : (newFailCount > 0 ? '+' + newFailCount : newFailCount);
                })
                .classed('worse', function (d) {
                    return d.getNewFailCount() > 0;
                })
                .classed('better', function (d) {
                    return d.getNewFailCount() < 0;
                });

            node.selectAll("path")
                .attr("class", function (d) {
                    return d.status;
                });

            node.selectAll("a text.core").transition()
                .attr("dy", 0);

            node.selectAll("a text tspan.revision").transition()
                .text(function (d) {
                    return d.revision;
                });

            node.transition().attr("transform", function (d) {
                return "translate(" + d.x + "," + d.y + ")";
            });

            node.exit().remove();
        };

        return my;
    };

    var buildData = function (nodeToUpdate) {
        var jobName = nodeToUpdate.jobName;
        var resultDef = $.Deferred();
        var findRevision = function (envVars) {
            for (var i = 0; i < envVars.length; i++) {
                var env = envVars[i];
                if (env.name === "REV") {
                    return parseInt(env.value, 10);
                }
            }
        };

        var nodeFromProject = function(project) {
            return buildNode(project.name, nodeToUpdate.revision, project.url);
        };

        var buildKeys =
            "number,url,result,actions[triggeredProjects[name,url,downstreamProjects[url,name]],failCount,skipCount,totalCount,urlName],changeSet[items[commitId,author,msg]]";

        var jobRequest = getJSON(
            my.jenkinsUrl + "/job/" + jobName +
            "/api/json?tree=url,downstreamProjects[url,name],lastCompletedBuild[" + buildKeys + "]"
        ).then(function (job) {
                return job;
            });

        var buildDef = jobRequest.then(function (job) {
            if (nodeToUpdate.url === undefined) {
                nodeToUpdate.url = job.url;
                $(data).trigger("change");
            }
            return job.lastCompletedBuild;
        });

        var getEnvVars = function (build) {
            return build === undefined ? undefined : getJSON(build.url +
                "injectedEnvVars/export");
        };
        var getRevision = function (build) {
            if (build === undefined) {
                return undefined;
            }
            return getEnvVars(build).then(function (envVars) {
                return findRevision(envVars.envVars.envVar)
            })
        };

        var buildUrl = function (buildNumber) {
            return my.jenkinsUrl + "/job/" + nodeToUpdate.jobName + "/" + buildNumber +
                                "/api/json?tree=" + buildKeys;
        };

        var getBuildDef = function (buildNumber) {
            return getJSON(buildUrl(buildNumber)).then(function (build) {
                return build;
            });
        };

        var buildForRevision = function (buildDef) {
            return $.when(buildDef, buildDef.then(getRevision)).then(
                function (build, revision) {
                    if (build === undefined) {
                        return undefined;
                    }
                    build.revision = revision;
                    if (revision < nodeToUpdate.revision) {
                        return undefined;
                    } else if (revision === nodeToUpdate.revision) {
                        return build;
                    } else {
                        return buildForRevision(getBuildDef(build.number - 1))
                            .then(function (previousBuild) {
                            if (previousBuild === undefined) {
                                return build;
                            } else {
                                return previousBuild;
                            }
                        })
                    }
                })
        };

        var getTriggeredProjects = function (build) {
            return build.actions.filter(function (el) {
                return el.triggeredProjects;
            }).map(function (el) {
                return el.triggeredProjects;
            }).reduce(function (a, b) {
                return a.concat(b);
            }, []);
        };

        var getTestResult = function (build) {
            var actions = build.actions;

            var testReports = actions.filter(function (action) {
                return action.urlName === "testReport";
            });

            if (testReports.length > 0) {
                return testReports[0];
            }
            return {
                failCount: 0,
                skipCount: 0,
                totalCount: 0
            };
        };

        var foundBuildDef = buildForRevision(buildDef);

        var previousBuildDef = foundBuildDef.then(function (build) {
            return build ? (build.number > 1 ? getBuildDef(build.number - 1) : undefined) : undefined;
        });

        $.when(foundBuildDef, previousBuildDef).then(function (build, previousBuild) {
            if (build === undefined) {
                toUpdate.push(nodeToUpdate);
                resultDef.resolve(nodeToUpdate);
            } else {
                nodeToUpdate.status = build.result.toLowerCase();
                nodeToUpdate.revision = build.revision;
                nodeToUpdate.url = build.url;
                nodeToUpdate.testResult = getTestResult(build);
                if (previousBuild !== undefined) {
                    var previousTestResult = getTestResult(previousBuild);
                    nodeToUpdate.newFailCount = nodeToUpdate.testResult.failCount - previousTestResult.failCount;
                }

                var triggeredProjects = getTriggeredProjects(build);
                var children = triggeredProjects.map(function (project) {
                    var node = nodeFromProject(project);
                    node.downstreamProjects = project.downstreamProjects.map(nodeFromProject);
                    return node;
                });

                children.map(buildData);
                nodeToUpdate.downstreamProjects.map(buildData);

                nodeToUpdate.children = children;

                $(data).trigger("change");

                resultDef.resolve(nodeToUpdate);
            }
        }, function () {
            toUpdate.push(nodeToUpdate);
        });

        return resultDef;
    };

    var updateNext = function () {
        if (toUpdate.length > 0) {
            var toUpdateNow = toUpdate.slice(0, my.bulkUpdateSize);
            toUpdate = toUpdate.slice(my.bulkUpdateSize);
            toUpdateNow.map(buildData);
        }
    };

    my.init = function () {
        data = buildNode(my.startJob, parseInt(getQueryVariable("revision"), 10));
        toUpdate.push(data);

        var r = renderer(this, data);

        $(data).bind("change", function () {
            needsUpdate = true;
            setTimeout(function () {
                if (needsUpdate) {
                    r.renderData();
                    needsUpdate = false;
                }
            }, 0);
        });
        $(data).trigger("change");

        updateNext();
        updateLinks();

        setInterval(updateLinks, my.commitUpdateInterval);
        setInterval(updateNext, my.updateInterval);
    };

    return my;

}($, d3);
<|endoftext|>


<commit_before>'use strict';

const _ = require('lodash');
const Script = require('smooch-bot').Script;
var pg = require('pg');
var Q = require("q");
var request = require("request");
var newUser = require("./db");
var nlp = require("./nlp");
var pushConv = require("./push");

const scriptRules = require('./script.json');

function wait(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

module.exports = new Script({
    processing: {
        //prompt: (bot) => bot.say('Beep boop...'),
        receive: () => 'processing'
    },

    start: {
        receive: (bot) => {
            return bot.say('Hello!  I\'m A16, the Agile2016 EventBot Concierge.  To find out what I can help you with type MENU for options or KEY for Keywords.')
                .then(() => 'speak');
        }
    },

    speak: {
        receive: (bot, message) => {
            console.log("===bot user ");
            console.log("===receive step 1",message);
            let upperText = message.text.trim().toUpperCase();

            var botUser = bot.userId;
            var authUsers = ['a30fa820d0a0f0216fa26070'];

            //Undone - currently only creates new user
            //needs to create conversation record and update it throughout the prcoess
            console.log("===before db",bot);
            newUser(bot)
              .then (console.log("===after db", bot.userId))

              //undone - test for userid and or message
              //look at stacking messages in DB and looking them up
              //end conversation and do not send a response to the user that kicked things off
              //
              if (authUsers.indexOf(bot.userId) !== -1) {
                if (message.text.substr(0,5) == '/msg ') {
                  upperText = upperText.substr(0,4);
                  pushConv(bot, message.text.substr(5));
                  console.log("****after push msg:  ",message.text);
                }
              }

            function updateSilent() {
                switch (upperText) {
                    case "CONNECT ME":
                        return bot.setProp("silent", true);
                    case "/SUPPORT":
                        return bot.setProp("silent", true);
                    case "DISCONNECT":
                        return bot.setProp("silent", false);
                    case "/A16":
                        console.log("*** ",upperText," ***");
                        processMessage(false);
                        return bot.setProp("silent", false);
                    default:
                        return Promise.resolve();
                }
            }

            console.log("===receive step 2",upperText);

            function getSilent() {
                return bot.getProp("silent");
            }

            function processMessage(isSilent) {
                if (isSilent) {
                    return Promise.resolve("speak");
                }

                var promises = [];
                var source;
                var fulfillmentSpeech;
                var simplified;
                promises.push(nlp(upperText, bot.userId));

                Q.all(promises).then(function(responses) {
                    // response is the JSON from API.ai
                    responses.forEach(function(response) {
                        //console.log("===in Q.all");
                        console.log("===received result from API.ai",response);
                        source = response.result.source;
                        if (source && source !== 'agent')
                        {
                            fulfillmentSpeech = response.result.fulfillment.speech;
                            simplified = response.result.parameters.simplified;
                        }
                        console.log("source: ", source);
                        console.log("fulfillmentSpeech: ", fulfillmentSpeech);
                        console.log("simplified: ", simplified);

                        respondMessage(source, fulfillmentSpeech, simplified);
                    });
                }, function(error) {
                    console.log("===Q all error ", error);
                });
                //return next();

            }

            function respondMessage(source, fulfillmentSpeech, simplified)
            {
                console.log("source: ", source);
                console.log("fulfillmentSpeech: ", fulfillmentSpeech);
                console.log("simplified: ", simplified);
                console.log("===receive step 3",upperText);

              if (source != 'agent')
                {
                    console.log("===source is ", source);
                    if (fulfillmentSpeech)
                    {
                        console.log("fulfillmentSpeech is: ", fulfillmentSpeech);
                        //return bot.say(fulfillmentSpeech).then(() => 'speak');
                        upperText = simplified.trim().toUpperCase();
                    }
                    else if (simplified)
                    {
                        console.log("simplified is: ", simplified);
                        upperText = simplified.toUpperCase();
                    }
                }
                if (!_.has(scriptRules, upperText)) {
                    console.log("===no rule", upperText);
                    return bot.say(`I'm sorry that is not something I know.  Type MENU or KEY for a list of things I can help you with.`).then(() => 'speak');
                }

                console.log("===receive step 3",upperText);

                var response = scriptRules[upperText];
                var lines = response.split('\n');

                bot.userId = botUser;

                var p = Promise.resolve();
                _.each(lines, function(line) {
                    line = line.trim();
                    p = p.then(function() {
                        console.log("=== p line",line);
                        return wait(50).then(function() {
                            return bot.say(line);
                        });
                    });
                });
                return p.then(() => 'speak');
            }

            return updateSilent()
                .then(getSilent)
                .then(processMessage);
        }
    }
});
<commit_msg>bot.store<commit_after>'use strict';

const _ = require('lodash');
const Script = require('smooch-bot').Script;
var pg = require('pg');
var Q = require("q");
var request = require("request");
var newUser = require("./db");
var nlp = require("./nlp");
var pushConv = require("./push");

const scriptRules = require('./script.json');

function wait(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

module.exports = new Script({
    processing: {
        //prompt: (bot) => bot.say('Beep boop...'),
        receive: () => 'processing'
    },

    start: {
        receive: (bot) => {
            return bot.say('Hello!  I\'m A16, the Agile2016 EventBot Concierge.  To find out what I can help you with type MENU for options or KEY for Keywords.')
                .then(() => 'speak');
        }
    },

    speak: {
        receive: (bot, message) => {
            console.log("===bot user ");
            console.log("===receive step 1",message);
            let upperText = message.text.trim().toUpperCase();

            var botUser = bot.userId;
            var authUsers = ['a30fa820d0a0f0216fa26070'];

            //Undone - currently only creates new user
            //needs to create conversation record and update it throughout the prcoess
            console.log("===before db",bot.store);
            newUser(bot)
              .then (console.log("===after db", bot.userId))

              //undone - test for userid and or message
              //look at stacking messages in DB and looking them up
              //end conversation and do not send a response to the user that kicked things off
              //
              if (authUsers.indexOf(bot.userId) !== -1) {
                if (message.text.substr(0,5) == '/msg ') {
                  upperText = upperText.substr(0,4);
                  pushConv(bot, message.text.substr(5));
                  console.log("****after push msg:  ",message.text);
                }
              }

            function updateSilent() {
                switch (upperText) {
                    case "CONNECT ME":
                        return bot.setProp("silent", true);
                    case "/SUPPORT":
                        return bot.setProp("silent", true);
                    case "DISCONNECT":
                        return bot.setProp("silent", false);
                    case "/A16":
                        console.log("*** ",upperText," ***");
                        processMessage(false);
                        return bot.setProp("silent", false);
                    default:
                        return Promise.resolve();
                }
            }

            console.log("===receive step 2",upperText);

            function getSilent() {
                return bot.getProp("silent");
            }

            function processMessage(isSilent) {
                if (isSilent) {
                    return Promise.resolve("speak");
                }

                var promises = [];
                var source;
                var fulfillmentSpeech;
                var simplified;
                promises.push(nlp(upperText, bot.userId));

                Q.all(promises).then(function(responses) {
                    // response is the JSON from API.ai
                    responses.forEach(function(response) {
                        //console.log("===in Q.all");
                        console.log("===received result from API.ai",response);
                        source = response.result.source;
                        if (source && source !== 'agent')
                        {
                            fulfillmentSpeech = response.result.fulfillment.speech;
                            simplified = response.result.parameters.simplified;
                        }
                        console.log("source: ", source);
                        console.log("fulfillmentSpeech: ", fulfillmentSpeech);
                        console.log("simplified: ", simplified);

                        respondMessage(source, fulfillmentSpeech, simplified);
                    });
                }, function(error) {
                    console.log("===Q all error ", error);
                });
                //return next();

            }

            function respondMessage(source, fulfillmentSpeech, simplified)
            {
                console.log("source: ", source);
                console.log("fulfillmentSpeech: ", fulfillmentSpeech);
                console.log("simplified: ", simplified);
                console.log("===receive step 3",upperText);

              if (source != 'agent')
                {
                    console.log("===source is ", source);
                    if (fulfillmentSpeech)
                    {
                        console.log("fulfillmentSpeech is: ", fulfillmentSpeech);
                        //return bot.say(fulfillmentSpeech).then(() => 'speak');
                        upperText = simplified.trim().toUpperCase();
                    }
                    else if (simplified)
                    {
                        console.log("simplified is: ", simplified);
                        upperText = simplified.toUpperCase();
                    }
                }
                if (!_.has(scriptRules, upperText)) {
                    console.log("===no rule", upperText);
                    return bot.say(`I'm sorry that is not something I know.  Type MENU or KEY for a list of things I can help you with.`).then(() => 'speak');
                }

                console.log("===receive step 3",upperText);

                var response = scriptRules[upperText];
                var lines = response.split('\n');

                bot.userId = botUser;

                var p = Promise.resolve();
                _.each(lines, function(line) {
                    line = line.trim();
                    p = p.then(function() {
                        console.log("=== p line",line);
                        return wait(50).then(function() {
                            return bot.say(line);
                        });
                    });
                });
                return p.then(() => 'speak');
            }

            return updateSilent()
                .then(getSilent)
                .then(processMessage);
        }
    }
});
<|endoftext|>


<commit_before>var margin = {top: 20, right: 20, bottom: 50, left: 60},
    width = 900 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;

var formatPercent = d3.format(".0%");

var x = d3.scale.ordinal()
    .rangeRoundBands([0, width], .2);

var y = d3.scale.linear()
    .domain([105000, 140000])
    .range([height, 0]);

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left")
    .ticks(10);

var tip = d3.tip()
  .attr('class', 'd3-tip')
  .offset([-10, 0])
  .html(function(d) {
    return "Population: " + d.frequency + "";
  })

var svg = d3.select("#graph1").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

svg.call(tip);

d3.tsv("data.tsv", type, function(error, data) {
  x.domain(data.map(function(d) { return d.letter; }));
  y.domain([105000, 140000]);

  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);

    svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)
    .append("text")
      .attr("transform", "rotate(0)")
      .attr("y", -12)
        .attr("x", 8)
        .attr("font-size", 11)
        .attr("font-family", "ROBOTO")
      .attr("dy", "0")
      .style("text-anchor", "start")
      .text("Population");

  svg.selectAll(".bar")
      .data(data)
    .enter().append("rect")
      .attr("class", "bar")
      .attr("x", function(d) { return x(d.letter); })
      .attr("width", x.rangeBand())
      .attr("y", function(d) { return y(d.frequency); })
      .attr("height", function(d) { return height - y(d.frequency); })
      .on('mouseover', tip.show)
      .on('mouseout', tip.hide)

});

function type(d) {
  d.frequency = +d.frequency;
  return d;
}<commit_msg>W+H<commit_after>var margin = {top: 20, right: 20, bottom: 50, left: 60},
    width = 1000 - margin.left - margin.right,
    height = 600 - margin.top - margin.bottom;

var formatPercent = d3.format(".0%");

var x = d3.scale.ordinal()
    .rangeRoundBands([0, width], .2);

var y = d3.scale.linear()
    .domain([105000, 140000])
    .range([height, 0]);

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left")
    .ticks(10);

var tip = d3.tip()
  .attr('class', 'd3-tip')
  .offset([-10, 0])
  .html(function(d) {
    return "Population: " + d.frequency + "";
  })

var svg = d3.select("#graph1").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

svg.call(tip);

d3.tsv("data.tsv", type, function(error, data) {
  x.domain(data.map(function(d) { return d.letter; }));
  y.domain([105000, 140000]);

  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);

    svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)
    .append("text")
      .attr("transform", "rotate(0)")
      .attr("y", -12)
        .attr("x", 8)
        .attr("font-size", 11)
        .attr("font-family", "ROBOTO")
      .attr("dy", "0")
      .style("text-anchor", "start")
      .text("Population");

  svg.selectAll(".bar")
      .data(data)
    .enter().append("rect")
      .attr("class", "bar")
      .attr("x", function(d) { return x(d.letter); })
      .attr("width", x.rangeBand())
      .attr("y", function(d) { return y(d.frequency); })
      .attr("height", function(d) { return height - y(d.frequency); })
      .on('mouseover', tip.show)
      .on('mouseout', tip.hide)

});

function type(d) {
  d.frequency = +d.frequency;
  return d;
}<|endoftext|>


<commit_before>"use strict";

var runkeeper, web3;

function newCommitment(user_id) {
  $('#user_id').val(user_id);
  $('#create').show();
}

function listCommitments() {
  $('#runkeeper').on('click', function(event) {
    event.preventDefault();
    location = "https://www.realitykeys.com/runkeeper/start-auth?return_url=" + encodeURIComponent(location.protocol + '//' + location.host + location.pathname);
  });

  $('#commitments').show();

  var numCommitments = runkeeper.getMyCommitmentCount({}, 'pending');
  if (numCommitments == 0) {
    $('td.loading').hide();
  }

  for (var i = 0; i < numCommitments; i++) {
    var hash = runkeeper.getMyCommitmentHash(i, {}, 'pending');
    var details = runkeeper.getCommitment(hash, {}, 'pending');
    var factId = details[0].toFixed();
    var amount = details[2].toFixed();

    $.get("https://www.realitykeys.com/api/v1/runkeeper/" + factId + "?accept_terms_of_service=current", function(data) {

      $('td.loading').hide();

      let status;
      if (data.signature_v2.signed_value === null) {
        status = 'pending';
      }
      else if (data.signature_v2.signed_value === 0) {
        status = 'failure';
      }
      else {
        status = 'success';
      }

      $('#commitments table tbody').append('
' + data.goal + '	' + data.settlement_date + '	' + web3.fromWei(details[2], 'ether') + '	' + status + '	' + (details[6] ? "true" : "false") + '	view
');

      $('.hash-' + hash).on('click', function(event) {
        showCommitment(hash);
      });
    });
  }
}

function showCommitment(hash) {
  $('#main').fadeTo('slow', 0);

  var details = runkeeper.getCommitment(hash, {}, 'pending');
  var factId = details[0].toFixed();
  var amount = details[2].toFixed();

  $.get("https://www.realitykeys.com/api/v1/runkeeper/" + factId + "?accept_terms_of_service=current", function(data) {
    $('#main').empty();
    $('#main').fadeTo('fast', 1);
    $('#main').append('
Commitment information
');

    let status;
    if (data.signature_v2.signed_value === null) {
      status = 'pending';
    }
    else if (data.signature_v2.signed_value === 0) {
      status = 'failure';
    }
    else {
      status = 'success';
    }

    var table = '

';
    table += '
User ID	' + data.user_id + '
';
    table += '
Activity	' + data.activity + '
';
    table += '
Goal	' + data.goal + 'm
';
    table += '
Settlement date	' + data.settlement_date + '
';
    table += '
Amount	' +  web3.fromWei(details[2], 'ether') + ' ether
';
    table += '
Success payout address	' + details[3] + '
';
    table += '
Failure payout address	' + details[4] + '
';
    table += '
Status	' + status + '
';
    table += '
Settled	' +  (details[6] ? "true" : "false") + '
';
    table += '

';
    $('#main').append(table);

    if (!details[6] && data.signature_v2.signed_value !== null) {
      $('#main').append("Attempting to settle...
");
      var tx = runkeeper.settle(hash, '0x' + data.signature_v2.signed_value, data.signature_v2.sig_v, '0x' + data.signature_v2.sig_r, '0x' + data.signature_v2.sig_s, {gas: 250000}, function(err, tx) {
          if (err) {
            alert(err);
          }
          else {
            showCommitment(hash);
          }
      });
    }
  });
}

$(document).ready(function() {

  var queries = {};
  $.each(document.location.search.substr(1).split('&'), function(c,q){
      var i = q.split('=');
      if (i.length > 1) {
        queries[i[0].toString()] = i[1].toString();
      }
  });

  web3 = new Web3();
  web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));
  if (!web3.isConnected()) {
    alert("Unable to connect to Ethereum.");
    return;
  }
  web3.eth.defaultAccount = web3.eth.accounts[0];

  var runkeeperContract = web3.eth.contract([{"constant":false,"inputs":[{"name":"hash","type":"bytes32"},{"name":"resultHex","type":"bytes32"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"}],"name":"settle","outputs":[{"name":"","type":"bool"}],"type":"function"},{"constant":true,"inputs":[{"name":"hash","type":"bytes32"}],"name":"getCommitment","outputs":[{"name":"factId","type":"uint256"},{"name":"factHash","type":"bytes32"},{"name":"amount","type":"uint256"},{"name":"owner","type":"address"},{"name":"defaultAccount","type":"address"},{"name":"oracle","type":"address"},{"name":"settled","type":"bool"}],"type":"function"},{"constant":true,"inputs":[],"name":"getMyCommitmentCount","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"factId","type":"uint256"},{"name":"factHash","type":"bytes32"},{"name":"defaultAccount","type":"address"},{"name":"oracle","type":"address"}],"name":"makeCommitment","outputs":[{"name":"hash","type":"bytes32"}],"type":"function"},{"constant":true,"inputs":[{"name":"i","type":"uint256"}],"name":"getMyCommitmentHash","outputs":[{"name":"","type":"bytes32"}],"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"hash","type":"bytes32"},{"indexed":false,"name":"result","type":"bool"}],"name":"commitmentSettled","type":"event"}]);

  runkeeper = runkeeperContract.at("0x8d4a168bfabd4bfb4e2539828ad966a72b4ffc70");

  if (queries.completed_user_id > 0) {
    newCommitment(queries.completed_user_id);
  }
  else {
    listCommitments();
  }

  $("#create").submit(function(event) {

    // Stop form from submitting normally
    event.preventDefault();

    var meters = $("#meters").val();
    var defaultAccount = $("#default_account").val();

    var data = {
      user_id: $("#user_id").val(),
      activity: "running",
      measurement: "total_distance",
      comparison: "ge",
      goal: meters,
      settlement_date: $("#end_date").val(),
      objection_period_secs: "604800",
      accept_terms_of_service: "current",
      use_existing: "1"
    };

    $.post("https://www.realitykeys.com/api/v1/runkeeper/new", data, function(data) {
      console.log(data);
      if (data.hasOwnProperty('errors')) {
        for (let key in data.errors) {
          alert(key + ': ' + data.errors[key]);
        }
      }
      else {
        var tx = runkeeper.makeCommitment(data.id, "0x" + data.signature_v2.fact_hash, defaultAccount, "0x" + data.signature_v2.ethereum_address, {value: web3.toWei($("#amount").val(), "ether"), gas: 250000}, function(err, tx) {
          if (err) {
            alert(err);
          }
          else {
            window.location = window.location.pathname;
          }
        });
      }
    });
  });
});
<commit_msg>Use a closure to prevent variables changing in async callback.<commit_after>"use strict";

var runkeeper, web3;

function newCommitment(user_id) {
  $('#user_id').val(user_id);
  $('#create').show();
}

function addCommitmentToList(hash, details, data) {
  $('td.loading').hide();

  let status;
  if (data.signature_v2.signed_value === null) {
    status = 'pending';
  }
  else if (data.signature_v2.signed_value === 0) {
    status = 'failure';
  }
  else {
    status = 'success';
  }

  $('#commitments table tbody').append('
' + data.goal + '	' + data.settlement_date + '	' + web3.fromWei(details[2], 'ether') + '	' + status + '	' + (details[6] ? "true" : "false") + '	view
');

  $('.hash-' + hash).on('click', function(event) {
    showCommitment(hash);
  });
}

function listCommitments() {
  $('#runkeeper').on('click', function(event) {
    event.preventDefault();
    location = "https://www.realitykeys.com/runkeeper/start-auth?return_url=" + encodeURIComponent(location.protocol + '//' + location.host + location.pathname);
  });

  $('#commitments').show();

  var numCommitments = runkeeper.getMyCommitmentCount({}, 'pending');
  if (numCommitments == 0) {
    $('td.loading').hide();
  }

  for (var i = 0; i < numCommitments; i++) {
    var hash = runkeeper.getMyCommitmentHash(i, {}, 'pending');
    var details = runkeeper.getCommitment(hash, {}, 'pending');
    var factId = details[0].toFixed();

    $.get("https://www.realitykeys.com/api/v1/runkeeper/" + factId + "?accept_terms_of_service=current", (function(hash, details) {
      return function(data) {
        addCommitmentToList(hash, details, data);
      }
    })(hash, details));
  }
}

function showCommitment(hash) {
  $('#main').fadeTo('slow', 0);

  var details = runkeeper.getCommitment(hash, {}, 'pending');
  var factId = details[0].toFixed();
  var amount = details[2].toFixed();

  $.get("https://www.realitykeys.com/api/v1/runkeeper/" + factId + "?accept_terms_of_service=current", function(data) {
    $('#main').empty();
    $('#main').fadeTo('fast', 1);
    $('#main').append('
Commitment information
');

    let status;
    if (data.signature_v2.signed_value === null) {
      status = 'pending';
    }
    else if (data.signature_v2.signed_value === 0) {
      status = 'failure';
    }
    else {
      status = 'success';
    }

    var table = '

';
    table += '
User ID	' + data.user_id + '
';
    table += '
Activity	' + data.activity + '
';
    table += '
Goal	' + data.goal + 'm
';
    table += '
Settlement date	' + data.settlement_date + '
';
    table += '
Amount	' +  web3.fromWei(details[2], 'ether') + ' ether
';
    table += '
Success payout address	' + details[3] + '
';
    table += '
Failure payout address	' + details[4] + '
';
    table += '
Status	' + status + '
';
    table += '
Settled	' +  (details[6] ? "true" : "false") + '
';
    table += '

';
    $('#main').append(table);

    if (!details[6] && data.signature_v2.signed_value !== null) {
      $('#main').append("Attempting to settle...
");
      var tx = runkeeper.settle(hash, '0x' + data.signature_v2.signed_value, data.signature_v2.sig_v, '0x' + data.signature_v2.sig_r, '0x' + data.signature_v2.sig_s, {gas: 250000}, function(err, tx) {
          if (err) {
            alert(err);
          }
          else {
            showCommitment(hash);
          }
      });
    }
  });
}

$(document).ready(function() {

  var queries = {};
  $.each(document.location.search.substr(1).split('&'), function(c,q){
      var i = q.split('=');
      if (i.length > 1) {
        queries[i[0].toString()] = i[1].toString();
      }
  });

  web3 = new Web3();
  web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));
  if (!web3.isConnected()) {
    alert("Unable to connect to Ethereum.");
    return;
  }
  web3.eth.defaultAccount = web3.eth.accounts[0];

  var runkeeperContract = web3.eth.contract([{"constant":false,"inputs":[{"name":"hash","type":"bytes32"},{"name":"resultHex","type":"bytes32"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"}],"name":"settle","outputs":[{"name":"","type":"bool"}],"type":"function"},{"constant":true,"inputs":[{"name":"hash","type":"bytes32"}],"name":"getCommitment","outputs":[{"name":"factId","type":"uint256"},{"name":"factHash","type":"bytes32"},{"name":"amount","type":"uint256"},{"name":"owner","type":"address"},{"name":"defaultAccount","type":"address"},{"name":"oracle","type":"address"},{"name":"settled","type":"bool"}],"type":"function"},{"constant":true,"inputs":[],"name":"getMyCommitmentCount","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[{"name":"factId","type":"uint256"},{"name":"factHash","type":"bytes32"},{"name":"defaultAccount","type":"address"},{"name":"oracle","type":"address"}],"name":"makeCommitment","outputs":[{"name":"hash","type":"bytes32"}],"type":"function"},{"constant":true,"inputs":[{"name":"i","type":"uint256"}],"name":"getMyCommitmentHash","outputs":[{"name":"","type":"bytes32"}],"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"hash","type":"bytes32"},{"indexed":false,"name":"result","type":"bool"}],"name":"commitmentSettled","type":"event"}]);

  runkeeper = runkeeperContract.at("0x8d4a168bfabd4bfb4e2539828ad966a72b4ffc70");

  if (queries.completed_user_id > 0) {
    newCommitment(queries.completed_user_id);
  }
  else {
    listCommitments();
  }

  $("#create").submit(function(event) {

    // Stop form from submitting normally
    event.preventDefault();

    var meters = $("#meters").val();
    var defaultAccount = $("#default_account").val();

    var data = {
      user_id: $("#user_id").val(),
      activity: "running",
      measurement: "total_distance",
      comparison: "ge",
      goal: meters,
      settlement_date: $("#end_date").val(),
      objection_period_secs: "604800",
      accept_terms_of_service: "current",
      use_existing: "1"
    };

    $.post("https://www.realitykeys.com/api/v1/runkeeper/new", data, function(data) {
      console.log(data);
      if (data.hasOwnProperty('errors')) {
        for (let key in data.errors) {
          alert(key + ': ' + data.errors[key]);
        }
      }
      else {
        var tx = runkeeper.makeCommitment(data.id, "0x" + data.signature_v2.fact_hash, defaultAccount, "0x" + data.signature_v2.ethereum_address, {value: web3.toWei($("#amount").val(), "ether"), gas: 250000}, function(err, tx) {
          if (err) {
            alert(err);
          }
          else {
            window.location = window.location.pathname;
          }
        });
      }
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

const _ = require('lodash');
const Script = require('smooch-bot').Script;
var pg = require('pg');
var Q = require("q");
var request = require("request");

const scriptRules = require('./script.json');

function wait(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

//move to separeate file
function nlp(query,sessionId){
	var deferred = Q.defer();
	var options = {
		"method" : "POST",
		"url" : "https://api.api.ai/v1/query?v=20150910",
		"json" : {
			"query" : query,
			"lang" : "en",
			"sessionId" : sessionId
		},
		"headers" : {
			"Authorization" : "Bearer " + process.env.API_AI_TOKEN,
			"Content-Type" : "application/json"
		}
	};

	console.log("===nlp");
	console.log("===query: ",query);
	console.log("===sessionId",sessionId);
	request(options,function(err,response,body){
		if(err){
			console.log("===nlp failed because: ",err.message);
			deferred.reject(err);
		}else{
			body.sessionId = sessionId;
			if(response.statusCode == 200){
				console.log("===nlp succeeded ");
				deferred.resolve(body);
			}else{
				deferred.reject(body);
			}
		}
	});
	return deferred.promise;
}

module.exports = new Script({
    processing: {
        //prompt: (bot) => bot.say('Beep boop...'),
        receive: () => 'processing'
    },

    start: {
        receive: (bot) => {
            return bot.say('Get started by saying BOT.')
                .then(() => 'speak');
        }
    },

    speak: {
        receive: (bot, message) => {
            console.log("===bot user ",bot.userId);
            let upperText = message.text.trim().toUpperCase();

            pg.defaults.ssl = true;
            pg.connect(process.env.DATABASE_URL, function(err,client){
                if (err) throw err;
                console.log('====Connected to postgres!!!!!');

                client
                    .query('insert into Attendees (SmoochId, Unsubscribed, UnsubscribedDate, CreatedDate) values ($1,$2, null, CURRENT_TIMESTAMP);', [bot.userId, 'f'],
                    function(err,result) {
                        if (err) {
                            if (err.code == '23505'){
                                console.log("===user already exists: ", bot.userId);
                            }
                            else{
                                console.log("===Unknown error: ", err);
                            }
                        } else {
                            console.log(JSON.stringify(result.rows[0]));
                        }
                    });
            });

            function updateSilent() {
                switch (upperText) {
                    case "CONNECT ME":
                        return bot.setProp("silent", true);
                    case "DISCONNECT":
                        return bot.setProp("silent", false);
                    default:
                        return Promise.resolve();
                }
            }

            function getSilent() {
                return bot.getProp("silent");
            }

            function processMessage(isSilent) {
                if (isSilent) {
                    return Promise.resolve("speak");
                }

                promises.push(nlp(text, senderId));

                Q.all(promises).then(function(responses) {
                    // response is the JSON from API.ai
                    responses.forEach(function(response) {
                        console.log("===received result from API.ai",response);
                        var userSaid = response.result.resolvedQuery;
                        console.log("===user sent",userSaid);
                        afterNlp(response);
                    });
                }, function(error) {
                    console.log("[webhook_post.js]", error);
                });
                return next();

                console.log("===API_AI msg ", )

                if (!_.has(scriptRules, upperText)) {
                    return bot.say(`So, I'm good at structured conversations but stickers, emoji and sentences still confuse me. Say 'more' to chat about something else.`).then(() => 'speak');
                }

                var response = scriptRules[upperText];
                var lines = response.split('\n');

                var p = Promise.resolve();
                _.each(lines, function(line) {
                    line = line.trim();
                    p = p.then(function() {
                        console.log(line);
                        return wait(50).then(function() {
                            return bot.say(line);
                        });
                    });
                });

                return p.then(() => 'speak');
            }

            return updateSilent()
                .then(getSilent)
                .then(processMessage);
        }
    }
});
<commit_msg>api.ai v2<commit_after>'use strict';

const _ = require('lodash');
const Script = require('smooch-bot').Script;
var pg = require('pg');
var Q = require("q");
var request = require("request");

const scriptRules = require('./script.json');

function wait(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

//move to separeate file
function nlp(query,sessionId){
	var deferred = Q.defer();
	var options = {
		"method" : "POST",
		"url" : "https://api.api.ai/v1/query?v=20150910",
		"json" : {
			"query" : query,
			"lang" : "en",
			"sessionId" : sessionId
		},
		"headers" : {
			"Authorization" : "Bearer " + process.env.API_AI_TOKEN,
			"Content-Type" : "application/json"
		}
	};

	console.log("===nlp");
	console.log("===query: ",query);
	console.log("===sessionId",sessionId);
	request(options,function(err,response,body){
		if(err){
			console.log("===nlp failed because: ",err.message);
			deferred.reject(err);
		}else{
			body.sessionId = sessionId;
			if(response.statusCode == 200){
				console.log("===nlp succeeded ");
				deferred.resolve(body);
			}else{
				deferred.reject(body);
			}
		}
	});
	return deferred.promise;
}

module.exports = new Script({
    processing: {
        //prompt: (bot) => bot.say('Beep boop...'),
        receive: () => 'processing'
    },

    start: {
        receive: (bot) => {
            return bot.say('Get started by saying BOT.')
                .then(() => 'speak');
        }
    },

    speak: {
        receive: (bot, message) => {
            console.log("===bot user ",bot.userId);
            let upperText = message.text.trim().toUpperCase();

            pg.defaults.ssl = true;
            pg.connect(process.env.DATABASE_URL, function(err,client){
                if (err) throw err;
                console.log('====Connected to postgres!!!!!');

                client
                    .query('insert into Attendees (SmoochId, Unsubscribed, UnsubscribedDate, CreatedDate) values ($1,$2, null, CURRENT_TIMESTAMP);', [bot.userId, 'f'],
                    function(err,result) {
                        if (err) {
                            if (err.code == '23505'){
                                console.log("===user already exists: ", bot.userId);
                            }
                            else{
                                console.log("===Unknown error: ", err);
                            }
                        } else {
                            console.log(JSON.stringify(result.rows[0]));
                        }
                    });
            });

            function updateSilent() {
                switch (upperText) {
                    case "CONNECT ME":
                        return bot.setProp("silent", true);
                    case "DISCONNECT":
                        return bot.setProp("silent", false);
                    default:
                        return Promise.resolve();
                }
            }

            function getSilent() {
                return bot.getProp("silent");
            }

            function processMessage(isSilent) {
                if (isSilent) {
                    return Promise.resolve("speak");
                }

                promises.push(nlp(text, senderId));

                Q.all(promises).then(function(responses) {
                    // response is the JSON from API.ai
                    responses.forEach(function(response) {
                        console.log("===received result from API.ai",response);
                        var userSaid = response.result.resolvedQuery;
                        console.log("===user sent",userSaid);
                        afterNlp(response);
                    });
                }, function(error) {
                    console.log("[webhook_post.js]", error);
                });
                return next();

                if (!_.has(scriptRules, upperText)) {
                    return bot.say(`So, I'm good at structured conversations but stickers, emoji and sentences still confuse me. Say 'more' to chat about something else.`).then(() => 'speak');
                }

                var response = scriptRules[upperText];
                var lines = response.split('\n');

                var p = Promise.resolve();
                _.each(lines, function(line) {
                    line = line.trim();
                    p = p.then(function() {
                        console.log(line);
                        return wait(50).then(function() {
                            return bot.say(line);
                        });
                    });
                });

                return p.then(() => 'speak');
            }

            return updateSilent()
                .then(getSilent)
                .then(processMessage);
        }
    }
});
<|endoftext|>


<commit_before>// Structure of items.
//var items = [{
//    id: "",
//    entityType: "",
//    rarity: 1,
//    type: "",
//    subType: "",
//    ts: 0,
//    plus: 0,
//    ageLevel: 0,
//    handed: 1,
//    stats: {
//        hp: 0,
//        attackMin: 0,
//        attackMax: 0,
//        defense: 0,
//        overkill: 0,
//        heal: 0,
//        hpBonus: 0
//    },
//    name: "", // {Helmet, Armor, Gloves, Leggings, Boots, Sword, 2-handed Sword, Bow, Crossbow, Wand, Staff, Shield}
//
//}];

/** ============= Battle INF Script to End All Scripts ==========
 * Authored by Sam 'Halithor' Marquart.
 * Licenced under MIT (https://opensource.org/licenses/MIT).
 *
 * Features:
 * - Sells items below a threshold.
 * - Crafts new items into equipped items and optionally, inventory items.
 * - Equips items that are better than currently equipped items.
 */

// Settings for the game. Edit these to fit your character better.
var settings = {
    version: 1.0,
    sellBelow: 2, //< The threshold below which we automatically sell, without combining. Increase this as you like.
    keepAtMax: 4, // The rarity that we DO NOT ever auto sell at.
    craftInventory: true, // Whether or not to craft items in your inventory.
    forceEquipHighestRarity: false // If you always want to equip the highest rarity, no matter the stats. I recommend this to be true if you don't craft the inventory.
};

var _rarities = ["None", "Gray", "Green", "Blue", "Red", "Orange", "Purple", "Teal"];
var _ages = ["Worn" , "Fine", "Refined", "Aged", "Exotic", "Famous", "Master", "Heroic", "Ancient", "Fabled", "Ascended", "Legendary", "Eternal"];

function postMessage(text) {
    console.log(text);
    API.notifications.create("SteaS: " + text, 10);
}

function getItemString(item) {
    return _rarities[item.rarity] + " " + _ages[item.ageLevel] + " " + item.name  + " +" + item.plus;
}

function isItemAtMaxPlus(item) {
    return item.plus >= (5 + item.rarity * 5);
}

function isSameItemType(first, second) {
    return first.type == second.type && first.subType == second.subType
}

// Tries to find a good item from items for secondary to combined into. Picks the first one found.
function findPrimaryCraft(items, secondary) {
    for (var j = 0; j < items.length; j++) {
        var candidate = items[j];
        if (candidate.name == secondary.name
            && candidate.rarity == secondary.rarity
            && !isItemAtMaxPlus(candidate)) {
            return candidate;
        }
    }
}

// Find the item equipped of a given type.
function findEquipped(equipment, primary) {
    for (var i in equipment) {
        var candidate = equipment[i];
        if (isSameItemType(primary, candidate)) {
            return candidate;
        }
    }
}

// Returns true if first is better than second. False otherwise.
// Does not care about rarity, age, etc. Purely based on stats.
function isItemBetter(first, second) {
    if (!isSameItemType(first, second)) {
        return false; // Don't even compare if not the same.
    }

    switch (first.subType) {
        case 'SHIELD':
        case 'ARMOR':
            var armorRatio = first.stats.defense / second.stats.defense;
            var hpBonusDiff = (first.hpBonus - second.hpBonus);
            return armorRatio + (hpBonusDiff/50) > 1.0;
        case 'SWORD':
        case 'TWO_HANDED_SWORD':
        case 'BOW':
        case 'CROSSBOW':
            var damageFirst = (first.stats.attackMax + first.stats.attackMin) / 2;
            var damageSecond = (second.stats.attackMax + second.stats.attackMin) / 2;
            var damageRatio = damageFirst / damageSecond;
            var overkillDiff = first.stats.overkill - second.stats.overkill;
            return damageRatio + (overkillDiff / 20) > 1.0;
        case "STAFF":
        case "WAND":
            var healRatio = (first.stats.heal / second.stats.heal);
            return healRatio > 1.0;
        default: // Uncomparable, make no assumptions.
            return false;
    }
}

function isItemRarer(first, second) {
    return first.rarity > second.rarity;
}

// Sells an item if it's at the max level.
function sellIfMax(item) {
    if (isItemAtMaxPlus(item) && item.rarity <= settings.keepAtMax) {
        postMessage("Selling " + getItemString(item));
        API.inventory.sell(item);
    }
}

// Tries to equip the item if better. Returns the unequiped item if it works, false otherwise.
function equipIfBetter(item) {
    var equipment = ScriptAPI.$user.character.equipment;
    var equip = findEquipped(equipment, item);

    if (equip && (isItemBetter(item, equip) || (settings.forceEquipHighestRarity && isItemRarer(item, equip)) ) ) {
        postMessage("Changed equipped " + equip.type + ":" + equip.subType);
        API.inventory.unequip(equip);
        API.inventory.equip(item);
        return equip;
    }
    return false;
}

// Get a sorted list of the inventory items.
var inventory = ScriptAPI.$user.inventory.items.sort(function (a, b) {
    if (a.rarity == b.rarity) {
        if (a.plus == b.plus) {
            if (a.ageLevel == b.ageLevel) {
                return 0;
            } else {
                return a.ageLevel > b.ageLevel ? -1 : 1;
            }
        } else {
            return a.plus > b.plus ? -1 : 1;
        }
    } else {
        return a.rarity > b.rarity ? -1 : 1;
    }
});

// Get the equipment
var equipment = ScriptAPI.$user.character.equipment;

items.forEach(function (item) {

    if (item.rarity < settings.sellBelow) {
        postMessage('Selling ' + getItemString(item));
        API.inventory.sell(item);
        return;
    }

    // Now we want to combine the item with the inventory into more powerful items. First, we want to upgrade your currently
    // equipped items fully. Then we want to try to combine between items in your inventory. After combining, we look to see
    // if any of the items we have are better than equipped, if so, switch them. Finally, if anything has
    // reached the max Plus value that it can, and it isn't equipped,  sell it.

    // Find a good candidate to craft this item into.
    var isEquipped = false;
    var primary = findPrimaryCraft(equipment, item);
    if (primary) isEquipped = true;

    if (!primary && settings.craftInventory) {
        primary = findPrimaryCraft(inventory, item);
    }

    if (primary) {
        postMessage("Crafting " + getItemString(primary) + " with " + getItemString(item) + (isEquipped ? " [equipped]" : " [inventory]"));
        API.inventory.craft(primary, item);

        // Primary has now been upgraded. Compare it to the currently equipped piece of equipment, and if it wins, equip it.
        if (!isEquipped) {
            var equip = equipIfBetter(primary);

            // If we changed equipment, try to sell the un-equipped item.
            if (equip) {
                sellIfMax(equip);
            } else {
                sellIfMax(primary);
            }
        }
    } else {
        equipIfBetter(item);
    }
});

// Age up everything that we own, if possible.
inventory.forEach(ScriptAPI.$craftingService.ageUpItem);
equipment.forEach(ScriptAPI.$craftingService.ageUpItem);

<commit_msg>Added little stars to the notifications<commit_after>// Structure of items.
//var items = [{
//    id: "",
//    entityType: "",
//    rarity: 1,
//    type: "",
//    subType: "",
//    ts: 0,
//    plus: 0,
//    ageLevel: 0,
//    handed: 1,
//    stats: {
//        hp: 0,
//        attackMin: 0,
//        attackMax: 0,
//        defense: 0,
//        overkill: 0,
//        heal: 0,
//        hpBonus: 0
//    },
//    name: "", // {Helmet, Armor, Gloves, Leggings, Boots, Sword, 2-handed Sword, Bow, Crossbow, Wand, Staff, Shield}
//
//}];

/** ============= Battle INF Script to End All Scripts ==========
 * Authored by Sam 'Halithor' Marquart.
 * Licenced under MIT (https://opensource.org/licenses/MIT).
 *
 * Features:
 * - Sells items below a threshold.
 * - Crafts new items into equipped items and optionally, inventory items.
 * - Equips items that are better than currently equipped items.
 */

// Settings for the game. Edit these to fit your character better.
var settings = {
    version: 1.0,
    sellBelow: 2, //< The threshold below which we automatically sell, without combining. Increase this as you like.
    keepAtMax: 4, // The rarity that we DO NOT ever auto sell at.
    craftInventory: true, // Whether or not to craft items in your inventory.
    forceEquipHighestRarity: false // If you always want to equip the highest rarity, no matter the stats. I recommend this to be true if you don't craft the inventory.
};

var _rarities = ["None", "Gray", "Green", "Blue", "Red", "Orange", "Purple", "Teal"];
var _ages = ["Worn" , "Fine", "Refined", "Aged", "Exotic", "Famous", "Master", "Heroic", "Ancient", "Fabled", "Ascended", "Legendary", "Eternal"];

function postMessage(text) {
    console.log(text);
    API.notifications.create("SteaS: " + text, 10);
}

function getItemString(item) {
    return '<i class="fa fa-star"></i>' + item.rarity + " " + _ages[item.ageLevel] + " " + item.name  + " +" + item.plus;
}

function isItemAtMaxPlus(item) {
    return item.plus >= (5 + item.rarity * 5);
}

function isSameItemType(first, second) {
    return first.type == second.type && first.subType == second.subType
}

// Tries to find a good item from items for secondary to combined into. Picks the first one found.
function findPrimaryCraft(items, secondary) {
    for (var j = 0; j < items.length; j++) {
        var candidate = items[j];
        if (candidate.name == secondary.name
            && candidate.rarity == secondary.rarity
            && !isItemAtMaxPlus(candidate)) {
            return candidate;
        }
    }
}

// Find the item equipped of a given type.
function findEquipped(equipment, primary) {
    for (var i in equipment) {
        var candidate = equipment[i];
        if (isSameItemType(primary, candidate)) {
            return candidate;
        }
    }
}

// Returns true if first is better than second. False otherwise.
// Does not care about rarity, age, etc. Purely based on stats.
function isItemBetter(first, second) {
    if (!isSameItemType(first, second)) {
        return false; // Don't even compare if not the same.
    }

    switch (first.subType) {
        case 'SHIELD':
        case 'ARMOR':
            var armorRatio = first.stats.defense / second.stats.defense;
            var hpBonusDiff = (first.hpBonus - second.hpBonus);
            return armorRatio + (hpBonusDiff/50) > 1.0;
        case 'SWORD':
        case 'TWO_HANDED_SWORD':
        case 'BOW':
        case 'CROSSBOW':
            var damageFirst = (first.stats.attackMax + first.stats.attackMin) / 2;
            var damageSecond = (second.stats.attackMax + second.stats.attackMin) / 2;
            var damageRatio = damageFirst / damageSecond;
            var overkillDiff = first.stats.overkill - second.stats.overkill;
            return damageRatio + (overkillDiff / 20) > 1.0;
        case "STAFF":
        case "WAND":
            var healRatio = (first.stats.heal / second.stats.heal);
            return healRatio > 1.0;
        default: // Uncomparable, make no assumptions.
            return false;
    }
}

function isItemRarer(first, second) {
    return first.rarity > second.rarity;
}

// Sells an item if it's at the max level.
function sellIfMax(item) {
    if (isItemAtMaxPlus(item) && item.rarity <= settings.keepAtMax) {
        postMessage("Selling " + getItemString(item));
        API.inventory.sell(item);
    }
}

// Tries to equip the item if better. Returns the unequiped item if it works, false otherwise.
function equipIfBetter(item, callback) {
    var equipment = ScriptAPI.$user.character.equipment;
    var equip = findEquipped(equipment, item);

    if (equip && (isItemBetter(item, equip) || (settings.forceEquipHighestRarity && isItemRarer(item, equip)) ) ) {
        postMessage("Changed equipped " + equip.type + ":" + equip.subType);
        API.inventory.unequip(equip, function() {
            API.inventory.equip(item, function() {
                callback(equip);
            });
        });
    }
    if (callback) {
        callback(false);
    }
}

// Get a sorted list of the inventory items.
var inventory = ScriptAPI.$user.inventory.items.sort(function (a, b) {
    if (a.rarity == b.rarity) {
        if (a.plus == b.plus) {
            if (a.ageLevel == b.ageLevel) {
                return 0;
            } else {
                return a.ageLevel > b.ageLevel ? -1 : 1;
            }
        } else {
            return a.plus > b.plus ? -1 : 1;
        }
    } else {
        return a.rarity > b.rarity ? -1 : 1;
    }
});

// Get the equipment
var equipment = ScriptAPI.$user.character.equipment;

items.forEach(function (item) {

    if (item.rarity < settings.sellBelow) {
        postMessage('Selling ' + getItemString(item));
        API.inventory.sell(item);
        return;
    }

    // Now we want to combine the item with the inventory into more powerful items. First, we want to upgrade your currently
    // equipped items fully. Then we want to try to combine between items in your inventory. After combining, we look to see
    // if any of the items we have are better than equipped, if so, switch them. Finally, if anything has
    // reached the max Plus value that it can, and it isn't equipped,  sell it.

    // Find a good candidate to craft this item into.
    var isEquipped = false;
    var primary = findPrimaryCraft(equipment, item);
    if (primary) isEquipped = true;

    if (!primary && settings.craftInventory) {
        primary = findPrimaryCraft(inventory, item);
    }

    if (primary) {
        postMessage("Crafting " + getItemString(primary) + (isEquipped ? " [equipped]" : " [inventory]") + " with " + getItemString(item));
        API.inventory.craft(primary, item);

        // Primary has now been upgraded. Compare it to the currently equipped piece of equipment, and if it wins, equip it.
        if (!isEquipped) {
            equipIfBetter(primary, function(unequippedItem) {
                // If we changed equipment, try to sell the un-equipped item.
                if (unequippedItem) {
                    sellIfMax(unequippedItem);
                } else {
                    sellIfMax(primary);
                }
            });
        }
    } else {
        equipIfBetter(item, function (unequippedItem) {
            if (unequippedItem) {
                sellIfMax(unequippedItem);
            }
        });
    }
});

// Age up everything that we own, if possible.
inventory.forEach(ScriptAPI.$craftingService.ageUpItem);
equipment.forEach(ScriptAPI.$craftingService.ageUpItem);

<|endoftext|>