A new version of EToys was added to project The Inbox:
http://source.squeak.org/inbox/EToys-cbc.296.mcz ==================== Summary ==================== Name: EToys-cbc.296 Author: cbc Time: 24 April 2017, 10:57:41.788173 pm UUID: 2c3776dc-61d6-40bb-a34a-fdb9fa107ddf Ancestors: EToys-ul.295, EToys-cbc.294 Merge with latest. Also, additional removal of ExternalForm/ExternalScreen forks in Form methods. That is, simplified Form methods where possible to not include any tests for ExternalForm/ExternalScreen, and instead let polymorphism take care of most of those issues. =============== Diff against EToys-ul.295 =============== Item was changed: SystemOrganization addCategory: #'Etoys-Buttons'! SystemOrganization addCategory: #'Etoys-CustomEvents'! SystemOrganization addCategory: #'Etoys-Experimental'! SystemOrganization addCategory: #'Etoys-Outliner'! SystemOrganization addCategory: #'Etoys-Protocols'! SystemOrganization addCategory: #'Etoys-Protocols-Type Vocabularies'! SystemOrganization addCategory: #'Etoys-Scripting'! SystemOrganization addCategory: #'Etoys-Scripting Support'! SystemOrganization addCategory: #'Etoys-Scripting Tiles'! SystemOrganization addCategory: #'Etoys-Squeakland-BroomMorphs-Base'! SystemOrganization addCategory: #'Etoys-Squeakland-BroomMorphs-Connectors'! SystemOrganization addCategory: #'Etoys-Squeakland-EToys-Kedama'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Buttons'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Calendar'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Debugger'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Help'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Input'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Scripting'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Scripting Support'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Scripting Tiles'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-SpeechBubbles'! SystemOrganization addCategory: #'Etoys-Squeakland-Etoys-Tile Scriptors'! - SystemOrganization addCategory: #'Etoys-Squeakland-Graphics-External'! SystemOrganization addCategory: #'Etoys-Squeakland-Graphics-Text'! SystemOrganization addCategory: #'Etoys-Squeakland-Graphics-Tools-Intersection'! SystemOrganization addCategory: #'Etoys-Squeakland-Graphics-Tools-Simplification'! SystemOrganization addCategory: #'Etoys-Squeakland-Graphics-Tools-Triangulation'! SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-AdditionalMorphs'! SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-Charts'! SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-Postscript Filters'! SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-WebCam'! SystemOrganization addCategory: #'Etoys-Squeakland-MorphicExtras-Widgets'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Basic'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Books'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Components'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Demo'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Experimental'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Games'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Games-Chess'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-GeeMail'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Kernel'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Mentoring'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Navigators'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-PartsBin'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-PDA'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Support'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Widgets'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Windows'! SystemOrganization addCategory: #'Etoys-Squeakland-Morphic-Worlds'! SystemOrganization addCategory: #'Etoys-Squeakland-Multilingual-Languages'! SystemOrganization addCategory: #'Etoys-Squeakland-Multilingual-TextConversion'! SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Formatter'! SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Forms'! SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Parser'! SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Parser Entities'! SystemOrganization addCategory: #'Etoys-Squeakland-Network-HTML-Tokenizer'! SystemOrganization addCategory: #'Etoys-Squeakland-Network-MIME'! SystemOrganization addCategory: #'Etoys-Squeakland-Network-TelNet WordNet'! SystemOrganization addCategory: #'Etoys-Squeakland-Network-UI'! SystemOrganization addCategory: #'Etoys-Squeakland-Network-Url'! SystemOrganization addCategory: #'Etoys-Squeakland-Protocols-Type Vocabularies'! SystemOrganization addCategory: #'Etoys-Squeakland-Sound-Interface'! SystemOrganization addCategory: #'Etoys-Squeakland-Sound-Ogg'! SystemOrganization addCategory: #'Etoys-Squeakland-Sound-Scores'! SystemOrganization addCategory: #'Etoys-Squeakland-ST80-Morphic'! SystemOrganization addCategory: #'Etoys-Squeakland-SUnit'! SystemOrganization addCategory: #'Etoys-Squeakland-Sugar'! SystemOrganization addCategory: #'Etoys-Squeakland-System-Clipboard-Extended'! SystemOrganization addCategory: #'Etoys-Squeakland-System-Compiler'! SystemOrganization addCategory: #'Etoys-Squeakland-System-Exceptions Kernel'! SystemOrganization addCategory: #'Etoys-Squeakland-System-Support'! SystemOrganization addCategory: #'Etoys-Squeakland-Tools-Changes'! SystemOrganization addCategory: #'Etoys-Squeakland-Tools-Explorer'! SystemOrganization addCategory: #'Etoys-Squeakland-Tools-Process Browser'! SystemOrganization addCategory: #'Etoys-Squeakland-Tweak-Kedama-ObjectVectors'! SystemOrganization addCategory: #'Etoys-Squeakland-Tweak-Kedama-ParseTreeTransformer'! SystemOrganization addCategory: #'Etoys-Squeakland-Tweak-Kedama-ParseTree-AttributeDefinition'! SystemOrganization addCategory: #'Etoys-Stacks'! SystemOrganization addCategory: #'Etoys-StarSqueak'! SystemOrganization addCategory: #'Etoys-Support'! SystemOrganization addCategory: #'Etoys-Tests'! SystemOrganization addCategory: #'Etoys-Tile Scriptors'! SystemOrganization addCategory: #'Etoys-Widgets'! SystemOrganization addCategory: #'Etoys-Squeakland-Support'! SystemOrganization addCategory: #'Etoys-Squeakland-SISS-Serialization'! SystemOrganization addCategory: #'Etoys-OLPC-Display'! SystemOrganization addCategory: #'Etoys-ReleaseBuilder'! SystemOrganization addCategory: #'Etoys-UserInterfaceTheme'! Item was removed: - Form subclass: #ExternalForm - instanceVariableNames: 'display argbMap' - classVariableNames: '' - poolDictionaries: '' - category: 'Etoys-Squeakland-Graphics-External'! - - !ExternalForm commentStamp: '<historical>' prior: 0! - An ExternalForm is just like any other form. It's only difference is that it is allocated on a specific display and can be used for accelerated blts on the particular display. - - Upon shutdown of the system ExternalForms will be deallocated from the display and be kept in their internalized form.! Item was removed: - ----- Method: ExternalForm>>colormapFromARGB (in category 'accessing') ----- - colormapFromARGB - "Return a ColorMap mapping from canonical ARGB pixel values into the receiver" - ^argbMap ifNil:[argbMap := ColorMap mappingFromARGB: self rgbaBitMasks].! Item was removed: - ----- Method: ExternalForm>>colormapFromARGB: (in category 'accessing') ----- - colormapFromARGB: aMap - "Set the ColorMap mapping from canonical ARGB pixel values into the receiver" - argbMap := aMap! Item was removed: - ----- Method: ExternalForm>>destroy (in category 'initialize-release') ----- - destroy - "Destroy the receiver" - display ifNotNil:[display destroyForm: self]! Item was removed: - ----- Method: ExternalForm>>displayScreen (in category 'accessing') ----- - displayScreen - "Return the display screen the receiver is allocated on." - ^display! Item was removed: - ----- Method: ExternalForm>>getExternalHandle (in category 'private') ----- - getExternalHandle - "Private. Return the virtual handle used to represent the receiver" - ^bits! Item was removed: - ----- Method: ExternalForm>>hasNonStandardPalette (in category 'testing') ----- - hasNonStandardPalette - "Quite possible." - ^display notNil or:[argbMap notNil]! Item was removed: - ----- Method: ExternalForm>>isExternalForm (in category 'testing') ----- - isExternalForm - "I am an external form but only as long as I'm allocated on a display" - ^display notNil! Item was removed: - ----- Method: ExternalForm>>rgbaBitMasks (in category 'accessing') ----- - rgbaBitMasks - "Return the masks for specifying the R,G,B, and A components in the receiver" - display - ifNil:[^super rgbaBitMasks] - ifNotNil:[^display rgbaBitMasksOfForm: self]! Item was removed: - ----- Method: ExternalForm>>setExternalHandle:on: (in category 'private') ----- - setExternalHandle: aHandle on: aDisplay - "Initialize the receiver from the given external handle" - display := aDisplay. - bits := aHandle.! Item was removed: - ----- Method: ExternalForm>>shutDown (in category 'initialize-release') ----- - shutDown - "System is going down. Internalize my bits and be finished." - | copy | - copy := Form extent: self extent depth: self depth. - self displayOn: copy. - copy hibernate. "compact bits of copy" - self destroy. "Release my external handle" - bits := copy bits. "Now compressed" - display := nil. "No longer allocated" - argbMap := nil. "No longer external"! Item was removed: - WeakKeyDictionary subclass: #ExternalFormRegistry - instanceVariableNames: 'lockFlag' - classVariableNames: '' - poolDictionaries: '' - category: 'Etoys-Squeakland-Graphics-External'! - - !ExternalFormRegistry commentStamp: '<historical>' prior: 0! - The ExternalFormRegistry needs to be synchronized with rendering to prevent forms from being destroyed during rendering. Only at certain points (that is after a rendering cycle is completed) the texture registry may be cleaned up.! Item was removed: - ----- Method: ExternalFormRegistry>>finalizeValues (in category 'finalization') ----- - finalizeValues - "This message is sent when an element has gone away." - lockFlag == true ifTrue:[^self]. - self forceFinalization.! Item was removed: - ----- Method: ExternalFormRegistry>>forceFinalization (in category 'finalization') ----- - forceFinalization - self associationsDo:[:assoc| - assoc key isNil ifTrue:[assoc value destroy]. - ]. - super finalizeValues.! Item was removed: - ----- Method: ExternalFormRegistry>>lock (in category 'accessing') ----- - lock - lockFlag := true! Item was removed: - ----- Method: ExternalFormRegistry>>unlock (in category 'accessing') ----- - unlock - lockFlag := false.! Item was removed: - DisplayScreen subclass: #ExternalScreen - instanceVariableNames: 'argbMap allocatedForms' - classVariableNames: '' - poolDictionaries: '' - category: 'Etoys-Squeakland-Graphics-External'! - - !ExternalScreen commentStamp: '<historical>' prior: 0! - I represent a DisplayScreen that is not part of the Squeak universe. Subclasses must implement the appropriate primitives for creating, destroying and allocating the appropriate external objects. - - Note: It is assumed that all external display surfaces are accessible by FXBlt, meaning that any support code must register the surfaces with the surface plugin. This requires that the support code will have a way of accessing the bits of the surface. Although this can be terribly expensive (such as on X where a roundtrip to the server might be required or for an OpenGL display where glReadPixels usually is slow as hell) the appropriate methods should be implemented. This allows for a gradual transition to less expensive model (such as implementing an X11Canvas supporting the drawing primitives of X) and is therefore the preferred solution. - - In the eventual case that it's known that BitBlt/FXBlt will *never* be used in conjunction with a particular drawing surface, the support code should return a handle that is a) not a SmallInteger (these are used by the surface plugin) and b) not of the 'bitsSize' of a Form. One possible representation for such a handle would be a ByteArray of a non-integral word size (e.g., a ByteArray of size 5,6, or 7). In this case, all attempts to use FXBlt with the drawing surface will simply fail. - ! Item was removed: - ----- Method: ExternalScreen>>allocateForm: (in category 'form support') ----- - allocateForm: extentPoint - "Allocate a new form which is similar to the receiver and can be used for accelerated blts" - | formHandle displayForm | - formHandle := self primAllocateForm: self depth width: extentPoint x height: extentPoint y. - formHandle = nil ifTrue:[^super allocateForm: extentPoint]. - displayForm := (ExternalForm extent: extentPoint depth: self depth bits: nil) - setExternalHandle: formHandle on: self. - allocatedForms at: displayForm put: displayForm executor. - ^displayForm! Item was removed: - ----- Method: ExternalScreen>>colormapFromARGB (in category 'accessing') ----- - colormapFromARGB - "Return a ColorMap mapping from canonical ARGB pixel values into the receiver" - ^argbMap ifNil:[argbMap := ColorMap mappingFromARGB: self rgbaBitMasks].! Item was removed: - ----- Method: ExternalScreen>>copyBits:from:at:clippingBox:rule:fillColor:map: (in category 'blitting support') ----- - copyBits: sourceRect from: sourceForm at: destOrigin clippingBox: clipRect rule: rule fillColor: hf map: map - "Attempt to accelerate blts to the receiver" - | r | - ((self isBltAccelerated: rule for: sourceForm) and:[map == nil and:[hf == nil]]) ifTrue:[ - "Try an accelerated blt" - r := (destOrigin extent: sourceRect extent) intersect: (clipRect intersect: clippingBox). - r area <= 0 ifTrue:[^self]. - (self primBltFast: bits from: sourceForm getExternalHandle - at: r origin from: sourceRect origin - extent: r extent) ifNotNil:[^self]. - ]. - ^super copyBits: sourceRect from: sourceForm at: destOrigin clippingBox: clipRect rule: rule fillColor: hf map: map! Item was removed: - ----- Method: ExternalScreen>>destroy (in category 'initialize-release') ----- - destroy - "Destroy the receiver" - allocatedForms ifNotNil:[ - allocatedForms lock. "Make sure we don't get interrupted" - allocatedForms forceFinalization. "Clean up all lost references" - allocatedForms keys do:[:stillValid| stillValid shutDown]. - "All remaining references are simply destroyed" - allocatedForms associationsDo:[:assoc| assoc key: nil]. - allocatedForms forceFinalization. "destroy all others" - allocatedForms := nil. - ]. - bits ifNotNil:[self primDestroyDisplaySurface: bits]. - bits := nil.! Item was removed: - ----- Method: ExternalScreen>>destroyForm: (in category 'form support') ----- - destroyForm: anExternalForm - "Destroy the given external form" - self primDestroyForm: anExternalForm getExternalHandle. - anExternalForm setExternalHandle: nil on: nil. - allocatedForms removeKey: anExternalForm ifAbsent:[].! Item was removed: - ----- Method: ExternalScreen>>displayOn:at:clippingBox:rule:fillColor: (in category 'blitting support') ----- - displayOn: destForm at: destOrigin clippingBox: clipRect rule: rule fillColor: hf - "Attempt to accelerate blts to aDisplayMedium" - | sourceRect | - ((self isBltAccelerated: rule for: destForm) and:[hf = nil]) ifTrue:[ - "Try an accelerated blt" - sourceRect := (clipRect translateBy: destOrigin negated) intersect: clippingBox. - (self primBltFast: bits to: destForm getExternalHandle - at: 0@0 from: sourceRect origin - extent: sourceRect extent) ifNotNil:[^self]]. - destForm copyBits: self boundingBox - from: self - at: destOrigin + self offset - clippingBox: clipRect - rule: rule - fillColor: hf - map: (self colormapIfNeededFor: destForm). - ! Item was removed: - ----- Method: ExternalScreen>>fill:rule:fillColor: (in category 'blitting support') ----- - fill: aRectangle rule: anInteger fillColor: aColor - "Replace a rectangular area of the receiver with the pattern described by aForm - according to the rule anInteger." - | rect | - (self isFillAccelerated: anInteger for: aColor) ifTrue:[ - rect := aRectangle intersect: clippingBox. - (self primFill: bits - color: (self pixelWordFor: aColor) - x: rect left - y: rect top - w: rect width - h: rect height) ifNotNil:[^self]]. - ^super fill: aRectangle rule: anInteger fillColor: aColor! Item was removed: - ----- Method: ExternalScreen>>finish (in category 'initialize-release') ----- - finish - "Flush the receiver" - self primFinish: bits. - "Now is the time to do some cleanup" - allocatedForms unlock. - allocatedForms finalizeValues.! Item was removed: - ----- Method: ExternalScreen>>flush (in category 'initialize-release') ----- - flush - "Flush the receiver" - self primFlush: bits.! Item was removed: - ----- Method: ExternalScreen>>hasNonStandardPalette (in category 'testing') ----- - hasNonStandardPalette - "Quite possible." - ^true! Item was removed: - ----- Method: ExternalScreen>>isBltAccelerated:for: (in category 'blitting support') ----- - isBltAccelerated: ruleInteger for: aForm - "Return true if the receiver can perform accelerated blt operations by itself. - It is assumed that blts of forms allocated on the receiverusing Form>>over - may be accelerated. - Although some hardware may allow source-key blts (that is, Form>>paint or similar) - this is usually questionable and the additional effort for allocating and - maintaining the OS form doesn't quite seem worth the effort." - ^aForm displayScreen == self and:[ruleInteger = Form over]! Item was removed: - ----- Method: ExternalScreen>>isExternalForm (in category 'testing') ----- - isExternalForm - "Sorta. Kinda." - ^true! Item was removed: - ----- Method: ExternalScreen>>isFillAccelerated:for: (in category 'blitting support') ----- - isFillAccelerated: ruleInteger for: aColor - "Return true if the receiver can perform accelerated fill operations by itself. - It is assumed that the hardware can accelerate plain color fill operations." - ^ruleInteger = Form over and:[aColor isColor]! Item was removed: - ----- Method: ExternalScreen>>primAllocateForm:width:height: (in category 'primitives-forms') ----- - primAllocateForm: d width: w height: h - "Primitive. Allocate a form with the given parameters" - ^nil! Item was removed: - ----- Method: ExternalScreen>>primBltFast:from:at:from:extent: (in category 'primitives-display') ----- - primBltFast: displayHandle from: sourceHandle at: destOrigin from: sourceOrigin extent: extent - "Primitive. Perform a fast blt operation. Return the receiver if successful." - ^nil! Item was removed: - ----- Method: ExternalScreen>>primBltFast:to:at:from:extent: (in category 'primitives-display') ----- - primBltFast: displayHandle to: dstHandle at: destOrigin from: sourceOrigin extent: extent - "Primitive. Perform a fast blt operation. Return the receiver if successful." - ^nil! Item was removed: - ----- Method: ExternalScreen>>primCreateDisplaySurface:width:height: (in category 'primitives-display') ----- - primCreateDisplaySurface: d width: w height: h - "Primitive. Create a new external display surface. Return the handle used to identify the receiver. Fail if the surface cannot be created." - ^nil! Item was removed: - ----- Method: ExternalScreen>>primDestroyDisplaySurface: (in category 'primitives-display') ----- - primDestroyDisplaySurface: aHandle - "Primitive. Destroy the display surface associated with the given handle." - ^nil! Item was removed: - ----- Method: ExternalScreen>>primDestroyForm: (in category 'primitives-forms') ----- - primDestroyForm: aHandle - "Primitive. Destroy the form associated with the given handle." - ^nil! Item was removed: - ----- Method: ExternalScreen>>primDisplay:colorMasksInto: (in category 'primitives-display') ----- - primDisplay: aHandle colorMasksInto: anArray - "Primitive. Store the bit masks for each color into the given array." - ^nil! Item was removed: - ----- Method: ExternalScreen>>primFill:color:x:y:w:h: (in category 'primitives-display') ----- - primFill: handle color: pixelWord x: x y: y w: w h: h - "Primitive. Perform an accelerated fill operation on the receiver." - ^nil! Item was removed: - ----- Method: ExternalScreen>>primFinish: (in category 'primitives-display') ----- - primFinish: aHandle - "Primitive. Finish all rendering operations on the receiver. - Do not return before all rendering operations have taken effect." - ^nil! Item was removed: - ----- Method: ExternalScreen>>primFlush: (in category 'primitives-display') ----- - primFlush: aHandle - "Primitive. If any rendering operations are pending, force them to be executed. - Do not wait until they have taken effect." - ^nil! Item was removed: - ----- Method: ExternalScreen>>primForm:colorMasksInto: (in category 'primitives-forms') ----- - primForm: aHandle colorMasksInto: anArray - "Primitive. Store the bit masks for each color into the given array." - ^nil! Item was removed: - ----- Method: ExternalScreen>>release (in category 'initialize-release') ----- - release - "I am no longer Display. Release any resources if necessary" - self destroy! Item was removed: - ----- Method: ExternalScreen>>rgbaBitMasks (in category 'accessing') ----- - rgbaBitMasks - "Return the masks for specifying the R,G,B, and A components in the receiver" - | rgbaBitMasks | - rgbaBitMasks := Array new: 4. - self primDisplay: bits colorMasksInto: rgbaBitMasks. - ^rgbaBitMasks! Item was removed: - ----- Method: ExternalScreen>>rgbaBitMasksOfForm: (in category 'form support') ----- - rgbaBitMasksOfForm: anExternalForm - | rgbaBitMasks | - rgbaBitMasks := Array new: 4. - self primForm: anExternalForm getExternalHandle colorMasksInto: rgbaBitMasks. - ^rgbaBitMasks! Item was removed: - ----- Method: ExternalScreen>>setExtent:depth: (in category 'private') ----- - setExtent: aPoint depth: bitsPerPixel - "Create a 3D accelerated display screen" - | screen | - (bits isInteger and:[depth == bitsPerPixel and: [aPoint = self extent and: - [self supportsDisplayDepth: bitsPerPixel]]]) ifFalse: [ - bits ifNotNil:[self primDestroyDisplaySurface: bits]. - bits := nil. "Free up old bitmap in case space is low" - DisplayChangeSignature := (DisplayChangeSignature ifNil: [0]) + 1. - (self supportsDisplayDepth: bitsPerPixel) - ifTrue:[depth := bitsPerPixel] - ifFalse:["Search for a suitable depth" - depth := self findAnyDisplayDepthIfNone:[nil]]. - depth == nil ifFalse:[ - bits := self primCreateDisplaySurface: depth - width: aPoint x height: aPoint y]. - "Bail out if surface could not be created" - (bits == nil) ifTrue:[ - screen := DisplayScreen extent: aPoint depth: bitsPerPixel. - self == Display ifTrue:[ - Display := screen. - Display beDisplay]. - ^screen]. - width := aPoint x. - height := aPoint y. - ]. - clippingBox := super boundingBox. - allocatedForms ifNil:[ - allocatedForms := ExternalFormRegistry new. - WeakArray addWeakDependent: allocatedForms]. - ! Item was removed: - ----- Method: ExternalScreen>>shutDown (in category 'initialize-release') ----- - shutDown - "Minimize Display memory saved in image" - self destroy. - width := 240. - height := 120. - bits := Bitmap new: self bitsSize.! Item was removed: - ----- Method: ExternalScreen>>supportsDisplayDepth: (in category 'primitives-display') ----- - supportsDisplayDepth: pixelDepth - "Return true if this pixel depth is supported on the current host platform." - ^false! |
Free forum by Nabble | Edit this page |