From 2b79008596351f6948d8de80c7887446d97b068c Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Fri, 15 May 2020 00:03:41 -0700
Subject: renamed new_fields to fields

---
 src/client/views/animationtimeline/Keyframe.tsx | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

(limited to 'src/client/views/animationtimeline/Keyframe.tsx')

diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx
index bbd7b2676..92b0f05b3 100644
--- a/src/client/views/animationtimeline/Keyframe.tsx
+++ b/src/client/views/animationtimeline/Keyframe.tsx
@@ -4,10 +4,10 @@ import "./Timeline.scss";
 import "../globalCssVariables.scss";
 import { observer } from "mobx-react";
 import { observable, reaction, action, IReactionDisposer, observe, computed, runInAction, trace } from "mobx";
-import { Doc, DocListCast, DocListCastAsync, Opt } from "../../../new_fields/Doc";
-import { Cast, NumCast } from "../../../new_fields/Types";
-import { List } from "../../../new_fields/List";
-import { createSchema, defaultSpec, makeInterface, listSpec } from "../../../new_fields/Schema";
+import { Doc, DocListCast, DocListCastAsync, Opt } from "../../../fields/Doc";
+import { Cast, NumCast } from "../../../fields/Types";
+import { List } from "../../../fields/List";
+import { createSchema, defaultSpec, makeInterface, listSpec } from "../../../fields/Schema";
 import { Transform } from "../../util/Transform";
 import { TimelineMenu } from "./TimelineMenu";
 import { Docs } from "../../documents/Documents";
-- 
cgit v1.2.3-70-g09d2


From e23602188d575c3f2303bfc85114ac82561c7bbe Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 29 May 2020 13:14:59 -0400
Subject: added toggle to switch from fade to default keyframe. added
 mixBlendMode for collections

---
 src/client/views/animationtimeline/Keyframe.tsx    | 60 +++++++++-------------
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  1 +
 2 files changed, 26 insertions(+), 35 deletions(-)

(limited to 'src/client/views/animationtimeline/Keyframe.tsx')

diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx
index 92b0f05b3..e3274fb35 100644
--- a/src/client/views/animationtimeline/Keyframe.tsx
+++ b/src/client/views/animationtimeline/Keyframe.tsx
@@ -12,11 +12,9 @@ import { Transform } from "../../util/Transform";
 import { TimelineMenu } from "./TimelineMenu";
 import { Docs } from "../../documents/Documents";
 import { CollectionDockingView } from "../collections/CollectionDockingView";
-import { undoBatch, UndoManager } from "../../util/UndoManager";
 import { emptyPath } from "../../../Utils";
 
 
-
 /**
  * Useful static functions that you can use. Mostly for logic, but you can also add UI logic here also 
  */
@@ -100,16 +98,11 @@ export namespace KeyframeFunc {
     export const convertPixelTime = (pos: number, unit: "mili" | "sec" | "min" | "hr", dir: "pixel" | "time", tickSpacing: number, tickIncrement: number) => {
         const time = dir === "pixel" ? (pos * tickSpacing) / tickIncrement : (pos / tickSpacing) * tickIncrement;
         switch (unit) {
-            case "mili":
-                return time;
-            case "sec":
-                return dir === "pixel" ? time / 1000 : time * 1000;
-            case "min":
-                return dir === "pixel" ? time / 60000 : time * 60000;
-            case "hr":
-                return dir === "pixel" ? time / 3600000 : time * 3600000;
-            default:
-                return time;
+            case "mili": return time;
+            case "sec": return dir === "pixel" ? time / 1000 : time * 1000;
+            case "min": return dir === "pixel" ? time / 60000 : time * 60000;
+            case "hr": return dir === "pixel" ? time / 3600000 : time * 3600000;
+            default: return time;
         }
     };
 }
