[Enh][VM] primitiveApplyToFromTo for the heart of the enumeration of collections?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
86 messages Options
12345
Reply | Threaded
Open this post in threaded view
|

Re: Squeak for the masses? [was: primitiveApplyToFromTo]

David Mitchell-10

> Ralph Johnson wrote,
>
> There have been a number of Smalltalk projects with dozens, sometimes
> hundreds, of people on them.  None have been successful.  On large
> projects, politics and management issues overwhelm technical decisions
> and the value of Smalltalk gets lost.

Of course, "none" is an absolute, so it is easily disproven. I've been
on two large systems written in Smalltalk and both were incredibly
successful. One was a banking recordkeeping system (stock trading) and
the other ran the policyholder information for a large insurance carrier
(including a web application to process changes online back in 98). Both
of these systems had over 50 developers. Note that both used small teams
(6-12) to develop parts of the application. The insurance carrier used
Smalltalk in a number of other mission critical applications, each with
development teams around 40-60.

Reply | Threaded
Open this post in threaded view
|

RE: Strongtalk VM for Squeak

J J-6
In reply to this post by Michael Latta
>From: "Michael Latta" <[hidden email]>
>Reply-To: The general-purpose Squeak developers
>list<[hidden email]>
>To: "'The general-purpose Squeak developers
>list'"<[hidden email]>
>Subject: RE: Strongtalk VM for Squeak
>Date: Mon, 18 Sep 2006 22:08:43 -0700
>
>Actually the Java and .Net worlds are both coming to the conclusion that
>dynamic typing is the future.  Both communities are learning that the cost
>of maintaining all that typing information is a larger problem than the one
>it solves.  Namely that type errors are just not all that common, and are
>easily found with adequate testing, which is required even with static
>typing.

Early in my software career I was strongly in the static typing camp.  A big
reason for this was, the only representative of the dynamic typing camp I
was
familiar with was perl.  So naturally I saw dynamic typing as a synonym for
run slow,
etc., etc..

Now that I have had time to get exposed to languages designed with actual
thought
(or CS educated thought, if you prefer) I have to say I agree that the
static typing
causes more trouble then it is helping.  It is just a specific case of a
more general
situation:  testing.

It is better to have all the tests in one place, instead of some delegated
to the compiler
as in a staticly typed language.  Especially since the preprogrammed
compiler tests do not
apply in some cases, forcing the language to design new syntax to get around
it and the
user to use this syntax to fight with the compiler.

So my vote would be that instead of trying to get static type support into
squeak we focus
on the real issue:  education.  If users get exposed to a well designed
lanugage then the
bad press about not being statically typed will be exposed as being wrong.



Reply | Threaded
Open this post in threaded view
|

Re: Strongtalk VM for Squeak

Tapple Gao
In reply to this post by Yanni Chiu
On Tue, Sep 19, 2006 at 02:21:23AM -0400, Yanni Chiu wrote:

> Ramon Leon wrote:
> >>It seems to me that adding strong typing (or whatever the correct
> >>term is) to Squeak would chip away a one more perceived "deficiency",
> >>and win some political points in the "language wars". That should
> >>end the arguments: we've got both.
> >
> >
> >Only if you consider manifest types to be a good thing, most
> >Smalltalkers don't.
>
> I see it purely as a marketing issue. If typing is something
> that's blocking wider adoption (whether justified or not),
> and we have a way to fix it, then just do it and move on.
> But it's possible that we won't have to, if the mindset has
> changed (as Michael points out in his message).
>
> On a similar vein, a C++ based VM (and the Strongtalk mystique)
> might have some marketing points (but, once again, don't sacrifice
> scarce developer resources). But the message might just end up:
> "we now have the Smalltalk technology that the Java VM
> implementers bought and adapted (nearly 10 years ago)."
>
> Another point about typing:  would the typing information
> be useful for improving the developer tools (e.g. refactoring
> could be more precise)?

I just stumbled across RoelTyper, a type checker for smalltalk:
http://decomp.ulb.ac.be/roelwuyts/smalltalk/roeltyper/
http://www.squeaksource.com/RoelTyper.html

--
Matthew Fulmer

Reply | Threaded
Open this post in threaded view
|

Re: Strongtalk VM for Squeak

