@zzish/sdk-js 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/zzish.js ADDED
@@ -0,0 +1,2186 @@
1
+ // Global Zzish object
2
+ (function () {
3
+
4
+
5
+ Zzish = {};
6
+
7
+ /**** FRONT END JAVASCRIPT STUFF (WITH STATE) ***/
8
+
9
+ //STATE THAT NEEDS TO BE TRACK PER USER (ON THE CLIENT SIDE)
10
+
11
+ //appConfig
12
+ var appConfig;
13
+ //tracks this device
14
+ var deviceId;
15
+ //tracks a session (resets when a new user is selected)
16
+ var sessionId;
17
+ //the app Id (sandbox or production) generated from developer console (https://developer.zzish.com)
18
+ var appId;
19
+ //keep track of the current user (so we know when session needs to be updated)
20
+ var currentUser = null;
21
+
22
+ //store for storage
23
+ var dataStorage = {};
24
+
25
+ //Socket Info
26
+ var WebSocket;
27
+ if (stateful() && window !== undefined) {
28
+ WebSocket = window.WebSocket || window.MozWebSocket;
29
+ }
30
+ var opencallback;
31
+ var errorcallback;
32
+ var messagecallback;
33
+ var connection;
34
+
35
+
36
+ /**** CONFIGURATION ******/
37
+
38
+ var defaultProtocol = "https://";
39
+ var baseUrl = "zapi.zzish.com/";
40
+ var webUrl = "https://live.zzish.com/";
41
+ var logEnabled = false;
42
+ var header = "X-api-key";
43
+ var headerprefix = "";
44
+ var makeStateless = false;
45
+ var socketUrl = "socket.zzish.com";
46
+ var connectedToSocket;
47
+ var currentSocketRetry = 0;
48
+ var maxSocketRetry = 10;
49
+
50
+ var getDataValue = function(key) {
51
+ if (dataStorage[key]) {
52
+ return dataStorage[key];
53
+ }
54
+ try {
55
+ if (typeof localStorage !== "undefined") {
56
+ return localStorage.getItem(key);
57
+ }
58
+ }
59
+ catch (err) {
60
+
61
+ }
62
+ return undefined;
63
+ };
64
+
65
+ var setDataValue = function(key, value) {
66
+ dataStorage[key] = value;
67
+ try {
68
+ if (typeof localStorage !== "undefined") {
69
+ return localStorage.setItem(key, value);
70
+ }
71
+ }
72
+ catch (err) {
73
+
74
+ }
75
+ };
76
+
77
+ var removeDataValue = function(key) {
78
+ delete dataStorage[key];
79
+ try {
80
+ if (typeof localStorage !== "undefined") {
81
+ localStorage.removeItem(key);
82
+ }
83
+ }
84
+ catch (err) {
85
+
86
+ }
87
+ };
88
+
89
+ var clearDataValue = function() {
90
+ for (var i in dataStorage) {
91
+ delete dataStorage[i];
92
+ }
93
+ try {
94
+ if (typeof localStorage !== "undefined") {
95
+ localStorage.clear();
96
+ }
97
+ }
98
+ catch (err) {
99
+
100
+ }
101
+ };
102
+
103
+ /**
104
+ * Checks to see if localStorage is defined. Then it's a stateful session
105
+ */
106
+ function stateful() {
107
+ //if localstorage is not defined
108
+ if (makeStateless) return false;
109
+ return (typeof localStorage != 'undefined');
110
+ }
111
+
112
+
113
+ function getBaseUrl() {
114
+ if (stateful() && window !== undefined && window.location !== undefined && window.location.href !== undefined) {
115
+ // var url = window.location.href;
116
+ // if (url!=undefined) {
117
+ // var arr = url.split("/");
118
+ // if (arr[0]=="file:") arr[0] = "http:";
119
+ // return arr[0] + "//" + baseUrl;
120
+ // }
121
+ }
122
+ return defaultProtocol + baseUrl;
123
+ }
124
+
125
+
126
+ function getQueryParams() {
127
+ var params = {}, tokens,
128
+ re = /[?&]?([^=]+)=([^&]*)/g;
129
+ try {
130
+ var qs = "";
131
+ if (location.search!="") {
132
+ qs = location.search;
133
+ }
134
+ else if (location.hash!="") {
135
+ qs = location.hash;
136
+ indexOf = qs.indexOf("?");
137
+ qs = qs.substring(indexOf+1);
138
+ }
139
+ qs = qs.split("+").join(" ");
140
+ while (tokens = re.exec(qs)) {
141
+ params[decodeURIComponent(tokens[1])]
142
+ = decodeURIComponent(tokens[2]);
143
+ }
144
+ }
145
+ catch (err) {
146
+
147
+ }
148
+ return params;
149
+ }
150
+
151
+ function getConfigValue(config,field,originalValue) {
152
+ if (config[field]!=undefined) return config[field];
153
+ return originalValue;
154
+ }
155
+
156
+ var sendEvent = function(event, callback) {
157
+ var request = {
158
+ method: "POST",
159
+ url: getBaseUrl() + "statements/events",
160
+ data: {
161
+ platform : "js",
162
+ action: "START",
163
+ appId: appId
164
+ }
165
+ };
166
+ sendData(request, function (err, data) {
167
+ callCallBack(err, data, callback);
168
+ });
169
+ }
170
+
171
+ /**
172
+ * Initialise Zzish instance
173
+ */
174
+ Zzish.init = function (config) {
175
+ //generate a device if we don't have one
176
+ appConfig = config;
177
+ deviceId = getDataValue("deviceId");
178
+ if (deviceId == null) {
179
+ deviceId = v4();
180
+ setDataValue("deviceId", deviceId);
181
+ }
182
+ if (typeof config =='string') {
183
+ try
184
+ {
185
+ config = JSON.parse(config);
186
+ Zzish.init(config);
187
+ }
188
+ catch (err) {
189
+ appId = config;
190
+ setDataValue("appConfig",config);
191
+ }
192
+
193
+ }
194
+ else if (typeof config =='object') {
195
+ appId = getConfigValue(config,'api');
196
+ defaultProtocol = getConfigValue(config,'protocol',defaultProtocol);
197
+ baseUrl = getConfigValue(config,'baseUrl',baseUrl);
198
+ webUrl = getConfigValue(config,'webUrl',webUrl);
199
+ header = getConfigValue(config,'header',header);
200
+ headerprefix = getConfigValue(config,'headerprefix',headerprefix);
201
+ logEnabled = getConfigValue(config,'logEnabled',logEnabled);
202
+ socketUrl = getConfigValue(config,'socketUrl',socketUrl);
203
+ setDataValue("appConfig",JSON.stringify(config));
204
+ }
205
+ sendEvent("START");
206
+ };
207
+
208
+
209
+ /**
210
+ * Stop Zzish instance
211
+ */
212
+ Zzish.stop = function (callback) {
213
+ //generate a device if we don't have one
214
+ sendEvent("STOP");
215
+ };
216
+
217
+ var params = getQueryParams();
218
+ if (params["zzishtoken"]!=null) {
219
+ Zzish.init(params["zzishtoken"]);
220
+ }
221
+ if (params["cancel"]!=undefined) {
222
+ removeDataValue("token");
223
+ }
224
+
225
+
226
+
227
+ /**** SERVER SIDE (NO STATE) *****/
228
+
229
+ /**
230
+ * Presets the deviceId and SessionId which the developer stores if there is not state to store that info
231
+ */
232
+ Zzish.initState = function(iDeviceId,iSessionId) {
233
+ deviceId = iDeviceId;
234
+ sessionId = iSessionId;
235
+ return zzish;
236
+ };
237
+
238
+ /**** CLIENT SIDE (REQUIRE STATE) *****/
239
+
240
+ /**
241
+ * Get the User (if the id is the same as the current one, returns the current user)
242
+ *
243
+ * @param id - A unique Id for the user (required)
244
+ * @param name - The name of the user (optional)
245
+ * @param callback - An optional callback after user has been saved on server
246
+ * @return The user (returns a server user if it already exists). If it's the current User, returns that user
247
+ */
248
+ Zzish.getUser = function (id, name, callback) {
249
+ if (id==undefined) id = v4();
250
+ if (stateful()) {
251
+ //that means we have a front end service so we can check state
252
+ if (currentUser==undefined || currentUser.id != id) {
253
+ sessionId = v4();
254
+ Zzish.createUser(id,name,function(err,message) {
255
+ if (!err) {
256
+ //set the current user if we don't have an error
257
+ currentUser = message;
258
+ }
259
+ callCallBack(err, {status: 200, payload: message}, callback);
260
+ });
261
+ }
262
+ else {
263
+ callCallBack(null, {status: 200, payload: currentUser}, callback);
264
+ }
265
+ }
266
+ else {
267
+ Zzish.createUser(id,name,callback);
268
+ }
269
+ };
270
+
271
+ /**
272
+ * Get the User by the zzish user code
273
+ *
274
+ * @param code - Their zzish user code
275
+ * @param callback - An optional callback after user has been saved on server
276
+ * @return The user (returns a server user if it already exists). If it's the current User, returns that user
277
+ */
278
+ Zzish.getUserByCode = function (code, callback) {
279
+ var request = {
280
+ method: "GET",
281
+ url: getBaseUrl() + "profiles/code/" + code
282
+ };
283
+ sendData(request, function (err, data) {
284
+ callCallBack(err, data, callback);
285
+ })
286
+ };
287
+
288
+ /**
289
+ * Get a list of users
290
+ *
291
+ * @param ids - A unique Id for the user (required)
292
+ * @param callback - An optional callback after user has been saved on server
293
+ * @return The user (returns a server user if it already exists). If it's the current User, returns that user
294
+ */
295
+ Zzish.getUsers = function (ids, callback) {
296
+ var request = {
297
+ method: "GET",
298
+ url: getBaseUrl() + "profiles/list/" + encodeURIComponent(ids.join(";"))
299
+ };
300
+ sendData(request, function (err, data) {
301
+ callCallBack(err, data, callback);
302
+ })
303
+ };
304
+
305
+ /**
306
+ * Get a list of users (POST)
307
+ *
308
+ * @param ids - A unique Id for the user (required)
309
+ * @param callback - An optional callback after user has been saved on server
310
+ * @return The user (returns a server user if it already exists). If it's the current User, returns that user
311
+ */
312
+ Zzish.getUsersByList = function (ids, callback) {
313
+ var request = {
314
+ method: "POST",
315
+ url: getBaseUrl() + "profiles/listusers/",
316
+ data: ids
317
+ };
318
+ sendData(request, function (err, data) {
319
+ callCallBack(err, data, callback);
320
+ })
321
+ };
322
+
323
+ /**
324
+ * Save the User (if the id is the same as the current one, returns the current user)
325
+ *
326
+ * @param id - A unique Id for the user (required)
327
+ * @param user - The user object to save
328
+ * @param callback - An optional callback after user has been saved on server
329
+ * @return The user (returns a server user if it already exists). If it's the current User, returns that user
330
+ */
331
+ Zzish.saveUser = function (id, user, callback) {
332
+ var request = {
333
+ method: "POST",
334
+ url: getBaseUrl() + "profiles",
335
+ data: user
336
+ };
337
+ sendData(request, function (err, data) {
338
+ callCallBack(err, data, callback);
339
+ })
340
+ };
341
+
342
+ /**
343
+ * Create a Zzish group for a user
344
+ *
345
+ * @param id - A unique Id for the user (required)
346
+ * @param group - The group object to save
347
+ * @param callback - An optional callback after user has been saved on server
348
+ * @return The group (returns a server user if it already exists). If it's the current User, returns that user
349
+ */
350
+ Zzish.saveGroup = function (id, group, callback) {
351
+ var request = {
352
+ method: "POST",
353
+ url: getBaseUrl() + "profiles/" + id + "/groups",
354
+ data: group
355
+ };
356
+ sendData(request, function (err, data) {
357
+ callCallBack(err, data, callback);
358
+ })
359
+ };
360
+
361
+
362
+ /**
363
+ * Create a game
364
+ *
365
+ * @param userId - The userId of the user (required)
366
+ * @param game - The game Object (required)
367
+ * @param callback - A callback to be called after message is sent (returns error,message)
368
+ * @return The game uuid
369
+ */
370
+ Zzish.createGame = function (userId, game, callback) {
371
+ if (game.uuid === undefined) {
372
+ game.uuid = v4();
373
+ }
374
+ var request = {
375
+ method: "POST",
376
+ url: getBaseUrl() + "statements/" + userId + "/games",
377
+ data: game
378
+ };
379
+ sendData(request, function (err, data) {
380
+ callCallBack(err, data, callback);
381
+ })
382
+ return game.uuid;
383
+ };
384
+
385
+
386
+
387
+ /**
388
+ * Get results of a game
389
+ *
390
+ * @param gameId - The Game uuid
391
+ * @param callback - A callback to be called after message is sent (returns error,message)
392
+ * @return The game uuid
393
+ */
394
+ Zzish.getGameActivities = function (userId,gameId, callback) {
395
+ var request = {
396
+ method: "GET",
397
+ url: getBaseUrl() + "statements/" + userId + "/games/" + gameId + "/activities"
398
+ };
399
+ sendData(request, function (err, data) {
400
+ callCallBack(err, data, callback);
401
+ })
402
+ };
403
+
404
+ /**
405
+ * Get activity result
406
+ *
407
+ * @param gameId - The Game uuid
408
+ * @param uuid - The Activity uuid
409
+ * @param callback - A callback to be called after message is sent (returns error,message)
410
+ * @return The game uuid
411
+ */
412
+ Zzish.getGameActivity = function (userId,gameId, uuid, callback) {
413
+ var request = {
414
+ method: "GET",
415
+ url: getBaseUrl() + "statements/" + userId + "/games/" + gameId + "/activities/" + uuid
416
+ };
417
+ sendData(request, function (err, data) {
418
+ callCallBack(err, data, callback);
419
+ })
420
+ };
421
+
422
+ /**
423
+ * Generate an activityId
424
+ *
425
+ * @return A unique id for the activityId
426
+ */
427
+ Zzish.generateActivityId = function () {
428
+ return v4();
429
+ };
430
+
431
+ /**
432
+ * Start Activity with name
433
+ *
434
+ * @param userId - The userId of the user (required)
435
+ * @param activityName - The name of the activity (required)
436
+ * @param code - The Zzish Class Code when creating a class in the learning hub (optional)
437
+ * @param callback - A callback to be called after message is sent (returns error,message)
438
+ */
439
+ Zzish.startActivity = function (userId, activityName, code, callback) {
440
+ var parameters = {
441
+ activityDefinition: {
442
+ type: activityName
443
+ },
444
+ extensions: {
445
+ groupCode: code
446
+ }
447
+ };
448
+ Zzish.startActivityWithObjects(userId,parameters, callback);
449
+ };
450
+
451
+ /**
452
+ * Start Activity with name
453
+ *
454
+ * @param userId - The userId of the user (required)
455
+ * @param parameters - The parameters Object which contains various configurations of the activity
456
+ * @param callback - A callback to be called after message is sent (returns error,message)
457
+ */
458
+ Zzish.startActivityWithObjects = function (userId, parameters, callback) {
459
+ sendEvent("START_ACTIVITY");
460
+ if (!currentUser || !stateful() || userId!=currentUser.id) {
461
+ currentUser = {
462
+ uuid: userId
463
+ };
464
+ }
465
+ var message = {
466
+ verb: "http://activitystrea.ms/schema/1.0/start",
467
+ activityUuid: parameters.activityId || v4()
468
+ };
469
+ sendMessage(message, parameters, callback);
470
+ };
471
+
472
+ /**
473
+ * stop Activity with aid
474
+ *
475
+ * @param activityId - The activity id (returned from startActivity) (required)
476
+ * @param states - A string represented JSON of attributes to save for this activity (optional)
477
+ * @param callback - A callback to be called after message is sent (returns error,message)
478
+ *
479
+ */
480
+ Zzish.stopActivity = function (activityId, states, callback) {
481
+ sendEvent("STOP_ACTIVITY");
482
+ var pro = undefined;
483
+ var haveState = false;
484
+ if (states!=undefined && states.proficiency!=undefined) {
485
+ pro = states.proficiency;
486
+ delete states.proficiency;
487
+ }
488
+ var stateMap = {
489
+ states: states
490
+ }
491
+ if (pro!=undefined) {
492
+ stateMap.proficiency = pro;
493
+ haveState = true;
494
+ }
495
+ for (i in states) {
496
+ haveState = true;
497
+ }
498
+ sendMessage({
499
+ verb: "http://activitystrea.ms/schema/1.0/complete",
500
+ activityUuid: activityId
501
+ }, { states: haveState?stateMap:undefined},callback)
502
+ };
503
+
504
+ /** * Update an activity instance with images
505
+ *
506
+ * @param activityId - The activity instance id of activity
507
+ * @param images - object with stringified image urls/keys
508
+ * @param callback - A callback to be called after message is sent (returns error,message)
509
+ */
510
+ Zzish.updateActivityImages = function (activityId, images, callback) {
511
+ var request = {
512
+ method: "POST",
513
+ url: getBaseUrl() + "statements/activityinstances/" + activityId + "/images",
514
+ data: images,
515
+ };
516
+ sendData(request, function (err, data) {
517
+ callCallBack(err, data, callback);
518
+ })
519
+ };
520
+
521
+ /**
522
+ * Cancel Activity with aid
523
+ *
524
+ * @param activityId - The activity id (returned from startActivity) (required)
525
+ * @param callback - A callback to be called after message is sent (returns error,message)
526
+ *
527
+ */
528
+ Zzish.cancelActivity = function (activityId, callback) {
529
+ sendEvent("CANCEL_ACTIVITY");
530
+ sendMessage({
531
+ verb: "http://activitystrea.ms/schema/1.0/cancel",
532
+ activityUuid: activityId
533
+ }, {}, callback)
534
+ };
535
+
536
+ /**
537
+ * Log an Action
538
+ *
539
+ * @param activityId - The activity id (returned from startActivity) (required)
540
+ * @param actionName - The name of the action (required)
541
+ * @param response - A string representation of the action (optional)
542
+ * @param score - A float score (optional)
543
+ * @param duration - A long duration (optional)
544
+ * @param attempts - The number of attempts
545
+ * @param attributes - JSON Attributes
546
+ * @param callback - A callback to be called after message is sent (returns error,message)
547
+ *
548
+ */
549
+ Zzish.logAction = function (activityId, actionName, response, score, correct, duration, attempts, attributes, callback) {
550
+ var definition = {
551
+ type: actionName
552
+ };
553
+ var result = {};
554
+ if (response != undefined) {
555
+ result["response"] = response;
556
+ }
557
+ if (score != undefined) {
558
+ result["score"] = parseFloat(score);
559
+ }
560
+ if (correct != undefined) {
561
+ result["correct"] = correct;
562
+ }
563
+ if (duration != undefined) {
564
+ result["duration"] = parseInt(duration);
565
+ }
566
+ if (attempts != undefined) {
567
+ result["attempts"] = parseInt(attempts);
568
+ }
569
+ Zzish.logActionWithObjects(activityId,{definition:definition, result: result},callback);
570
+ };
571
+
572
+ Zzish.logActionWithObjects = function (activityId, parameters, callback) {
573
+ sendEvent("ACTION");
574
+ if (parameters.definition==undefined) {
575
+ parameters.definition = {};
576
+ }
577
+ var action = createActionObject(parameters);
578
+ sendMessage({
579
+ verb: "http://activitystrea.ms/schema/1.0/start",
580
+ activityUuid: activityId,
581
+ actions: [action]
582
+ }, parameters, callback);
583
+ }
584
+
585
+ function createActionObject(parameters) {
586
+ var action = parameters.result;
587
+ if (action == undefined) {
588
+ action = {};
589
+ }
590
+ action.definition = parameters.definition;
591
+ action.uuid = parameters.uuid || v4();
592
+ action.state = parameters.state;
593
+ if (typeof parameters.attributes === "string") {
594
+ action.attributes = JSON.parse(parameters.attributes);
595
+ }
596
+ else {
597
+ action.attributes = parameters.attributes;
598
+ }
599
+ return action;
600
+ }
601
+
602
+ Zzish.logActions = function (activityId, parameters, actionObjects, callback) {
603
+ sendEvent("ACTION");
604
+ var actions = actionObjects.map(function(action) {
605
+ return createActionObject(action);
606
+ });
607
+ sendMessage({
608
+ verb: "http://activitystrea.ms/schema/1.0/start",
609
+ activityUuid: activityId,
610
+ actions: actions
611
+ }, parameters, callback);
612
+ };
613
+
614
+ /**
615
+ * send message to REST API
616
+ *
617
+ * @param data - A partial tincan statement
618
+ * @param callback - An optional callback to call when done (returns error,message)
619
+ *
620
+ */
621
+ var sendMessage = function (data, parameters, callback) {
622
+ if (currentUser) {
623
+ data.userUuid = currentUser.uuid;
624
+ }
625
+ if (parameters.extensions==undefined) {
626
+ parameters.extensions = {};
627
+ }
628
+ parameters.extensions["deviceId"] = deviceId;
629
+ parameters.extensions["sessionId"] = sessionId;
630
+ var message = buildSimulationMessage(data,parameters);
631
+ var headers = {
632
+ 'Content-Type': 'application/json'
633
+ };
634
+ headers[header] = headerprefix + appId;
635
+ var request = {
636
+ method: "POST",
637
+ url: getBaseUrl() + "statements",
638
+ data: message
639
+ };
640
+ sendData(request, function (err, data) {
641
+ callCallBack(err, data, callback);
642
+ })
643
+ };
644
+
645
+ /**
646
+ * Build an (extended) TinCan statement
647
+ * @param data
648
+ * @returns partially built TinCan message
649
+ */
650
+ var buildSimulationMessage = function (data,parameters) {
651
+ if (parameters.activityDefinition==undefined) {
652
+ parameters.activityDefinition = {};
653
+ }
654
+ var message = {
655
+ actor: {
656
+ account: {
657
+ homePage: "http://www.zzish.com/" + appId,
658
+ name: data.userUuid
659
+ }
660
+ },
661
+ verb: {
662
+ id: data.verb
663
+ },
664
+ object: {
665
+ definition: parameters.activityDefinition
666
+ },
667
+ id: data.activityUuid,
668
+ context: {
669
+ extensions: {}
670
+ }
671
+ };
672
+ if (parameters.states!=undefined) {
673
+ message.object.state = parameters.states;
674
+ }
675
+ if (parameters.stored !== undefined) {
676
+ message.stored = parameters.stored;
677
+ }
678
+ if (parameters.timestamp !== undefined) {
679
+ message.timestamp = parameters.timestamp;
680
+ }
681
+ if (parameters.extensions) {
682
+ for (i in parameters.extensions) {
683
+ message.context.extensions["http://www.zzish.com/context/extension/"+i] = parameters.extensions[i];
684
+ }
685
+ }
686
+ if (data.actions !== undefined) {
687
+ message.actions = data.actions;
688
+ }
689
+ return message;
690
+ };
691
+
692
+
693
+
694
+ /**
695
+ * Simple replaceAll method
696
+ *
697
+ * @param find - What to find
698
+ * @param replace - What to replace with
699
+ * @param str - The string to search
700
+ * @return The result after the replace is done
701
+ */
702
+ function replaceAll(find, replace, str) {
703
+ if (str){
704
+ return str.replace(new RegExp(find, 'g'), replace);
705
+ }
706
+ }
707
+
708
+ /**
709
+ * Helper method to call callback
710
+ * err - error response from making call
711
+ * data - response from making call
712
+ * callback - callback method
713
+ */
714
+ function callCallBack(err, data, callback) {
715
+ //check if callback exists
716
+ if (callback != undefined) {
717
+ if (err != undefined) { console.error(err); }
718
+ if (err != undefined && isObject(err) && err.status) {
719
+ //an error has ocurred when trying to get response
720
+ callback(err.status, err.message);
721
+ }
722
+ else if (data != undefined) {
723
+ //check if api returns 200
724
+ if (data.status == 200) {
725
+ //return payload as message will be null
726
+ callback(undefined, data.payload);
727
+ }
728
+ else {
729
+ //return message
730
+ callback(data.status, data.message);
731
+ }
732
+ }
733
+ else {
734
+ callback(400, "Zzish error");
735
+ }
736
+ }
737
+ }
738
+
739
+ /**** BACK END STUFF TO SEND DATA ***/
740
+
741
+ /**** LOGINSTUFF ***/
742
+
743
+ /**
744
+ * Returns true if it's a valid class code (not necessarily whether it exists)
745
+ *
746
+ * @param code - The Zzish Class code (required)
747
+ */
748
+ Zzish.validateClassCode = function (code) {
749
+ if (code!=undefined && code.length>1) {
750
+ var charLast = code.slice(-1);
751
+ var total = 0;
752
+ for (counter=0;counter<code.length-1;counter++) {
753
+ total+=code.charCodeAt(counter);
754
+ }
755
+ total = total%10;
756
+ if (charLast==total) {
757
+ return true;
758
+ }
759
+ }
760
+ return false;
761
+ };
762
+
763
+ /**
764
+ * Authenticate user based on name and classcode.
765
+ * Returns 409 if user has logged in on a different device with the same name
766
+ * within a specied period (see error message for details)
767
+ *
768
+ * @param id - A unique Id for the user (required)
769
+ * @param name - The name of the user (required)
770
+ * @param code - The Zzish Class code (required)
771
+ * @param callback - An optional callback after user has been saved on server
772
+ */
773
+ Zzish.authUser = function (id, name, code, callback) {
774
+ var message = {
775
+ uuid : id,
776
+ username : name,
777
+ passwordText: code
778
+ };
779
+ //create new session
780
+ sessionId = uuid.v4();
781
+ var request = {
782
+ method: "POST",
783
+ url: getBaseUrl() + "profiles/auth",
784
+ data: message
785
+ };
786
+ sendData(request, function (err, data) {
787
+ if (!err) {
788
+ currentUser = data;
789
+ }
790
+ callCallBack(err, data, callback);
791
+ })
792
+ };
793
+
794
+ /**
795
+ * Logout a user
796
+ *
797
+ * @param id - A unique Id for the user (required)
798
+ * @param callback - An optional callback after user has been saved on server
799
+ */
800
+
801
+ Zzish.unauthUser = function (id, callback) {
802
+ var request = {
803
+ method: "POST",
804
+ url: getBaseUrl() + "profiles/"+id+"/logout",
805
+ data: {}
806
+ };
807
+ sendData(request, function (err, data) {
808
+ callCallBack(err, data, callback);
809
+ })
810
+ };
811
+
812
+ /**
813
+ * Create a user
814
+ *
815
+ * @param id - A unique Id for the user (required)
816
+ * @param name - The name of the user (optional)
817
+ * @param callback - An optional callback after user has been saved on server
818
+ */
819
+ Zzish.createUser = function (id, name, callback) {
820
+ var message = {
821
+ uuid : id,
822
+ name : name
823
+ };
824
+ var request = {
825
+ method: "POST",
826
+ url: getBaseUrl() + "profiles",
827
+ data: message
828
+ };
829
+ sendData(request, function (err, data) {
830
+ callCallBack(err, data, callback);
831
+ })
832
+ };
833
+
834
+
835
+ /**
836
+ * Get List of Groups for user
837
+ *
838
+ * @param profileId - A unique Id for the user (required)
839
+ * @param callback - An optional callback after user has been saved on server
840
+ */
841
+ Zzish.listGroups = function (profileId, callback) {
842
+ var request = {
843
+ method: "GET",
844
+ url: getBaseUrl() + "profiles/"+profileId+"/groups"
845
+ };
846
+ sendData(request, function (err, data) {
847
+ if (!err && data && data.payload) {
848
+ for (var i in data.payload) {
849
+ var link = replaceAll("/","-----",data.payload[i].link);
850
+ link = replaceAll("\\\\","=====",link)
851
+ data.payload[i].link = webUrl + "learning-hub/tclassroom/" + link +"/live";
852
+ }
853
+ }
854
+ callCallBack(err, data, callback);
855
+ });
856
+ };
857
+
858
+ /**
859
+ * Get List of Students for Group
860
+ *
861
+ * @param profileId - The owner of the group
862
+ * @param groupCode - The code of the group
863
+ * @param callback - An optional callback after user has been saved on server
864
+ */
865
+ Zzish.listStudents = function (profileId, groupCode, callback) {
866
+ var request = {
867
+ method: "GET",
868
+ url: getBaseUrl() + "profiles/"+profileId+"/groups/code/"+groupCode+"/students"
869
+ };
870
+ sendData(request, function (err, data) {
871
+ callCallBack(err, data, callback);
872
+ })
873
+ };
874
+
875
+
876
+ /**
877
+ * Get List of Content assigned to all groups of the profile
878
+ *
879
+ * @param id - A unique Id for the user (required)
880
+ * @param callback - An optional callback after user has been saved on server
881
+ */
882
+ Zzish.listGroupContentForProfile = function (id, callback) {
883
+ var request = {
884
+ method: "GET",
885
+ url: getBaseUrl() + "profiles/"+id+"/groups/contents",
886
+ };
887
+ sendData(request, function (err, data) {
888
+ callCallBack(err, data, callback);
889
+ })
890
+ };
891
+
892
+
893
+ /**** USER MANAGEMENT *****/
894
+
895
+ /**
896
+ * Authenticate based on user and password (which is md5') for app
897
+ * Returns 409 if user has logged in on a different device with the same name
898
+ * within a specied period (see error message for details)
899
+ *
900
+ * @param email - The email of the user
901
+ * @param password - The password of the user
902
+ * @param callback - An optional callback after user has been saved on server
903
+ */
904
+ Zzish.authenticate = function (email, password, callback) {
905
+ if ((password==undefined || password =="") && (email=="" || email==undefined)) {
906
+ callback(400,"Email and Password are required");
907
+ }
908
+ else {
909
+ var message = {
910
+ email : email,
911
+ password: password
912
+ };
913
+ var request = {
914
+ method: "POST",
915
+ url: getBaseUrl() + "profiles/authenticate",
916
+ data: message
917
+ };
918
+ sendData(request, function (err, data) {
919
+ callCallBack(err, data, callback);
920
+ })
921
+ }
922
+ };
923
+
924
+ /**
925
+ * Gets a user based on the Profile User Id
926
+ *
927
+ * @param uuid - The profile User Id
928
+ * @param callback - An optional callback after user has been saved on server
929
+ */
930
+ Zzish.user = function (uuid, callback) {
931
+ var request = {
932
+ method: "GET",
933
+ url: getBaseUrl() + "profiles/authenticate/"+uuid,
934
+ };
935
+ sendData(request, function (err, data) {
936
+ callCallBack(err, data, callback);
937
+ })
938
+ };
939
+
940
+ /**
941
+ * Searchs a user by Attributes
942
+ *
943
+ * @param attributes - A set of attributes to search for on user. String key/value pairs
944
+ * @param callback - An optional callback after user has been saved on server
945
+ */
946
+ Zzish.userByAttributes = function (attributes, callback) {
947
+ var request = {
948
+ method: "POST",
949
+ url: getBaseUrl() + "profiles/authenticate/search",
950
+ data: attributes
951
+ };
952
+ sendData(request, function (err, data) {
953
+ callCallBack(err, data, callback);
954
+ })
955
+ };
956
+
957
+ /**
958
+ * Creates a user object on the Zzish User Database. Email and password is at least required.
959
+ *
960
+ * @param email - The email of the user
961
+ * @param password - The password of the user
962
+ * @param callback - An optional callback after user has been saved on server
963
+ */
964
+ Zzish.registerUser = function (email, password, callback) {
965
+ var message = {
966
+ email : email,
967
+ password: password
968
+ };
969
+ var request = {
970
+ method: "POST",
971
+ url: getBaseUrl() + "profiles/authenticate/register",
972
+ data: message
973
+ };
974
+ sendData(request, function (err, data) {
975
+ callCallBack(err, data, callback);
976
+ })
977
+ };
978
+
979
+ /**
980
+ * Update user object on the Zzish User Database
981
+ *
982
+ * @param user - The user object
983
+ * @param callback - An optional callback after user has been saved on server
984
+ */
985
+ Zzish.updateUser = function (user, callback) {
986
+ var request = {
987
+ method: "POST",
988
+ url: getBaseUrl() + "profiles/authenticate/update",
989
+ data: user
990
+ };
991
+ sendData(request, function (err, data) {
992
+ callCallBack(err, data, callback);
993
+ })
994
+ };
995
+
996
+ /**
997
+ * Update the user password
998
+ *
999
+ * @param uuid - The user uuid
1000
+ * @param password - The password
1001
+ * @param callback - An optional callback after user has been saved on server
1002
+ */
1003
+ Zzish.updatePassword = function (uuid, password, callback) {
1004
+ var request = {
1005
+ method: "POST",
1006
+ url: getBaseUrl() + "profiles/authenticate/" + uuid + "/password",
1007
+ data: {password: password}
1008
+ };
1009
+ sendData(request, function (err, data) {
1010
+ callCallBack(err, data, callback);
1011
+ })
1012
+ };
1013
+
1014
+ /**
1015
+ * Authorizes user to log in straight from the developer's app by authorizing the user. An email will be sent
1016
+ *
1017
+ * @param userId - The Developer User Id
1018
+ * @param email - The email of the user
1019
+ * @param name - The optional name fo the user
1020
+ * @param callback - An optional callback after user has been saved on server
1021
+ */
1022
+ Zzish.registerUserWithZzish = function (userId, email, name, callback) {
1023
+ var message = {
1024
+ email: email,
1025
+ profile: {
1026
+ uuid: userId,
1027
+ name: name
1028
+ }
1029
+ };
1030
+ var request = {
1031
+ method: "POST",
1032
+ url: getBaseUrl() + "profiles/authenticate/eregister",
1033
+ data: message
1034
+ };
1035
+ sendData(request, function (err, data) {
1036
+ callCallBack(err, data, callback);
1037
+ });
1038
+ };
1039
+
1040
+ /**
1041
+ * Returns a token to be used for accessing Zzish website
1042
+ *
1043
+ * @param userId - The Developer User Id
1044
+ * @param callback - An optional callback after user has been saved on server
1045
+ */
1046
+ Zzish.getTokenForUser = function (userId, callback) {
1047
+ var message = {
1048
+ uuid: userId
1049
+ };
1050
+ var request = {
1051
+ method: "POST",
1052
+ url: getBaseUrl() + "profiles/authenticate/token",
1053
+ data: message
1054
+ };
1055
+ sendData(request, function (err, data) {
1056
+ callCallBack(err, data, function(err, message) {
1057
+ var url = webUrl + "account/app/" + message + "/token";
1058
+ callback(err, url);
1059
+ });
1060
+ });
1061
+ };
1062
+
1063
+ /**** BACKEND CONTENT STUFF ***/
1064
+
1065
+ /**
1066
+ * Save a Zzish content object
1067
+ * @param profileId - The id of the profile to which to save the content for
1068
+ * @param type - The content type
1069
+ * @param uuid - Unique id of the content
1070
+ * @param meta - A Json Object of tags associated with the object. Special tags are name, categoryId and code.
1071
+ * @param content - The JSON object to save
1072
+ * @param callback - An optional callback to call when done (returns error,message)
1073
+ */
1074
+ Zzish.postContent = function (profileId, type, uuid,meta, tags, content, callback) {
1075
+ var data = {
1076
+ uuid: uuid,
1077
+ meta: meta,
1078
+ tags: tags,
1079
+ payload: JSON.stringify(content)
1080
+ };
1081
+ var request = {
1082
+ method: "POST",
1083
+ url: getBaseUrl() + "profiles/" + profileId + "/contents/" + type + "/" + uuid,
1084
+ data: data
1085
+ };
1086
+ sendData(request, function (err, data) {
1087
+ callCallBack(err, data, callback);
1088
+ });
1089
+ };
1090
+
1091
+ /**
1092
+ * Save a Zzish content object
1093
+ * @param profileId - The id of the profile to which to save the content for
1094
+ * @param type - The content type
1095
+ * @param uuid - Unique id of the content
1096
+ * @param meta - A Json Object of tags associated with the object. Special tags are name, categoryId and code.
1097
+ * @param content - The JSON object to save
1098
+ * @param tags - The JSON object to save
1099
+ * @param callback - An optional callback to call when done (returns error,message)
1100
+ */
1101
+ Zzish.postContentTagged = function (profileId, type, uuid, meta, content, tags, callback) {
1102
+ var data = {
1103
+ uuid: uuid,
1104
+ meta: meta,
1105
+ payload: JSON.stringify(content),
1106
+ tags: tags
1107
+ };
1108
+ var request = {
1109
+ method: "POST",
1110
+ url: getBaseUrl() + "profiles/" + profileId + "/contents/" + type + "/" + uuid,
1111
+ data: data
1112
+ };
1113
+ sendData(request, function (err, data) {
1114
+ callCallBack(err, data, callback);
1115
+ });
1116
+ };
1117
+
1118
+ /**
1119
+ * Delete a Zzish content object
1120
+ * @param profileId - The id of the profile to which to save the content for
1121
+ * @param type - The content type
1122
+ * @param id - The id of the content
1123
+ * @param callback - An optional callback to call when done (returns error,message)
1124
+ */
1125
+ Zzish.deleteContent = function (profileId, type, id, callback) {
1126
+ var request = {
1127
+ method: "DELETE",
1128
+ url: getBaseUrl() + "profiles/" + profileId + "/contents/" + type + "/" + id
1129
+ };
1130
+ sendData(request, function (err, data) {
1131
+ callCallBack(err, data, callback);
1132
+ });
1133
+ };
1134
+
1135
+ var formatContentObject = function(content,includePayload) {
1136
+ if (content) {
1137
+ var result = {
1138
+ uuid: content.uuid,
1139
+ type: content.type,
1140
+ tags: content.tags || [],
1141
+ meta : content.meta,
1142
+ attributes: content.attributes
1143
+ };
1144
+ if (includePayload && content.payload!==undefined && content.payload!="") {
1145
+ result.payload = JSON.parse(content.payload);
1146
+ }
1147
+ return result;
1148
+ }
1149
+ return null;
1150
+ };
1151
+
1152
+ var formatListContents = function(data,includePayload) {
1153
+ var list = [];
1154
+ if (data){
1155
+ for (var i in data.payload) {
1156
+ list.push(formatContentObject(data.payload[i],includePayload));
1157
+ }
1158
+ }
1159
+ return list;
1160
+ };
1161
+
1162
+ var formatListCategoryContents = function(data) {
1163
+ if (data && data.payload.contents){
1164
+ var list = [];
1165
+ for (var i in data.payload.contents) {
1166
+ var result = formatContentObject(data.payload.contents[i],false);
1167
+ list.push(result);
1168
+ }
1169
+ data.payload.contents = list;
1170
+ return data.payload;
1171
+ }
1172
+ return data;
1173
+ };
1174
+
1175
+ /**
1176
+ * Get a Zzish content object
1177
+ * @param profileId - The id of the profile to which to get the content for
1178
+ * @param type - The content type
1179
+ * @param uuid - THe uuid to get
1180
+ * @param callback - A callback to call when done (returns error AND (message or data))
1181
+ */
1182
+ Zzish.getContent = function (profileId, type, uuid, callback) {
1183
+ var request = {
1184
+ method: "GET",
1185
+ url: getBaseUrl() + "profiles/" + profileId + "/contents/" + type + "/" + uuid
1186
+ };
1187
+ sendData(request, function (err, data) {
1188
+ callCallBack(err, data, function (status, message) {
1189
+ if (!err) {
1190
+ if (data && data.payload!==undefined && data.payload!=null) {
1191
+ callback(err,formatContentObject(data.payload,true));
1192
+ }
1193
+ else {
1194
+ callback("Invalid Data");
1195
+ }
1196
+ }
1197
+ else {
1198
+ callback(status, message);
1199
+ }
1200
+ });
1201
+ });
1202
+ };
1203
+
1204
+ /**
1205
+ * Get the Zzish assignment
1206
+ * @param profileId - The id of the profile to which to get the content for
1207
+ * @param type - The content type
1208
+ * @param uuid - THe uuid of the student assignement
1209
+ * @param callback - A callback to call when done (returns error AND (message or data))
1210
+ */
1211
+ Zzish.getAssignment = function (profileId, type, uuid, callback) {
1212
+ var request = {
1213
+ method: "GET",
1214
+ url: getBaseUrl() + "profiles/" + profileId + "/contents/" + type + "/assignments/" + uuid
1215
+ };
1216
+ sendData(request, function (err, data) {
1217
+ callCallBack(err, data, function (status, message) {
1218
+ if (!err) {
1219
+ if (data && data.payload!==undefined && data.payload!=null) {
1220
+ callback(err,formatContentObject(data.payload,true));
1221
+ }
1222
+ else {
1223
+ callback("Invalid Data");
1224
+ }
1225
+ }
1226
+ else {
1227
+ callback(status, message);
1228
+ }
1229
+ });
1230
+ });
1231
+ };
1232
+
1233
+
1234
+
1235
+ /**
1236
+ * Get a Zzish content object
1237
+ * @param profileId - The id of the profile to which to get the content for
1238
+ * @param type - The content type
1239
+ * @param uuids - An array of uuids
1240
+ * @param callback - A callback to call when done (returns error AND (message or data))
1241
+ */
1242
+ Zzish.getContents = function (profileId, type, uuids, callback) {
1243
+ var request = {
1244
+ method: "POST",
1245
+ url: getBaseUrl() + "profiles/" + profileId + "/contents/" + type + "/list",
1246
+ data: uuids
1247
+ };
1248
+ sendData(request, function (err, data) {
1249
+ callCallBack(err, data, function (status, message) {
1250
+ if (!err) {
1251
+ if (data && data.payload!==undefined && data.payload!=null) {
1252
+ callback(err, formatListContents(data,true));
1253
+ }
1254
+ else {
1255
+ callback("Invalid Data");
1256
+ }
1257
+ }
1258
+ else {
1259
+ callback(status, message);
1260
+ }
1261
+ });
1262
+ });
1263
+ };
1264
+
1265
+
1266
+ function convertToParameters(obj) {
1267
+ var str = "";
1268
+ for (var key in obj) {
1269
+ if (str != "") {
1270
+ str += "&";
1271
+ }
1272
+ if (Array.isArray(obj[key])) {
1273
+ for (var i in obj[key]) {
1274
+ str += key + "=" + encodeURIComponent(JSON.stringify(obj[key][i]));
1275
+ }
1276
+ }
1277
+ else {
1278
+ str += key + "=" + encodeURIComponent(JSON.stringify(obj[key]));
1279
+ }
1280
+ }
1281
+ return str;
1282
+ }
1283
+
1284
+ /**
1285
+ * Search all content objects
1286
+ * @param type - The content type
1287
+ * @param meta - A list of parameters to search on meta part
1288
+ * @param callback - A callback to call when done (returns error AND (message or data))
1289
+ */
1290
+ Zzish.searchPublicContent = function (type, meta, callback) {
1291
+ var request = {
1292
+ method: "GET",
1293
+ url: getBaseUrl() + "profiles/publicconsumers/" + type + "/search?" + convertToParameters(meta)
1294
+ };
1295
+ sendData(request, function (err, data) {
1296
+ callCallBack(err, data, function (status, message) {
1297
+ if (!err) {
1298
+ callback(err, formatListContents(data,false));
1299
+ }
1300
+ else {
1301
+ callback(status, message);
1302
+ }
1303
+ });
1304
+ });
1305
+ };
1306
+
1307
+ /**
1308
+ * Search a list of Zzish content object
1309
+ * @param profileId - The id of the profile to which to get the content for
1310
+ * @param type - The content type
1311
+ * @param meta - A list of parameters to search on meta part
1312
+ * @param callback - A callback to call when done (returns error AND (message or data))
1313
+ */
1314
+ Zzish.searchContent = function (profileId, type, meta, callback) {
1315
+ var request = {
1316
+ method: "GET",
1317
+ url: getBaseUrl() + "profiles/" + profileId + "/contents/" + type + "/search?" + convertToParameters(meta)
1318
+ };
1319
+ sendData(request, function (err, data) {
1320
+ callCallBack(err, data, function (status, message) {
1321
+ if (!err) {
1322
+ callback(err, formatListContents(data,false));
1323
+ }
1324
+ else {
1325
+ callback(status, message);
1326
+ }
1327
+ });
1328
+ });
1329
+ };
1330
+
1331
+ /**
1332
+ * Get a list of Zzish content object
1333
+ * @param profileId - The id of the profile to which to get contents for
1334
+ * @param type - The content type
1335
+ * @param callback - A callback to call when done (returns error AND (message or list of zzish,name))
1336
+ */
1337
+ Zzish.listContent = function (profileId, type, callback) {
1338
+ var request = {
1339
+ method: "GET",
1340
+ url: getBaseUrl() + "profiles/" + profileId + "/contents/" + type
1341
+ };
1342
+ sendData(request, function (err, data) {
1343
+ callCallBack(err, data, function (status, message) {
1344
+ if (!err) {
1345
+ callback(err, formatListContents(data,false));
1346
+ }
1347
+ else {
1348
+ callback(status, message);
1349
+ }
1350
+ });
1351
+ });
1352
+ };
1353
+
1354
+
1355
+ /**
1356
+ * Publish a content to a group
1357
+ * @param profileId - The id of the profile to which to get contents for
1358
+ * @param type - The content type
1359
+ * @param uuid - The id of the content
1360
+ * @param options-email - The email of the person so we can send them a link to register their account so they can access the group
1361
+ * @param options-code - The Zzish code of an existing class (optional)
1362
+ * @param options-access - the number of times a user can access the publish
1363
+ * @param options-groupName - the name of the group
1364
+ * @param options-public - whether to make the content public
1365
+ * @param callback - A callback to call when done (returns error AND (message or list of zzish,name))
1366
+ */
1367
+ Zzish.publishContent = function (profileId, type, uuid, options, callback) {
1368
+ var request = {
1369
+ method: "POST",
1370
+ url: getBaseUrl() + "profiles/" + profileId + "/contents/" + type + "/" + uuid + "/publish",
1371
+ data: options
1372
+ };
1373
+ sendData(request, function (err, data) {
1374
+ callCallBack(err, data, callback);
1375
+ });
1376
+ };
1377
+
1378
+ /**
1379
+ * UnPublish a content
1380
+ * @param profileId - The id of the profile to which to get contents for
1381
+ * @param type - The content type
1382
+ * @param uuid - The email of the person so we can send them a link to register their account so they can access the group
1383
+ * @param groupCode - The Zzish code of an existing class
1384
+ * @param callback - A callback to call when done (returns error AND (message or list of zzish,name))
1385
+ */
1386
+ Zzish.unpublishContent = function (profileId, type, uuid, groupCode, callback) {
1387
+ var request = {
1388
+ method: "POST",
1389
+ url: getBaseUrl() + "profiles/" + profileId + "/contents/" + type + "/" + uuid + "/" + groupCode + "/unpublish",
1390
+ data: {}
1391
+ };
1392
+ sendData(request, function (err, data) {
1393
+ callCallBack(err, data, callback);
1394
+ });
1395
+ };
1396
+
1397
+ /**
1398
+ * Return a list of contents and categories for a particular class code
1399
+ *
1400
+ * @param profileId - The Profile Id
1401
+ * @param code - The Zzish group Code
1402
+ * @param callback - A callback to be called after message is sent (returns error,message)
1403
+ *
1404
+ */
1405
+ Zzish.listContentForGroup = function(profileId, code, callback) {
1406
+ var request = {
1407
+ method: "GET",
1408
+ url: getBaseUrl() + "profiles/" + profileId + "/consumers/"+code,
1409
+ };
1410
+ sendData(request, function (err, data) {
1411
+ callCallBack(err, data, function (status, message) {
1412
+ if (!err) {
1413
+ callback(err, formatListCategoryContents(data));
1414
+ }
1415
+ else {
1416
+ callback(status, message);
1417
+ }
1418
+ });
1419
+ })
1420
+ };
1421
+
1422
+ /**
1423
+ * Register user with class, Return a list of contents and categories
1424
+ *
1425
+ * @param profileId - The Profile Id
1426
+ * @param code - The Zzish group Code
1427
+ * @param callback - A callback to be called after message is sent (returns error,message)
1428
+ *
1429
+ */
1430
+ Zzish.registerUserWithGroup = function(profileId, code, callback) {
1431
+ var request = {
1432
+ method: "POST",
1433
+ url: getBaseUrl() + "profiles/" + profileId + "/consumers/" + code + "/register",
1434
+ data: {}
1435
+ };
1436
+ sendData(request, function (err, data) {
1437
+ callCallBack(err, data, function (status, message) {
1438
+ if (!err) {
1439
+ callback(err, formatListCategoryContents(data));
1440
+ }
1441
+ else {
1442
+ callback(status, message);
1443
+ }
1444
+ });
1445
+ })
1446
+ };
1447
+
1448
+ /**
1449
+ * Get results for Zzish content object
1450
+ * @param uuid - THe uuid to get
1451
+ * @param parameters - Optional parameters to modify result
1452
+ * limit: The nubmer of activity records (max 10) to return per request (default: 10)
1453
+ skip: Used for pagination (default: 0)
1454
+ iprofile: Include profile information (default: 0)
1455
+ idetails: Include individual actions for each activity instance (default: false)
1456
+ aggregate: Aggregate Results per activity definition (default: false)
1457
+ data: Return individual activity instance records. Works with limit and skip variables (default: false)
1458
+ * @param callback - A callback to call when done (returns error AND (message or data))
1459
+ * Result object
1460
+ data - An array of activity instance records (if data = true)
1461
+ aggregate - An array of stats per activity (if aggregate = true)
1462
+ meta - The meta descriptions for the data and aggregate fields
1463
+ - data_total - The total number of activity instance records
1464
+ - agg_total - The total number of aggregate records
1465
+ query - A Summary of query parameters passed in (as the request)
1466
+
1467
+ */
1468
+ Zzish.getUserResults = function (profileId, parameters, callback) {
1469
+ var request = {
1470
+ method: "GET",
1471
+ url: getBaseUrl() + "statements/" + profileId + "/results?" + convertToParameters(parameters)
1472
+ };
1473
+ sendData(request, function (err, data) {
1474
+ callCallBack(err, data, callback);
1475
+ });
1476
+ };
1477
+
1478
+
1479
+ /*
1480
+ * Get practice content
1481
+ * @param uuid - THe profileId of the user
1482
+ * @param parameters - Optional parameters to modify result
1483
+ * questionsToReturn: 10 (default)
1484
+ * @param callback - A callback to call when done (returns error AND (message or data))
1485
+ * Result object
1486
+ actions - A list of actions to practice
1487
+ aggregate -
1488
+ meta - The meta descriptions for the data and aggregate fields
1489
+ - data_total - The total number of activity instance records
1490
+ - agg_total - The total number of aggregate records
1491
+ query - A Summary of query parameters passed in (as the request)
1492
+
1493
+ */
1494
+ Zzish.loadPracticeQuiz = function (profileId, parameters, callback) {
1495
+ var request = {
1496
+ method: "GET",
1497
+ url: getBaseUrl() + "profiles/" + profileId + "/consumers/practice?" + convertToParameters(parameters)
1498
+ };
1499
+ sendData(request, function (err, data) {
1500
+ callCallBack(err, data, callback);
1501
+ });
1502
+ };
1503
+
1504
+
1505
+
1506
+ /**
1507
+ * Get results for Zzish content object
1508
+ * @param profileId - The id of the profile to which to get the content for
1509
+ * @param type - The content type
1510
+ * @param uuid - THe uuid to get
1511
+ * @param callback - A callback to call when done (returns error AND (message or data))
1512
+ */
1513
+ Zzish.getContentResults = function (profileId, type, uuid, callback) {
1514
+ var request = {
1515
+ method: "GET",
1516
+ url: getBaseUrl() + "profiles/" + profileId + "/contents/" + type + "/" + uuid+"/results"
1517
+ };
1518
+ sendData(request, function (err, data) {
1519
+ callCallBack(err, data, callback);
1520
+ });
1521
+ };
1522
+
1523
+ /**
1524
+ * Get results for Zzish public content object
1525
+ * @param type - The content type
1526
+ * @param uuid - THe uuid to get
1527
+ * @param callback - A callback to call when done (returns error AND (message or data))
1528
+ */
1529
+ Zzish.getPublicContentResults = function (type, uuid, callback) {
1530
+ var request = {
1531
+ method: "GET",
1532
+ url: getBaseUrl() + "profiles/publicconsumers/" + type + "/" + uuid+"/results"
1533
+ };
1534
+ sendData(request, function (err, data) {
1535
+ callCallBack(err, data, callback);
1536
+ });
1537
+ };
1538
+
1539
+ /**
1540
+ * Get a Zzish public content object (as a consumer)
1541
+ * @param type - The content type
1542
+ * @param uuid - The Zzish content (JSON)
1543
+ * @param callback - A callback to call when done (returns error AND (message or data))
1544
+ */
1545
+ Zzish.getPublicContent = function (type,uuid, callback) {
1546
+ var request = {
1547
+ method: "GET",
1548
+ url: getBaseUrl() + "profiles/publicconsumers/" + type + "/" + uuid
1549
+ };
1550
+ sendData(request, function (err, data) {
1551
+ callCallBack(err, data, function (status, message) {
1552
+ if (!err) {
1553
+ if (data) {
1554
+ callback(err,formatContentObject(data.payload,true));
1555
+ }
1556
+ else {
1557
+ callback(status, message);
1558
+ }
1559
+ }
1560
+ else {
1561
+ callback(status, message);
1562
+ }
1563
+ });
1564
+ });
1565
+ };
1566
+
1567
+ /**
1568
+ * Get a Zzish content object (as a consumer) by code
1569
+ * @param type - The content type
1570
+ * @param code - The Zzish content code
1571
+ * @param callback - A callback to call when done (returns error AND (message or data))
1572
+ */
1573
+ Zzish.getPublicContentByCode = function (type,code, callback) {
1574
+ var request = {
1575
+ method: "GET",
1576
+ url: getBaseUrl() + "profiles/publicconsumers/" + type + "/code/" + code
1577
+ };
1578
+ sendData(request, function (err, data) {
1579
+ callCallBack(err, data, function (status, message) {
1580
+ if (!err) {
1581
+ callback(err,formatContentObject(data.payload,true));
1582
+ }
1583
+ else {
1584
+ callback(status, message);
1585
+ }
1586
+ });
1587
+ });
1588
+ };
1589
+
1590
+ /**
1591
+ * Get a list of Zzish content object
1592
+ * @param type - The content type
1593
+ * @param callback - A callback to call when done (returns error AND (message or list of zzish,name))
1594
+ */
1595
+ Zzish.listPublicContent = function (type,callback) {
1596
+ var request = {
1597
+ method: "GET",
1598
+ url: getBaseUrl() + "profiles/publicconsumers/" + type
1599
+ };
1600
+ sendData(request, function (err, data) {
1601
+ callCallBack(err, data, function (status, message) {
1602
+ if (!err) {
1603
+ callback(err, formatListCategoryContents(data));
1604
+ }
1605
+ else {
1606
+ callback(status, message);
1607
+ }
1608
+ });
1609
+ });
1610
+ };
1611
+
1612
+ /**
1613
+ * Save a Zzish category object
1614
+ * @param profileId - The id of the profile to which to save the category for
1615
+ * @param category - The category object
1616
+ * @param callback - An optional callback to call when done (returns error,message)
1617
+ */
1618
+ Zzish.postCategory = function (profileId, category, callback) {
1619
+ var request = {
1620
+ method: "POST",
1621
+ url: getBaseUrl() + "profiles/" + profileId + "/categories/",
1622
+ data: category
1623
+ };
1624
+ sendData(request, function (err, data) {
1625
+ callCallBack(err, data, callback);
1626
+ });
1627
+ };
1628
+
1629
+ /**
1630
+ * Delete a Zzish category object
1631
+ * @param profileId - The id of the profile to which to save the category for
1632
+ * @param id - The id of the category
1633
+ * @param callback - An optional callback to call when done (returns error,message)
1634
+ */
1635
+ Zzish.deleteCategory = function (profileId, id, callback) {
1636
+ var request = {
1637
+ method: "DELETE",
1638
+ url: getBaseUrl() + "profiles/" + profileId + "/categories/" + id
1639
+ };
1640
+ sendData(request, function (err, data) {
1641
+ callCallBack(err, data, callback);
1642
+ });
1643
+ };
1644
+
1645
+ /**
1646
+ * Get a list of Zzish category object
1647
+ * @param profileId - The id of the profile to which to get categorys for
1648
+ * @param callback - A callback to call when done (returns error AND (message or list of zzish,name))
1649
+ */
1650
+ Zzish.listCategories = function (profileId, callback) {
1651
+ var request = {
1652
+ method: "GET",
1653
+ url: getBaseUrl() + "profiles/" + profileId + "/categories"
1654
+ };
1655
+ sendData(request, function (err, data) {
1656
+ callCallBack(err, data, callback);
1657
+ });
1658
+ };
1659
+
1660
+ /**** USER STUFF ***/
1661
+
1662
+
1663
+ function loadLoginWithToken(type,params,callback) {
1664
+ sendEvent("LOGIN");
1665
+ var url = webUrl + 'account/applogin?token='+params.token;
1666
+ if (type=="pop") {
1667
+ var win = window.open(url, 'Zzish Login', 'width=800, height=600');
1668
+ var pollTimer = window.setInterval(
1669
+ function() {
1670
+ try {
1671
+ if (win.document.URL.indexOf(webUrl) === -1) {
1672
+ window.clearInterval(pollTimer);
1673
+ win.close();
1674
+ Zzish.getCurrentUser(token,callback);
1675
+ }
1676
+ } catch(e) {
1677
+ }
1678
+ }, 500);
1679
+ }
1680
+ else {
1681
+ window.location.href = url;
1682
+ }
1683
+ }
1684
+
1685
+ /**
1686
+ * Create a Token
1687
+ * @param type - "pop" (default) will do a popup. "redirect" will go to zzish and then come back
1688
+ * @param options - a list of optinos for token
1689
+ * @param callback - A callback to call when done (returns error AND (message or user))
1690
+ */
1691
+ Zzish.createToken = function (type,options,callback) {
1692
+ var token_request = {
1693
+ method: "POST",
1694
+ url: getBaseUrl() + "profiles/tokens",
1695
+ data: { options: options }
1696
+ };
1697
+ //create a token first
1698
+ sendData(token_request, callback);
1699
+ };
1700
+
1701
+ /**
1702
+ * Upate a Token
1703
+ * @param uuid - The uuid of the token
1704
+ * @param options - a list of optinos for token
1705
+ * @param callback - A callback to call when done (returns error AND (message or user))
1706
+ */
1707
+ Zzish.updateToken = function (uuid, options,callback) {
1708
+ var token_request = {
1709
+ method: "POST",
1710
+ url: getBaseUrl() + "profiles/tokens/" + uuid,
1711
+ data: { options: options }
1712
+ };
1713
+ //create a token first
1714
+ sendData(token_request, callback);
1715
+ };
1716
+
1717
+
1718
+
1719
+ /**
1720
+ * Get a Token
1721
+ * @param uuid - The token uuid
1722
+ * @param callback - A callback to call when done (returns error AND (message or user))
1723
+ */
1724
+ Zzish.getToken = function (uuid,callback) {
1725
+ var token_request = {
1726
+ method: "GET",
1727
+ url: getBaseUrl() + "profiles/tokens/" + uuid
1728
+ }
1729
+ //create a token first
1730
+ sendData(token_request, callback);
1731
+ };
1732
+
1733
+
1734
+ /**
1735
+ * Login to Zzish
1736
+ * @param type - "pop" (default) will do a popup. "redirect" will go to zzish and then come back
1737
+ * @param options - a list of optinos for login
1738
+ redirectURL - A URL hosted on the domain you are calling so that it can monitor success (will redirect to this page after succesful login and then close the page)
1739
+ * @param callback - A callback to call when done (returns error AND (message or user))
1740
+ */
1741
+ Zzish.login = function (type,options,callback) {
1742
+ var token_request = {
1743
+ method: "POST",
1744
+ url: getBaseUrl() + "profiles/tokens",
1745
+ data: { options: options }
1746
+ };
1747
+ //create a token first
1748
+ sendData(token_request, function (err, data) {
1749
+ callCallBack(err, data, function(err,token) {
1750
+ options['token']=token;
1751
+ setDataValue("token", token);
1752
+ loadLoginWithToken(type,options,callback);
1753
+ });
1754
+ });
1755
+ };
1756
+
1757
+ Zzish.getCurrentUser = function(token,callback) {
1758
+ sendEvent("LAUNCH");
1759
+ if (token==undefined) {
1760
+ //see if we can get token from query params
1761
+ token = getQueryParams()["token"];
1762
+ }
1763
+ if (token==undefined) {
1764
+ token = getDataValue("token");
1765
+ }
1766
+ if (token !== undefined && token!="Zzish error" && token!="undefined") {
1767
+ var token_request = {
1768
+ method: "GET",
1769
+ url: getBaseUrl() + "profiles/tokens/" + token
1770
+ }
1771
+ //create a token first
1772
+ sendData(token_request, function (err, data) {
1773
+ callCallBack(err, data, function(err,data) {
1774
+ if (data) {
1775
+ data.token = token;
1776
+ }
1777
+ callback(err,data);
1778
+ });
1779
+ });
1780
+ }
1781
+ else {
1782
+ callback();
1783
+ }
1784
+ }
1785
+
1786
+ /**
1787
+ * Logout from Zzish
1788
+ * @param callback - A callback to call when done (returns error AND (message or user))
1789
+ */
1790
+ Zzish.logout = function (token,callback) {
1791
+ var request = {
1792
+ method: "DELETE",
1793
+ url: getBaseUrl() + "profiles/tokens/" + token
1794
+ }
1795
+ removeDataValue("token");
1796
+ sendData(request, function (err, data) {
1797
+ callCallBack(err, data, callback);
1798
+ });
1799
+ }
1800
+
1801
+ /**
1802
+ * Gets a user profile with Zzish meta data
1803
+ *
1804
+ * @param uuid - The profile User Id
1805
+ * @param callback - An optional callback after user profile has been fetched
1806
+ */
1807
+ Zzish.getProfileWithMeta = function (uuid, callback) {
1808
+ var request = {
1809
+ method: "GET",
1810
+ url: getBaseUrl() + "profiles/"+uuid+"/meta",
1811
+ };
1812
+ sendData(request, function (err, data) {
1813
+ callCallBack(err, data, callback);
1814
+ })
1815
+ };
1816
+
1817
+ Zzish.connectToSocket = function(opencallback, errorcallback, messagecallback, msg) {
1818
+
1819
+ var start = function() {
1820
+ connection = new WebSocket('ws://' + socketUrl);
1821
+ connection.onopen = function () {
1822
+ if (connection.readyState === 1) {
1823
+ Zzish.connectedToSocket = true;
1824
+ currentSocketRetry = 0;
1825
+ if (opencallback) {
1826
+ opencallback();
1827
+ connection.send(JSON.stringify(msg));
1828
+ }
1829
+ }
1830
+ };
1831
+
1832
+ connection.onerror = function (error) {
1833
+ if (errorcallback) {
1834
+ errorcallback(error);
1835
+ }
1836
+ };
1837
+
1838
+ // most important part - incoming messages
1839
+ connection.onmessage = function (message) {
1840
+ // try to parse JSON message. Because we know that the server always returns
1841
+ // JSON this should work without any problem but we should make sure that
1842
+ // the massage is not chunked or otherwise damaged.
1843
+ try {
1844
+ messagecallback(message);
1845
+ } catch (e) {
1846
+ errorcallback("Invalid JSON");
1847
+ }
1848
+ };
1849
+ }
1850
+
1851
+ setInterval(function() {
1852
+ if (connection.readyState !== 1) {
1853
+ Zzish.connectedToSocket = false;
1854
+ if (currentSocketRetry < maxSocketRetry) {
1855
+ currentSocketRetry ++;
1856
+ start();
1857
+ }
1858
+ else {
1859
+ errorcallback("Socket disconnected");
1860
+ }
1861
+ }
1862
+ }, 3000);
1863
+
1864
+ start();
1865
+ }
1866
+
1867
+ Zzish.postToSocket = function(message) {
1868
+ if (connection) {
1869
+ connection.send(JSON.stringify(message));
1870
+ }
1871
+ }
1872
+
1873
+ /**** PROXY STUFF TO SEND DATA ***/
1874
+ /*** REQUEST has 3 attributes (method, url and data) ****/
1875
+
1876
+ if (typeof window === 'undefined') {
1877
+ // we running in node so use https://www.npmjs.org/package/xmlhttprequest
1878
+ XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
1879
+ }
1880
+
1881
+
1882
+ var req;
1883
+ var ocallback;
1884
+
1885
+
1886
+ function sendData(request, callback) {
1887
+ if (typeof request.method === 'undefined') {
1888
+ request.method = "POST";
1889
+ }
1890
+ req = new XMLHttpRequest();
1891
+ if(req.addEventListener){
1892
+ req.addEventListener('load', function () {
1893
+ response(this, callback, logEnabled);
1894
+ }, false);
1895
+
1896
+ req.addEventListener('error', function () {
1897
+ error(this, callback, logEnabled);
1898
+ }, false);
1899
+ }else{
1900
+ ocallback = callback;
1901
+ req.onload = outputResult;
1902
+ }
1903
+
1904
+
1905
+ req.open(request.method, request.url, true);
1906
+ req.setRequestHeader(header, headerprefix+appId);
1907
+ req.setRequestHeader('Content-Type', 'application/json');
1908
+ req.send(JSON.stringify(request.data));
1909
+ }
1910
+
1911
+ function outputResult() {
1912
+ if (typeof ocallback === 'function') {
1913
+ var responseText = typeof req.responseText === 'string' ? JSON.parse(req.responseText) : req.responseText;
1914
+ ocallback(null, responseText);
1915
+ }
1916
+ }
1917
+
1918
+ function response(resp, callback, log) {
1919
+ var err = null, res = null;
1920
+ try {
1921
+ if (resp.status >= 200 && resp.status < 300) {
1922
+ res = JSON.parse(resp.responseText);
1923
+ } else {
1924
+ err = JSON.parse(resp.responseText);
1925
+ }
1926
+ } catch (e) {
1927
+ err = resp.responseText;
1928
+ }
1929
+ if (typeof callback === 'function') {
1930
+ callback(err, res);
1931
+ }
1932
+ }
1933
+
1934
+ function error(evt, callback, log) {
1935
+ callback(evt.currentTarget, null);
1936
+ }
1937
+
1938
+ /*** UUID STUFF from zzish.js ***/
1939
+
1940
+
1941
+ var _global = this;
1942
+
1943
+ // Unique ID creation requires a high quality random # generator. We feature
1944
+ // detect to determine the best RNG source, normalizing to a function that
1945
+ // returns 128-bits of randomness, since that's what's usually required
1946
+ var _rng;
1947
+
1948
+ // Node.js crypto-based RNG - http://nodejs.org/docs/v0.6.2/api/crypto.html
1949
+ //
1950
+ // Moderately fast, high quality
1951
+ if (typeof(_global.require) == 'function') {
1952
+ try {
1953
+ var _rb = _global.require('crypto').randomBytes;
1954
+ _rng = _rb && function () {
1955
+ return _rb(16);
1956
+ };
1957
+ } catch (e) {
1958
+ }
1959
+ }
1960
+
1961
+ if (!_rng && _global.crypto && crypto.getRandomValues) {
1962
+ // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
1963
+ //
1964
+ // Moderately fast, high quality
1965
+ var _rnds8 = new Uint8Array(16);
1966
+ _rng = function whatwgRNG() {
1967
+ crypto.getRandomValues(_rnds8);
1968
+ return _rnds8;
1969
+ };
1970
+ }
1971
+
1972
+ if (!_rng) {
1973
+ // Math.random()-based (RNG)
1974
+ //
1975
+ // If all else fails, use Math.random(). It's fast, but is of unspecified
1976
+ // quality.
1977
+ var _rnds = new Array(16);
1978
+ _rng = function () {
1979
+ for (var i = 0, r; i < 16; i++) {
1980
+ if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
1981
+ _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
1982
+ }
1983
+
1984
+ return _rnds;
1985
+ };
1986
+ }
1987
+
1988
+ // Buffer class to use
1989
+ var BufferClass = typeof(_global.Buffer) == 'function' ? _global.Buffer : Array;
1990
+
1991
+ // Maps for number <-> hex string conversion
1992
+ var _byteToHex = [];
1993
+ var _hexToByte = {};
1994
+ for (var i = 0; i < 256; i++) {
1995
+ _byteToHex[i] = (i + 0x100).toString(16).substr(1);
1996
+ _hexToByte[_byteToHex[i]] = i;
1997
+ }
1998
+
1999
+ // **`parse()` - Parse a UUID into it's component bytes**
2000
+ function parse(s, buf, offset) {
2001
+ var i = (buf && offset) || 0, ii = 0;
2002
+
2003
+ buf = buf || [];
2004
+ s.toLowerCase().replace(/[0-9a-f]{2}/g, function (oct) {
2005
+ if (ii < 16) { // Don't overflow!
2006
+ buf[i + ii++] = _hexToByte[oct];
2007
+ }
2008
+ });
2009
+
2010
+ // Zero out remaining bytes if string was short
2011
+ while (ii < 16) {
2012
+ buf[i + ii++] = 0;
2013
+ }
2014
+
2015
+ return buf;
2016
+ }
2017
+
2018
+ // **`unparse()` - Convert UUID byte array (ala parse()) into a string**
2019
+ function unparse(buf, offset) {
2020
+ var i = offset || 0, bth = _byteToHex;
2021
+ return bth[buf[i++]] + bth[buf[i++]] +
2022
+ bth[buf[i++]] + bth[buf[i++]] + '-' +
2023
+ bth[buf[i++]] + bth[buf[i++]] + '-' +
2024
+ bth[buf[i++]] + bth[buf[i++]] + '-' +
2025
+ bth[buf[i++]] + bth[buf[i++]] + '-' +
2026
+ bth[buf[i++]] + bth[buf[i++]] +
2027
+ bth[buf[i++]] + bth[buf[i++]] +
2028
+ bth[buf[i++]] + bth[buf[i++]];
2029
+ }
2030
+
2031
+ // **`v1()` - Generate time-based UUID**
2032
+ //
2033
+ // Inspired by https://github.com/LiosK/UUID.js
2034
+ // and http://docs.python.org/library/zzish.html
2035
+
2036
+ // random #'s we need to init node and clockseq
2037
+ var _seedBytes = _rng();
2038
+
2039
+ // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
2040
+ var _nodeId = [
2041
+ _seedBytes[0] | 0x01,
2042
+ _seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5]
2043
+ ];
2044
+
2045
+ // Per 4.2.2, randomize (14 bit) clockseq
2046
+ var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
2047
+
2048
+ // Previous zzish creation time
2049
+ var _lastMSecs = 0, _lastNSecs = 0;
2050
+
2051
+ // See https://github.com/broofa/node-zzish for API details
2052
+ function v1(options, buf, offset) {
2053
+ var i = buf && offset || 0;
2054
+ var b = buf || [];
2055
+
2056
+ options = options || {};
2057
+
2058
+ var clockseq = options.clockseq != null ? options.clockseq : _clockseq;
2059
+
2060
+ // UUID timestamps are 100 nano-second units since the Gregorian epoch,
2061
+ // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
2062
+ // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
2063
+ // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
2064
+ var msecs = options.msecs != null ? options.msecs : new Date().getTime();
2065
+
2066
+ // Per 4.2.1.2, use count of zzish's generated during the current clock
2067
+ // cycle to simulate higher resolution clock
2068
+ var nsecs = options.nsecs != null ? options.nsecs : _lastNSecs + 1;
2069
+
2070
+ // Time since last zzish creation (in msecs)
2071
+ var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs) / 10000;
2072
+
2073
+ // Per 4.2.1.2, Bump clockseq on clock regression
2074
+ if (dt < 0 && options.clockseq == null) {
2075
+ clockseq = clockseq + 1 & 0x3fff;
2076
+ }
2077
+
2078
+ // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
2079
+ // time interval
2080
+ if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
2081
+ nsecs = 0;
2082
+ }
2083
+
2084
+ // Per 4.2.1.2 Throw error if too many uuids are requested
2085
+ if (nsecs >= 10000) {
2086
+ throw new Error('zzish.v1(): Can\'t create more than 10M uuids/sec');
2087
+ }
2088
+
2089
+ _lastMSecs = msecs;
2090
+ _lastNSecs = nsecs;
2091
+ _clockseq = clockseq;
2092
+
2093
+ // Per 4.1.4 - Convert from unix epoch to Gregorian epoch
2094
+ msecs += 12219292800000;
2095
+
2096
+ // `time_low`
2097
+ var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
2098
+ b[i++] = tl >>> 24 & 0xff;
2099
+ b[i++] = tl >>> 16 & 0xff;
2100
+ b[i++] = tl >>> 8 & 0xff;
2101
+ b[i++] = tl & 0xff;
2102
+
2103
+ // `time_mid`
2104
+ var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
2105
+ b[i++] = tmh >>> 8 & 0xff;
2106
+ b[i++] = tmh & 0xff;
2107
+
2108
+ // `time_high_and_version`
2109
+ b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
2110
+ b[i++] = tmh >>> 16 & 0xff;
2111
+
2112
+ // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
2113
+ b[i++] = clockseq >>> 8 | 0x80;
2114
+
2115
+ // `clock_seq_low`
2116
+ b[i++] = clockseq & 0xff;
2117
+
2118
+ // `node`
2119
+ var node = options.node || _nodeId;
2120
+ for (var n = 0; n < 6; n++) {
2121
+ b[i + n] = node[n];
2122
+ }
2123
+
2124
+ return buf ? buf : unparse(b);
2125
+ }
2126
+
2127
+ // **`v4()` - Generate random UUID**
2128
+
2129
+ // See https://github.com/broofa/node-zzish for API details
2130
+ function v4(options, buf, offset) {
2131
+ // Deprecated - 'format' argument, as supported in v1.2
2132
+ var i = buf && offset || 0;
2133
+
2134
+ if (typeof(options) == 'string') {
2135
+ buf = options == 'binary' ? new BufferClass(16) : null;
2136
+ options = null;
2137
+ }
2138
+ options = options || {};
2139
+
2140
+ var rnds = options.random || (options.rng || _rng)();
2141
+
2142
+ // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
2143
+ rnds[6] = (rnds[6] & 0x0f) | 0x40;
2144
+ rnds[8] = (rnds[8] & 0x3f) | 0x80;
2145
+
2146
+ // Copy bytes to buffer, if provided
2147
+ if (buf) {
2148
+ for (var ii = 0; ii < 16; ii++) {
2149
+ buf[i + ii] = rnds[ii];
2150
+ }
2151
+ }
2152
+
2153
+ return buf || unparse(rnds);
2154
+ }
2155
+
2156
+ function isObject(obj) {
2157
+ return Object.prototype.toString.call(obj) === "[object Object]";
2158
+ }
2159
+
2160
+ // Export public API
2161
+
2162
+
2163
+ var zzish = Zzish;
2164
+
2165
+ if (typeof define === 'function' && define.amd) {
2166
+ // Publish as AMD module
2167
+ define(function () {
2168
+ return zzish;
2169
+ });
2170
+ } else if (typeof(module) != 'undefined' && module.exports) {
2171
+ // Publish as node.js module
2172
+ module.exports = zzish;
2173
+ } else {
2174
+ // Publish as global (in browsers)
2175
+ var _previousRoot = _global.uuid;
2176
+
2177
+ // **`noConflict()` - (browser only) to reset global 'zzish' var**
2178
+ zzish.noConflict = function () {
2179
+ _global.zzish = _previousRoot;
2180
+ return zzish;
2181
+ };
2182
+
2183
+ _global.zzish = zzish;
2184
+ }
2185
+
2186
+ })();