@@ -333,31 +326,28 @@ export class Keyframe extends React.Component<IProps> {
      */
     @action
     makeKeyframeMenu = (kf: Doc, e: MouseEvent) => {
-        TimelineMenu.Instance.addItem("button", "Show Data", () => {
-            runInAction(() => {
+        TimelineMenu.Instance.addItem("button", "Toggle Fade Only", () => {
+            kf.type = kf.type === KeyframeFunc.KeyframeType.fade ? KeyframeFunc.KeyframeType.default : KeyframeFunc.KeyframeType.fade;
+        }),
+            TimelineMenu.Instance.addItem("button", "Show Data", action(() => {
                 const kvp = Docs.Create.KVPDocument(kf, { _width: 300, _height: 300 });
                 CollectionDockingView.AddRightSplit(kvp, emptyPath);
-            });
-        }),
-            TimelineMenu.Instance.addItem("button", "Delete", () => {
-                runInAction(() => {
-                    (this.regiondata.keyframes as List<Doc>).splice(this.keyframes.indexOf(kf), 1);
-                    this.forceUpdate();
-                });
-            }),
-            TimelineMenu.Instance.addItem("input", "Move", (val) => {
-                runInAction(() => {
-                    let cannotMove: boolean = false;
-                    const kfIndex: number = this.keyframes.indexOf(kf);
-                    if (val < 0 || (val < NumCast(this.keyframes[kfIndex - 1].time) || val > NumCast(this.keyframes[kfIndex + 1].time))) {
-                        cannotMove = true;
-                    }
-                    if (!cannotMove) {
-                        this.keyframes[kfIndex].time = parseInt(val, 10);
-                        this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn;
-                    }
-                });
-            });
+            })),
+            TimelineMenu.Instance.addItem("button", "Delete", action(() => {
+                (this.regiondata.keyframes as List<Doc>).splice(this.keyframes.indexOf(kf), 1);
+                this.forceUpdate();
+            })),
+            TimelineMenu.Instance.addItem("input", "Move", action((val) => {
+                let cannotMove: boolean = false;
+                const kfIndex: number = this.keyframes.indexOf(kf);
+                if (val < 0 || (val < NumCast(this.keyframes[kfIndex - 1].time) || val > NumCast(this.keyframes[kfIndex + 1].time))) {
+                    cannotMove = true;
+                }
+                if (!cannotMove) {
+                    this.keyframes[kfIndex].time = parseInt(val, 10);
+                    this.keyframes[1].time = this.regiondata.position + this.regiondata.fadeIn;
+                }
+            }));
         TimelineMenu.Instance.addMenu("Keyframe");
         TimelineMenu.Instance.openMenu(e.clientX, e.clientY);
     }
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 697111ac8..910aa744d 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -154,6 +154,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 width: this.width,
                 height: this.height,
                 zIndex: this.ZInd,
+                mixBlendMode: StrCast(this.layoutDoc.mixBlendMode) as any,
                 display: this.ZInd === -99 ? "none" : undefined,
                 pointerEvents: this.props.Document.isBackground || this.Opacity === 0 ? "none" : this.props.pointerEvents ? "all" : undefined
             }} >
-- 
cgit v1.2.3-70-g09d2


From 5c4a948d506de2497d685f9ccba56ef6a855af1d Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 29 May 2020 21:52:00 -0400
Subject: added a version of client-side ACL's

---
 src/client/views/animationtimeline/Keyframe.tsx |  8 ++---
 src/client/views/collections/CollectionView.tsx | 16 ++++++----
 src/client/views/nodes/DocumentContentsView.tsx |  4 +--
 src/client/views/nodes/DocumentView.tsx         |  6 +++-
 src/fields/Doc.ts                               | 40 ++++++++++++++++++++++---
 src/fields/util.ts                              | 10 +++++--
 6 files changed, 66 insertions(+), 18 deletions(-)

(limited to 'src/client/views/animationtimeline/Keyframe.tsx')

diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx
index e3274fb35..b562bd957 100644
--- a/src/client/views/animationtimeline/Keyframe.tsx
+++ b/src/client/views/animationtimeline/Keyframe.tsx
@@ -180,10 +180,10 @@ export class Keyframe extends React.Component<IProps> {
             const fadeIn = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.fadeIn, KeyframeFunc.KeyframeType.fade);
             const fadeOut = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, KeyframeFunc.KeyframeType.fade);
             const finish = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration, KeyframeFunc.KeyframeType.end);
