Compare commits

..

No commits in common. "master" and "detached/2" have entirely different histories.

141 changed files with 284 additions and 1116 deletions

View File

@ -5,13 +5,10 @@ baseline: spec
for: #common for: #common
do: [ do: [
"Dependencies" "Dependencies"
"self xmlParserHTML: spec." self xmlParserHTML: spec.
self reStore: spec. "self rssTools: spec."
self miniDocs: spec.
"self roassal3Exporters: spec."
"self tiddlyWikiPharo: spec."
"Packages" "Packages"
spec spec
package: 'Socialmetrica' package: 'Socialmetrica'
with: [ spec requires: #('ReStore' 'MiniDocs' "'XMLParserHTML' 'Roassal3Exporters' 'TiddlyWikiPharo'") ] with: [ spec requires: #('XMLParserHTML' "'RSSTools'") ]
] ]

View File

@ -1,8 +0,0 @@
accessing
miniDocs: spec
| repo |
repo := ExoRepo new
repository: 'https://code.sustrato.red/Offray/MiniDocs'.
repo load.
spec baseline: 'MiniDocs' with: [ spec repository: 'gitlocal://', repo local fullName ]

View File

@ -1,10 +0,0 @@
baselines
reStore: spec
Metacello new
repository: 'github://rko281/ReStoreForPharo';
baseline: 'ReStore';
onConflict: [ :ex | ex useLoaded ];
onWarningLog;
load: 'all'.
spec baseline: 'ReStore' with: [ spec repository: 'github://rko281/ReStoreForPharo']

View File

@ -1,7 +0,0 @@
baselines
roassal3Exporters: spec
Metacello new
baseline: 'Roassal3Exporters';
repository: 'github://ObjectProfile/Roassal3Exporters';
load.
spec baseline: 'Roassal3Exporters' with: [ spec repository: 'github://ObjectProfile/Roassal3Exporters']

View File

@ -0,0 +1,10 @@
baselines
rssTools: spec
Metacello new
repository: 'github://brackendev/RSSTools-Pharo:v1.0.1/src';
baseline: 'RSSTools';
onConflict: [ :ex | ex useLoaded ];
onUpgrade: [ :ex | ex useLoaded ];
onDowngrade: [ :ex | ex useLoaded ];
load.
spec baseline: 'RSSTools' with: [ spec repository: 'github://brackendev/RSSTools-Pharo:v1.0.1/src']

View File

@ -1,8 +0,0 @@
baselines
tiddlyWikiPharo: spec
| repo |
repo := ExoRepo new
repository: 'https://code.sustrato.red/Offray/TiddlyWikiPharo'.
repo load.
spec baseline: 'TiddlyWikiPharo' with: [ spec repository: 'gitlocal://', repo local fullName ]

View File

@ -4,6 +4,8 @@ xmlParserHTML: spec
baseline: 'XMLParserHTML'; baseline: 'XMLParserHTML';
repository: 'github://pharo-contributions/XML-XMLParserHTML/src'; repository: 'github://pharo-contributions/XML-XMLParserHTML/src';
onConflict: [ :ex | ex useLoaded ]; onConflict: [ :ex | ex useLoaded ];
onUpgrade: [ :ex | ex useLoaded ];
onDowngrade: [ :ex | ex useLoaded ];
onWarningLog; onWarningLog;
load. load.
spec baseline: 'XMLParserHTML' with: [spec repository: 'github://pharo-contributions/XML-XMLParserHTML/src'] spec baseline: 'XMLParserHTML' with: [spec repository: 'github://pharo-contributions/XML-XMLParserHTML/src']

View File

@ -6,7 +6,7 @@ To install, first install [ExoRepo](https://code.tupale.co/Offray/ExoRepo) and t
```smalltalk ```smalltalk
ExoRepo new ExoRepo new
repository: 'https://code.sustrato.red/Offray/Socialmetrica'; repository: 'https://code.tupale.co/Offray/Socialmetrica';
load. load.
``` ```

View File

@ -1,8 +0,0 @@
accessing
columnsDictionary
^ {
'url' -> 'url' .
'healthy' -> 'healthy'.
'healthy_percentage_overall' -> 'uptime' .
'rss' -> 'rss' .
'version' -> 'version'} asDictionary

View File

@ -1,4 +0,0 @@
accessing
exportInstanceReport
MiniDocs exportAsSton: self instances on: FileLocator temp / 'instances.ston'.
^ FileLocator temp / 'instances.ston'

View File

@ -1,8 +0,0 @@
accessing
instanceRows
^ (self instances at: 'hosts') collect: [:rawRow | | newRow |
newRow := NitterInstance new.
self columnsDictionary keysAndValuesDo: [:key :value |
newRow writeSlotNamed: value value: (rawRow at: key) ].
newRow
].

View File

@ -1,3 +0,0 @@
accessing
instances
^ self instanceRows

View File

@ -1,9 +0,0 @@
accessing
instancesCache
| cache cacheFile |
cacheFile := FileLocator temp / 'nitter-instances.ston'.
cacheFile exists
ifFalse: [
cache := STON fromString: 'https://status.d420.de/api/v1/instances' asUrl retrieveContents.
MarkupFile exportAsFileOn: cacheFile containing: cache ].
^ STON fromString: cacheFile contents

View File

@ -1,2 +0,0 @@
accessing
instancesTable

View File

@ -1,21 +0,0 @@
accessing
viewInstancesFor: aView
<gtView>
| columnedList columnNamesMap |
self instances isEmptyOrNil ifTrue: [ ^ aView empty].
columnedList := aView columnedList
title: 'Instances';
items: [ self instanceRows ];
priority: 1.
columnNamesMap := {
'Instance' -> 'url'.
'Healthy' -> 'healthy'.
'Uptime %' -> 'uptime'.
'RSS' -> 'rss'.
'Nitter Version' -> 'version'} asOrderedDictionary.
columnNamesMap keysAndValuesDo: [:aName :value |
columnedList
column: aName
text: [:instanceRow | (instanceRow readSlotNamed: value) ifNil: [''] ]
].
^ columnedList

View File

@ -1,11 +0,0 @@
{
"commentStamp" : "",
"super" : "Object",
"category" : "Socialmetrica",
"classinstvars" : [ ],
"pools" : [ ],
"classvars" : [ ],
"instvars" : [ ],
"name" : "Nitter",
"type" : "normal"
}

View File

@ -1,7 +0,0 @@
I model a Nitter instance uptime & health tracker as described in https://status.d420.de/about.
Taken from the official documentation, in the previous linkm the fields we are modelling are:
- healthy: stands for hosts which are reachable and pass a content check.
- rss: whether the host has RSS feeds enabled.
- version: which nitter version the host reports.

View File

@ -1,3 +0,0 @@
accessing
hasRSS
^ self rss

View File

@ -1,3 +0,0 @@
accessing
healthy
^ healthy

View File

@ -1,3 +0,0 @@
accessing
isHealthy
^ self healthy

View File

@ -1,5 +0,0 @@
accessing
printOn: aStream
super printOn: aStream.
^ aStream
nextPutAll: '( ', self url ,' | uptime: ', self uptime asString, ' )'

View File

@ -1,3 +0,0 @@
accessing
rss
^ rss

View File

@ -1,3 +0,0 @@
accessing
uptime
^ uptime

View File

@ -1,3 +0,0 @@
accessing
url
^ url

View File

@ -1,17 +0,0 @@
{
"commentStamp" : "<historical>",
"super" : "Object",
"category" : "Socialmetrica",
"classinstvars" : [ ],
"pools" : [ ],
"classvars" : [ ],
"instvars" : [
"url",
"healthy",
"uptime",
"rss",
"version"
],
"name" : "NitterInstance",
"type" : "normal"
}

View File

@ -3,4 +3,4 @@ nitterProvider
"For a full list of Nitter providers, see: "For a full list of Nitter providers, see:
https://github.com/zedeus/nitter/wiki/Instances" https://github.com/zedeus/nitter/wiki/Instances"
^ 'https://nitter.net/' ^ 'https://nitter.42l.fr/'

View File

@ -1,29 +1,7 @@
accessing accessing
asDictionary asDictionary
| tweets tweetsHistogramData repliesHistogramData quotesHistogramData retweetsHistogramData | ^ { 'profile-card-avatar' -> self profileImageFile values first fullName.
[self config at: 'lang']
onErrorDo: [ ^ self inform: 'Please put a lang key with a language (for example: en) in the object config.' ].
tweets := self messages.
tweetsHistogramData := self tweetsByWeeksTimeSpan.
repliesHistogramData := self repliesByWeeksTimeSpan.
quotesHistogramData := self quotesReportData.
retweetsHistogramData := self retweetsReportData.
^ { 'profile-card-avatar' -> self profileImageFile fullName.
'profile-card-avatar-url' -> self profileImageUrl.
'profile-card-fullname' -> self name . 'profile-card-fullname' -> self name .
'profile-card-username' -> self userName . 'profile-card-username' -> self userName .
'profile-bio' -> self profileBio. 'profile-bio' -> self profileBio } asDictionary
'messages-size' -> tweets size.
'messages-newest' -> tweets newest created asDate greaseString.
'messages-oldest' -> tweets oldest created asDate greaseString.
'tweets-histogram-labels' -> tweetsHistogramData third.
'tweets-histogram-quantity' -> tweetsHistogramData second.
'replies-histogram-labels' -> repliesHistogramData third.
'replies-histogram-quantity' -> repliesHistogramData second.
'retweets-histogram-labels' -> retweetsHistogramData third.
'retweets-histogram-quantity' -> retweetsHistogramData second.
'quotes-histogram-labels' -> quotesHistogramData third.
'quotes-histogram-quantity' -> quotesHistogramData second.
'wordcloud-data' -> (self wordcloudDataLanguage: (self config at: 'lang')) first.
} asDictionary

View File

@ -1,28 +0,0 @@
accessing
asDictionaryForWeb
| tweets tweetsHistogramData repliesHistogramData quotesHistogramData retweetsHistogramData |
tweets := self messages.
tweetsHistogramData := self tweetsByTimeSpan: 7.
repliesHistogramData := self repliesByTimeSpan: 7.
quotesHistogramData := self quotesReportData.
retweetsHistogramData := self retweetsReportData.
^ { 'profile-card-avatar' -> self profileImageFile fullName.
'profile-card-avatar-url' -> self profileImageUrl.
'profile-card-fullname' -> self name .
'profile-card-username' -> self userName .
'profile-bio' -> self profileBio.
'messages-size' -> tweets size.
'messages-newest' -> tweets newest created asDate greaseString.
'messages-oldest' -> tweets oldest created asDate greaseString.
'tweets-histogram-labels' -> tweetsHistogramData third.
'tweets-histogram-quantity' -> tweetsHistogramData second.
'replies-histogram-labels' -> repliesHistogramData third.
'replies-histogram-quantity' -> repliesHistogramData second.
'retweets-histogram-labels' -> retweetsHistogramData third.
'retweets-histogram-quantity' -> retweetsHistogramData second.
'quotes-histogram-labels' -> quotesHistogramData third.
'quotes-histogram-quantity' -> quotesHistogramData second.
'wordcloud-data' -> self wordcloudData first.
} asDictionary

View File

@ -1,16 +0,0 @@
accessing
asTiddler
| tempDict tiddler |
tiddler := Tiddler new.
tiddler customFields.
tempDict := self asDictionary.
tempDict keysAndValuesDo: [ :key :value |
tiddler customFields at: key put: value
].
^ tiddler
created;
title: (tiddler customFields at: 'profile-card-username');
type: 'text/vnd.tiddlywiki';
text:
'<<image-card "', self profileImageUrl, '" title:', ($' asString), '<$transclude field="profile-card-fullname"/>', ($' asString), 'text:', ($' asString), '<$transclude field="profile-bio"/>', ($' asString), 'footer:', ($' asString), '@<$transclude field="profile-card-username"/>', ($' asString), 'align:"center" pos:"top">>'.

View File

@ -1,4 +0,0 @@
accessing
authorIds
^ TwitterUser storedInstances select: [ :each | each userName = self userName ] thenCollect: [ :each | each id ]

View File

@ -1,12 +1,10 @@
accessing accessing
avatarPicture avatarPicture
| response profileImgFile| | response tempImage |
profileImgFile := self profileImageFile.
profileImgFile exists
ifTrue: [ ^ (ImageReadWriter formFromFileNamed: profileImgFile fullName) asElement ].
response := ZnClient new url: (self profileImageUrl); get; response. response := ZnClient new url: (self profileImageUrl); get; response.
response contentType = ZnMimeType imageJpeg response contentType = ZnMimeType imageJpeg
ifTrue: [ ^ (PluginBasedJPEGReadWriter gtFromBuffer: response contents) asElement ]. ifTrue: [ ^ (PluginBasedJPEGReadWriter gtFromBuffer: response contents) asElement ].
response contentType = ZnMimeType imagePng response contentType = ZnMimeType imagePng
ifTrue: [ ^ (PNGReadWriter gtFromBuffer: response contents) asElement ]. ifTrue: [ ^ (PNGReadWriter gtFromBuffer: response contents) asElement ].
^ GtABContact new avatar tempImage on: Error do: [ ^ GtABContact new avatar ].
^ tempImage value asElement .

View File

@ -1,33 +0,0 @@
accessing
collectRawTweetsFrom: anUrl upToPage: anInteger
| pagesDict response customQuery |
pagesDict := self getPagesContentsFrom: anUrl upTo: anInteger.
response := TweetsCollection new.
customQuery := Dictionary new
at: 'parameters' put: pagesDict keys;
at: 'date' put: DateAndTime now;
yourself.
response query: customQuery.
pagesDict keysAndValuesDo: [ :key :rawTweets | | temp |
temp := (rawTweets xpath: '//div[@class="timeline-item "]') asOrderedCollection
collect: [ :xmlElement | xmlElement postCopy ].
temp do: [ :tweet | | tempTweet |
tempTweet := Tweet new fromNitterHtmlItem: tweet.
tempTweet metadata
at: DateAndTime now asString put: key;
yourself.
response add: tempTweet.
]
].
response messages: (response messages select: [ :tweet | tweet isNotNil ]).
response messages doWithIndex: [ :tweet :i |
| current previous |
current := response messages at: i.
i < response lastIndex ifTrue: [
previous := response messages at: i + 1.
current timelines
at: self userName put: previous id;
yourself ]].
^ response.

View File

@ -1,5 +0,0 @@
accessing
collectRawTweetsFromOldestUpToPage: anInteger
^ self collectRawTweetsFrom: self oldestTweetPageCursor upToPage: anInteger

View File

@ -1,5 +1,32 @@
accessing accessing
collectRawTweetsUpToPage: anInteger collectRawTweetsUpToPage: anInteger
^ self collectRawTweetsFrom: self userNameLinkWithReplies upToPage: anInteger | pagesDict response customQuery |
pagesDict := self getPagesContentsUpto: anInteger.
response := TweetsCollection new.
customQuery := Dictionary new
at: 'parameters' put: pagesDict keys;
at: 'date' put: DateAndTime now;
yourself.
response query: customQuery.
pagesDict keysAndValuesDo: [ :key :rawTweets | | temp |
temp := (rawTweets xpath: '//div[@class="timeline-item "]') asOrderedCollection
collect: [ :xmlElement | xmlElement postCopy ].
temp do: [ :tweet | | tempTweet |
tempTweet := Tweet new fromNitterHtmlItem: tweet.
tempTweet metadata
at: DateAndTime now asString put: key;
yourself.
response messages add: tempTweet.
]
].
response messages doWithIndex: [ :tweet :i |
| current previous |
current := response messages at: i.
i < response messages size ifTrue: [
previous := response messages at: i + 1.
current timelines
at: self userName put: previous id;
yourself ]].
^ response.

View File

@ -1,8 +0,0 @@
accessing
configureDefaultReportingPeriod
[ config at: 'reportingPeriod' ]
onErrorDo: [ self config
at: 'reportingPeriod'
put: (Timespan
starting: messages oldest created asDateAndTime
ending: messages newest created asDateAndTime + 1 minute) ]

View File

@ -2,7 +2,5 @@ accessing
createdAt createdAt
^ createdAt ifNil: [| joinDateString | ^ createdAt ifNil: [| joinDateString |
joinDateString := ((self documentTree xpath: '//div[@class="profile-joindate"]/span/@title') stringValue). joinDateString := ((self documentTree xpath: '//div[@class="profile-joindate"]/span/@title') stringValue).
createdAt := (ZTimestampFormat fromString:'4:05 PM - 03 Feb 2001') parse: joinDateString.
createdAt := (ZTimestampFormat fromString:'4:05 PM - 3 Feb 2001') parse: joinDateString.
createdAt := createdAt asDateAndTime
] ]

View File

@ -1,3 +1,3 @@
operation operation
documentTree documentTree
^ self documentTreeFor: self userNameLinkWithReplies ^ self documentTreeFor: (self userNameLink, '/with_replies')

View File

@ -1,12 +1,4 @@
accessing accessing
downloadProfileImage downloadProfileImage
self remoteIsFound ^ self exportProfileImageOn: self folder / 'profile-image', 'jpg'
ifTrue: [ ^ self exportProfileImageOn: self folder / 'profile-image', 'jpg' ]
ifFalse: [ | tempFile |
tempFile := (self folder / 'profile-image', 'jpg') asFileReference.
tempFile ensureCreateFile.
tempFile binaryWriteStreamDo: [ :stream |
stream nextPutAll: 'https://mutabit.com/repos.fossil/mutabit/uv/wiki/commons/twitter-user-image-default.jpg' asUrl retrieveContents.
super class inform: 'Exported as: ', String cr, tempFile fullName.
^ self folder / 'profile-image', 'jpg' ]]

View File

@ -1,40 +0,0 @@
as yet unclassified
downloadWithRenaming: fileReference
| file tempFile fileHash tempFileHash |
file := fileReference asFileReference .
tempFile := FileLocator temp / fileReference basename.
tempFile ensureCreateFile.
tempFile binaryWriteStreamDo: [ :stream |
stream nextPutAll: profileImageUrl asUrl retrieveContents.
super class inform: 'Exported as: ', String cr, tempFile fullName.
].
OSSUnixSubprocess new
command: 'openssl';
arguments: { 'dgst' . '-sha256' . file fullName};
workingDirectory: (self folder) fullName;
redirectStdout;
redirectStderr;
runAndWaitOnExitDo: [ :process :outString |
fileHash := (outString splitOn: ' ') second trimmed].
OSSUnixSubprocess new
command: 'openssl';
arguments: { 'dgst' . '-sha256' . tempFile fullName};
workingDirectory: (self folder) fullName;
redirectStdout;
redirectStderr;
runAndWaitOnExitDo: [ :process :outString |
tempFileHash := (outString splitOn: ' ' ) second trimmed].
fileHash = tempFileHash
ifFalse: [
file copyTo: self folder /
(file basenameWithoutExtension , '-',
('-' join:
((file creationTime asLocalStringYMDHM) splitOn: ' ')), '.jpg').
file ensureDelete.
^ { 'Profile image changed' ->
(tempFile moveTo: file)} asDictionary ].
^ { 'Same Profile Image' -> file } asDictionary

View File

@ -1,6 +1,4 @@
accessing accessing
exportDefaultReport exportDefaultReport
(self hasFolder: 'templates') ^ self exportWithTemplate: TweetsCollection dataStore / 'templates' / 'template.mus.tex' into: self folder
ifFalse: [ self installTemplate ].
^ self exportWithTemplate: (TweetsCollection dataStore / 'templates' / 'template.mus.tex') into: self folder

View File

@ -1,9 +0,0 @@
accessing
exportEmptyHistogramNamed: aDictionary
| histogram |
histogram := RSChart new.
histogram extent: (aDictionary at: 'extent').
histogram build.
histogram canvas exportAsFileNamed: (aDictionary at: 'messagesType'), '-histogram' into: self folder.
^ self

View File

@ -1,49 +0,0 @@
accessing
exportHistogramFor: aDictionary By: aTypeString
"TODO: quotes and retweets"
| messagesDict histogram diagram tempMessages labels subtotals |
tempMessages := self perform: (aDictionary at: 'messagesType') asSymbol.
tempMessages ifEmpty: [ self exportEmptyHistogramNamed:
(aDictionary at: 'messagesType'), '-histogram' ].
((((aDictionary at: 'messagesType') = 'tweets') or: [(aDictionary at: 'messagesType') = 'replies'])
and: aTypeString isNumber)
ifTrue: [ messagesDict := tempMessages splitBytimeSpansOf: aTypeString ].
(aTypeString = 'day' or: [ aTypeString = 'days' ])
ifTrue: [ messagesDict := tempMessages splitByDays ].
(aTypeString = 'week' or: [ aTypeString = 'weeks' ])
ifTrue: [ messagesDict := tempMessages splitByWeeks ].
(((aDictionary at: 'messagesType') = 'retweets') or: [ (aDictionary at: 'messagesType') = 'quotes' ])
ifTrue: [
messagesDict := tempMessages asMessagesUserNamesSortedByOccurrences.
((aTypeString > messagesDict size) or: [ aTypeString = 1 ])
ifFalse: [ | keysToRemove |
keysToRemove := OrderedCollection new.
1 to: messagesDict size - aTypeString do:
[ :i | keysToRemove add: (messagesDict keys at: i + aTypeString) ].
messagesDict removeKeys: keysToRemove. ].
labels := messagesDict keys.
labels := labels collect: [ :profiles | ('@', profiles) ].
subtotals := messagesDict values
]
ifFalse: [ labels := messagesDict keys.
subtotals := (messagesDict values collect: [ :collection | collection size ])].
histogram := RSChart new.
histogram extent: (aDictionary at: 'extent').
diagram := RSBarPlot new
y: subtotals.
diagram color: (aDictionary at: 'color').
histogram addPlot: diagram.
histogram addDecoration: (RSHorizontalTick new
fromNames: labels;
labelRotation: 0;
fontSize: 68 /messagesDict size;
yourself).
histogram addDecoration: (RSVerticalTick new
integer;
fontSize: 68 /messagesDict size).
histogram build.
^ histogram canvas exportAsFileNamed: (aDictionary at: 'messagesType'), '-histogram' into: self folder

View File

@ -1,11 +0,0 @@
accessing
exportOverviewReportLatex
| weeks floor divisions |
weeks := ((self newestTweet created - self oldestTweet created) days / 7).
floor := weeks floor.
(weeks - floor) > 0.4
ifTrue: [ divisions := floor ]
ifFalse: [ divisions := floor + 1 ].
self exportOverviewReportLatexWithBars: divisions.
^ self folder

View File

@ -1,11 +0,0 @@
accessing
exportOverviewReportLatexWithBars: anInteger
self
exportDefaultReport;
externalWordCloud;
exportTweetsHistogramWithBars: anInteger;
exportRetweetsHistogramWithBars: anInteger;
exportRepliesHistogramWithBars: anInteger;
exportQuotesHistogramWithBars: anInteger.
^ self folder

View File

@ -1,13 +1,48 @@
accessing accessing
exportProfileImageOn: fileReference exportProfileImageOn: fileReference
| file | | file tempFile tempFileHash fileHash |
file := fileReference asFileReference. file := fileReference asFileReference.
file exists ifFalse: [ file exists
file ensureCreateFile. ifFalse: [ file ensureCreateFile.
file binaryWriteStreamDo: [ :stream | file binaryWriteStreamDo: [ :stream |
stream nextPutAll: profileImageUrl asUrl retrieveContents ]. stream nextPutAll: profileImageUrl retrieveContents ].
self class inform: 'Exported as: ', String cr, file fullName. super class inform: 'Exported as: ', String cr, file fullName.
^ file ^ file]
].
self downloadWithRenaming: fileReference ifTrue: [
tempFile := FileLocator temp / fileReference basename.
tempFile ensureCreateFile.
tempFile binaryWriteStreamDo: [ :stream |
stream nextPutAll: profileImageUrl asUrl retrieveContents.
super class
inform: 'Exported as: ', String cr, tempFile fullName. ].
OSSUnixSubprocess new
command: 'openssl';
arguments: { 'dgst' . '-sha256' . file fullName};
workingDirectory: (self folder)fullName;
redirectStdout;
redirectStderr;
runAndWaitOnExitDo: [ :process :outString |
fileHash := (outString splitOn: ' ' ) second trimmed].
OSSUnixSubprocess new
command: 'openssl';
arguments: { 'dgst' . '-sha256' . tempFile fullName};
workingDirectory: (self folder)fullName;
redirectStdout;
redirectStderr;
runAndWaitOnExitDo: [ :process :outString |
tempFileHash := (outString splitOn: ' ' ) second trimmed].
fileHash = tempFileHash
ifFalse: [
file copyTo: self folder /
(file basenameWithoutExtension , '-',
('-' join:
((file creationTime asLocalStringYMDHM) splitOn: ' ')), '.jpg').
file ensureDelete.
^ { 'Profile image changed' ->
(tempFile moveTo: file)} asDictionary ]].
^ { 'Same Profile Image' -> file } asDictionary

View File

@ -1,49 +0,0 @@
accessing
exportQuotesHistogramWithBars: aNumberOfBars
| quotesDict |
quotesDict := {
'messagesType' -> 'quotes'.
'extent' -> (800@200).
'color' -> (Color r:(89/255) g:(217/255) b:(95/255))
} asDictionary.
^ self exportHistogramFor: quotesDict By: aNumberOfBars
"| keysToRemove quotes labels quotesHistogram diagram |
quotes := self quotes asMessagesUserNamesSortedByOccurrences.
(aNumberOfBars > quotes size) ifTrue: [ ^ self exportQuotesHistogram ].
keysToRemove := OrderedCollection new.
1 to: quotes size - aNumberOfBars do:
[ :i | keysToRemove add: (quotes keys at: i + aNumberOfBars) ].
quotes removeKeys: keysToRemove.
labels := quotes keys.
labels := labels collect: [ :profiles | ('@', profiles) ].
quotesHistogram := RSChart new.
quotesHistogram extent: 800@200.
diagram := RSBarPlot new
y: quotes values.
diagram color: (Color r:(89/255) g:(217/255) b:(95/255)).
quotesHistogram addPlot: diagram.
quotesHistogram addDecoration: (RSHorizontalTick new
fromNames: labels;
labelRotation: 0;
fontSize: 72 /quotes size;
yourself).
quotesHistogram addDecoration: (RSVerticalTick new
asFloat: 2;
fontSize: 72 /quotes size).
quotesHistogram build.
quotesHistogram canvas pdfExporter
zoomToShapes;
noFixedShapes;
fileName: (self folder / 'quotes-histogram.pdf')fullName;
export.
quotesHistogram canvas pngExporter
zoomToShapes;
noFixedShapes;
fileName: (self folder / 'quotes-histogram.png')fullName;
export.
^ self folder / 'quotes-histogram.png'"

View File

@ -1,10 +1,34 @@
accessing accessing
exportRepliesHistogramWithBars: aNumberOfBars exportRepliesHistogramWithBars: aNumberOfBars
| repliesDict | | tweetsByTimeSpan subtotals repliesColor x tweetsHistogram diagram |
repliesDict := {
'messagesType' -> 'replies'. tweetsByTimeSpan := self collectMessages: [ self replies ] byTimeSpanSplits: aNumberOfBars.
'extent' -> (800@200). subtotals := tweetsByTimeSpan values collect: [ :collection | collection size ].
'color' -> (Color r:(246/255) g:(185/255) b:(46/255)) repliesColor := (Color r:(246/255) g:(185/255) b:(46/255)).
} asDictionary. x := 1 to: subtotals size.
^ self exportHistogramFor: repliesDict By: aNumberOfBars tweetsHistogram := RSChart new.
tweetsHistogram extent: 800@200.
diagram := RSBarPlot new x: x y:subtotals.
diagram color: repliesColor.
tweetsHistogram addPlot: diagram.
tweetsHistogram addDecoration: (RSHorizontalTick new
fromNames: tweetsByTimeSpan keys;
labelRotation: 0;
fontSize: 80 /aNumberOfBars;
yourself).
tweetsHistogram addDecoration: (RSVerticalTick new
integer;
fontSize: 80 /aNumberOfBars).
tweetsHistogram build.
tweetsHistogram canvas pngExporter
zoomToShapes;
noFixedShapes;
fileName: (self folder / 'replies-histogram.png')fullName;
export.
tweetsHistogram canvas pdfExporter
zoomToShapes;
noFixedShapes;
fileName: (self folder / 'replies-histogram.pdf')fullName;
export.
^ self folder / 'replies-histogram.png'

View File

@ -1,10 +0,0 @@
accessing
exportRetweetsHistogramWithBars: aNumberOfBars
| retweetsDict |
retweetsDict := {
'messagesType' -> 'retweets'.
'extent' -> (800@200).
'color' -> (Color r:(217/255) g:(56/255) b: (124/255))
} asDictionary.
^ self exportHistogramFor: retweetsDict By: aNumberOfBars

View File

@ -1,8 +0,0 @@
accessing
exportStaticWebReport
(self hasFolder: 'commons')
ifFalse: [ self installCommons ].
(self hasFolder: 'templates')
ifFalse: [ self installTemplate ].
^ self exportWithTemplate: (TweetsCollection dataStore / 'templates' / 'index.mus.html') into: self folder

View File

@ -1,10 +1,34 @@
accessing accessing
exportTweetsHistogramWithBars: aNumberOfBars exportTweetsHistogramWithBars: aNumberOfBars
| tweetsDict | | tweetsByTimeSpan subtotals tweetsColor x tweetsHistogram diagram |
tweetsDict := {
'messagesType' -> 'tweets'. tweetsByTimeSpan := self collectMessages: [ self tweets] byTimeSpanSplits: aNumberOfBars.
'extent' -> (800@200). subtotals := tweetsByTimeSpan values collect: [ :collection | collection size ].
'color' -> (Color r:(91/255) g:(131/255) b:(222/255)) tweetsColor := (Color r:(91/255) g:(131/255) b:(222/255)).
} asDictionary. x := 1 to: subtotals size.
^ self exportHistogramFor: tweetsDict By: aNumberOfBars tweetsHistogram := RSChart new.
tweetsHistogram extent: 800@200.
diagram := RSBarPlot new x: x y:subtotals.
diagram color: tweetsColor.
tweetsHistogram addPlot: diagram.
tweetsHistogram addDecoration: (RSHorizontalTick new
fromNames: tweetsByTimeSpan keys;
labelRotation: 0;
fontSize: 80 /aNumberOfBars;
yourself).
tweetsHistogram addDecoration: (RSVerticalTick new
integer;
fontSize: 80 /aNumberOfBars).
tweetsHistogram build.
tweetsHistogram canvas pngExporter
zoomToShapes;
noFixedShapes;
fileName: (self folder / 'tweets-histogram.png')fullName;
export.
tweetsHistogram canvas pdfExporter
zoomToShapes;
noFixedShapes;
fileName: (self folder / 'tweets-histogram.pdf')fullName;
export.
^ self folder / 'tweets-histogram.png'

View File

@ -1,11 +0,0 @@
accessing
exportWeekReportLatexBeginningAt: aDay
self config
at: 'reportingPeriod'
put: (Timespan starting: aDay asDateAndTime ending: ( aDay asDateAndTime + 7 days)).
self messages: self messages.
self
exportDefaultReport;
externalWordCloud.
^ self folder

View File

@ -1,29 +1,13 @@
accessing accessing
exportWithTemplate: mustacheFile into: folder exportWithTemplate: mustacheFile into: folder
| tempDictionary bioModified userModified nameModified | | tempDictionary modified |
tempDictionary := self asDictionary copy. tempDictionary := self asDictionary copy.
(mustacheFile fullName endsWith: '.html') modified := self asDictionary at: 'profile-bio'.
ifTrue: [ ^ MarkupFile modified := modified copyReplaceAll: '@' with: '\@'.
exportAsFileOn: (folder / self userName , 'html') modified := modified copyReplaceAll: '_' with: '\_'.
containing:(mustacheFile asMustacheTemplate value: tempDictionary)]. modified := modified copyReplaceAll: '#' with: '\#'.
tempDictionary at: 'profile-bio' put: modified.
(mustacheFile fullName endsWith: '.tex') ^ MarkupFile
ifTrue: [ bioModified := self asDictionary at: 'profile-bio'. exportAsFileOn: (folder / self userName , 'tex')
bioModified := bioModified copyReplaceAll: '@' with: '\@'. containing:(mustacheFile asMustacheTemplate value: tempDictionary)
bioModified := bioModified copyReplaceAll: '_' with: '\_'.
bioModified := bioModified copyReplaceAll: '#' with: '\#'.
bioModified := bioModified copyReplaceAll: '👑😎' with: ''.
bioModified := bioModified copyReplaceAll: '🇨🇴' with: ''.
bioModified := bioModified copyReplaceAll: '|' with: ''.
userModified := self asDictionary at: 'profile-card-username'.
userModified := userModified copyReplaceAll: '_' with: '\_'.
nameModified := self asDictionary at: 'profile-card-fullname'.
nameModified := nameModified copyReplaceAll: '🇨🇴' with: ''.
tempDictionary at: 'profile-bio' put: bioModified;
at: 'profile-card-username' put: userModified;
at: 'profile-card-fullname' put: nameModified.
^ MarkupFile
exportAsFileOn: (folder / self userName , 'tex')
containing:(mustacheFile asMustacheTemplate value: tempDictionary)]

View File

@ -1,12 +1,11 @@
accessing accessing
externalWordCloud externalWordCloud
"TO DO: refactor with externalWordCloudWithLanguage:"
| text outputFile | | text outputFile |
self areCommonFilesInstalled self areCommonFilesInstalled
ifFalse: [ self installCommons ]. ifFalse: [ self installExternalWordCloudCommons ].
self writeWordsFile. self writeWordsFile.
outputFile := (self folder / 'wordcloud.png') fullName. outputFile := (self folder / 'nube.png') fullName.
text := (self folder / 'words', 'txt') fullName. text := (self folder / 'words', 'txt') fullName.
OSSUnixSubprocess new OSSUnixSubprocess new
command: 'wordcloud_cli'; command: 'wordcloud_cli';
@ -17,9 +16,8 @@ externalWordCloud
'--height' . '357' . '--height' . '357' .
'--background' . 'white' . '--background' . 'white' .
'--mode' . 'RGBA' . '--mode' . 'RGBA' .
'--stopwords' . '../../../commons/stopwords-es.txt'. '--stopwords' . '../../../commons/stopwords-es.txt' .
"'--mask' . '../../../commons/nube-mascara.jpg'" '--mask' . '../../../commons/nube-mascara.jpg'};
};
workingDirectory: self folder fullName; workingDirectory: self folder fullName;
redirectStdout; redirectStdout;
redirectStderr; redirectStderr;