Ramon Leon-4
> I just stumbled across RoelTyper, a type checker for smalltalk:
> http://decomp.ulb.ac.be/roelwuyts/smalltalk/roeltyper/
> http://www.squeaksource.com/RoelTyper.html

A type inference engine, and already used by the latest eCompletion to
enhance it's accuracy, both very nice tools.

Ramon Leon
http://onsmalltalk.com



Reply | Threaded
Open this post in threaded view
|

Re: self send inliner (was: [Enh][VM] primitiveApplyToFromTo for the heart of theenumeration of collections?)

Philippe Marschall
In reply to this post by Avi Bryant
2006/9/19, Avi Bryant <[hidden email]>:

>
> On Sep 19, 2006, at 10:14 AM, Philippe Marschall wrote:
>
> > 2006/9/18, Jecel Assumpcao Jr <[hidden email]>:
> >> Avi Bryant wrote:
> >> Has anyone ever played with a simple self-sends inliner?  No de-
> >> inlining when debugging, no post-inlining optimization, no attempt to
> >> deal with polymorphism, just inlining monomorphic self-sends...
> >
> > Well, I'm toying around with something even simpler:
> >
> > - Does not uninline when methods are added. So you need to load all
> > your code first and then recompile it.
> > - Can only implement methods that contain no return or the return is
> > the last statement.
> >
> > Do you have a case study?
>
> I think the Collection hierarchy would be the right place to start.
> I was always impressed by how Strongtalk could do things like
> implement #at: in terms of #at:ifAbsent:.

Below is a list of the selectors such a primtive inliner coud inline
taking only the classes Collection, SequenceableCollection,
ArrayedCollection, Array, OrderedCollection, Set, Dictionary and
String into account.

Philippe