-            (fadeIn.key as Doc).opacity = 1;
-            (fadeOut.key as Doc).opacity = 1;
-            (start.key as Doc).opacity = 0.1;
-            (finish.key as Doc).opacity = 0.1;
+            (fadeIn as Doc).opacity = 1;
+            (fadeOut as Doc).opacity = 1;
+            (start as Doc).opacity = 0.1;
+            (finish as Doc).opacity = 0.1;
             this.forceUpdate(); //not needed, if setTimeout is gone...
         }, 1000);
     }
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index ee4755355..fecba32c5 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -8,7 +8,7 @@ import * as React from 'react';
 import Lightbox from 'react-image-lightbox-with-rotate';
 import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app
 import { DateField } from '../../../fields/DateField';
-import { DataSym, Doc, DocListCast, Field, Opt } from '../../../fields/Doc';
+import { DataSym, Doc, DocListCast, Field, Opt, AclSym, AclAddonly, AclReadonly } from '../../../fields/Doc';
 import { List } from '../../../fields/List';
 import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from '../../../fields/Types';
 import { ImageField } from '../../../fields/URLField';
@@ -126,10 +126,16 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
         const docList = DocListCast(targetDataDoc[this.props.fieldKey]);
         const added = docs.filter(d => !docList.includes(d));
         if (added.length) {
-            added.map(doc => doc.context = this.props.Document);
-            added.map(add => Doc.AddDocToList(Cast(Doc.UserDoc().myCatalog, Doc, null), "data", add));
-            targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, ...added]);
-            targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
+            if (this.dataDoc[AclSym] === AclReadonly) {
+                return false;
+            } else if (this.dataDoc[AclSym] === AclAddonly) {
+                added.map(doc => Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc));
+            } else {
+                added.map(doc => doc.context = this.props.Document);
+                added.map(add => Doc.AddDocToList(Cast(Doc.UserDoc().myCatalog, Doc, null), "data", add));
+                targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, ...added]);
+                targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
+            }
         }
         return true;
     }
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index ef56e6fcd..126e9ac14 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -1,6 +1,6 @@
 import { computed } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, Opt, Field } from "../../../fields/Doc";
+import { Doc, Opt, Field, AclSym, AclPrivate } from "../../../fields/Doc";
 import { Cast, StrCast, NumCast } from "../../../fields/Types";
 import { OmitKeys, Without, emptyPath } from "../../../Utils";
 import DirectoryImportBox from "../../util/Import & Export/DirectoryImportBox";
@@ -185,7 +185,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
         const bindings = this.CreateBindings(onClick, onInput);
         //  layoutFrame = splits.length > 1 ? splits[0] + splits[1].replace(/{([^{}]|(?R))*}/, replacer4) : ""; // might have been more elegant if javascript supported recursive patterns
 
-        return (this.props.renderDepth > 12 || !layoutFrame || !this.layoutDoc) ? (null) :
+        return (this.props.renderDepth > 12 || !layoutFrame || !this.layoutDoc || this.layoutDoc[AclSym] === AclPrivate) ? (null) :
             <ObserverJsxParser
                 key={42}
                 blacklistedAttrs={[]}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 2de7b3460..7a4ecfa9c 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -4,7 +4,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, observable, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import * as rp from "request-promise";
-import { Doc, DocListCast, HeightSym, Opt, WidthSym, DataSym } from "../../../fields/Doc";
+import { Doc, DocListCast, HeightSym, Opt, WidthSym, DataSym, AclSym, AclReadonly, AclPrivate } from "../../../fields/Doc";
 import { Document } from '../../../fields/documentSchemas';
 import { Id } from '../../../fields/FieldSymbols';
 import { InkTool } from '../../../fields/InkField';
@@ -742,6 +742,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
         const more = cm.findByDescription("More...");
         const moreItems: ContextMenuProps[] = more && "subitems" in more ? more.subitems : [];
+        moreItems.push({ description: "Make Add Only", event: () => this.layoutDoc.ACL = this.dataDoc.ACL = "addOnly", icon: "concierge-bell" });
+        moreItems.push({ description: "Make Read Only", event: () => this.layoutDoc.ACL = this.dataDoc.ACL = "readOnly", icon: "concierge-bell" });
+        moreItems.push({ description: "Make Private", event: () => this.layoutDoc[AclSym] = this.dataDoc[AclSym] = "noAccess", icon: "concierge-bell" });
         moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" });
         moreItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" });
         moreItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