View File

@ -1,26 +0,0 @@
accessing
externalWordCloudWithLanguage: language
"I proces and render a wordcloud image without stopwords in: es and en."
| text outputFile |
self areCommonFilesInstalled
ifFalse: [ self installCommons ].
self writeWordsFile.
outputFile := (self folder / 'wordcloud.png') fullName.
text := (self folder / 'words', 'txt') fullName.
OSSUnixSubprocess new
command: 'wordcloud_cli';
arguments: { '--text' . text .
'--imagefile' . outputFile .
'--color' . '#5B83DE' .
'--width' . '1153' .
'--height' . '357' .
'--background' . 'white' .
'--mode' . 'RGBA' .
'--stopwords' . '../../../commons/stopwords-', language, '.txt'.
"'--mask' . '../../../commons/nube-mascara.jpg'"
};
workingDirectory: self folder fullName;
redirectStdout;
redirectStderr;
runAndWaitOnExitDo: [ :process :outString | ^ outputFile asFileReference ]

View File

@ -1,5 +1,4 @@
accessing accessing
getMessages getMessages
self getLocalMessages ifNil: [ self getRemoteMessagesFromRss ].
self getLocalMessages ifNil: [ self getRemoteMessagesFromHtml ].
^ self messages ^ self messages

View File