#inject:into: in #max of Collection
#do:separatedBy: in #asStringOn:delimiter:last: of Collection
#reject: in #difference: of Collection
#do:separatedBy: in #asStringOn:delimiter: of Collection
#max in #range of Collection
#min in #range of Collection
#as: in #asSortedCollection of Collection
#subclassResponsibility in #add: of Collection
#as: in #asSkipList of Collection
#asSortedCollection in #asSortedArray of Collection
#inject:into: in #sum of Collection
#error: in #adaptToCollection:andSend: of Collection
#error: in #errorNotFound: of Collection
#error: in #errorNotKeyed of Collection
#reject: in #copyWithoutAll: of Collection
#asSortedCollection in #median of Collection
#errorNotFound: in #remove: of Collection
#sum in #average of Collection
#subclassResponsibility in #do: of Collection
#subclassResponsibility in #remove:ifAbsent: of Collection
#error: in #errorNoMatch of Collection
#reject: in #copyWithout: of Collection
#errorNotFound: in #detect: of Collection
#as: in #asOrderedCollection of Collection
#do:separatedBy: in #printOn:delimiter:last: of Collection
#do:separatedBy: in #printElementsOn: of Collection
#as: in #asIdentitySkipList of Collection
#do:separatedBy: in #printOn:delimiter: of Collection
#reject: in #reject:thenDo: of Collection
#inject:into: in #do:displayingProgress: of Collection
#error: in #errorEmptyCollection of Collection
#asStringOn:delimiter:last: in #asCommaStringAnd of Collection
#inject:into: in #min of Collection
#emptyCheck in #anyOne of Collection
#addToSequence: in #asAstSquenceNode of Collection
#printNameOn: in #printOn: of Collection
#error: in #toBraceStack: of Collection
#errorEmptyCollection in #emptyCheck of Collection
#asStringOn:delimiter: in #asCommaString of Collection
#first: in #copyUpTo: of SequenceableCollection
#indexOf:ifAbsent: in #copyUpTo: of SequenceableCollection
#indexOf:ifAbsent: in #indexOf: of SequenceableCollection
#combinationsAt:in:after:do: in #combinations:atATimeDo: of
SequenceableCollection
#error: in #changeOfChangesInSlopes: of SequenceableCollection
#atWrap: in #changeOfChangesInSlopes: of SequenceableCollection
#withIndexCollect: in #collectWithIndex: of SequenceableCollection
#asOrderedCollection in #explorerContents of SequenceableCollection
#allButFirst: in #copyAfterLast: of SequenceableCollection
#lastIndexOf:ifAbsent: in #copyAfterLast: of SequenceableCollection
#with:collect: in #@ of SequenceableCollection
#withIndexDo: in #do:displayingProgress: of SequenceableCollection
#before:ifAbsent: in #before: of SequenceableCollection
#errorNotFound: in #before: of SequenceableCollection
#assert: in #assertSlopesWith:from:to: of SequenceableCollection
#assert: in #assertSlopesWith:from:to: of SequenceableCollection
#assert: in #assertSlopesWith:from:to: of SequenceableCollection
#assert: in #assertSlopesWith:from:to: of SequenceableCollection
#nilTransitions in #naturalFillinList of SequenceableCollection
#errorNotFound: in #findBinaryIndex: of SequenceableCollection
#withIndexDo: in #transitions of SequenceableCollection
#error: in #closedCubicSlopes of SequenceableCollection
#closedCubicSlopes in #closedCubicSlopes: of SequenceableCollection
#swap:with: in #permutationsStartingAt:do: of SequenceableCollection
#swap:with: in #permutationsStartingAt:do: of SequenceableCollection
#withIndexDo: in #transitions: of SequenceableCollection
#atWrap: in #nilTransitions of SequenceableCollection
#errorNotFound: in #findBinary: of SequenceableCollection
#copyWithoutFirst in #asTraitComposition of SequenceableCollection
#error: in #with:do: of SequenceableCollection
#error: in #replaceFrom:to:with: of SequenceableCollection
#error: in #errorFirstObject: of SequenceableCollection
#nilTransitions in #closedFillinList of SequenceableCollection
#allButLast: in #allButLast of SequenceableCollection
#copyReplaceAll:with:asTokens: in #copyReplaceAll:with: of
SequenceableCollection
#deprecated: in #upTo: of SequenceableCollection
#last: in #copyLast: of SequenceableCollection
#errorNotFound: in #literalIndexOf: of SequenceableCollection
#assert: in #asCubic of SequenceableCollection
#assert: in #asCubic of SequenceableCollection
#error: in #changeInSlopes: of SequenceableCollection
#atWrap: in #changeInSlopes: of SequenceableCollection
#shuffledBy: in #shuffled of SequenceableCollection
#atWrap: in #slopesWith:from:to: of SequenceableCollection
#atWrap:put: in #slopesWith:from:to: of SequenceableCollection
#atWrap: in #slopesWith:from:to: of SequenceableCollection
#atWrap:put: in #slopesWith:from:to: of SequenceableCollection
#atWrap: in #slopesWith:from:to: of SequenceableCollection
#atWrap: in #flipRotated: of SequenceableCollection
#first: in #copyUpToLast: of SequenceableCollection
#lastIndexOf:ifAbsent: in #copyUpToLast: of SequenceableCollection
#allButFirst: in #allButFirst of SequenceableCollection
#errorNoMatch in #reverseWith:do: of SequenceableCollection
#error: in #checkedAt: of SequenceableCollection
#asDigitsAt:in:do: in #asDigitsToPower:do: of SequenceableCollection
#after:ifAbsent: in #after: of SequenceableCollection
#errorNotFound: in #after: of SequenceableCollection
#error: in #with:collect: of SequenceableCollection
#withIndexDo: in #doWithIndex: of SequenceableCollection
#isString in #copyReplaceAll:with:asTokens: of SequenceableCollection
#error: in #copyReplaceAll:with:asTokens: of SequenceableCollection
#inject:into: in #concatenation of SequenceableCollection
#atLast:ifAbsent: in #atLast: of SequenceableCollection
#error: in #atLast: of SequenceableCollection
#collectWithIndex: in #segmentedSlopes of SequenceableCollection
#atWrap: in #segmentedSlopes of SequenceableCollection
#allButFirst in #copyWithoutFirst of SequenceableCollection
#asSortedCollection: in #sortBy: of SequenceableCollection
#shouldNotImplement in #remove:ifAbsent: of SequenceableCollection
#error: in #errorOutOfBounds of SequenceableCollection
#error: in #errorLastObject: of SequenceableCollection
#error: in #naturalCubicSlopes of SequenceableCollection
#first: in #startsWith: of SequenceableCollection
#allButFirst: in #copyAfter: of SequenceableCollection
#indexOf:ifAbsent: in #copyAfter: of SequenceableCollection
#sort: in #sort of ArrayedCollection
#storeElementsFrom:to:on: in #storeOn: of ArrayedCollection
#shouldNotImplement in #add: of ArrayedCollection
#bytesPerBasicElement in #byteSize of ArrayedCollection
#assert: in #mergeSortFrom:to:by: of ArrayedCollection
#assert: in #mergeSortFrom:to:by: of ArrayedCollection
#primitiveFailed in #elementsForwardIdentityTo: of Array
#printAsLiteralFormOn: in #printOn: of Array
#printAsSelfEvaluatingFormOn: in #printOn: of Array
#error: in #preMultiplyByMatrix: of Array
#printElementsOn: in #printAsLiteralFormOn: of Array
#error: in #elementsExchangeIdentityWith: of Array
#error: in #elementsExchangeIdentityWith: of Array
#error: in #elementsExchangeIdentityWith: of Array
#error: in #elementsExchangeIdentityWith: of Array
#with:do: in #elementsExchangeIdentityWith: of Array
#error: in #elementsExchangeIdentityWith: of Array
#primitiveFailed in #elementsExchangeIdentityWith: of Array
#do:separatedBy: in #printAsSelfEvaluatingFormOn: of Array
#first in #hashMappedBy: of Array
#last in #hashMappedBy: of Array
#with:do: in #literalEqual: of Array
#error: in #preMultiplyByArray: of Array
#first in #preMultiplyByArray: of Array
#primitiveFailed in #elementsForwardIdentityTo:copyHash: of Array
#addFirst: in #addAllFirstUnlessAlreadyPresent: of OrderedCollection
#insert:before: in #add:after: of OrderedCollection
#reset in #setCollection: of OrderedCollection
#insert:before: in #add:before: of OrderedCollection
#errorNoSuchElement in #at: of OrderedCollection
#emptyCheck in #removeLast of OrderedCollection
#errorOutOfBounds in #copyReplaceFrom:to:with: of OrderedCollection
#species in #copyReplaceFrom:to:with: of OrderedCollection
#error: in #errorNoSuchElement of OrderedCollection
#species in #copyFrom:to: of OrderedCollection
#species in #copyFrom:to: of OrderedCollection
#isEmpty in #hasContentsInExplorer of OrderedCollection
#addAllLast: in #addAll: of OrderedCollection
#species in #copyEmpty of OrderedCollection
#insert:before: in #add:afterIndex: of OrderedCollection
#species in #withIndexCollect: of OrderedCollection
#errorNoSuchElement in #at:put: of OrderedCollection
#error: in #with:collect: of OrderedCollection
#species in #with:collect: of OrderedCollection
#species in #collect: of OrderedCollection
#growSize in #grow of OrderedCollection
#removeLast in #removeLast: of OrderedCollection
#removeIndex: in #remove:ifAbsent: of OrderedCollection
#removeFirst in #removeFirst: of OrderedCollection
#removeIndex: in #removeAt: of OrderedCollection
#addFirst: in #addAllFirst: of OrderedCollection
#species in #reversed of OrderedCollection
#reverseDo: in #reversed of OrderedCollection
#grow in #makeRoomAtLast of OrderedCollection
#errorNoSuchElement in #collect:from:to: of OrderedCollection
#species in #collect:from:to: of OrderedCollection
#grow in #makeRoomAtFirst of OrderedCollection
#errorNotFound: in #find: of OrderedCollection
#add:afterIndex: in #add:beforeIndex: of OrderedCollection
#error: in #errorConditionNotSatisfied of OrderedCollection
#emptyCheck in #removeFirst of OrderedCollection
#error: in #findElementOrNil: of Set
#swap:with: in #fixCollisionsFrom: of Set
#isEmpty in #hasContentsInExplorer of Set
#emptyCheck in #atRandom: of Set
#doWithIndex: in #atRandom: of Set
#errorEmptyCollection in #atRandom: of Set
#error: in #add: of Set
#atNewIndex:put: in #add: of Set
#species in #rehash of Set
#asOrderedCollection in #explorerContents of Set
#growSize in #grow of Set
#fullCheck in #atNewIndex:put: of Set
#keysSortedSafely in #explorerContents of Dictionary
#shouldNotImplement in #remove: of Dictionary
#keysSortedSafely in #printElementsOn: of Dictionary
#systemNavigation in #unreferencedKeys of Dictionary
#associationAt: in #unreferencedKeys of Dictionary
#species in #rehash of Dictionary
#species in #select: of Dictionary
#atNewIndex:put: in #at:put: of Dictionary
#errorKeyNotFound in #associationAt: of Dictionary
#errorValueNotFound in #keyAtIdentityValue: of Dictionary
#errorKeyNotFound in #removeKey: of Dictionary
#species in #associationsSelect: of Dictionary
#unreferencedKeys in #removeUnreferencedKeys of Dictionary
#removeKey: in #removeUnreferencedKeys of Dictionary
#atNewIndex:put: in #add: of Dictionary
#errorKeyNotFound in #at: of Dictionary
#error: in #errorValueNotFound of Dictionary
#error: in #errorKeyNotFound of Dictionary
#isEmpty in #hasContentsInExplorer of Dictionary
#atNewIndex:put: in #valueAtNewKey:put:atIndex:declareFrom: of Dictionary
#atNewIndex:put: in #valueAtNewKey:put:atIndex:declareFrom: of Dictionary
#shouldNotImplement in #remove:ifAbsent: of Dictionary
#errorValueNotFound in #keyAtValue: of Dictionary
#removeKey: in #keysAndValuesRemove: of Dictionary
#error: in #asFourCode of String
#inject:into: in #asFourCode of String
#error: in #asFourCode of String
#subclassResponsibility in #byteAt:put: of String
#encodeForHTTPWithTextEncoding:conditionBlock: in
#encodeForHTTPWithTextEncoding: of String
#expandMacrosWithArguments: in #expandMacrosWith:with:with: of String
#asNumber in #adaptToCollection:andSend: of String
#inject:into: in #asPacked of String
#encodeForHTTPWithTextEncoding:conditionBlock: in #encodeForHTTP of String
#correctAgainstEnumerator:continuedFrom: in
#correctAgainst:continuedFrom: of String
#correctAgainstEnumerator:continuedFrom: in
#correctAgainst:continuedFrom: of String
#compare:caseSensitive: in #caseSensitiveLessOrEqual: of String
#correctAgainst:continuedFrom: in #correctAgainst: of String
#correctAgainst:continuedFrom: in #correctAgainst: of String
#compare:caseSensitive: in #caseInsensitiveLessOrEqual: of String
#readStream in #convertFromWithConverter: of String
#first in #startsWithDigit of String
#translateWith: in #translateToLowercase of String
#copyReplaceAll:with: in #asHtml of String
#indexOfAnyOf:startingAt: in #unescapePercentsWithTextEncoding: of String
#copyFrom:to: in #unescapePercentsWithTextEncoding: of String
#copyFrom:to: in #unescapePercentsWithTextEncoding: of String
#reverseDo: in #romanNumber of String
#last in #endsWithDigit of String
#error: in #utf8ToIso of String
#error: in #utf8ToIso of String
#error: in #utf8ToIso of String
#subclassResponsibility in #byteSize of String
#first in #withoutQuoting of String
#copyFrom:to: in #withoutQuoting of String
#findTokens: in #findTokens:includes: of String
#last in #numArgs of String
#substrings in #subStrings of String
#displayOn:at: in #displayAt: of String
#findString:startingAt: in #includesSubString: of String
#isEmpty in #withSeparatorsCompacted of String
#readStream in #withSeparatorsCompacted of String
#copyFrom:to: in #tabDelimitedFieldsDo: of String
#copyFrom:to: in #truncateWithElipsisTo: of String
#copyFrom:to: in #truncateTo: of String
#asText in #asParagraph of String
#expandMacrosWithArguments: in #expandMacrosWith:with:with:with: of String
#displayOn:at: in #displayOn: of String
#translateFrom:to:table: in #translateWith: of String
#copyFrom:to: in #findTokens: of String
#copyFrom:to: in #linesDo: of String
#asNumber in #adaptToNumber:andSend: of String
#copyFrom:to: in #findTokens:keep: of String
#copyFrom:to: in #findTokens:keep: of String
#readStream in #convertToSystemString of String
#expandMacrosWithArguments: in #expandMacrosWith: of String
#copyFrom:to: in #compressWithTable: of String
#first in #asCharacter of String
#correctAgainstEnumerator:continuedFrom: in
#correctAgainstDictionary:continuedFrom: of String
#correctAgainstEnumerator:continuedFrom: in
#correctAgainstDictionary:continuedFrom: of String
#subclassResponsibility in #byteAt: of String
#ifEmpty: in #withFirstCharacterDownshifted of String
#copyFrom:to: in #withoutLeadingBlanks of String
#errorOutOfBounds in #asAlphaNumeric:extraChars:mergeUID: of String
#asDisplayText in #displayOn:at:textColor: of String
#indexOfAnyOf:startingAt: in #indexOfAnyOf: of String
#printString in #asExplorerString of String
#error: in #startingAt:match:startingAt: of String
#error: in #startingAt:match:startingAt: of String
#copyFrom:to: in #startingAt:match:startingAt: of String
#last in #endsWithAColon of String
#convertToEncoding: in #convertToSuperSwikiServerString of String
#copyFrom:to: in #withBlanksTrimmed of String
#findAnySubStr:startingAt: in #findBetweenSubStrs: of String
#copyFrom:to: in #findBetweenSubStrs: of String
#copyFrom:to: in #withoutLeadingDigits of String
#first in #initialIntegerOrNil of String
#copyFrom:to: in #initialIntegerOrNil of String
#findString:startingAt: in #findString: of String
#copyFrom:to: in #do:toFieldNumber: of String
#readStream in #convertToWithConverter: of String
#copyFrom:to: in #withoutTrailingDigits of String
#error: in #subStrings: of String
#error: in #asUnHtml of String
#serviceOrNil in #service of String
#copyFrom:to: in #contractTo: of String
#copyReplaceFrom:to:with: in #contractTo: of String
#stemAndNumericSuffix in #numericSuffix of String
#asNumber in #adaptToString:andSend: of String
#displayOn:at:textColor: in #displayOn:at: of String
#first in #asLegalSelector of String
#asNumber in #adaptToPoint:andSend: of String
#copyFrom:to: in #substrings of String
#copyFrom:to: in #withoutTrailingBlanks of String
#convertFromEncoding: in #convertFromSuperSwikiServerString of String
#translateWith: in #translateToUppercase of String
#error: in #withNoLineLongerThan: of String
#copyFrom:to: in #withNoLineLongerThan: of String
#copyFrom:to: in #withNoLineLongerThan: of String
#copyFrom:to: in #withNoLineLongerThan: of String
#copyFrom:to: in #translatedIfCorresponds of String
#readStream in #format: of String
#getEnclosedExpressionFrom: in #format: of String
#alike: in #correctAgainstEnumerator:continuedFrom: of String
#asNumber in #splitInteger of String
#first in #splitInteger of String
#copyFrom:to: in #splitInteger of String
#copyFrom:to: in #splitInteger of String
#copyFrom:to: in #splitInteger of String
#copyFrom:to: in #splitInteger of String
#copyReplaceAll:with:asTokens: in #copyReplaceTokens:with: of String
#isEmpty in #writeLeadingCharRunsOn: of String
#last in #writeLeadingCharRunsOn: of String
#asText in #asDisplayText of String
#expandMacrosWithArguments: in #expandMacros of String
#compare:caseSensitive: in #sameAs: of String
#findString:startingAt: in #lineNumber: of String
#findString:startingAt: in #lineNumber: of String
#copyFrom:to: in #lineNumber: of String
#isEmpty in #capitalized of String
#compare:caseSensitive: in #compare: of String
#expandMacrosWithArguments: in #expandMacrosWith:with: of String

Reply | Threaded
Open this post in threaded view
|

Send performance/real closures question

J J-6
In reply to this post by Bryce Kampjes
>From: Bryce Kampjes <[hidden email]>
>Reply-To: The general-purpose Squeak developers
>list<[hidden email]>
>To: The general-purpose Squeak developers
>list<[hidden email]>
>Subject: Re: [Enh][VM] primitiveApplyToFromTo for the heart of
>theenumeration of collections?
>Date: Sun, 17 Sep 2006 17:22:25 +0100
>
>Anthony Hannan's send performance work was rejected even though it
>did speed up sends and came with proper block closures. Proper block
>closures are something we really should have.
>
>Bryce

Why was this work rejected?  What was wrong with it, and can it still be
downloaded?



12345