-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathP7-Tweet.st
1268 lines (1007 loc) · 37 KB
/
P7-Tweet.st
1
Object subclass: #TWTweet instanceVariableNames: 'text id_str retweet_count source user hashtags created_at in_reply_to_status_id_str coordinates favorite_count place' classVariableNames: '' poolDictionaries: '' category: 'Practica7-Tweet'!!TWTweet commentStamp: 'ArturoZambrano 2/15/2014 23:12' prior: 0!A Tweet is a tweet or Status object according to Twitter API.Instance Variables id_str: <Object> retweet_count: <Object> source: <Object> text: <Object> user: <Object>id_str - xxxxxretweet_count - xxxxxsource - xxxxxtext - xxxxxuser - xxxxx!!TWTweet methodsFor: 'comparing' stamp: 'RosarioSantaMarina 3/18/2014 14:07'!<= anotherTweet ^ id_str <= anotherTweet id_str! !!TWTweet methodsFor: 'comparing' stamp: 'RosarioSantaMarina 3/18/2014 16:46'!= anotherTweet"Answer whether the receiver and the argument has the same id_str" (anotherTweet isKindOf: self class) ifFalse: [ ^ false ]. id_str = anotherTweet id_str ifFalse: [ ^ false ]. ^ true! !!TWTweet methodsFor: 'comparing' stamp: 'RosarioSantaMarina 3/18/2014 16:43'!hash"#hash is re-implemented because #= is re-implemented" ^ id_str hash! !!TWTweet methodsFor: 'accessing' stamp: 'ArturoZambrano 4/5/2014 18:19'!coordinates ^coordinates! !!TWTweet methodsFor: 'accessing' stamp: 'RosarioSM 1/22/2014 16:09'!user ^ user! !!TWTweet methodsFor: 'accessing' stamp: 'ArturoZambrano 1/16/2014 12:48'!text ^ text! !!TWTweet methodsFor: 'accessing' stamp: 'RosarioSM 1/22/2014 16:09'!user: anObject user := anObject! !!TWTweet methodsFor: 'accessing' stamp: 'ArturoZambrano 5/9/2014 23:33'!favorite_count ^ favorite_count! !!TWTweet methodsFor: 'accessing' stamp: 'RosarioSM 1/23/2014 11:14'!source ^ source! !!TWTweet methodsFor: 'accessing' stamp: 'RosarioSantaMarina 2/19/2014 13:59'!hashtags: aCollection hashtags := aCollection! !!TWTweet methodsFor: 'accessing' stamp: 'RosarioSantaMarina 3/6/2014 12:53'!created_at: aDatecreated_at := aDate! !!TWTweet methodsFor: 'accessing' stamp: 'ArturoZambrano 4/18/2014 17:50'!coordinatePoint "^(coordinates at: #latitude) @ (coordinates at: #longitude)" ^coordinates.! !!TWTweet methodsFor: 'accessing' stamp: 'RosarioSM 1/23/2014 11:13'!id_str ^ id_str! !!TWTweet methodsFor: 'accessing' stamp: 'RosarioSantaMarina 3/6/2014 12:53'!created_at^created_at! !!TWTweet methodsFor: 'accessing' stamp: 'RosarioSM 1/23/2014 11:14'!source: anObject source := anObject! !!TWTweet methodsFor: 'accessing' stamp: 'RosarioSM 1/23/2014 11:13'!retweet_count ^ retweet_count! !!TWTweet methodsFor: 'accessing' stamp: 'ArturoZambrano 1/16/2014 12:48'!text: anObject text := anObject! !!TWTweet methodsFor: 'accessing' stamp: 'RosarioSM 1/23/2014 11:13'!retweet_count: anObject retweet_count := anObject! !!TWTweet methodsFor: 'accessing' stamp: 'ArturoZambrano 4/15/2014 22:42'!timestamp ^self created_at asTimeStamp ! !!TWTweet methodsFor: 'accessing' stamp: 'RosarioSantaMarina 5/5/2014 13:39'!hashtags | col | col := OrderedCollection new. hashtags isNotNil ifTrue: [ hashtags do: [ :each | | stream | stream := WriteStream on: ''. stream nextPutAll: '#'. stream nextPutAll: each. col add: stream contents asLowercase ] ]. ^ col! !!TWTweet methodsFor: 'accessing' stamp: 'RosarioSM 1/23/2014 11:13'!id_str: anObject id_str := anObject! !!TWTweet methodsFor: 'accessing' stamp: 'RosarioSantaMarina 4/8/2014 15:52'!place ^ place! !!TWTweet methodsFor: 'time' stamp: 'RosarioSantaMarina 6/30/2014 15:57'!hour24 ^self created_at hour24! !!TWTweet methodsFor: 'time' stamp: 'ArturoZambrano 4/17/2014 17:51'!adjustTimestamp: aDuration created_at:= created_at+ aDuration.! !!TWTweet methodsFor: 'actions' stamp: 'RosarioSantaMarina 8/29/2014 13:17'!includesSubstring: aString "Returns true if tweet text includes aString. Otherwise false is returned" ^ self text includesSubstring: aString! !!TWTweet methodsFor: 'actions' stamp: 'RosarioSantaMarina 9/12/2014 16:14'!countryCode ^ place at: 'country_code'! !!TWTweet methodsFor: 'initialization' stamp: 'ArturoZambrano 10/28/2016 18:04'!initialize super initialize. ! !!TWTweet methodsFor: 'private' stamp: 'ArturoZambrano 4/15/2014 14:54'!monthFrom:aString aString = 'Jan' ifTrue:[ ^1].aString = 'Feb' ifTrue:[ ^2].aString = 'Mar' ifTrue:[ ^3].aString = 'Apr' ifTrue:[ ^4].^1.! !!TWTweet methodsFor: 'private' stamp: 'ArturoZambrano 4/18/2014 17:54'!coordinates:aPoint coordinates:=aPoint.! !!TWTweet methodsFor: 'printing' stamp: 'ArturoZambrano 2/12/2014 14:50'!printOn: aStream aStream nextPutAll: 'Tweet: '; nextPut:$'; nextPutAll: text; nextPut: $'. ! !"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!TWTweet class instanceVariableNames: ''!!TWTweet class methodsFor: 'constructor' stamp: 'DavidGomez 8/18/2015 17:54'!new ^ super new initialize ! !Object subclass: #TWUser instanceVariableNames: 'name id_str screen_name followers_count friends_count friends followers profile_image_url lang time_zone statuses_count location profileFormPicture' classVariableNames: '' poolDictionaries: '' category: 'Practica7-Tweet'!!TWUser commentStamp: 'ArturoZambrano 3/22/2014 21:56' prior: 0!An User represent a Twitter user.Instance Variables followers: <Object> followers_count: <Object> friends: <Object> friends_count: <Object> id_str: <Object> name: <Object> screen_name: <Object>followers - xxxxxfollowers_count - xxxxxfriends - xxxxxfriends_count - xxxxxid_str - xxxxxname - xxxxxscreen_name - xxxxx!!TWUser methodsFor: 'private profile-picture' stamp: 'ArturoZambrano 5/22/2014 22:31'!defaultForm ^ Form fromBinaryStream: (Base64MimeConverter mimeDecodeToBytes: '/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5OjcBCgoKDQwNGg8PGjclHyU3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3N//AABEIAF4AXgMBEQACEQEDEQH/xAAbAAEAAgMBAQAAAAAAAAAAAAAABgcCAwQFAf/EADAQAAICAQIEBAQGAwEAAAAAAAABAgMEBREGEiExUYGRoQdxcsETI0FSYWIzkrEi/8QAGQEBAAMBAQAAAAAAAAAAAAAAAAEEBQMC/8QAJBEBAAICAQMDBQAAAAAAAAAAAAECAxESBCExIkFREzIzUmH/2gAMAwEAAhEDEQA/APANJkAAAAAAAAAAAAAAAAAAA6sTTc/Njz4eDlXw/dVTKS9UtiJtWPMpitp8Q1ZOLkYln4eXj3UTfaNtbg36kxMT4JiY8tQQAAAAAAAAAJ/wRwZDIqr1LWK+aE1zUY8uzX7pfZepWy5demq3hwb9VliwpjGKjGKjGK2SS2SRWXGnO0/Gz8eWPmUQupl3jNb+ng/5JiZidwi1YtGpVLxlwvZoGQraHKzAtltXN94P9svsy5jyc47+WfmxfTnt4Rs6uIAAAAAACQcE6Kta1mKvjzYuOlZcn2l4R837JnPLfjV1w4+dv5C5oFFpNqA+7bgcWq6fj6ngX4WVHmqujyvxXg1/KfUmszWdw82rFo1KiNRwrtNz78LJ/wAtE3CTXZ+DX8NbPzNCJi0bhl2rNZmJc5KAAAAAALX+HmCsLh+u6S2sypO2T/r2j7LfzKWa27NDp68ab+UsjM5O7bGQGXMB8kwKx+KunqvMxNSrWyui6rPqXWPtv6Frp7dphS6qveLIIWFUAAAAHx7tbR7vsBeeJVHFxaceHSNVcYLyWxnTO521ojUadMZkJbYzAz5wDmBFfiLSr+GL5bbypshZH/blftJnXDOruHURvGqYus8AAAAGdLUbq5Psppv1E+Ex5Xdz9WZrWZxkBsUwMvxADmB4XGk0uGNQ3feEV6yR0xffDln/AByqIvM0AAAAHxrdNEi39Gzln6Vi5KfWda5vqXR++5nXrxtMNTHblWJd6meXtkpgZKYGSkBE/iLmKrR68VP/AN5Fq6f1j1fvynfBXdtq3U21TXyrgtqIAAAAAEt4F1mGNc9NyZKNdst6ZPsp+Hn/AN+Zwz49+qFrp8mp4yn3L4FRdZKIGUUAssrprlZbOMK4JylKT2SXiTEbRM6VNxNq71nVJ3x3VEFyUxfTaPj833L2OnCumblyc7beSe3MAAAAAABMNB41njQjj6tGd0F0jfHrNfUv1+ff5le+Dfeq1j6mYjVkqp4l0S6CktUxYb/pbYq36S2OE47/AAsfWx/s15nFmiYsHJZ1d8v0jj/mN+a6erJjFefZE58ce6D8R8UZOs/kwi6MNPf8NPrP6n9izjxRXv7qmXNN+3s8E6uIAAAAAAAAAbAAAAAAAAAAAAAAAAAAAAAAf//Z' readStream)! !!TWUser methodsFor: 'private profile-picture' stamp: 'ArturoZambrano 5/11/2014 20:19'!restoreProfilePictureFromCache "Profile picture is not in memory, we try to recover it from chache." self pictureFilename asFileReference exists ifFalse: [ self retriveProfilePictureFromTwitter ]. [profileFormPicture := Form fromFileNamed: self pictureFilename.] on:Exception do:[profileFormPicture := Form fromFileNamed: '/Users/arturo/tmp/twitter.jpeg']. ^ profileFormPicture! !!TWUser methodsFor: 'private profile-picture' stamp: 'ArturoZambrano 5/11/2014 15:07'!retriveProfilePictureFromTwitter "Dowloads the users's profile picture"| response | response := ZnClient new url: self profile_image_url; downloadTo: self pictureFilename . " | response | response := ZnClient new url: self profile_image_url; get; response. response isSuccess ifTrue: [ ^ (ImageReadWriter formFromStream: response entity readStream) inspect. ] "! !!TWUser methodsFor: 'private profile-picture' stamp: 'ArturoZambrano 5/11/2014 20:13'!pictureFilename "Returns the local filename where the image profile of the receiver should be stored"^ 'twrpt-cache/', self screen_name , '.', self profile_image_url asFileReference extension! !!TWUser methodsFor: 'initialize' stamp: 'RosarioSantaMarin 12/29/2014 15:02'!initialize super initialize. defaultProfileFormPicture := false. urlChanged := false. friends := OrderedCollection new. followers := OrderedCollection new! !!TWUser methodsFor: 'as yet unclassified ' stamp: 'RosarioSantaMarina 11/17/2014 14:51'!gender "Returns the user gender (femenine or masculine)" ^ GDMHeuristics genderFromComplexName: screen_name providedBy: GDMGenderAPIProvider new estimatedBy: GDMGroupGenderEstimator new! !!TWUser methodsFor: 'as yet unclassified ' stamp: 'ArturoZambrano 12/16/2014 09:27'!updateInformation | queryHelper login newUserInfo | login := TwitterLogin restoreExistingAccessToken. login accessToken ifNil: [ login manualLogin; save ]. queryHelper := RESTQueryHelper login: login. newUserInfo := queryHelper userShow: id_str. self followers_count: newUserInfo followers_count. self friends_count: newUserInfo friends_count. self lang: newUserInfo lang. self location: newUserInfo location. self profile_image_url: newUserInfo profile_image_url. self statuses_count: newUserInfo statuses_count. self time_zone: newUserInfo time_zone! !!TWUser methodsFor: 'printing' stamp: 'ArturoZambrano 2/12/2014 14:52'!printOn: aStream aStream nextPutAll: 'User: '; nextPutAll: name.! !!TWUser methodsFor: 'printing' stamp: 'RosarioSantaMarina 5/23/2014 15:57'!screenNameWithoutAt "Returns user's screen_name without character @" (screen_name beginsWith: '@') ifTrue: [ ^ screen_name allButFirst ]. ^ screen_name ! !!TWUser methodsFor: 'comparing' stamp: 'RosarioSantaMarina 3/18/2014 16:16'!= anUser (anUser isKindOf: self class) ifFalse: [ ^ false ]. ^ name = anUser name and: (id_str = anUser id_str and: (screen_name = anUser screen_name and: (followers_count = anUser followers_count and: friends_count = anUser friends_count)))! !!TWUser methodsFor: 'comparing' stamp: 'RosarioSantaMarina 3/18/2014 16:55'!hash<fix: 'bitXor with all/which variables?'> "#hash is re-implemented because #= is re-implemented" ^ id_str hash bitXor: screen_name hash! !!TWUser methodsFor: 'string manipulation' stamp: 'RosarioSantaMarina 11/26/2014 15:31'!addString: aString atBeginningOf: anotherString | stream | stream := WriteStream on: ''. stream nextPutAll: aString. stream nextPutAll: anotherString. aString := stream contents! !!TWUser methodsFor: 'string manipulation' stamp: 'RosarioSantaMarina 11/26/2014 15:25'!deleteString: aString from: anotherString | pos str | str := aString. pos := profile_image_url findString: str. pos = 0 ifTrue: [ ^ anotherString ]. ^ anotherString copyReplaceFrom: pos to: pos + str size - 1 with: ''! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSantaMarina 4/7/2014 16:01'!profile_image_url: aUrl profile_image_url := aUrl! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSantaMarina 4/7/2014 16:01'!lang: aLang lang := aLang! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSantaMarina 4/7/2014 16:01'!profile_image_url ^ profile_image_url! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSantaMarina 2/26/2014 15:48'!addFollowers: aUser followers isNil ifTrue: [ followers := OrderedCollection new ]. followers add: aUser! !!TWUser methodsFor: 'accessing' stamp: 'ArturoZambrano 4/28/2014 11:53'!location ^ location! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSantaMarina 4/7/2014 16:02'!statuses_count ^ statuses_count! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSantaMarina 4/7/2014 16:02'!time_zone: aTimeZone time_zone := aTimeZone! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSM 1/23/2014 11:44'!friends_count: anObject friends_count := anObject! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSM 1/22/2014 16:10'!name ^ name! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSantaMarina 2/26/2014 15:47'!addFriends: aUser friends isNil ifTrue: [ friends := OrderedCollection new ]. friends add: aUser! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSM 1/23/2014 11:44'!friends_count ^ friends_count! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSM 1/23/2014 11:44'!followers_count ^ followers_count! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSantaMarina 4/7/2014 16:02'!time_zone ^ time_zone! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSantaMarin 12/22/2014 17:02'!profilePictureResized: aNumber "Restore the users's profile picture" | form | form := self profilePicture. ^ FormResizer squareResize: form to: aNumber! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSantaMarina 4/7/2014 16:02'!statuses_count: aNumber statuses_count := aNumber! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSM 1/22/2014 16:10'!name: aName name := aName! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSM 1/22/2014 16:09'!id_str ^ id_str! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSantaMarina 4/29/2014 15:09'!screen_name: aString (aString beginsWith: '@') ifFalse: [ | stream | stream := WriteStream on: ''. stream nextPutAll: '@'. stream nextPutAll: aString. aString := stream contents ]. screen_name := aString! !!TWUser methodsFor: 'accessing' stamp: 'ArturoZambrano 4/28/2014 11:53'!location: anObject location := anObject! !!TWUser methodsFor: 'accessing' stamp: 'ArturoZambrano 5/11/2014 15:12'!profilePicture "Restore the users's profile picture" profileFormPicture isNil ifTrue:[ self restoreProfilePictureFromCache .]. ^profileFormPicture! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSantaMarina 4/7/2014 16:01'!lang ^ lang! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSantaMarina 4/29/2014 15:16'!screen_name ^ screen_name! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSM 1/23/2014 11:44'!followers_count: anObject followers_count := anObject! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSM 1/22/2014 16:10'!id_str: anId id_str := anId! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSM 2/11/2014 14:10'!friends ^ friends! !!TWUser methodsFor: 'accessing' stamp: 'RosarioSM 2/12/2014 15:28'!followers ^ followers! !!TWUser methodsFor: 'initialize-release' stamp: 'RosarioSantaMarina 4/29/2014 15:09'!initializeName: aName followers: followersCount friends: friendsCount id: idStr screen_name: screenName profile_image_url: aUrl lang: aLang time_zone: aTimeZone statuses_count: aNumber name := aName. followers_count := followersCount. friends_count := friendsCount. id_str := idStr. self screen_name: screenName. profile_image_url := aUrl. lang := aLang. time_zone := aTimeZone. statuses_count := aNumber. friends := OrderedCollection new. followers := OrderedCollection new.! !!TWUser methodsFor: 'initialize-release' stamp: 'RosarioSantaMarina 4/29/2014 15:09'!initializeName: aName followers: followersCount friends: friendsCount id: idStr screen_name: screenName profile_image_url: aUrl lang: aLang time_zone: aTimeZone statuses_count: aNumber location:aString name := aName. followers_count := followersCount. friends_count := friendsCount. id_str := idStr. self screen_name: screenName. profile_image_url := aUrl. lang := aLang. time_zone := aTimeZone. statuses_count := aNumber. friends := OrderedCollection new. followers := OrderedCollection new. location:= aString.! !"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!TWUser class instanceVariableNames: ''!!TWUser class methodsFor: 'instance creation' stamp: 'RosarioSantaMarina 11/26/2014 15:58'!newFrom: aDictionary ^ self new name: (aDictionary at: 'name'); followers_count: (aDictionary at: 'followers_count'); friends_count: (aDictionary at: 'friends_count'); id_str: (aDictionary at: 'id_str'); screen_name: (aDictionary at: 'screen_name'); profile_image_url: (aDictionary at: 'profile_image_url'); lang: (aDictionary at: 'lang'); time_zone: (aDictionary at: 'time_zone'); statuses_count: (aDictionary at: 'statuses_count'); location: (aDictionary at: 'location'); yourself! !!TWUser class methodsFor: 'instance creation' stamp: 'RosarioSantaMarina 9/11/2014 11:44'!name: aString followers_count: aNumber ^ self new name: aString; followers_count: aNumber; yourself! !!TWUser class methodsFor: 'instance creation' stamp: 'RosarioSantaMarina 4/7/2014 16:05'!newName: aName followers: followers_count friends: friends_count id: id_str screen_name: screen_name profile_image_url: aUrl lang: aLang time_zone: aTimeZone statuses_count: aNumber ^ self new initializeName: aName followers: followers_count friends: friends_count id: id_str screen_name: screen_name profile_image_url: aUrl lang: aLang time_zone: aTimeZone statuses_count: aNumber! !!TWUser class methodsFor: 'instance creation' stamp: 'ArturoZambrano 5/12/2014 17:53'!name:aString ^ self new name: aString! !!TWUser class methodsFor: 'instance creation' stamp: 'ArturoZambrano 4/28/2014 11:41'!newName: aName followers: followers_count friends: friends_count id: id_str screen_name: screen_name profile_image_url: aUrl lang: aLang time_zone: aTimeZone statuses_count: aNumber location: aString ^ self new initializeName: aName followers: followers_count friends: friends_count id: id_str screen_name: screen_name profile_image_url: aUrl lang: aLang time_zone: aTimeZone statuses_count: aNumber location: aString! !!TWUser class methodsFor: 'instance creation' stamp: 'RosarioSantaMarina 9/18/2014 10:27'!name: aString screen_name: anotherString followers_count: aNumber ^ self new name: aString; screen_name: anotherString; followers_count: aNumber; yourself! !!TWUser class methodsFor: 'creating' stamp: 'DavidGomez 8/24/2015 00:18'!createBlockEqualSearch: aCondition aCondition property compare: 'name' ifTrue: [ ^ [ :each | each name = aCondition value ] ]. aCondition property compare: 'id_str' ifTrue: [ ^ [ :each | each id_str = aCondition value ] ]! !TestCase subclass: #TestTWT instanceVariableNames: 'base' classVariableNames: '' poolDictionaries: '' category: 'Practica7-Tweet'!!TestTWT methodsFor: 'initialization' stamp: 'ema 5/20/2018 03:09'!testDesviation "base deviationTweetsPerUser debe dar aprox 0.816496172679334" self assert: (base deviationTweetsPerUser truncateTo: 0.00001) equals: 0.81649! !!TestTWT methodsFor: 'initialization' stamp: 'ema 5/20/2018 02:49'!setUp | u1 u2 u3 | "crea la base" base := TweetBase new. "crea usuarios" u1 := TWUser name: ' u1'. u2 := TWUser name: 'u2'. u3 := TWUser name: 'u3'. "agrega tweets para cada usuario" 1 to: 2 do: [ :i | base add: (TWTweet new user: u1; id_str: u1 printString , i printString) ]. 1 to: 3 do: [ :i | base add: (TWTweet new user: u2; id_str: u2 printString , i printString) ]. 1 to: 4 do: [ :i | base add: (TWTweet new user: u3; id_str: u3 printString , i printString) ]! !!TestTWT methodsFor: 'initialization' stamp: 'ema 5/20/2018 19:37'!testVariance "base varianceTweetsPerUser. debe dar aprox 0.6666666666" self assert: (base varianceTweetsPerUser truncateTo: 0.001) equals: 0.666! !Object subclass: #TweetBase instanceVariableNames: 'filename hashtag tweets' classVariableNames: 'bases' poolDictionaries: '' category: 'Practica7-Tweet'!!TweetBase commentStamp: 'ArturoZambrano 2/15/2014 23:05' prior: 0!A TweetBase stores many tweets recovered in several querys to API.Instance Variables filename: <Object> hashtag: <Object>filename - xxxxxhashtag - xxxxx!!TweetBase methodsFor: 'accessing' stamp: 'ArturoZambrano 11/26/2014 18:59'!size ^tweets size.! !!TweetBase methodsFor: 'accessing' stamp: 'RosarioSantaMarina 3/6/2014 10:31'!tweets: aCollection tweets := aCollection! !!TweetBase methodsFor: 'accessing' stamp: 'ArturoZambrano 12/9/2014 22:21'!name ^name.! !!TweetBase methodsFor: 'accessing' stamp: 'RosarioSantaMarina 2/20/2014 10:34'!filename ^ self class filenameFrom: hashtag! !!TweetBase methodsFor: 'accessing' stamp: 'ArturoZambrano 12/9/2014 08:54'!name: anObject name := anObject! !!TweetBase methodsFor: 'accessing' stamp: 'RosarioSantaMarina 2/19/2014 13:42'!tweets ^ tweets! !!TweetBase methodsFor: 'accessing' stamp: 'RosarioSantaMarina 2/14/2014 11:26'!hashtag ^ hashtag! !!TweetBase methodsFor: 'accessing' stamp: 'RosarioSantaMarina 2/14/2014 11:26'!hashtag: aHashtag hashtag := aHashtag! !!TweetBase methodsFor: 'accessing' stamp: 'ArturoZambrano 12/8/2014 18:07'!criteria: aHashtag hashtag := aHashtag! !!TweetBase methodsFor: 'accessing' stamp: 'ArturoZambrano 1/22/2015 17:05'!geoLocatedTweets^ tweets select: [ :t | t coordinates notNil and: [ (t coordinates = (0.0@0.0 )) not ] ]! !!TweetBase methodsFor: 'accessing' stamp: 'ArturoZambrano 12/8/2014 18:08'!criteria ^ criteria! !!TweetBase methodsFor: 'adding' stamp: 'ema 5/18/2018 03:34'!tweetAdd: unTweet tweets add: unTweet! !!TweetBase methodsFor: 'utility' stamp: 'ArturoZambrano 3/7/2015 08:38'!purge tweets:= tweets select: [ :t | t text notNil and:[t created_at notNil] ].! !!TweetBase methodsFor: 'printing' stamp: 'ArturoZambrano 2/26/2014 22:31'!printOn: aStream aStream nextPutAll: 'TweetBase hashtag: '. hashtag printOn: aStream. aStream nextPutAll: ' count: '; nextPutAll: tweets size asString! !!TweetBase methodsFor: 'reporting' stamp: 'ArturoZambrano 12/16/2014 11:51'!fullReport | stream sortedTweets users sortedUsers | stream := WriteStream on: ''. stream nextPutAll: 'Number of Tweets: ' , self size printString; cr. sortedTweets := tweets asSortedCollection: [ :a :b | a timestamp < b timestamp ]. stream nextPutAll: 'First tweet: '; nextPutAll: sortedTweets first timestamp printString; nextPutAll: ' Last tweet: '; nextPutAll: sortedTweets last timestamp printString; cr. users := tweets asBag collect: [ :t | t user ]. stream nextPutAll: 'Users count: '; nextPutAll: users asSet size printString; cr. stream nextPutAll: 'Devices count: '; nextPutAll: self allDevices size printString; cr. sortedUsers := users sortedCounts. stream nextPutAll: 'Top Tweeters: '. 1 to: 10 do: [ :i | stream crtab; nextPutAll: (sortedUsers at: i) key printString; nextPutAll: ' -> ' ; nextPutAll: (sortedUsers at: i) value name]. ^ stream contents! !!TweetBase methodsFor: 'as yet unclassified' stamp: 'ema 5/20/2018 19:42'!calculateMeanFrom: tweetsByUser ^ (tweetsByUser inject: 0 into: [ :sum :user | sum + user ]) / tweetsByUser size ! !!TweetBase methodsFor: 'tweets manipulation' stamp: 'ArturoZambrano 1/22/2015 16:53'!geolocatedTweetsself halt. ^ tweets select: [ :each | each place isNotNil or: [each user location isNotNil] ]! !!TweetBase methodsFor: 'tweets manipulation' stamp: 'RosarioSantaMarina 11/28/2014 14:35'!cleanTweets "Remove from the collection all tweets which not contain errors" self tweets: (tweets reject: [ :each | each id_str = nil ])! !!TweetBase methodsFor: 'tweets manipulation' stamp: 'ArturoZambrano 4/21/2014 16:01'!adjustTimestamp: aDuration tweets do:[:t | t adjustTimestamp: aDuration]! !!TweetBase methodsFor: 'summarized data' stamp: 'ArturoZambrano 3/8/2015 15:37'!tweetCountByDevice:devices | result | result := Dictionary new. tweets do: [ :tweet | devices do: [ :device | (tweet source includesSubstring: device) ifTrue: [ result at: device ifAbsentPut: 1. result at: device put: (result at: device) + 1 ] ] ]. ^ result! !!TweetBase methodsFor: 'summarized data' stamp: 'RosarioSantaMarina 9/3/2014 15:25'!countTweetsFollowersByUserLimit: aNumber | dict i array | dict := self tweetCountByUserLimit: aNumber. i := 1. array := Array new: aNumber. dict keysAndValuesDo: [ :key :value | array at: i put: (Array with: value with: key followers_count). i := i + 1 ]. ^ array! !!TweetBase methodsFor: 'summarized data' stamp: 'RosarioSantaMarina 11/13/2014 11:53'!tweetCountByMinute "returns a dictionary with the number of tweets per minute" | result | result := Dictionary new. tweets do: [ :tweet | | hhmm | hhmm := (WriteStream on: ' ') nextPutAll: (tweet timestamp hour24 printStringPadded: 2); nextPutAll: ':'; nextPutAll: (tweet timestamp minute printStringPadded: 2); contents. result at: hhmm ifAbsentPut: 1. result at: hhmm put: (result at: hhmm) + 1 ]. ^ result! !!TweetBase methodsFor: 'summarized data' stamp: 'ema 5/19/2018 22:41'!tweetCountByUserGender | tweetsByGender | tweetsByGender := Bag new. tweets do: [ :tweet | tweetsByGender add: tweet gender ]. ^ tweetsByGender! !!TweetBase methodsFor: 'summarized data' stamp: 'RosarioSantaMarina 6/23/2014 13:59'!countOcurrences: wordsCollection "for each word counts in how many tweets it occurs" | result | result := Dictionary new. wordsCollection do: [ :w | result at: w asLowercase put: 0 ]. tweets do: [ :tweet | wordsCollection do: [ :word | tweet text isNotNil ifTrue: [ (tweet text findString: word startingAt: 1 caseSensitive: false) > 0 ifTrue: [ result at: word asLowercase put: (result at: word asLowercase) + 1 ] ] ] ]. ^ result! !!TweetBase methodsFor: 'summarized data' stamp: 'RosarioSantaMarina 6/30/2014 16:27'!tweetsPerHour "Returns a dictionary containing how many tweets were made per hour" | dic | dic := Dictionary new. tweets do: [ :tweet | dic at: tweet hour24 ifAbsentPut: 0. dic at: tweet hour24 put: (dic at: tweet hour24) + 1 ]. ^ dic ! !!TweetBase methodsFor: 'summarized data' stamp: 'ArturoZambrano 12/13/2014 21:58'!allDevices | helper | helper := HTMLHelper new. ^(tweets collect: [ :t | t source ]) collect: [ :sourceString | helper extractContentFromAnchorTag: sourceString ]! !!TweetBase methodsFor: 'summarized data' stamp: 'ArturoZambrano 3/8/2015 17:01'!keywordsCount | bag counts | bag := Bag new. tweets do: [ :t | bag addAll: t text asLowercase substrings ]. counts := bag sortedCounts. 1 to: counts size do: [ :i | (counts at: i) value size < 4 ifTrue: [ counts at: i put: nil ] ]. ^ (counts asOrderedCollection select: [ :each | each notNil ]) asSortedCollection: [ :assocA :assocB | assocA key > assocB key ]! !!TweetBase methodsFor: 'summarized data' stamp: 'ArturoZambrano 12/13/2014 21:59'!popularDevices ^ {'Android'. 'iPhone'. 'BlackBerry'. 'Mobile Web'. 'iPad'. 'Windows Phone'. 'Twitter for Mac'. 'Twitter for Windows'. 'PlayStation'. 'Symbian'. ' Nokia'}! !!TweetBase methodsFor: 'summarized data' stamp: 'RosarioSantaMarina 9/24/2014 14:09'!tweetsPerCountryCodeFrom: aHashtag "Returns the number of tweets per country that contains a particular haghtag" | dic | dic := Dictionary new. self geolocatedTweets do: [ :tweet | | text code | text := tweet text asLowercase. code := tweet countryCode. (text includesSubstring: aHashtag) ifTrue: [ dic at: code ifAbsentPut: 0. dic at: code put: (dic at: code) + 1 ] ]. ^ dic! !!TweetBase methodsFor: 'summarized data' stamp: 'RosarioSantaMarina 6/30/2014 16:27'!averageTweetsPerHour "Returns a float representing the average tweets per hour from a collection of tweets" | dic | dic := self tweetsPerHour. ^ ((dic values inject: 0 into: [ :total :value | total + value ]) / dic keys size) asFloat rounded! !!TweetBase methodsFor: 'summarized data' stamp: 'ArturoZambrano 7/17/2015 17:30'!wordCount "this code is not beauty, tries to be fast" | result | result := Dictionary new. tweets do: [ :tweet | tweet words do: [ :word | result at: word ifAbsentPut: 1. result at: word put: (result at: word ) + 1 ] ]. result removeKey: self name asLowercase ifAbsent:[]. ^ result! !!TweetBase methodsFor: 'summarized data' stamp: 'ema 5/20/2018 19:36'!tweetCountByUser | result | result := Dictionary new. tweets do: [ :tweet | | user | user := tweet user. result at: user ifAbsentPut: 0. result at: user put: (result at: user) + 1 ]. ^ result! !!TweetBase methodsFor: 'summarized data' stamp: 'ArturoZambrano 12/13/2014 22:01'!tweetCountByDevice "returns a dictionary with the number of tweets per minute" ^self tweetCountByDevice: self allDevices ! !!TweetBase methodsFor: 'summarized data' stamp: 'ArturoZambrano 12/13/2014 22:00'!tweetCountByPopularDevice "returns a dictionary with the number of tweets per minute" ^self tweetCountByDevice: self popularDevices ! !!TweetBase methodsFor: 'summarized data' stamp: 'RosarioSantaMarin 12/17/2014 17:59'!tweetCountByHashtag "this code is not beauty, tries to be fast" | result | result := Dictionary new. tweets do: [ :tweet | tweet hashtags do: [ :ht | result at: ht asLowercase ifAbsentPut: 1. result at: ht asLowercase put: (result at: ht asLowercase) + 1 ] ]. result removeKey: self name asLowercase ifAbsent:[]. result removeKey: '#rating' ifAbsent:[] . "(self hashtag asLowercase at: 1 put: Character space; yourself) trimLeft." ^ result! !!TweetBase methodsFor: 'summarized data' stamp: 'RosarioSantaMarina 9/3/2014 17:01'!countByMinuteArray | values count data | values := self tweetCountByMinute. count := 1. data := Array new: values size. values keys asSortedCollection do: [ :k | data at: count put: (Array with: (Time fromString: k) minutes with: (values at: k)). "data at: count put: (Array with: (Time fromString:k) with: (values at: k))." count := count + 1 ]. ^ data! !!TweetBase methodsFor: 'summarized data' stamp: 'RosarioSantaMarina 5/17/2014 10:36'!tweetCountByUserLimit: aNumber "Returns a sorted collection containing the number of tweets made by each user" | dict sorted top | dict := self tweetCountByUser. sorted := dict associations asSortedCollection: [ :assocA :assocB | assocA value > assocB value ]. top := sorted allButLast: sorted size - aNumber. ^ top asDictionary! !!TweetBase methodsFor: 'stats' stamp: 'ema 5/20/2018 20:01'!deviationTweetsPerUser ^ (self varianceTweetsPerUser) sqrt asFloat! !!TweetBase methodsFor: 'stats' stamp: 'ema 5/24/2018 06:03'!varianceTweetsPerUser "returns the variance of tweets groups by user" | result total mean | result := self tweetCountByUser. mean := self calculateMeanFrom: result. total := 0. result associationsDo: [ :assoc | total := total + ((assoc value - mean) * (assoc value - mean)) ]. ^ total / result size! !!TweetBase methodsFor: 'class analysis' stamp: 'ArturoZambrano 5/9/2014 20:47'!countByUserLimit: aNumber | dict sorted top | dict := self countByUser. sorted := dict associations asSortedCollection: [ :assocA :assocB | assocA value > assocB value ]. top := sorted allButLast: sorted size - aNumber. ^ top asDictionary! !!TweetBase methodsFor: 'class analysis' stamp: 'ArturoZambrano 4/28/2014 12:09'!countByUser "returns a dictionary with the number of tweets per user in this tweet base" | result | result := Dictionary new. tweets do: [ :tweet | | user| user:= tweet user. result at: user ifAbsentPut: 0. result at: user put: (result at: user) + 1 ]. ^ result! !!TweetBase methodsFor: 'class analysis' stamp: 'ArturoZambrano 4/15/2014 18:26'!countByMinute "returns a dictionary with the number of tweets per minute" | result | result := Dictionary new. tweets do: [ :tweet | | hhmm | hhmm := (tweet timestamp hour24 printStringPadded: 2 ), ':' , (tweet timestamp minute printStringPadded: 2). result at: hhmm ifAbsentPut: 0. result at: hhmm put: (result at: hhmm) + 1 ]. ^ result! !!TweetBase methodsFor: 'class analysis' stamp: 'RosarioSantaMarina 4/28/2014 16:35'!getUsersLimit: aNumber "returns a sorted collection with the number of tweets per user and the user who made them in this tweet base" | col users | users := self countByUserLimit: aNumber. col := SortedCollection new sortBlock: [ :a :b | | usA usB | usA := a at: #user. usB := b at: #user. (a at: #tweets) > (b at: #tweets) or: [ (a at: #tweets) = (b at: #tweets) and: usA followers_count > usB followers_count ] ]. users associationsDo: [ :each | | dict | dict := Dictionary new. dict at: #user put: each key. dict at: #tweets put: each value. col add: dict ]. ^ col! !!TweetBase methodsFor: 'class analysis' stamp: 'ArturoZambrano 4/24/2014 15:11'!allHashtagsCount "this code is not beauty, tries to be fast" | result | result := Dictionary new. tweets do: [ :tweet | tweet hashtags do: [ :ht | result at: ht asLowercase ifAbsentPut: 0. result at: ht asLowercase put: (result at: ht asLowercase) + 1 ] ]. result removeKey: self hashtag asLowercase . result removeKey: '#rating' . "(self hashtag asLowercase at: 1 put: Character space; yourself) trimLeft." ^ result! !!TweetBase methodsFor: 'class analysis' stamp: 'ArturoZambrano 4/24/2014 12:46'!countByDevice "returns a dictionary with the number of tweets per minute" | result devices | result := Dictionary new. devices := {'Android'. 'iPhone'. 'BlackBerry'. 'Mobile Web'. 'iPad'. 'Windows Phone'}. tweets do: [ :tweet | devices do: [ :device | (tweet source includesSubstring: device) ifTrue: [ result at: device ifAbsentPut: 1. result at: device put: (result at: device) + 1 ] ] ]. ^ result! !!TweetBase methodsFor: 'class analysis' stamp: 'ArturoZambrano 2/18/2014 20:02'!allHashtags | set | set := Set new. tweets do: [ :tw | set addAll: tw hashtags ]. ^ set! !!TweetBase methodsFor: 'filtering' stamp: 'ArturoZambrano 3/8/2015 15:46'!selcectTimeBetween: initTimestamp and: endTimestamp | tb | tb := TweetBase for: self name , 'filtered-' , initTimestamp printString , '-' , endTimestamp printString. tb criteria: criteria. tb tweets: (tweets select: [ :t | t timestamp >= initTimestamp and: [ t timestamp <= endTimestamp ] ]). ^ tb! !!TweetBase methodsFor: 'persistence' stamp: 'ArturoZambrano 5/3/2014 19:25'!restore | tb | tb := FLMaterializer materializeFromFileNamed: self filename. self class bases at: self hashtag put: self. ^ tb! !!TweetBase methodsFor: 'persistence' stamp: 'ArturoZambrano 6/7/2014 17:27'!saveIfNecessary tweets size \\ 1000 = 0 ifTrue: [ self save ]! !!TweetBase methodsFor: 'persistence' stamp: 'ArturoZambrano 2/17/2014 20:09'!save self filename asFileReference exists ifTrue:[self filename asFileReference delete]. FLSerializer serialize: self toFileNamed: self filename! !!TweetBase methodsFor: 'tweets' stamp: 'RosarioSantaMarina 3/18/2014 16:59'!append: aResponse "Adds the tweets recovered by a response" tweets addAll: aResponse tweets ! !!TweetBase methodsFor: 'tweets' stamp: 'RosarioSantaMarina 3/17/2014 15:53'!add: aTweet tweets add:aTweet ! !!TweetBase methodsFor: 'initialize - release' stamp: 'RosarioSantaMarina 3/6/2014 10:30'!initialize tweets := Set new! !"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!TweetBase class instanceVariableNames: ''!!TweetBase class methodsFor: 'misc' stamp: 'ArturoZambrano 2/17/2014 15:52'!filenameFrom:aHashtag ^aHashtag , '.tweets'! !!TweetBase class methodsFor: 'instance creation' stamp: 'ArturoZambrano 5/3/2014 19:34'!removeAllFromMemory "WARING: this method remove all the tweet bases from memory, they are still safe in your hard disk" bases removeAll! !!TweetBase class methodsFor: 'instance creation' stamp: 'RosarioSantaMarina 3/17/2014 15:56'!bases bases isNil ifTrue: [ bases := Dictionary new ]. ^ bases! !!TweetBase class methodsFor: 'instance creation' stamp: 'ArturoZambrano 12/9/2014 08:54'!newNamed: aString ^ self new name: aString; yourself! !!TweetBase class methodsFor: 'instance creation' stamp: 'ArturoZambrano 2/26/2014 22:44'!reset bases:= nil.! !!TweetBase class methodsFor: 'instance creation' stamp: 'ArturoZambrano 12/8/2014 18:07'!criteria: aHashtag ^ self new criteria: aHashtag; yourself! !!TweetBase class methodsFor: 'instance creation' stamp: 'ArturoZambrano 4/5/2014 11:49'!removeAll "WARING: this method remove all the tweet bases from your image and disk" bases do: [ :base | | ref | ref := base filename asFileReference. ref exists ifTrue: [ ref delete ] ]. bases removeAll! !!TweetBase class methodsFor: 'instance creation' stamp: 'ArturoZambrano 2/17/2014 15:36'!hashtag: aHashtag ^ self new hashtag: aHashtag; yourself! !!TweetBase class methodsFor: 'instance creation' stamp: 'RosarioSantaMarina 3/6/2014 09:43'!for: aHashtag ^ self bases at: aHashtag ifAbsent: [ | filename base | "self halt." filename := self filenameFrom: aHashtag. filename asFileReference exists ifTrue: [ base := FLMaterializer materializeFromFileNamed: filename ] ifFalse: [ base := self hashtag: aHashtag ]. self bases at: aHashtag put: base. base ]! !!TweetBase class methodsFor: 'instance creation' stamp: 'ArturoZambrano 1/21/2015 18:31'!removeFromMemory: aString Bases removeKey: aString. Smalltalk garbageCollect! !