@@ -1119,6 +1122,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 
     render() {
+        if (this.props.Document[AclSym] && this.props.Document[AclSym] === AclPrivate) return (null);
         if (!(this.props.Document instanceof Doc)) return (null);
         const backgroundColor = Doc.UserDoc().renderStyle === "comic" ? undefined : StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || StrCast(this.Document.backgroundColor) || this.props.backgroundColor?.(this.Document);
         const opacity = Cast(this.layoutDoc._opacity, "number", Cast(this.layoutDoc.opacity, "number", Cast(this.Document.opacity, "number", null)));
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 1ea686cbb..6891bf652 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -93,13 +93,40 @@ export const WidthSym = Symbol("Width");
 export const HeightSym = Symbol("Height");
 export const DataSym = Symbol("Data");
 export const LayoutSym = Symbol("Layout");
+export const AclSym = Symbol("Acl");
+export const AclPrivate = Symbol("AclNoAccess");
+export const AclReadonly = Symbol("AclReadOnly");
+export const AclAddonly = Symbol("AclAddonly");
 export const UpdatingFromServer = Symbol("UpdatingFromServer");
 const CachedUpdates = Symbol("Cached updates");
 
 
 function fetchProto(doc: Doc) {
+    if (doc.author !== Doc.CurrentUserEmail) {
+        if (doc.ACL === "noAccess") {
+            doc[AclSym] = AclPrivate;
+            return undefined;
+        } else if (doc.ACL === "readOnly") {
+            doc[AclSym] = AclReadonly;
+        } else if (doc.ACL === "addOnly") {
+            doc[AclSym] = AclAddonly;
+        }
+    }
+
     const proto = doc.proto;
     if (proto instanceof Promise) {
+        proto.then(proto => {
+            if (proto.author !== Doc.CurrentUserEmail) {
+                if (proto.ACL === "noAccess") {
+                    proto[AclSym] = doc[AclSym] = AclPrivate;
+                    return undefined;
+                } else if (proto.ACL === "readOnly") {
+                    proto[AclSym] = doc[AclSym] = AclReadonly;
+                } else if (proto.ACL === "addOnly") {
+                    proto[AclSym] = doc[AclSym] = AclAddonly;
+                }
+            }
+        });
         return proto;
     }
 }
@@ -113,10 +140,10 @@ export class Doc extends RefField {
             set: setter,
             get: getter,
             // getPrototypeOf: (target) => Cast(target[SelfProxy].proto, Doc) || null, // TODO this might be able to replace the proto logic in getter
-            has: (target, key) => key in target.__fields,
+            has: (target, key) => target[AclSym] !== AclPrivate && key in target.__fields,
             ownKeys: target => {
                 const obj = {} as any;
-                Object.assign(obj, target.___fields);
+                (target[AclSym] !== AclPrivate) && Object.assign(obj, target.___fields);
                 runInAction(() => obj.__LAYOUT__ = target.__LAYOUT__);
                 return Object.keys(obj);
             },
@@ -170,8 +197,11 @@ export class Doc extends RefField {
 
     private [Self] = this;
     private [SelfProxy]: any;
+    public [AclSym]: any = undefined;
     public [WidthSym] = () => NumCast(this[SelfProxy]._width);
     public [HeightSym] = () => NumCast(this[SelfProxy]._height);
+    public [ToScriptString]() { return `DOC-"${this[Self][Id]}"-`; }
+    public [ToString]() { return `Doc(${this[AclSym] === AclPrivate ? "-inaccessible-" : this.title})`; }
     public get [LayoutSym]() { return this[SelfProxy].__LAYOUT__; }
     public get [DataSym]() {
         const self = this[SelfProxy];
@@ -193,8 +223,6 @@ export class Doc extends RefField {
         return undefined;
     }
 
-    [ToScriptString]() { return `DOC-"${this[Self][Id]}"-`; }
-    [ToString]() { return `Doc(${this.title})`; }
 
     private [CachedUpdates]: { [key: string]: () => void | Promise<any> } = {};
     public static CurrentUserEmail: string = "";
@@ -794,6 +822,7 @@ export namespace Doc {
     }
     // don't bother memoizing (caching) the result if called from a non-reactive context. (plus this avoids a warning message)
     export function IsBrushedDegreeUnmemoized(doc: Doc) {
+        if (!doc || doc[AclSym] === AclPrivate || Doc.GetProto(doc)[AclSym] === AclPrivate) return 0;
         return brushManager.BrushedDoc.has(doc) ? 2 : brushManager.BrushedDoc.has(Doc.GetProto(doc)) ? 1 : 0;
     }
     export function IsBrushedDegree(doc: Doc) {
@@ -802,11 +831,13 @@ export namespace Doc {
         })(doc);
     }
     export function BrushDoc(doc: Doc) {
+        if (!doc || doc[AclSym] === AclPrivate || Doc.GetProto(doc)[AclSym] === AclPrivate) return doc;
         brushManager.BrushedDoc.set(doc, true);
         brushManager.BrushedDoc.set(Doc.GetProto(doc), true);
         return doc;
     }
     export function UnBrushDoc(doc: Doc) {
+        if (!doc || doc[AclSym] === AclPrivate || Doc.GetProto(doc)[AclSym] === AclPrivate) return doc;
         brushManager.BrushedDoc.delete(doc);
         brushManager.BrushedDoc.delete(Doc.GetProto(doc));
         return doc;
@@ -836,6 +867,7 @@ export namespace Doc {
     }
     const highlightManager = new HighlightBrush();
     export function IsHighlighted(doc: Doc) {
+        if (!doc || doc[AclSym] === AclPrivate || Doc.GetProto(doc)[AclSym] === AclPrivate) return false;
         return highlightManager.HighlightedDoc.get(doc) || highlightManager.HighlightedDoc.get(Doc.GetProto(doc));
     }
     export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true) {
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 024c0f80e..54e7eca28 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -1,5 +1,5 @@
 import { UndoManager } from "../client/util/UndoManager";
-import { Doc, Field, FieldResult, UpdatingFromServer, LayoutSym } from "./Doc";
+import { Doc, Field, FieldResult, UpdatingFromServer, LayoutSym, AclSym, AclPrivate } from "./Doc";
 import { SerializationHelper } from "../client/util/SerializationHelper";
 import { ProxyField, PrefetchProxy } from "./Proxy";
 import { RefField } from "./RefField";
@@ -106,6 +106,7 @@ const layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHe
     "LODdisable", "chromeStatus", "viewType", "gridGap", "xMargin", "yMargin", "autoHeight"];
 export function setter(target: any, in_prop: string | symbol | number, value: any, receiver: any): boolean {
     let prop = in_prop;
+    if (target[AclSym]) return true;
     if (typeof prop === "string" && prop !== "__id" && prop !== "__fields" && (prop.startsWith("_") || layoutProps.includes(prop))) {
         if (!prop.startsWith("_")) {
             console.log(prop + " is deprecated - switch to _" + prop);
@@ -124,6 +125,8 @@ export function setter(target: any, in_prop: string | symbol | number, value: an
 
 export function getter(target: any, in_prop: string | symbol | number, receiver: any): any {
     let prop = in_prop;
+    if (in_prop === AclSym) return target[AclSym];
+    if (target[AclSym] === AclPrivate) return undefined;
     if (prop === LayoutSym) {
         return target.__LAYOUT__;
     }
@@ -148,6 +151,9 @@ export function getter(target: any, in_prop: string | symbol | number, receiver:
 
 function getFieldImpl(target: any, prop: string | number, receiver: any, ignoreProto: boolean = false): any {
     receiver = receiver || target[SelfProxy];
+    if (target === undefined) {
+        console.log("");
+    }
     let field = target.__fields[prop];
     for (const plugin of getterPlugins) {
         const res = plugin(receiver, prop, field);
@@ -160,7 +166,7 @@ function getFieldImpl(target: any, prop: string | number, receiver: any, ignoreP
     }
     if (field === undefined && !ignoreProto && prop !== "proto") {
         const proto = getFieldImpl(target, "proto", receiver, true);//TODO tfs: instead of receiver we could use target[SelfProxy]... I don't which semantics we want or if it really matters
-        if (proto instanceof Doc) {
+        if (proto instanceof Doc && proto[AclSym] !== AclPrivate) {
             return getFieldImpl(proto[Self], prop, receiver, ignoreProto);
         }
         return undefined;
-- 
cgit v1.2.3-70-g09d2