@ -1,19 +0,0 @@
accessing
getPagesContentsFrom: anURL upTo: anInteger
"I retroactively get all pages contents until a specified page number.
TO DO: should this be splitted back to two methods, one getting the page urls and other its content?
or do we always be getting the cursor urls and its contents all the time.
[ ] Benchmark alternative approaches."
| response nextPageLink previousPageLink |
response := OrderedDictionary new.
response at: anURL put: (self documentTreeFor: anURL).
previousPageLink := anURL.
anInteger - 1 timesRepeat: [ | pageCursor |
pageCursor := self pageCursorFor:previousPageLink.
nextPageLink := self userNameLink, '/with_replies', pageCursor keys first.
response at: nextPageLink put: (XMLHTMLParser parse:nextPageLink asUrl retrieveContents).
previousPageLink := nextPageLink
].
^ response

View File

@ -1,4 +0,0 @@
accessing
getPagesContentsFromOldestUpto: anInteger
^ self getPagesContentsFrom: ((self oldestTweet metadata select: [ :item | item isString and: [ item beginsWith: 'https://' ]]) values first) upTo: anInteger

View File

@ -5,4 +5,15 @@ getPagesContentsUpto: anInteger
TO DO: should this be splitted back to two methods, one getting the page urls and other its content? TO DO: should this be splitted back to two methods, one getting the page urls and other its content?
or do we always be getting the cursor urls and its contents all the time. or do we always be getting the cursor urls and its contents all the time.
[ ] Benchmark alternative approaches." [ ] Benchmark alternative approaches."
^ self getPagesContentsFrom: self userNameLinkWithReplies upTo: anInteger | response nextPageLink previousPageLink |
response := OrderedDictionary new.
response at: (self userNameLink, '/with_replies') put: self documentTree.
previousPageLink := (self userNameLink, '/with_replies').
anInteger - 1 timesRepeat: [ | pageCursor |
pageCursor := self pageCursorFor:previousPageLink.
nextPageLink := self userNameLink, '/with_replies', pageCursor keys first.
response at: nextPageLink put: pageCursor values first.
previousPageLink := nextPageLink
].
^ response

