pxt-core 10.0.21 → 10.0.23

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.
Files changed (45) hide show
  1. package/built/pxt.js +12 -42
  2. package/built/pxtcompiler.d.ts +0 -1
  3. package/built/pxtcompiler.js +12 -42
  4. package/built/react-common/components/controls/Accordion/Accordion.d.ts +4 -0
  5. package/built/react-common/components/controls/Accordion/context.d.ts +11 -6
  6. package/built/react-common/components/util.d.ts +1 -0
  7. package/built/target.js +1 -1
  8. package/built/web/main.js +1 -1
  9. package/built/web/multiplayer/js/{main.0e73ac24.js → main.121cfaf0.js} +2 -2
  10. package/built/web/pxtasseteditor.js +1 -1
  11. package/built/web/pxtcompiler.js +1 -1
  12. package/built/web/pxtembed.js +1 -1
  13. package/built/web/pxtweb.js +1 -1
  14. package/built/web/pxtworker.js +1 -1
  15. package/built/web/react-common-authcode.css +1 -1
  16. package/built/web/react-common-multiplayer.css +1 -1
  17. package/built/web/react-common-skillmap.css +1 -1
  18. package/built/web/rtlreact-common-authcode.css +1 -1
  19. package/built/web/rtlreact-common-multiplayer.css +1 -1
  20. package/built/web/rtlreact-common-skillmap.css +1 -1
  21. package/built/web/rtlsemantic.css +1 -1
  22. package/built/web/semantic.css +1 -1
  23. package/built/web/skillmap/js/{main.f7e01730.js → main.e95746dc.js} +2 -2
  24. package/built/web/teachertool/css/main.00de32e9.css +1 -0
  25. package/built/web/teachertool/js/{main.dc513d1e.js → main.b94a6d6a.js} +2 -2
  26. package/built/web/tutorialtool/js/{main.c3bf42cf.js → main.03b71032.js} +2 -2
  27. package/common-docs/teachertool/catalog-shared.json +5 -0
  28. package/common-docs/teachertool/test/catalog-shared.json +1 -0
  29. package/docfiles/pxtweb/cookieCompliance.ts +15 -0
  30. package/package.json +1 -1
  31. package/react-common/components/controls/Accordion/Accordion.tsx +16 -7
  32. package/react-common/components/controls/Accordion/context.tsx +23 -16
  33. package/react-common/components/controls/EditorToggle.tsx +5 -1
  34. package/react-common/components/controls/FocusList.tsx +7 -38
  35. package/react-common/components/controls/FocusTrap.tsx +7 -7
  36. package/react-common/components/share/ShareInfo.tsx +8 -5
  37. package/react-common/components/util.tsx +21 -0
  38. package/react-common/styles/controls/Modal.less +3 -1
  39. package/react-common/styles/react-common-variables.less +1 -1
  40. package/react-common/styles/share/share.less +7 -0
  41. package/webapp/public/multiplayer.html +1 -1
  42. package/webapp/public/skillmap.html +1 -1
  43. package/webapp/public/teachertool.html +1 -1
  44. package/webapp/public/tutorialtool.html +1 -1
  45. package/built/web/teachertool/css/main.7ff56db5.css +0 -1
@@ -6,6 +6,7 @@
6
6
  "template": "${Block} used ${count} times",
7
7
  "description": "This block was used the specified number of times in your project.",
8
8
  "docPath": "/teachertool",
