make[1]: Entering directory `/home/bill/dev/schedule' Coverage

Coverage

91%
384
352
32

compat/indexof.js

4%
23
1
22
LineHitsSource
1// indexOf compares searchElement to elements of the Array using strict
2// equality (the same method used by the ===, or triple-equals, operator).
3//
4// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf
5//
61if (!Array.prototype.indexOf) {
70 Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
80 "use strict";
90 if (this == null) {
100 throw new TypeError();
11 }
120 var t = Object(this);
130 var len = t.length >>> 0;
140 if (len === 0) {
150 return -1;
16 }
170 var n = 0;
180 if (arguments.length > 1) {
190 n = Number(arguments[1]);
200 if (n != n) { // shortcut for verifying if it's NaN
210 n = 0;
220 } else if (n != 0 && n != Infinity && n != -Infinity) {
230 n = (n > 0 || -1) * Math.floor(Math.abs(n));
24 }
25 }
260 if (n >= len) {
270 return -1;
28 }
290 var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
300 for (; k < len; k++) {
310 if (k in t && t[k] === searchElement) {
320 return k;
33 }
34 }
350 return -1;
36 }
37}

compat/isarray.js

33%
3
1
2
LineHitsSource
1// Returns true if an object is an array, false if it is not.
2//
3// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
4
5
61if(!Array.isArray) {
70 Array.isArray = function (vArg) {
80 return Object.prototype.toString.call(vArg) === "[object Array]";
9 };
10}

core/create.js

100%
64
64
0
LineHitsSource
1/**
2* Schedule create
3* (c) 2013 Bill, BunKat LLC.
4*
5* Creates a schedule for each task that respects the task schedules, task
6* dependencies, resource schedules, project schedule, and start date provided.
7*
8* Schedule is freely distributable under the MIT license.
9* For all details and documentation:
10* http://github.com/bunkat/schedule
11*/
12
131schedule.create = function(tasks, resources, sched, startDate) {
14
1522 var taskGraph = schedule.dependencyGraph(tasks),
16 resMgr = schedule.resourceManager(resources, startDate),
17 scheduledTasks = {};
18
19 /**
20 * Main function, coordinates the process of creating a schedule.
21 */
2222 function generateSchedule() {
2322 var range, failedTasks = [];
24
25 // add required resources not supplied in resources array, the project
26 // schedule and all task schedules to the resource manager (these will
27 // be treated as resources to calculate valid reservations with)
2822 resMgr.addResource(taskGraph.resources, '', startDate);
2922 resMgr.addResource([{id: '_proj', schedule: sched}], '', startDate);
3022 resMgr.addResource(tasks, '_task', startDate);
31
3222 forwardPass(taskGraph.roots);
3322 range = getSummary(tasks, failedTasks);
3422 backwardPass(taskGraph.leaves, range[1]);
35
3622 return {
37 scheduledTasks: scheduledTasks,
38 failedTasks: failedTasks.length ? failedTasks : null,
39 success: failedTasks.length === 0,
40 start: range[0],
41 end: range[1]
42 };
43 }
44
45 /**
46 * Schedules each task as their dependencies are met, tracking dependency
47 * end dates in the dependencies map.
48 */
4922 function forwardPass(roots) {
5022 var readyTasks = roots.slice(0),
51 dependencies = {}; // holds count and earliest start date of dependencies
52
5322 for(var i = 0, len = roots.length; i < len; i++) {
5446 dependencies[roots[i]] = [0, startDate.getTime()];
55 }
56
5722 while(readyTasks.length) {
5869 schedule.sort.tasks(taskGraph, readyTasks);
59
6069 var task = taskGraph.tasks[readyTasks.pop()],
61 start = dependencies[task.id][1],
62 end = forwardPassTask(task, start);
63
6469 if(end && task.requiredBy) {
6520 updateDependencies(readyTasks, dependencies, task.requiredBy, end);
6620 resMgr.optimize(getMinStart(dependencies)); // clean up expired exceptions
67 }
68 }
69 }
70
71 /**
72 * Finds the next available time that all of a tasks constraints are met and
73 * makes the appropriate resource reservations. A task may be scheduled in a
74 * single contiguous block or multiple blocks of time.
75 */
7622 function forwardPassTask(task, start) {
7769 var resAll = ['_proj', '_task' + task.id],
78 resources = task.resources ? resAll.concat(task.resources) : resAll,
79 duration = task.duration,
80 next = start,
81 scheduledTask = {schedule: [], duration: task.duration};
82
8369 while(duration) {
8473 var r = resMgr.makeReservation(resources, next, task.minSchedule || 1, duration);
8575 if(!r.success) return undefined;
86
8771 scheduledTask.earlyStart = scheduledTask.earlyStart || r.start;
8871 scheduledTask.schedule.push(r);
8971 duration -= r.duration;
9071 next = r.end;
91 }
92
9367 scheduledTask.earlyFinish = next;
9467 scheduledTasks[task.id] = scheduledTask;
95
9667 return next;
97 }
98
99 /**
100 * Finds the start and end date of the schedule and adds any tasks that were
101 * scheduled to the failedTasks array.
102 */
10322 function getSummary(tasks, failedTasks) {
10422 var start, end;
105
10622 for(var i = 0, len = tasks.length; i < len; i++) {
10772 var t = scheduledTasks[tasks[i].id];
10872 if(t) {
10967 start = !start || t.earlyStart < start ? t.earlyStart : start;
11067 end = !end || t.earlyFinish > end ? t.earlyFinish : end;
111 }
112 else {
1135 failedTasks.push(tasks[i].id);
114 }
115 }
116
11722 return [start, end];
118 }
119
120 /**
121 * As tasks are scheduled, the information is tracked in the dependencies
122 * array. As a tasks dependencies are all met, the task is pushed onto the
123 * readyTasks array which means it is available to be scheduled.
124 */
12522 function updateDependencies(readyTasks, dependencies, tasks, end) {
12620 for(var i = 0, len = tasks.length; i < len; i++) {
12734 var tid = tasks[i],
128 dependsOn = taskGraph.tasks[tid].dependsOn,
129 metDeps = dependencies[tid] || (dependencies[tid] = [0, 0]);
130
13134 metDeps[0] += 1;
13234 metDeps[1] = end > metDeps[1] ? end : metDeps[1];
133
13434 if(!dependsOn || metDeps[0] >= dependsOn.length) {
13523 readyTasks.push(tid);
136 }
137 }
138 }
139
140 /**
141 * Finds the earliest time that any of the remaining tasks could be scheduled
142 * for. It is used to optimize the resource manager since nothing can be
143 * scheduled before this time.
144 */
14522 function getMinStart(dependencies) {
14620 var min;
14720 for(var id in dependencies) {
14889 if(!min || min > dependencies[id][1]) {
14920 min = dependencies[id][1];
150 }
151 }
15220 return min;
153 }
154
155 /**
156 * Calculates when a task must be completed by before it ends up slipping
157 * one of its dependencies or the schedule. Tasks with zero float amount
158 * are in the critical path.
159 */
16022 function backwardPass(tasks, finishDate) {
16159 for(var i = 0, len = tasks.length; i < len; i++) {
162114 var sTask = scheduledTasks[tasks[i]],
163 dependsOn = taskGraph.tasks[tasks[i]].dependsOn;
164
165114 if(sTask) {
166112 sTask.lateFinish = finishDate;
167112 sTask.floatAmt = (sTask.lateFinish - sTask.earlyFinish) / later.MIN;
168
169112 if(dependsOn) {
17037 backwardPass(dependsOn, sTask.earlyStart);
171 }
172 }
173 }
174 }
175
17622 return generateSchedule();
177};

core/dependency-graph.js

100%
79
79
0
LineHitsSource
1/**
2* Dependency graph
3* (c) 2013 Bill, BunKat LLC.
4*
5* Generates a dependency graph from a set of tasks and finds the root nodes,
6* leaf nodes, depth, and optimistic float (time between when a schedule starts
7* and when it must start to prevent a schedule slip). This information is used
8* by the schedule generator to schedule tasks against an actual timeline.
9*
10* Schedule is freely distributable under the MIT license.
11* For all details and documentation:
12* http://github.com/bunkat/schedule
13*/
14
151schedule.dependencyGraph = function(taskArr) {
16
17 /**
18 * Starting point for creating the dependency graph, clones the tasks and
19 * then fills out the graph properties.
20 */
2133 function createDependencyGraph(tasks) {
2233 var graph = {
23 tasks: {},
24 roots: [],
25 leaves: [],
26 resources: [],
27 depth: 0,
28 end : 0
29 };
30
3133 for(var i = 0, len = tasks.length; i < len; i++) {
32107 var t = tasks[i];
33107 graph.tasks[t.id] = {
34 id: t.id,
35 duration: t.duration,
36 priority: t.priority,
37 schedule: t.schedule,
38 minSchedule: t.minSchedule,
39 dependsOn: t.dependsOn,
40 resources: t.resources
41 };
42 }
43
4433 setResources(graph);
4533 setRequiredBy(graph.tasks);
4633 setRootsAndLeaves(graph);
47
4833 setDepth(graph, graph.leaves, 0);
4933 graph.depth += 1; // increment depth so it is 1 based
50
5133 forwardPass(graph, {}, graph.roots, 0);
5233 setEnd(graph, graph.leaves);
5333 backwardPass(graph, {}, graph.leaves, graph.end);
54
5533 return graph;
56 }
57
58 /**
59 * Creates an array of all the unique resources that are used by the tasks.
60 */
6133 function setResources(graph) {
6233 for(var id in graph.tasks) {
63107 var task = graph.tasks[id];
64107 if(!isEmpty(task.resources)) {
6538 for(var i = 0, len = task.resources.length; i < len; i++) {
6640 var resId = task.resources[i];
6740 if(graph.resources.indexOf(resId) === -1) {
6813 graph.resources.push(resId);
69 }
70 }
71 }
72 }
73 }
74
75 /**
76 * Creates the back links from child to parent based on the dependsOn property.
77 */
7833 function setRequiredBy(tasks) {
7933 for(var id in tasks) {
80107 var child = tasks[id],
81 dependsOn = child.dependsOn;
82
83107 if(!isEmpty(dependsOn)) {
8448 for(var i = 0, len = dependsOn.length; i < len; i++) {
8563 var parent = tasks[dependsOn[i]];
8663 (parent.requiredBy || (parent.requiredBy = [])).push(child.id);
87 }
88 }
89 }
90 }
91
92 /**
93 * Finds the roots and leaves of the dependency graph.
94 */
9533 function setRootsAndLeaves(graph) {
9633 for(var id in graph.tasks) {
97107 var task = graph.tasks[id];
98
99107 if(isEmpty(task.dependsOn)) {
10059 graph.roots.push(task.id);
101 }
102
103107 if(isEmpty(task.requiredBy)) {
10466 graph.leaves.push(task.id);
105 }
106 }
107 }
108
109 /**
110 * Determines the depth (maximum number of nodes that depend on the current
111 * node) of each node in the dependency graph.
112 */
11333 function setDepth(graph, tasks, depth) {
11496 for(var i = 0, len = tasks.length; i < len; i++) {
115162 var task = graph.tasks[tasks[i]],
116 dependsOn = task.dependsOn;
117
118162 task.depth = !task.depth || depth > task.depth ? depth : task.depth;
119162 graph.depth = depth > graph.depth ? depth : graph.depth;
120
121162 if(!isEmpty(dependsOn)) {
12263 setDepth(graph, dependsOn, task.depth + 1);
123 }
124 }
125 }
126
127 /**
128 * Generates an optimistic (assume all resources are available when needed)
129 * forward schedule for each node in the graph, respecting node dependencies.
130 */
13133 function forwardPass(graph, depEnds, tasks, start) {
13271 updateDependencies(depEnds, tasks, start);
13371 for(var i = 0, len = tasks.length; i < len; i++) {
134119 var tid = tasks[i],
135 task = graph.tasks[tid],
136 dependsOn = task.dependsOn,
137 dep = depEnds[tid];
138
139119 if(!task.earlyFinish && (isEmpty(dependsOn) || (dep && dep[0] === dependsOn.length))) {
140104 task.earlyStart = dep[1];
141104 task.earlyFinish = dep[1] + task.duration;
142
143104 if(!isEmpty(task.requiredBy)) {
14438 forwardPass(graph, depEnds, task.requiredBy, task.earlyFinish);
145 }
146 }
147 }
148 }
149
150 /**
151 * Finds the end of the optimistic forward pass schedule.
152 */
15333 function setEnd(graph, tasks) {
15433 for(var i = 0, len = tasks.length; i < len; i++) {
15566 var finish = graph.tasks[tasks[i]].earlyFinish;
15666 graph.end = finish > graph.end ? finish : graph.end;
157 }
158 }
159
160 /**
161 * Generates an optimistic (assume all resources are available when needed)
162 * backward schedule for each node in the graph, respecting node dependencies.
163 * Computes the float (time between earliest finish and latest finish).
164 */
16533 function backwardPass(graph, depEnds, tasks, end) {
16678 updateDependencies(depEnds, tasks, end, true);
16778 for(var i = 0, len = tasks.length; i < len; i++) {
168125 var tid = tasks[i],
169 task = graph.tasks[tid],
170 requiredBy = task.requiredBy,
171 dep = depEnds[tid];
172
173125 if(isEmpty(requiredBy) || (dep && dep[0] === requiredBy.length)) {
174103 task.lateStart = dep[1] - task.duration;
175103 task.lateFinish = dep[1];
176103 task.floatAmt = task.lateFinish - task.earlyFinish;
177
178103 if(!isEmpty(task.dependsOn)) {
17945 backwardPass(graph, depEnds, task.dependsOn, task.lateStart);
180 }
181 }
182 }
183 }
184
185 /**
186 * Tracks dependencies between nodes to ensure nodes are only scheduled once
187 * their dependencies have completed.
188 */
18933 function updateDependencies(deps, tasks, start, rev) {
190171 var compare = rev ? function(a,b) { return b > a; } :
19114 function(a,b) { return a > b; };
192
193149 for(var i = 0, len = tasks.length; i < len; i++) {
194244 var id = tasks[i];
195
196244 if(deps[id]) {
19736 deps[id][0] = deps[id][0] + 1;
19836 deps[id][1] = compare(start, deps[id][1]) ? start : deps[id][1];
199 }
200 else {
201208 deps[id] = [1, start];
202 }
203 }
204 }
205
206 /**
207 * Returns true if the array is undefined or empty.
208 */
20933 function isEmpty(arr) {
2101041 return !arr || arr.length === 0;
211 }
212
21333 return createDependencyGraph(taskArr);
214};

core/resource-manager.js

100%
116
116
0
LineHitsSource
1/**
2* Resource manager
3* (c) 2013 Bill, BunKat LLC.
4*
5* Manages all of the resources and schedule constraints (project schedule,
6* task schedule, and resource schedules) and reserves resources as needed. Finds
7* the earliest time that a set of resources can be reserved.
8*
9* Schedule is freely distributable under the MIT license.
10* For all details and documentation:
11* http://github.com/bunkat/schedule
12*/
13
141schedule.resourceManager = function(resourceDefinitions, startDate) {
15
1636 var defaultSched = {schedules: [{fd_a: [startDate.getTime()]}]},
17 rMap = buildResourceMap(resourceDefinitions, startDate);
18
19 /**
20 * Creates a map from the resource definitions that contains the schedule
21 * information for each of the resources (specifically when the resource
22 * will be next available and how to calculate future availability).
23 */
2436 function buildResourceMap(resourceDefinitions, start) {
2536 var map = {};
2636 if(resourceDefinitions) {
2735 for(var i = 0, len = resourceDefinitions.length; i < len; i++) {
2890 addResourceToMap(map, resourceDefinitions[i], start);
29 }
30 }
31
3236 return map;
33 }
34
35 /**
36 * Adds a resource to the resource map.
37 */
3836 function addResourceToMap(map, def, start) {
39188 var sched = JSON.parse(JSON.stringify(def.schedule || defaultSched)),
40 nextFn = schedule.memoizedRangeFn(later.schedule(sched).nextRange);
41
42188 map[def.id] = { schedule: sched, next: nextFn, nextAvail: nextFn(start) };
43 }
44
45 /**
46 * Attempts to find the next time that all resources are available, starting
47 * from the start time, with a duration of at least min minutes but no more
48 * than max minutes.
49 */
5036 function getReservation(resources, start, min, max) {
5192 var reservation, schedules = [], delays = {};
5292 maxTries = 50;
53
5492 initRanges(resources, start, schedules, delays);
5592 while(!(reservation = tryReservation(schedules, min, max)).success && --maxTries) {
56199 updateRanges(schedules, nextValidStart(schedules), delays);
57 }
58
5992 reservation.delays = delays;
6092 return reservation;
61 }
62
63 /**
64 * Initializes the resource schedule availablity based on the start date
65 * provided. Resources that were not immediately available are captured in
66 * the delays array to be reported with the reservation.
67 */
6836 function initRanges(resources, start, ranges, delays) {
69115 for(var i = 0, len = resources.length; i < len; i++) {
70282 var resId = resources[i];
71
72 // handles nested resources (OR)
73282 if(Array.isArray(resId)) {
7423 var subRanges = [], subDelays = {};
7523 initRanges(resId, start, subRanges, subDelays);
76
7723 var longDelay = getLongestDelay(subDelays);
7823 if(longDelay) {
7921 delays[longDelay] = subDelays[longDelay];
80 }
81
8223 var schedule = {subRanges: subRanges};
8323 setEarliestSubRange(schedule);
8423 ranges.push(schedule);
85 }
86 else {
87259 var res = rMap[resId],
88 range = res.nextAvail[0] >= start ? res.nextAvail :
89 res.next(start);
90
91259 if(range[0] > start && resId !== '_proj') {
9289 delays[resId] = { needed: start, available: range[0] };
93 }
94
95259 ranges.push({id: resId, range: range});
96 }
97 }
98 }
99
100 /**
101 * Determines if the current schedules overlap for at least min minutes. If
102 * they do, a reservation is created, otherwise a failure is reported.
103 */
10436 function tryReservation(schedules, min,max) {
105291 var reservation = {success: false},
106 resources = [], start, end;
107
108291 for(var i = 0, len = schedules.length; i < len; i++) {
109733 var schedule = schedules[i],
110 range = schedule.range;
111
112733 if(!isInternal(schedule)) {
113239 resources.push(schedule.id);
114 }
115
116733 start = !start || range[0] > start ? range[0] : start;
117733 end = !end || range[1] < end ? range[1] : end;
118 }
119
120291 var duration = (end - start) / later.MIN;
121291 if(duration >= min) {
12289 duration = max && duration > max ? max : duration;
12389 reservation = createReservation(resources, start, duration);
124 }
125
126291 return reservation;
127 }
128
129 /**
130 * Generates a new reservation object and reserves the associated resources.
131 */
13236 function createReservation(resources, start, duration) {
13389 var end = start + (duration * later.MIN),
134 reservation = {
135 resources: resources,
136 start: start,
137 end: end,
138 duration: duration,
139 success: true
140 };
141
14289 applyReservation(resources, start, end);
14389 return reservation;
144 }
145
146 /**
147 * Updates ranges after a failed reservation attempt. Resources that were not
148 * immediately available are captured in the delays array to be reported with
149 * the reservation.
150 */
15136 function updateRanges(resources, start, delays) {
152206 for(var i = 0, len = resources.length; i < len; i++) {
153511 var res = resources[i];
154789 if(res.range[1] > start) continue;
155
156233 if(res.subRanges) {
1577 updateRanges(res.subRanges, start, {});
1587 setEarliestSubRange(res);
159 }
160 else {
161226 res.range = rMap[res.id].next(start);
162
163226 if(res.id !== '_proj' && !delays[res.id]) {
16415 delays[res.id] = { needed: start, available: res.range[0] };
165 }
166 }
167 }
168 }
169
170 /**
171 * Applies a schedule reservation (by adding schedule exceptions) to any
172 * reservable resources that are indicated.
173 */
17436 function applyReservation(resources, start, end) {
17589 for(var i = 0, len = resources.length; i < len; i++) {
17669 var res = rMap[resources[i]];
177
178 // skip if this resource should not be reserved for single use
17969 if(res.isNotReservable) continue;
180
18169 if(start !== res.nextAvail[0]) {
18248 if(!res.schedule.exceptions) res.schedule.exceptions = [];
18338 res.schedule.exceptions.push({fd_a: [start], fd_b: [end] });
18438 res.next = schedule.memoizedRangeFn(later.schedule(res.schedule).nextRange);
18538 end = res.nextAvail[0];
186 }
187
18869 res.nextAvail = res.next(end);
189 }
190 }
191
192 /**
193 * Determines the earliest time that a schedule goes invalid which is the
194 * time that should be used to update resource ranges from.
195 */
19636 function nextValidStart(schedules) {
197199 var latest;
198199 for(var i = 0, len = schedules.length; i < len; i++) {
199497 var end = schedules[i].range[1];
200497 latest = !latest || end < latest ? end : latest;
201 }
202
203199 return latest;
204 }
205
206 /**
207 * Resources that are OR'd together (using a nested array) are treated as a
208 * single resource with sub resources. This function determines the resource
209 * that has the earliest start date which is then used for future calculations.
210 */
21136 function setEarliestSubRange(schedule) {
21230 var minId, minRange;
21330 for(var i = 0, len = schedule.subRanges.length; i < len; i++) {
21460 var sub = schedule.subRanges[i];
215
21660 if(!minId || (sub.range[0] < minRange[0])) {
21740 minId = sub.id;
21840 minRange = sub.range;
219 }
220 }
221
22230 schedule.id = minId;
22330 schedule.range = minRange;
224 }
225
226 /**
227 * Determines the longest delay amongst a set of delays. Used to determine
228 * which resource to report for resources that are OR'd together.
229 */
23036 function getLongestDelay(delays) {
23123 var latest, lid;
23223 for(var id in delays) {
23340 var available = delays[id].available;
23440 if(!latest || available < latest) {
23527 latest = available;
23627 lid = id;
237 }
238 }
239
24023 return lid;
241 }
242
243 /**
244 * Returns true if resource provided is an internal (not user specified)
245 * resource.
246 */
24736 function isInternal(resource) {
248733 return resource.id[0] === '_';
249 }
250
25136 return {
252
253 /**
254 * Returns the current resource schedule state for the specified resoruce id.
255 */
256 getResource: function(id) {
2574 return rMap[id];
258 },
259
260 /**
261 * Adds a new resource to the resource map if a resource doesn't already exist
262 * with that id. Expects resources to be passed in as an array and will
263 * prefix each resource with the prefix specified.
264 */
265 addResource: function(arr, prefix, start) {
26666 for(var i = 0, len = arr.length; i < len; i++) {
267107 var def = typeof arr[i] !== 'object' ?
268 { id: prefix + arr[i] } :
269 { id: prefix + arr[i].id, schedule: arr[i].schedule, isNotReservable: arr[i].isNotReservable };
270
271107 if(!rMap[def.id]) {
27298 addResourceToMap(rMap, def, start);
273 }
274 }
275 },
276
277 /**
278 * Attempts to reserve the set of resources at the earliest possible time from
279 * start time provide with a duration of at least min and no more than max
280 * minutes.
281 */
282 makeReservation: function(resources, start, min, max) {
28392 start = start ? new Date(start) : new Date();
28492 return getReservation(resources, start.getTime(), min || 1, max);
285 },
286
287 /**
288 * Optimizes the resource schedules by eliminating schedule reservations that
289 * occur before the start date provided (i.e. ones that can never occur
290 * again).
291 */
292 optimize: function(start) {
29323 for(var id in rMap) {
294174 var res = rMap[id];
295
296174 if(res.schedule.exceptions) {
29728 var curExceptions = res.schedule.exceptions;
29828 res.schedule.exceptions = [];
299
30028 for(var i = 0, len = curExceptions.length; i < len; i++) {
30133 if(!curExceptions[i].fd_b || curExceptions[i].fd_b > start) {
30226 res.schedule.exceptions.push(curExceptions[i]);
303 }
304 }
30528 res.next = schedule.memoizedRangeFn(later.schedule(res.schedule).nextRange);
306 }
307
308174 if(res.nextAvail[0] < start) {
30918 res.nextAvail = res.next(start);
310 }
311 }
312 }
313 };
314
315};

core/resources.js

100%
27
27
0
LineHitsSource
1/**
2* Resources
3* (c) 2013 Bill, BunKat LLC.
4*
5* Takes an array of objects and generates an array of valid schedule resources
6* objects.
7*
8* Schedule is freely distributable under the MIT license.
9* For all details and documentation:
10* http://github.com/bunkat/schedule
11*/
12
131schedule.resources = function() {
149 var id = resourcesId,
15 sched = resourcesSched,
16 isNotReservable = resourcesIsNotReservable;
17
18 /**
19 * Takes an array of objects and returns an array of schedule resource objects.
20 */
219 function resources(data) {
226 var items = [],
23 fid = schedule.functor(id),
24 fsched = schedule.functor(sched),
25 freserve = schedule.functor(isNotReservable);
26
276 for(var i = 0, len = data.length; i < len; i++) {
2816 var resource = data[i],
29 rId = fid.call(this, resource, i),
30 rSched = fsched.call(this, resource, i),
31 rReserve = freserve.call(this, resource, i);
32
3316 items.push({id: rId, schedule: rSched, isNotReservable: rReserve});
34 }
35
366 return items;
37 }
38
39 /**
40 * The function or value that should be used to generate the resource id. Sets the
41 * value to the argument passed in, returns current value if no arguments are
42 * passed in.
43 */
449 resources.id = function(_) {
453 if (!arguments.length) return id;
463 id = _;
473 return resources;
48 };
49
50 /**
51 * The function or value that should be used to generate the resource schedule. The
52 * schedule must be a valid Later.js schedule. Sets the value to the argument
53 * passed in, returns current value if no arguments are passed in.
54 */
559 resources.schedule = function(_) {
563 if (!arguments.length) return sched;
573 sched = _;
583 return resources;
59 };
60
61 /**
62 * The function or value that should be used to generate the resource is not
63 * reservable value. Sets the value to the argument passed in, returns current
64 * value if no arguments are passed in.
65 */
669 resources.isNotReservable = function(_) {
671 if (!arguments.length) return isNotReservable;
681 isNotReservable = _;
691 return resources;
70 };
71
729 return resources;
73};
74
75/**
76* The default id function.
77*/
781function resourcesId(d) {
799 return d.id;
80}
81
82/**
83* The default schedule function.
84*/
851function resourcesSched(d) {
869 return d.schedule;
87}
88
89/**
90* The default is not reservable function.
91*/
921function resourcesIsNotReservable(d) {
9313 return d.isNotReservable || false;
94}

core/tasks.js

84%
51
43
8
LineHitsSource
1/**
2* Tasks
3* (c) 2013 Bill, BunKat LLC.
4*
5* Takes an array of objects and generates an of array valid schedule task objects.
6*
7* Schedule is freely distributable under the MIT license.
8* For all details and documentation:
9* http://github.com/bunkat/schedule
10*/
11
121schedule.tasks = function() {
139 var id = tasksId,
14 duration = tasksDuration,
15 sched = tasksSched,
16 resources = tasksResources,
17 dependsOn = tasksDependsOn,
18 minSchedule = tasksMinSchedule,
19 priority = tasksPriority;
20
21 /**
22 * Takes an array of objects and returns an array of schedule task objects.
23 */
249 function tasks(data) {
253 var items = [],
26 fid = schedule.functor(id),
27 fduration = schedule.functor(duration),
28 fsched = schedule.functor(sched),
29 fresources = schedule.functor(resources),
30 fdependsOn = schedule.functor(dependsOn),
31 fminschedule = schedule.functor(minSchedule),
32 fpriority = schedule.functor(priority);
33
343 for(var i = 0, len = data.length; i < len; i++) {
3532 var task = data[i],
36 item = {
37 id: fid.call(this, task, i),
38 duration: fduration.call(this, task, i),
39 schedule: fsched.call(this, task, i),
40 resources: fresources.call(this, task, i),
41 dependsOn: fdependsOn.call(this, task, i),
42 minSchedule: fminschedule.call(this, task, i),
43 priority: fpriority.call(this, task, i)
44 };
45
4632 items.push(item);
47 }
48
493 return items;
50 }
51
52 /**
53 * The function or value that should be used to generate the task id. Sets the
54 * value to the argument passed in, returns current value if no arguments are
55 * passed in.
56 */
579 tasks.id = function(_) {
582 if (!arguments.length) return id;
592 id = _;
602 return tasks;
61 };
62
63 /**
64 * The function or value that should be used to generate the task duration. Sets the
65 * value to the argument passed in, returns current value if no arguments are
66 * passed in.
67 */
689 tasks.duration = function(_) {
692 if (!arguments.length) return duration;
702 duration = _;
712 return tasks;
72 };
73
74 /**
75 * The function or value that should be used to generate the task schedule. The
76 * schedule must be a valid Later.js schedule. Sets the value to the argument
77 * passed in, returns current value if no arguments are passed in.
78 */
799 tasks.schedule = function(_) {
802 if (!arguments.length) return sched;
812 sched = _;
822 return tasks;
83 };
84
85 /**
86 * The function or value that should be used to generate the resources array. Sets the
87 * value to the argument passed in, returns current value if no arguments are
88 * passed in.
89 */
909 tasks.resources = function(_) {
913 if (!arguments.length) return resources;
923 resources = _;
933 return tasks;
94 };
95
96 /**
97 * The function or value that should be used to generate the dependency array. Sets the
98 * value to the argument passed in, returns current value if no arguments are
99 * passed in.
100 */
1019 tasks.dependsOn = function(_) {
1020 if (!arguments.length) return dependsOn;
1030 dependsOn = _;
1040 return tasks;
105 };
106
107 /**
108 * The function or value that should be used to generate the min schedule. Sets the
109 * value to the argument passed in, returns current value if no arguments are
110 * passed in.
111 */
1129 tasks.minSchedule = function(_) {
1132 if (!arguments.length) return minSchedule;
1142 minSchedule = _;
1152 return tasks;
116 };
117
118 /**
119 * The function or value that should be used to generate the priority. Sets the
120 * value to the argument passed in, returns current value if no arguments are
121 * passed in.
122 */
1239 tasks.priority = function(_) {
1241 if (!arguments.length) return priority;
1251 priority = _;
1261 return tasks;
127 };
128
1299 return tasks;
130};
131
132/**
133* The default id function.
134*/
1351function tasksId(d) {
1360 return d.id;
137}
138
139/**
140* The default duration function.
141*/
1421function tasksDuration(d) {
1430 return d.duration;
144}
145
146/**
147* The default schedule function.
148*/
1491function tasksSched(d) {
1500 return d.schedule;
151}
152
153/**
154* The default resources function.
155*/
1561function tasksResources(d) {
1570 return d.resources;
158}
159
160/**
161* The default depends on function.
162*/
1631function tasksDependsOn(d) {
16432 return d.dependsOn;
165}
166
167/**
168* The default min schedule function.
169*/
1701function tasksMinSchedule(d) {
1710 return d.minSchedule;
172}
173
174/**
175* The default priority function.
176*/
1771function tasksPriority(d) {
17810 return d.priority;
179}

date/date.js

100%
1
1
0
LineHitsSource
11schedule.date = {};

date/timezone.js

100%
2
2
0
LineHitsSource
1/**
2* Timezone
3* (c) 2013 Bill, BunKat LLC.
4*
5* Configures Schedule to use local time or UTC. Schedule uses UTC time by default.
6*
7* Schedule is freely distributable under the MIT license.
8* For all details and documentation:
9* http://github.com/bunkat/schedule
10*/
11
12// pass through to Later to configure timezones
131schedule.date.UTC = function() { later.date.UTC(); };
145schedule.date.localTime = function() { later.date.localTime(); };

sort/sort.js

100%
1
1
0
LineHitsSource
11schedule.sort = {};

sort/tasks.js

100%
8
8
0
LineHitsSource
1/**
2* Sort tasks
3* (c) 2013 Bill, BunKat LLC.
4*
5* Determines the order that tasks are scheduled in when multiple tasks can be
6* scheduled in parallel. Default it to do highest priority tasks first, then
7* tasks that have been determined to have the largest float.
8*
9* Schedule is freely distributable under the MIT license.
10* For all details and documentation:
11* http://github.com/bunkat/schedule
12*/
13
141schedule.sort.tasks = function(taskGraph, readyTasks) {
1569 readyTasks.sort(function(a,b) {
16155 var ta = taskGraph.tasks[a],
17 tb = taskGraph.tasks[b];
18
19155 if(tb.priority && (!ta.priority || tb.priority > ta.priority)) {
20118 return -1;
21 }
22
2337 if(ta.priority && (!tb.priority || ta.priority > tb.priority)) {
2419 return 1;
25 }
26
2718 return taskGraph.tasks[b].floatAmt > taskGraph.tasks[a].floatAmt;
28 });
29};

util/functor.js

100%
2
2
0
LineHitsSource
1/**
2* Functor
3*
4* Wraps values in functions so that they can be called. Usage inspired by
5* Mike Bostock in d3.
6*
7* Schedule is freely distributable under the MIT license.
8* For all details and documentation:
9* http://github.com/bunkat/schedule
10*/
11
121schedule.functor = function(v) {
1364 return typeof v === "function" ? v : function() { return v; };
14};

util/memoized-range-fn.js

100%
7
7
0
LineHitsSource
1/**
2* MemoizedRangeFn
3* (c) 2013 Bill, BunKat LLC.
4*
5* Wraps later.schedule().nextRange to provide memoization of results. Calculating
6* valid occurrences can be expensive and so we want to reduce the amount of times
7* we calculate them as much as possible. Also cleans up undefined values so that
8* we don't have to deal with them later.
9*
10* Schedule is freely distributable under the MIT license.
11* For all details and documentation:
12* http://github.com/bunkat/schedule
13*/
14
151schedule.memoizedRangeFn = function(fn) {
16254 var cache = {}; // local store for memoization results
17
18254 return function(start) {
19566 if(!cache[start]) {
20550 var result = fn(1, start);
21550 cache[start] = [
22 result[0] ? result[0].getTime() : 4102444800000,// Jan 1, 2100
23 result[1] ? result[1].getTime() : 4102444800000 // Jan 1, 2100
24 ];
25 }
26
27566 return cache[start];
28 };
29};
make[1]: Leaving directory `/home/bill/dev/schedule'