View File

@ -1,4 +0,0 @@
accessing
getRemoteMessagesFromHtml
^ messages := self collectRawTweetsUpToPage: 1

View File

@ -0,0 +1,22 @@
accessing
getRemoteMessagesFromRss
| customQuery lastTweetsRaw lastTweets |
lastTweetsRaw := self rssFeed xmlDocument xpath: '//item'.
lastTweets := TweetsCollection new.
customQuery := Dictionary new
at: 'parameters' put: self userNameLink;
at: 'date' put: DateAndTime now;
yourself.
lastTweets query: customQuery.
lastTweetsRaw doWithIndex: [ :rssTweet :i |
| current previous |
current := Tweet new fromNitterRssItem: rssTweet.
i < lastTweetsRaw size ifTrue: [
previous := Tweet new fromNitterRssItem: (lastTweetsRaw at: i + 1).
current timelines
at: self userName put: previous id;
yourself ].
current queries add: customQuery.
lastTweets add: current ].
self messages: lastTweets

View File

@ -1,6 +0,0 @@
accessing
hasFolder: folderName
| fullFolderPath |
fullFolderPath :=(TweetsCollection dataStore / folderName ).
^ fullFolderPath exists and: [ fullFolderPath children isNotEmpty ]

View File

@ -1,7 +1,3 @@
accessing accessing
id id
^ id ifNil: [ ^ id ifNil: [ id := (self profileImageUrl asUrl segments select: [ :each | each isAllDigits ]) first.]
self profileImageUrl
ifNil: [ id := 0 ]
ifNotNil: [ id := (self profileImageUrl asUrl segments select: [ :each | each isAllDigits ]) first. ]
]