9
+ "tags": ["General"],
9
10
  "params": [
10
11
  {
11
12
  "name": "block",
@@ -27,6 +28,7 @@
27
28
  "description": "The project contains at least the specified number of comments.",
28
29
  "docPath": "/teachertool",
29
30
  "maxCount": 1,
31
+ "tags": ["General"],
30
32
  "params": [
31
33
  {
32
34
  "name": "count",
@@ -43,6 +45,7 @@
43
45
  "docPath": "/teachertool",
44
46
  "description": "The program uses at least this many loops of any kind (for, repeat, while, or for-of).",
45
47
  "maxCount": 1,
48
+ "tags": ["Code Elements"],
46
49
  "params": [
47
50
  {
48
51
  "name": "count",
@@ -59,6 +62,7 @@
59
62
  "docPath": "/teachertool",
60
63
  "description": "At least this many user-defined functions are created and called.",
61
64
  "maxCount": 1,
65
+ "tags": ["Code Elements"],
62
66
  "params": [
63
67
  {
64
68
  "name": "count",
@@ -75,6 +79,7 @@
75
79
  "docPath": "/teachertool",
76
80
  "description": "The program creates and uses at least this many user-defined variables.",
77
81
  "maxCount": 1,
82
+ "tags": ["Code Elements"],
78
83
  "params": [
79
84
  {
80
85
  "name": "count",
@@ -7,6 +7,7 @@
7
7
  "description": "Experimental: AI outputs may not be accurate. Use with caution and always review responses.",
8
8
  "docPath": "/teachertool",
9
9
  "maxCount": 10,
10
+ "tags": ["General"],
10
11
  "params": [
11
12
  {
12
13
  "name": "question",
@@ -9,6 +9,7 @@ namespace pxt {
9
9
  let analyticsLoaded = false;
10
10
  let interactiveConsent = false;
11
11
  let isProduction = false;
12
+ let partnerName: string;
12
13
 
13
14
  class TelemetryQueue<A, B, C> {
14
15
  private q: [A, B, C][] = [];
@@ -185,6 +186,16 @@ namespace pxt {
185
186
  }
186
187
 
187
188
  export function initializeAppInsightsInternal(includeCookie = false) {
189
+ try {
190
+ const params = new URLSearchParams(window.location.search);
191
+ if (params.has("partner")) {
192
+ partnerName = params.get("partner");
193
+ }
194
+ }
195
+ catch (e) {
196
+ console.warn("Could not parse search string", e);
197
+ }
198
+
188
199
  // loadAppInsights is defined in docfiles/tracking.html
189
200
  const loadAI = (window as any).loadAppInsights;
190
201
  if (loadAI) {
@@ -221,6 +232,10 @@ namespace pxt {
221
232
  telemetryItem.properties["target"] = pxtConfig.targetId;
222
233
  telemetryItem.properties["stage"] = (pxtConfig.relprefix || "/--").replace(/[^a-z]/ig, '')
223
234
 
235
+ if (partnerName) {
236
+ telemetryItem.properties["partner"] = partnerName;
237
+ }
238
+
224
239
  const userAgent = navigator.userAgent.toLowerCase();
225
240
  const electronRegexResult = /\belectron\/(\d+\.\d+\.\d+.*?)(?: |$)/i.exec(userAgent); // Example navigator.userAgent: "Mozilla/5.0 Chrome/61.0.3163.100 Electron/2.0.0 Safari/537.36"
226
241
  if (electronRegexResult) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pxt-core",
3
- "version": "10.0.21",
3
+ "version": "10.0.23",
4
4
  "description": "Microsoft MakeCode provides Blocks / JavaScript / Python tools and editors",
5
5
  "keywords": [
6
6
  "TypeScript",
@@ -1,15 +1,19 @@
1
1
  import * as React from "react";
2
2
  import { ContainerProps, classList, fireClickOnEnter } from "../../util";
3
3
  import { useId } from "../../../hooks/useId";
4
- import { AccordionProvider, clearExpanded, setExpanded, useAccordionDispatch, useAccordionState } from "./context";
4
+ import { AccordionProvider, removeExpanded, setExpanded, useAccordionDispatch, useAccordionState } from "./context";
5
5
 
6
6
  export interface AccordionProps extends ContainerProps {
7
+ multiExpand?: boolean;
8
+ defaultExpandedIds?: string[];
7
9
  children?: React.ReactElement<AccordionItemProps>[] | React.ReactElement<AccordionItemProps>;
8
10
  }
9
11
 
10
12
  export interface AccordionItemProps extends ContainerProps {
11
13
  children?: [React.ReactElement<AccordionHeaderProps>, React.ReactElement<AccordionPanelProps>];
12
14
  noChevron?: boolean;
15
+ itemId?: string;
16
+ onExpandToggled?: (expanded: boolean) => void;
13
17
  }
14
18
 
15
19
  export interface AccordionHeaderProps extends ContainerProps {
@@ -27,10 +31,12 @@ export const Accordion = (props: AccordionProps) => {
27
31
  ariaHidden,
28
32
  ariaDescribedBy,
29
33
  role,
34
+ multiExpand,
35
+ defaultExpandedIds
30
36
  } = props;
31
37
 
32
38
  return (
33
- <AccordionProvider>
39
+ <AccordionProvider multiExpand={multiExpand} defaultExpandedIds={defaultExpandedIds}>
34
40
  <div
35
41
  className={classList("common-accordion", className)}
36
42
  id={id}
@@ -54,23 +60,26 @@ export const AccordionItem = (props: AccordionItemProps) => {
54
60
  ariaHidden,
55
61
  ariaDescribedBy,
56
62
  role,
57
- noChevron
63
+ noChevron,
64
+ itemId,
65
+ onExpandToggled,
58
66
  } = props;
59
67
 
60
68
  const { expanded } = useAccordionState();
61
69
  const dispatch = useAccordionDispatch();
62
70
 
63
- const panelId = useId();
71
+ const panelId = itemId ?? useId();
64
72
  const mappedChildren = React.Children.toArray(children);
65
- const isExpanded = expanded === panelId;
73
+ const isExpanded = expanded.indexOf(panelId) !== -1;
66
74
 
67
75
  const onHeaderClick = React.useCallback(() => {
68
76
  if (isExpanded) {
69
- dispatch(clearExpanded());
77
+ dispatch(removeExpanded(panelId));
70
78
  }
71
79
  else {
72
80
  dispatch(setExpanded(panelId));
73
81
  }
82
+ onExpandToggled?.(!isExpanded);
74
83
  }, [isExpanded]);
75
84
 
76
85
  return (
@@ -150,4 +159,4 @@ export const AccordionPanel = (props: AccordionPanelProps) => {
150
159
  {children}
151
160
  </div>
152
161
  );
153
- }
162
+ }
@@ -1,17 +1,22 @@
1
1
  import * as React from "react";
2
2
 
3
3
  interface AccordionState {
4
- expanded?: string;
4
+ multiExpand?: boolean;
5
+ expanded: string[];
5
6
  }
6
7
 
7
8
  const AccordionStateContext = React.createContext<AccordionState>(null);
8
9
  const AccordionDispatchContext = React.createContext<(action: Action) => void>(null);
9
10
 
10
- export const AccordionProvider = ({ children }: React.PropsWithChildren<{}>) => {
11
- const [state, dispatch] = React.useReducer(
12
- accordionReducer,
13
- {}
14
- );
11
+ export const AccordionProvider = ({
12
+ multiExpand,
13
+ defaultExpandedIds,
14
+ children,
15
+ }: React.PropsWithChildren<{ multiExpand?: boolean; defaultExpandedIds?: string[] }>) => {
16
+ const [state, dispatch] = React.useReducer(accordionReducer, {
17
+ expanded: defaultExpandedIds ?? [],
18
+ multiExpand,
19
+ });
15
20
 
16
21
  return (
17
22
  <AccordionStateContext.Provider value={state}>
@@ -27,11 +32,12 @@ type SetExpanded = {
27
32
  id: string;
28
33
  };
29
34
 
30
- type ClearExpanded = {
31
- type: "CLEAR_EXPANDED";
35
+ type RemoveExpanded = {
36
+ type: "REMOVE_EXPANDED";
37
+ id: string;
32
38
  };
33
39
 
34
- type Action = SetExpanded | ClearExpanded;
40
+ type Action = SetExpanded | RemoveExpanded;
35
41
 
36
42
  export const setExpanded = (id: string): SetExpanded => (
37
43
  {
@@ -40,14 +46,15 @@ export const setExpanded = (id: string): SetExpanded => (
40
46
  }
41
47
  );
42
48
 
43
- export const clearExpanded = (): ClearExpanded => (
49
+ export const removeExpanded = (id: string): RemoveExpanded => (
44
50
  {
45
- type: "CLEAR_EXPANDED"
51
+ type: "REMOVE_EXPANDED",
52
+ id
46
53
  }
47
54
  );
48
55
 
49
56
  export function useAccordionState() {
50
- return React.useContext(AccordionStateContext)
57
+ return React.useContext(AccordionStateContext);
51
58
  }
52
59
 
53
60
  export function useAccordionDispatch() {
@@ -59,12 +66,12 @@ function accordionReducer(state: AccordionState, action: Action): AccordionState
59
66
  case "SET_EXPANDED":
60
67
  return {
61
68
  ...state,
62
- expanded: action.id
69
+ expanded: state.multiExpand ? [...state.expanded, action.id] : [action.id],
63
70
  };
64
- case "CLEAR_EXPANDED":
71
+ case "REMOVE_EXPANDED":
65
72
  return {
66
73
  ...state,
67
- expanded: undefined
74
+ expanded: state.expanded.filter((id) => id !== action.id),
68
75
  };
69
76
  }
70
- }
77
+ }
@@ -125,7 +125,11 @@ const EditorToggleAccessibleMenu = (props: EditorToggleProps) => {
125
125
  next.push({...current});
126
126
 
127
127
  // The selected item will always be a top-level option, not in a dropdown
128
- if (selected === index) next[next.length - 1].selected = true;
128
+ if (selected === index) {
129
+ next[next.length - 1].selected = true;
130
+ } else {
131
+ next[next.length - 1].selected = false;
132
+ }
129
133
 
130
134
  if (isDropdownItem(current)) {
131
135
  next.push(...current.items.filter(i => i.focusable))
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { ContainerProps } from "../util";
2
+ import { ContainerProps, findNextFocusableElement } from "../util";
3
3
 
4
4
  export interface FocusListProps extends ContainerProps {
5
5
  role: string;
@@ -62,37 +62,6 @@ export const FocusList = (props: FocusListProps) => {
62
62
  && getComputedStyle(e).display !== "none";
63
63
  }
64
64
 
65
- const firstFocusableElement = () => {
66
- return focusableElements.find(e => isFocusable(e))
67
- }
68
-
69
- const lastFocusableElement = () => {
70
- for (let i = 0; i < focusableElements.length; i++) {
71
- if (isFocusable(focusableElements[focusableElements.length - 1 - i])) {
72
- return focusableElements[focusableElements.length - 1 - i];
73
- }
74
- }
75
-
76
- return focusableElements[0];
77
- }
78
-
79
- const nextFocusableElement = (index: number, forwards: boolean) => {
80
- let current: HTMLElement
81
- for (let i = 1; i < focusableElements.length; i++) {
82
- if (forwards) {
83
- current = focusableElements[(index + i) % focusableElements.length];
84
- }
85
- else {
86
- current = focusableElements[(index + focusableElements.length - i) % focusableElements.length];
87
- }
88
-
89
- if (isFocusable(current)) {
90
- return current;
91
- }
92
- }
93
- return focusableElements[0];
94
- }
95
-
96
65
  const onKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {
97
66
  if (!focusableElements?.length) return;
98
67
 
@@ -120,31 +89,31 @@ export const FocusList = (props: FocusListProps) => {
120
89
  }
121
90
  else if (e.key === (useUpAndDownArrowKeys ? "ArrowDown" : "ArrowRight")) {
122
91
  if (index === focusableElements.length - 1 || target === focusList) {
123
- focus(firstFocusableElement());
92
+ focus(findNextFocusableElement(focusableElements, index, 0, true, isFocusable));
124
93
  }
125
94
  else {
126
- focus(nextFocusableElement(index, true));
95
+ focus(findNextFocusableElement(focusableElements, index, index + 1, true, isFocusable));
127
96
  }
128
97
  e.preventDefault();
129
98
  e.stopPropagation();
130
99
  }
131
100
  else if (e.key === (useUpAndDownArrowKeys ? "ArrowUp" : "ArrowLeft")) {
132
101
  if (index === 0 || target === focusList) {
133
- focus(lastFocusableElement());
102
+ focus(findNextFocusableElement(focusableElements, index, focusableElements.length - 1, false, isFocusable));
134
103
  }
135
104
  else {
136
- focus(nextFocusableElement(index, false));
105
+ focus(findNextFocusableElement(focusableElements, index, index - 1, false, isFocusable));
137
106
  }
138
107
  e.preventDefault();
139
108
  e.stopPropagation();
140
109
  }
141
110
  else if (e.key === "Home") {
142
- focus(firstFocusableElement());
111
+ focus(findNextFocusableElement(focusableElements, index, 0, true, isFocusable));
143
112
  e.preventDefault();
144
113
  e.stopPropagation();
145
114
  }
146
115
  else if (e.key === "End") {
147
- focus(lastFocusableElement());
116
+ focus(findNextFocusableElement(focusableElements, index, focusableElements.length - 1, true, isFocusable));
148
117
  e.preventDefault();
149
118
  e.stopPropagation();
150
119
  }
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { classList, nodeListToArray } from "../util";
2
+ import { classList, nodeListToArray, findNextFocusableElement } from "../util";
3
3
 
4
4
  export interface FocusTrapProps extends React.PropsWithChildren<{}> {
5
5
  onEscape: () => void;
@@ -58,24 +58,24 @@ export const FocusTrap = (props: FocusTrapProps) => {
58
58
 
59
59
  if (forward) {
60
60
  if (goToEnd) {
61
- focusable[focusable.length - 1].focus();
61
+ findNextFocusableElement(focusable, index, focusable.length - 1, forward).focus();
62
62
  }
63
63
  else if (index === focusable.length - 1) {
64
- focusable[0].focus();
64
+ findNextFocusableElement(focusable, index, 0, forward).focus();
65
65
  }
66
66
  else {
67
- focusable[index + 1].focus();
67
+ findNextFocusableElement(focusable, index, index + 1, forward).focus();
68
68
  }
69
69
  }
70
70
  else {
71
71
  if (goToEnd) {
72
- focusable[0].focus();
72
+ findNextFocusableElement(focusable, index, 0, forward).focus();
73
73
  }
74
74
  else if (index === 0) {
75
- focusable[focusable.length - 1].focus();
75
+ findNextFocusableElement(focusable, index, focusable.length - 1, forward).focus();
76
76
  }
77
77
  else {
78
- focusable[Math.max(index - 1, 0)].focus();
78
+ findNextFocusableElement(focusable, index, Math.max(index - 1, 0), forward).focus();
79
79
  }
80
80
  }
81
81
 
@@ -32,6 +32,7 @@ export interface ShareInfoProps {
32
32
  onClose: () => void;
33
33
  }
34
34
 
35
+
35
36
  export const ShareInfo = (props: ShareInfoProps) => {
36
37
  const {
37
38
  projectName,
@@ -323,7 +324,7 @@ export const ShareInfo = (props: ShareInfoProps) => {
323
324
  {showSimulator && shareState !== "gifrecord" &&
324
325
  <div className="project-share-thumbnail">
325
326
  {thumbnailUri
326
- ? <img src={thumbnailUri} />
327
+ ? <img src={thumbnailUri} alt={lf("Preview of your code running on the simulator")} aria-label={lf("Simulator preview")}/>
327
328
  : <div className="project-thumbnail-placeholder">
328
329
  <div className="common-spinner" />
329
330
  </div>
@@ -406,6 +407,7 @@ export const ShareInfo = (props: ShareInfoProps) => {
406
407
  <div className="common-input-attached-button">
407
408
  <Input
408
409
  ariaDescribedBy="share-input-title"
410
+ ariaLabel={lf("Your shareable project link")}
409
411
  handleInputRef={handleInputRef}
410
412
  initialValue={shareData.url}
411
413
  readOnly={true}
@@ -462,7 +464,7 @@ export const ShareInfo = (props: ShareInfoProps) => {
462
464
  className="menu-button project-qrcode"
463
465
  buttonRef={handleQRCodeButtonRef}
464
466
  title={lf("Show QR Code")}
465
- label={<img className="qrcode-image" src={shareData?.qr} />}
467
+ label={<img className="qrcode-image" src={shareData?.qr} alt={lf("QR code to access your project")} aria-label={lf("Project share link QR code")}/>}
466
468
  onClick={handleQRCodeClick}
467
469
  />
468
470
  </div>
@@ -475,7 +477,8 @@ export const ShareInfo = (props: ShareInfoProps) => {
475
477
  selected={embedOptions.findIndex(i => i.name === embedState)} />
476
478
  <Textarea readOnly={true}
477
479
  rows={5}
478
- initialValue={shareData?.embed[embedState]} />
480
+ initialValue={shareData?.embed[embedState]}
481
+ ariaLabel={lf("Embed code textarea")} />
479
482
  </div>}
480
483
  {kioskState &&
481
484
  <div>
@@ -511,9 +514,9 @@ export const ShareInfo = (props: ShareInfoProps) => {
511
514
  </div>
512
515
 
513
516
  {showQRCode &&
514
- <Modal title={lf("QR Code")} onClose={handleQRCodeModalClose}>
517
+ <Modal title={lf("QR Code")} onClose={handleQRCodeModalClose} ariaLabel={lf("QR Code modal")} >
515
518
  <div className="qrcode-modal-body">
516
- <img className="qrcode-image" src={shareData?.qr} />
519
+ <img className="qrcode-image" src={shareData?.qr} alt={lf("QR code to access your project")} aria-label={lf("Project share link QR code enlarged")} />
517
520
  </div>
518
521
  </Modal>
519
522
  }
@@ -91,4 +91,25 @@ export function screenToSVGCoord(ref: SVGSVGElement, coord: ClientCoordinates) {
91
91
  screenCoord.x = coord.clientX;
92
92
  screenCoord.y = coord.clientY;
93
93
  return screenCoord.matrixTransform(ref.getScreenCTM().inverse());
94
+ }
95
+
96
+ export function findNextFocusableElement(elements: HTMLElement[], focusedIndex: number, index: number, forward: boolean, isFocusable?: (e: HTMLElement) => boolean): HTMLElement {
97
+ const increment = forward ? 1 : -1;
98
+ const element = elements[index];
99
+ // in this case, there are no focusable elements
100
+ if (focusedIndex === index) {
101
+ return element;
102
+ }
103
+ if (isFocusable ? isFocusable(element) : getComputedStyle(element).display !== "none") {
104
+ return element;
105
+ } else {
106
+ if (index + increment >= elements.length) {
107
+ index = 0;
108
+ } else if (index + increment < 0) {
109
+ index = elements.length - 1;
110
+ } else {
111
+ index += increment;
112
+ }
113
+ }
114
+ return findNextFocusableElement(elements, focusedIndex, index, forward);
94
115
  }
@@ -20,8 +20,10 @@
20
20
  .common-modal {
21
21
  width: 50%;
22
22
  max-width: 40rem;
23
+ max-height: 100%;
23
24
  border-radius: .285rem;
24
- overflow: hidden;
25
+ overflow-x: hidden;
26
+ overflow-y: auto;
25
27
  }
26
28
 
27
29
  .wide > .common-modal {
@@ -105,7 +105,7 @@
105
105
  * EditorToggle *
106
106
  ****************************************************/
107
107
 
108
- @editorToggleBackgroundColor: rgba(52,73,94,.4);
108
+ @editorToggleBackgroundColor: rgba(52,73,94,.8);
109
109
  @editorToggleBorderColor: rgba(52,73,94,.2);
110
110
  @editorToggleBorderWidth: 3px;
111
111
 
@@ -150,6 +150,7 @@
150
150
  margin-top: 1rem;
151
151
  position: relative;
152
152
  margin-bottom: 2rem;
153
+ justify-content: space-between;
153
154
  }
154
155
 
155
156
  .project-share-social {
@@ -312,6 +313,12 @@
312
313
  .gif-recorder-content .thumbnail-controls {
313
314
  padding: 0 2rem;
314
315
  }
316
+
317
+ .common-button.square-button.embed.gray.mobile-portrait-hidden {
318
+ // important is need for color to override semantic ui's use of important
319
+ color: #323130 !important;
320
+ background: #e0e1e2;
321
+ }
315
322
  }
316
323
 
317
324
  @media @mobileAndBelow {
@@ -9,7 +9,7 @@
9
9
  <link rel="stylesheet" data-rtl="/blb/rtlsemantic.css" href="/blb/semantic.css">
10
10
  <link rel="stylesheet" href="/blb/icons.css">
11
11
  <link rel="stylesheet" href="/blb/react-common-multiplayer.css">
12
- <script defer="defer" src="/blb/multiplayer/js/main.0e73ac24.js"></script><link href="/blb/multiplayer/css/main.2a6ba47d.css" rel="stylesheet"></head>
12
+ <script defer="defer" src="/blb/multiplayer/js/main.121cfaf0.js"></script><link href="/blb/multiplayer/css/main.2a6ba47d.css" rel="stylesheet"></head>
13
13
  <body>
14
14
  <noscript>You need to enable JavaScript to run this app.</noscript>
15
15
 
@@ -7,7 +7,7 @@
7
7
  <link rel="stylesheet" data-rtl="/blb/rtlsemantic.css" href="/blb/semantic.css">
8
8
  <link rel="stylesheet" href="/blb/icons.css">
9
9
  <link rel="stylesheet" href="/blb/react-common-skillmap.css">
10
- <script defer="defer" src="/blb/skillmap/js/main.f7e01730.js"></script><link href="/blb/skillmap/css/main.3c703680.css" rel="stylesheet"></head>
10
+ <script defer="defer" src="/blb/skillmap/js/main.e95746dc.js"></script><link href="/blb/skillmap/css/main.3c703680.css" rel="stylesheet"></head>
11
11
  <body>
12
12
  <noscript>You need to enable JavaScript to run this app.</noscript>
13
13
 
@@ -16,7 +16,7 @@
16
16
  <!-- <link rel="manifest" href="/teachertool-data/manifest.json" /> -->
17
17
  <title>MakeCode Teacher Tool</title>
18
18
  <script>var pxtConfig=null</script>
19
- <script defer="defer" src="/blb/teachertool/js/main.dc513d1e.js"></script><link href="/blb/teachertool/css/main.7ff56db5.css" rel="stylesheet"></head>
19
+ <script defer="defer" src="/blb/teachertool/js/main.b94a6d6a.js"></script><link href="/blb/teachertool/css/main.00de32e9.css" rel="stylesheet"></head>
20
20
  <body>
21
21
  <noscript>You need to enable JavaScript to run this app.</noscript>
22
22
 
@@ -17,7 +17,7 @@
17
17
  <!-- <link rel="manifest" href="/tutorialtool-data/manifest.json" /> -->
18
18
  <title>MakeCode Tutorial Tool</title>
19
19
  <script>var pxtConfig=null</script>
20
- <script defer="defer" src="/blb/tutorialtool/js/main.c3bf42cf.js"></script><link href="/blb/tutorialtool/css/main.02bb1797.css" rel="stylesheet"></head>
20
+ <script defer="defer" src="/blb/tutorialtool/js/main.03b71032.js"></script><link href="/blb/tutorialtool/css/main.02bb1797.css" rel="stylesheet"></head>
21
21
 
22
22
  <body>
23
23
  <noscript>You need to enable JavaScript to run this app.</noscript>