View File

@ -1,22 +0,0 @@
accessing
installCommons
| commonFiles folder |
commonFiles := #(
'https://mutabit.com/repos.fossil/mutabit/raw?name=wiki/commons/stopwords-es.txt&ci=tip'
'https://mutabit.com/repos.fossil/mutabit/raw?name=wiki/commons/stopwords-en.txt&ci=tip'
'https://mutabit.com/repos.fossil/mutabit/uv/wiki/commons/nube-mascara.jpg'
'https://mutabit.com/repos.fossil/mutabit/uv/wiki/commons/logo-mutabit-negro.png').
folder := TweetsCollection dataStore / 'commons'.
folder exists
ifTrue: [ folder ensureDeleteAllChildren ]
ifFalse: [ folder ensureCreateDirectory].
commonFiles do: [ :fileUrl | | temp |
ZnClient new
url: fileUrl;
downloadTo: folder.
temp := (folder children select: [ :file | file basename includesSubstring: 'raw' ]).
temp isNotEmpty ifTrue: [
temp first renameTo: (((fileUrl splitOn: 'raw?') second splitOn: '/') last removeSuffix: '&ci=tip')].
].
^ folder

View File

@ -0,0 +1,19 @@
accessing
installExternalWordCloudCommons
| commonFiles folder |
commonFiles := #(
'https://mutabit.com/repos.fossil/mutabit/uv/wiki/commons/nube-mascara.jpg'
'https://mutabit.com/repos.fossil/mutabit/raw?name=wiki/commons/stopwords-es.txt&ci=tip').
folder := TweetsCollection dataStore / 'commons'.
folder exists
ifTrue: [ folder ensureDeleteAllChildren ]
ifFalse: [ folder ensureCreateDirectory].
commonFiles do: [ :fileUrl |
ZnClient new
url: fileUrl;
downloadTo: folder].
(folder children detect: [ :file | file basename includesSubstring: 'raw' ])
renameTo: (((commonFiles second splitOn: 'raw?') second splitOn: '/') last removeSuffix: '&ci=tip').
^ folder

View File

@ -3,11 +3,7 @@ installTemplate
| templateFiles folder | | templateFiles folder |
templateFiles := #( templateFiles := #(
'https://mutabit.com/repos.fossil/mutabit/raw?name=plantillas/TwentySecondsCV/twentysecondcvMod.cls&ci=tip' 'https://mutabit.com/repos.fossil/mutabit/raw?name=plantillas/TwentySecondsCV/twentysecondcvMod.cls&ci=tip' 'https://mutabit.com/repos.fossil/mutabit/raw?name=plantillas/TwentySecondsCV/template.mus.tex&ci=tip').
'https://mutabit.com/repos.fossil/mutabit/raw?name=plantillas/TwentySecondsCV/template.mus.tex&ci=tip'
'https://mutabit.com/repos.fossil/mutabit/raw?name=plantillas/SarissaPersonalBlog/index.mus.html&ci=tip'
'https://mutabit.com/repos.fossil/mutabit/raw?name=plantillas/SarissaPersonalBlog/output.css&ci=tip'
'https://mutabit.com/repos.fossil/mutabit/raw?name=plantillas/SarissaPersonalBlog/echarts-wordcloud.min.js&ci=tip').
folder := TweetsCollection dataStore / 'templates'. folder := TweetsCollection dataStore / 'templates'.
folder exists folder exists
ifTrue: [ folder ensureDeleteAllChildren ] ifTrue: [ folder ensureDeleteAllChildren ]

View File

@ -1,12 +0,0 @@
accessing
messages
messages ifNil: [ messages := TweetsCollection new ].
messages ifEmpty: [ self getLocalMessages ].
messages ifEmpty: [ self getRemoteMessagesFromHtml ].
config at: 'reportingPeriod' ifAbsent: [ ^ messages ].
"self configureDefaultReportingPeriod."
^ messages
select: [ :message |
message created
between: self reportingPeriod start
and: self reportingPeriod end ]

View File

@ -1,6 +1,3 @@
accessing accessing
name name
^ name ifNil: [ name := ((self rssFeed requiredItems title) splitOn: '/') first ]
| documentTree |
documentTree := [ self documentTree ] onErrorDo: [ ^ nil ].
^ name ifNil: [ name := (documentTree xpath: '//div[@class="profile-card-tabs-name"]//a[@class="profile-card-fullname"]') stringValue ]

View File

@ -1,4 +0,0 @@
accessing
newestTweet
^ (self tweets select: [ :tweet | tweet created = ((self tweets collect: [ :each | each created ]) asSortedCollection last)]) first.

View File

@ -1,4 +0,0 @@
accessing
oldestTweet
^ (self tweets select: [ :tweet | tweet created = ((self tweets collect: [ :each | each created ]) asSortedCollection first)]) first.

View File

@ -1,3 +0,0 @@
accessing
oldestTweetPageCursor
^ (self oldestTweet metadata select: [ :item | item isString and: [ item beginsWith: 'https://' ]]) values first value

View File

@ -2,8 +2,6 @@ accessing
profileImageFile profileImageFile
| file | | file |
file := (self folder / 'profile-image', 'jpg'). file := (self folder / self userName, 'jpg').
file exists ifTrue: [ file asFileReference size = 0 file exists ifTrue: [ ^ file ].
ifTrue:[ ^ self downloadProfileImage ].
^ file. ].
^ self downloadProfileImage ^ self downloadProfileImage

View File

@ -1,8 +1,4 @@
accessing accessing
profileImageUrl profileImageUrl
^ profileImageUrl ifNil: [
| documentTree | profileImageUrl := ((self rssFeed xmlDocument xpath: '//image/url') stringValue copyReplaceAll: '%2F' with: '/') ]
self remoteIsFound
ifFalse:[ ^ nil ].
documentTree := self documentTree.
^ profileImageUrl := self class nitterProvider, (((documentTree xpath: '//div[@class="profile-card-info"]//a[@class="profile-card-avatar"]') @ 'href') stringValue copyReplaceAll: '%2F' with: '/') copyWithoutFirst

View File

@ -3,7 +3,7 @@ quotes
self messages ifEmpty: [ self getMessages ]. self messages ifEmpty: [ self getMessages ].
^ TweetsCollection new ^ TweetsCollection new
messages: (self messages messages: (self messages messages
select: [ :each | select: [ :each |
(each metadata at: 'quote') isNotEmpty and: [ each user userName = self userName] ]); (each metadata at: 'quote') isNotEmpty and: [ each user userName = self userName] ]);
yourself yourself

View File

@ -1,22 +0,0 @@
accessing
quotesReportData
| tempDict labels xAxis |
self quotes isEmpty
ifTrue: [ ^ { OrderedDictionary new.
('[''', '0', ''']').
('[''', 'No quotes', ''']')} ].
tempDict := self quotes asMessagesUserNamesSortedByOccurrences.
tempDict size > 10 ifTrue: [
tempDict := (tempDict associations copyFrom: 1 to: 10) asOrderedDictionary ].
labels := tempDict keys.
labels := labels collect: [ :profile | ($' asString), '@', profile, ($' asString) ].
xAxis := tempDict values.
xAxis := xAxis collect: [ :value | ($' asString), (value asString), ($' asString) ].
^ {
tempDict.
('[', (',' join: xAxis), ']').
('[', (',' join: labels), ']').
}

View File

@ -1,4 +0,0 @@
accessing
refreshProfileImageUrl
self profileImageUrl: nil.
self profileImageUrl

View File

@ -1,5 +0,0 @@
accessing
remoteIsFound
^ (ZnClient new url: (self userNameLink asUrl); get; response) isNotFound not

View File

@ -3,5 +3,5 @@ replies
self messages ifEmpty: [ self getMessages ]. self messages ifEmpty: [ self getMessages ].
^ TweetsCollection new ^ TweetsCollection new
messages: (self tweets select: [ :each | (each metadata at: 'replie to') isNotEmpty]); messages: (self messages messages select: [ :each | (each metadata at: 'replie to') isNotEmpty ]);
yourself yourself

View File

@ -1,19 +0,0 @@
accessing
repliesByTimeSpan: divisions
| tweetsByTimeSpan xAxis labels |
tweetsByTimeSpan := self collectMessages: [ self replies ] byTimeSpanSplits: divisions.
xAxis := OrderedCollection new.
(tweetsByTimeSpan values collect: [ :collection | collection size ]) do: [ :number |
xAxis add: ($' asString), (number asString), ($' asString)
].
labels := OrderedCollection new.
tweetsByTimeSpan keys do: [ :string |
labels add: ($' asString), string, ($' asString)
].
^ {
tweetsByTimeSpan.
('[', (',' join: xAxis), ']').
('[', (',' join: labels), ']').
}

View File

@ -1,23 +0,0 @@
accessing
repliesByWeeksTimeSpan
| tweetsByTimeSpan xAxis labels |
self replies isEmpty
ifTrue: [ ^ { OrderedDictionary new.
('[''', '0', ''']').
('[''', 'No replies', ''']')} ].
tweetsByTimeSpan := self collectMessages: [ self replies ] byTimeSpanSplits: self tweetsDivisionsByWeeks.
xAxis := OrderedCollection new.
(tweetsByTimeSpan values collect: [ :collection | collection size ]) do: [ :number |
xAxis add: ($' asString), (number asString), ($' asString)
].
labels := OrderedCollection new.
tweetsByTimeSpan keys do: [ :string |
labels add: ($' asString), string, ($' asString)
].
^ {
tweetsByTimeSpan.
('[', (',' join: xAxis), ']').
('[', (',' join: labels), ']').
}

View File

@ -1,4 +0,0 @@
private
repliesFromImage
"Used for testing external classes, disposable"
^ self tweetsFromImage select: [ :tweet | (tweet metadata at: 'replie to') isNotEmpty]

View File

@ -1,5 +0,0 @@
accessing
reportingPeriod
^ self config
at: 'reportingPeriod'
ifAbsentPut: [ { self messages oldest created . self messages newest created } ]

View File

@ -3,5 +3,5 @@ retweets
self messages ifEmpty: [ self getMessages ]. self messages ifEmpty: [ self getMessages ].
^ TweetsCollection new ^ TweetsCollection new
messages: (self messages select: [ :each | each authorId ~= self id]); messages: (self messages messages select: [ :each | each authorId ~= self id]);
yourself yourself

View File

@ -1,18 +0,0 @@
accessing
retweetsReportData
| tempDict labels xAxis |
tempDict := self retweets asMessagesUserNamesSortedByOccurrences.
tempDict size > 10 ifTrue: [
tempDict := (tempDict associations copyFrom: 1 to: 10) asOrderedDictionary ].
labels := tempDict keys.
labels := labels collect: [ :profile | ($' asString), '@', profile, ($' asString) ].
xAxis := tempDict values.
xAxis := xAxis collect: [ :value | ($' asString), (value asString), ($' asString) ].
^ {
tempDict.
('[', (',' join: xAxis), ']').
('[', (',' join: labels), ']').
}

View File

@ -0,0 +1,4 @@
accessing
rssFeed
^ RSSTools createRSSFeedFor: self userNameLink , '/rss'

View File

@ -1,14 +1,6 @@
accessing accessing
tweets tweets
| subcollection |
self messages ifEmpty: [ self getMessages ]. self messages ifEmpty: [ self getMessages ].
"TO DO: It seems that Twitter changes the user id, which we thought was unchangeable. This deals with the detected changes so far."
subcollection := self messages
select: [ :each | self authorIds includes: each authorId ].
(#('FranciaMarquezM' 'sandralajas' 'IBetancourtCol' 'sergio_fajardo' 'ingrodolfohdez' 'CastilloMarelen') includes: self userName)
ifFalse: [ subcollection := self messages select: [ :each | each authorId = self id ]].
^ TweetsCollection new ^ TweetsCollection new
messages: subcollection; messages: (self messages messages select: [ :each | each authorId = self id ]);
yourself yourself

View File

@ -1,19 +0,0 @@
accessing
tweetsByTimeSpan: divisions
| tweetsByTimeSpan xAxis labels |
tweetsByTimeSpan := self collectMessages: [ self tweets] byTimeSpanSplits: divisions.
xAxis := OrderedCollection new.
(tweetsByTimeSpan values collect: [ :collection | collection size ]) do: [ :number |
xAxis add: ($' asString), (number asString), ($' asString)
].
labels := OrderedCollection new.
tweetsByTimeSpan keys do: [ :string |
labels add: ($' asString), string, ($' asString)
].
^ {
tweetsByTimeSpan.
('[', (',' join: xAxis), ']').
('[', (',' join: labels), ']').
}

View File

@ -1,19 +0,0 @@
accessing
tweetsByWeeksTimeSpan
| tweetsByTimeSpan xAxis labels |
tweetsByTimeSpan := self collectMessages: [ self tweets] byTimeSpanSplits: self tweetsDivisionsByWeeks.
xAxis := OrderedCollection new.
(tweetsByTimeSpan values collect: [ :collection | collection size ]) do: [ :number |
xAxis add: ($' asString), (number asString), ($' asString)
].
labels := OrderedCollection new.
tweetsByTimeSpan keys do: [ :string |
labels add: ($' asString), string, ($' asString)
].
^ {
tweetsByTimeSpan.
('[', (',' join: xAxis), ']').
('[', (',' join: labels), ']').
}

View File

@ -1,12 +0,0 @@
accessing
tweetsDivisionsByWeeks
| weeks floor divisions |
weeks := ((self newestTweet created - self oldestTweet created) days / 7).
floor := weeks floor.
(weeks - floor) > 0.4
ifTrue: [ floor = 0
ifTrue: [ divisions := 1 ]
ifFalse: [ divisions := floor]]
ifFalse: [ divisions := floor + 1 ].
^ divisions

View File

@ -1,4 +0,0 @@
private
tweetsFromImage
"Used for testing external classes, disposable"
^ self messages select: [ :tweet | tweet authorId = self id ]

View File

@ -1,12 +0,0 @@
accessing
updatedTweets
| currentTweetsPage response nextPageCursor |
response := TweetsCollection new.
currentTweetsPage := self collectRawTweetsFrom: self userNameLinkWithReplies upToPage: 2.
[ (currentTweetsPage collect: [ :tweet | tweet id ]) includes: self newestTweet id ] whileFalse: [
response addAll: currentTweetsPage.
nextPageCursor := currentTweetsPage nextCursor.
currentTweetsPage := self collectRawTweetsFrom: nextPageCursor upToPage: 2.
].
^ response

View File

@ -1,11 +1,7 @@
accessing accessing
url url
self remoteIsFound
ifFalse: [ ^ url := nil ].
^ url ifNil: [ | temp | ^ url ifNil: [ | temp |
temp := ((self documentTree xpath: '//div[@class="profile-website"]') // 'a' @@ 'href') first. temp := ((self documentTree xpath: '//div[@class="profile-website"]') // 'a' @@ 'href') first.
temp ifNil: [ ^ url := nil ]. temp ifNil: [ ^ url := nil ].
temp := temp replaceAll: with: $u. url := temp asUrl.
temp := temp replaceAll: with: $i.
url := temp.
] ]

View File

@ -1,3 +0,0 @@
operation
userNameLinkWithReplies
^ self userNameLink, '/with_replies'

View File

@ -1,4 +0,0 @@
accessing
wordcloudData
^ self wordcloudDataLanguage: 'en'

View File

@ -1,21 +0,0 @@
accessing
wordcloudDataLanguage: language
| stopwords stopwordsCapitalized occurrencesWords wordAndValue |
stopwords := (TweetsCollection dataStore / 'commons' / ('stopwords-', language, '.txt')) contents splitOn: Character lf.
stopwordsCapitalized := stopwords collect: [:each | each first asString asUppercase, each allButFirst asLowercase ].
occurrencesWords := ((((self writeWordsFile contents) splitOn: ' ') asBag asDictionary)
associations asSortedCollection: [:x :y | x value > y value]) asOrderedDictionary.
occurrencesWords removeKeys: stopwords.
occurrencesWords removeKeys: stopwordsCapitalized.
occurrencesWords removeKey: ''.
occurrencesWords size > 50 ifTrue: [
occurrencesWords := (occurrencesWords associations copyFrom: 1 to: 50) asOrderedDictionary ].
wordAndValue := OrderedCollection new.
occurrencesWords keysAndValuesDo: [ :k :v |
wordAndValue add: ('{name:', ($' asString), k, ($' asString), ',value:', v asString, '}')
].
^ {'[', ((',' join: wordAndValue) copyWithout: Character lf), ']'.
occurrencesWords}

View File

@ -3,11 +3,15 @@ writeWordsFile
"TO DO: Debug Tweet words to work better with Urls" "TO DO: Debug Tweet words to work better with Urls"
| rawTweets rawWords collectionsWords count | | rawTweets rawWords collectionsWords count |
self messages ifNil: [ ^ self ]. self messages ifNil: [ ^ self ].
rawTweets := self tweets. rawTweets := self tweets messages.
rawWords := OrderedCollection new. rawWords := OrderedCollection new.
collectionsWords := rawTweets collect: [ :tweet | (tweet words reject: [ :w | collectionsWords := ((rawTweets select:
w includesSubstring: (self class nitterProvider asUrl host copyWithoutAll: '.')])]. [ :tweet | tweet authorId = self id ])
collect: [ :tweet | (tweet words
reject: [ :w |
w includesSubstring:
((self class nitterProvider asUrl host copyWithoutAll: '.'))]) ]).
collectionsWords do: [ :word | rawWords addAll: word ]. collectionsWords do: [ :word | rawWords addAll: word ].
rawWords := ' ' join:rawWords. rawWords := ' ' join:rawWords.

View File

@ -1,13 +0,0 @@
*Socialmetrica
exportAsFileNamed: aName into: aFolder
| exporters |
exporters := {'png' -> #pngExporter .
'pdf' -> #pdfExporter } asDictionary.
exporters keysAndValuesDo: [:k :v |
(self perform: v)
zoomToShapes;
noFixedShapes;
fileName: (aFolder / (aName, '.', k)) fullName;
export.
].
^ aFolder / aName, 'png'

View File

@ -1,3 +0,0 @@
{
"name" : "RSCanvas"
}

View File

@ -1,5 +0,0 @@
*Socialmetrica
asDates
^ {self start.
(self start + self duration)}

View File

@ -1,9 +0,0 @@
*Socialmetrica
asDatesString
| dates firstDate |
dates := self asDatesStrings.
firstDate := dates first splitOn: ' '.
firstDate removeLast.
firstDate:= '' join: firstDate.
^ firstDate, '→', (dates second copyWithoutAll: ' ')

Some files were not shown because too many files have changed in this diff Show More