diff --git a/data/manual/coding-corrections.csv b/data/manual/coding-corrections.csv new file mode 100644 index 0000000..0f65392 --- /dev/null +++ b/data/manual/coding-corrections.csv @@ -0,0 +1,937 @@ +Song ID,Run,Type,To Be Replaced,Correct Term +song-1,run1,evidence,You still hit my phone up,you still hit my phone up +song-1,run2,evidence,You still hit my phone up,you still hit my phone up +song-1,run3,evidence,You still hit my phone up,you still hit my phone up +song-13,run1,evidence,"You needed me\nTo feel a little more, and give a little less","you needed me\nTo feel a little more, and give a little less" +song-15,run1,evidence,The people still think I'm a star,the people still think I'm a star +song-15,run2,evidence,The people still think I'm a star,the people still think I'm a star +song-15,run3,evidence,The people still think I'm a star,the people still think I'm a star +song-18,run2,evidence,Let's start living dangerously,let's start living dangerously +song-18,run3,evidence,Let's start living dangerously,let's start living dangerously +song-19,run1,evidence,"It's just me, myself and I","it's just me, myself and I" +song-19,run2,evidence,"It's just me, myself and I","it's just me, myself and I" +song-19,run3,evidence,"It's just me, myself and I","it's just me, myself and I" +song-20,run1,evidence,"""Who would you live for?"" ""Who would you die for?""\nAnd ""would you ever kill?""","""who would you live for?"" ""Who would you die for?""\nAnd ""would you ever kill?""" +song-21,run3,keyword,warning-and-danger,**REMOVE** +song-29,run1,evidence,Last night I think I lost my patience,last night I think I lost my patience +song-29,run2,evidence,Last night I came to a realization,"Last night, I came to a realization" +song-29,run3,evidence,Last night I think I lost my patience,last night I think I lost my patience +song-32,run1,evidence,All these motherfuckers want a relapse,all these motherfuckers want a relapse +song-32,run1,evidence,You gon' have to do it at my tempo,you gon' have to do it at my tempo +song-32,run1,evidence,You look even better than the photos,you look even better than the photos +song-32,run2,evidence,All these motherfuckers want a relapse,all these motherfuckers want a relapse +song-32,run3,evidence,All these motherfuckers want a relapse,all these motherfuckers want a relapse +song-32,run3,evidence,You look even better than the photos,you look even better than the photos +song-34,run3,evidence,From the concrete I had rose,from the concrete I had rose +song-47,run1,evidence,Go through the darkest of days,go through the darkest of days +song-47,run2,evidence,Go through the darkest of days,go through the darkest of days +song-47,run3,evidence,Go through the darkest of days,go through the darkest of days +song-48,run2,evidence,"She said, ""Once you take me with you, I'll never go back""","You said, ""Once you take me with you, I'll never go back""" +song-49,run2,evidence,Tell me you're never leaving,tell me you're never leaving +song-50,run1,evidence,Even after all this time I still wonder,even after all this time I still wonder +song-50,run2,evidence,Even after all this time I still wonder,even after all this time I still wonder +song-50,run3,evidence,Even after all this time I still wonder,even after all this time I still wonder +song-58,run1,evidence,"Coming for the king, that's a far cry, I","Comin' for the king, that's a far cry, I" +song-58,run2,evidence,"Coming for the king, that's a far cry, I","Comin' for the king, that's a far cry, I" +song-58,run3,evidence,"Coming for the king, that's a far cry, I","Comin' for the king, that's a far cry, I" +song-63,run1,evidence,And then I let him go,and then I let him go +song-63,run2,evidence,And then I let him go,and then I let him go +song-63,run3,evidence,And then I let him go,and then I let him go +song-64,run1,evidence,And that red dress brings me to my knees,and that red dress brings me to my knees +song-64,run1,evidence,If I never get to build my mansion in Georgia,if I never get to build my mansion in Georgia +song-64,run2,evidence,Baby last night was hands down one of the best nights,Baby last night was hands down\nOne of the best nights +song-64,run2,evidence,Between the bottle of wine and the look in your eyes and the Marvin Gaye,Between the bottle of wine\nAnd the look in your eyes and the Marvin Gaye +song-64,run2,evidence,But that black dress makes it hard to breathe,but that black dress makes it hard to breathe +song-64,run3,evidence,Baby last night was hands down one of the best nights,Baby last night was hands down\nOne of the best nights +song-64,run3,evidence,Between the bottle of wine and the look in your eyes and the Marvin Gaye,Between the bottle of wine\nAnd the look in your eyes and the Marvin Gaye +song-64,run3,evidence,But that black dress makes it hard to breathe,but that black dress makes it hard to breathe +song-65,run3,evidence,Jump all them Jordans,jump all them Jordans +song-79,run1,evidence,I bet these memories follow you around,I bet these memories\nFollow you around +song-86,run1,evidence,He knows dirty secrets that I keep,He knows\nDirty secrets that I keep +song-90,run1,evidence,"Any car, any house\nBaby you can get like any ring, anything","any car, any house\nBaby you can get like any ring, anything" +song-90,run1,evidence,"Baby the cars on decline\nYou roll with me, you miss shine","baby the cars on decline\nYou roll with me, you miss shine" +song-90,run2,evidence,"Any car, any house\nBaby you can get like any ring, anything","any car, any house\nBaby you can get like any ring, anything" +song-90,run2,evidence,Baby the cars on decline,baby the cars on decline +song-90,run2,evidence,You don't have to worry 'bout a thing,You don't have to worry ‘bout a thing +song-90,run3,evidence,"'Cause I may not know you, just let me hold you","‘Cause I may not know you, just let me hold you" +song-90,run3,evidence,"Any car, any house\nBaby you can get like any ring, anything","any car, any house\nBaby you can get like any ring, anything" +song-90,run3,evidence,Baby the cars on decline,baby the cars on decline +song-90,run3,evidence,"You be my soldier, and you from the 'Nolia","You be my soldier, and you from the ‘Nolia" +song-92,run1,evidence,All my diamonds shine 'cause they really diamonds,All my diamonds shine ‘cause they really diamonds +song-92,run1,evidence,I look like I been ballin' 'cause I'm really ballin',I look like I been ballin' ‘cause I'm really ballin' +song-92,run2,evidence,All my diamonds shine 'cause they really diamonds,All my diamonds shine ‘cause they really diamonds +song-92,run2,evidence,I look like I been ballin' 'cause I'm really ballin',I look like I been ballin' ‘cause I'm really ballin' +song-92,run3,evidence,All my diamonds shine 'cause they really diamonds,All my diamonds shine ‘cause they really diamonds +song-92,run3,evidence,I look like I been ballin' 'cause I'm really ballin',I look like I been ballin' ‘cause I'm really ballin' +song-92,run3,evidence,I'm shining bright 'cause I'm really grinding,I'm shining bright ‘cause I'm really grinding +song-98,run1,evidence,"Dead niggas with 'em, dead niggas, get 'em","Dead niggas with 'em, dead niggas, get ’em" +song-98,run1,evidence,"Ten niggas with 'em, ten clappin' on 'em","Ten niggas with ’em, ten clappin' on 'em" +song-98,run1,evidence,"Young boy walkin', wishin' for a burner","Young boy walkin’, wishin’ for a burner" +song-98,run2,evidence,"Dead niggas with 'em, dead niggas, get 'em","Dead niggas with 'em, dead niggas, get ’em" +song-98,run2,evidence,"Young boy walkin', wishin' for a burner","Young boy walkin’, wishin’ for a burner" +song-98,run3,evidence,"Dead niggas with 'em, dead niggas, get 'em","Dead niggas with 'em, dead niggas, get ’em" +song-98,run3,evidence,"Ten niggas with 'em, ten clappin' on 'em","Ten niggas with ’em, ten clappin' on 'em" +song-98,run3,evidence,"Young boy walkin', wishin' for a burner","Young boy walkin’, wishin’ for a burner" +song-99,run3,evidence,Hard work forever pays now I see you in a better place,hard work forever pays now I see you in a better place +song-106,run3,evidence,"Sim, armadilha jovem negro com o Ak (rrah)","Sim, dessa forma, armadilha jovem negro com o Ak (rrah)" +song-110,run1,evidence,You made me feel as though I was enough,You made me feel as though\nI was enough +song-110,run2,evidence,You made me feel as though I was enough,You made me feel as though\nI was enough +song-112,run1,keyword,alcohol-and-substance-use,alcohol-and-substance-abuse +song-113,run1,evidence,"Buy my Range, make 'em go insane","Buy my Range, make ‘em go insane" +song-113,run1,evidence,"Tек and beams, go to those extremes","Tek and beams, go to those extremes" +song-113,run2,evidence,"Buy my Range, make 'em go insane","Buy my Range, make ‘em go insane" +song-113,run2,evidence,"Tек and beams, go to those extremes","Tek and beams, go to those extremes" +song-113,run3,evidence,"Buy my Range, make 'em go insane","Buy my Range, make ‘em go insane" +song-120,run3,keyword,manipulation,**REMOVE** +song-128,run2,evidence,So she tries to cover up her pain,"So, she tries to cover up her pain" +song-128,run3,evidence,So she tries to cover up her pain,"So, she tries to cover up her pain" +song-129,run1,evidence,"It's the lightness in the air\nWhen you're there, chest to chest with a lover","it's the lightness in the air\nWhen you're there, chest to chest with a lover" +song-129,run2,evidence,"It's the lightness in the air\nWhen you're there, chest to chest with a lover","it's the lightness in the air\nWhen you're there, chest to chest with a lover" +song-129,run3,evidence,"It's the lightness in the air\nWhen you're there, chest to chest with a lover","it's the lightness in the air\nWhen you're there, chest to chest with a lover" +song-136,run2,keyword,reputation-and-gossess,reputation-and-gossip +song-141,run1,keyword,sacrifice,**REMOVE** +song-141,run2,keyword,sacrifice-and-surrender,**REMOVE** +song-143,run1,evidence,Second chance you'll never get,second chance you'll never get +song-143,run2,evidence,Second chance you'll never get,second chance you'll never get +song-143,run3,evidence,Second chance you'll never get,second chance you'll never get +song-146,run3,evidence,Wanna leave my own life behind,wanna leave my own life behind +song-148,run1,evidence,"Aw, this the strip club anthem, nigga, what's up?","Aw, this the strip club anthem, nigga, what’s up?" +song-148,run2,evidence,"Aw, this the strip club anthem, nigga, what's up?","Aw, this the strip club anthem, nigga, what’s up?" +song-148,run3,evidence,"Aw, this the strip club anthem, nigga, what's up?","Aw, this the strip club anthem, nigga, what’s up?" +song-156,run1,evidence,Killings on the way,killings on the way +song-156,run1,evidence,Sleepin' in a villa,sleepin' in a villa +song-156,run2,evidence,Sleepin' in a villa,sleepin' in a villa +song-156,run3,evidence,Pessimists never struck my nerve,pessimists never struck my nerve +song-156,run3,evidence,Sleepin' in a villa,sleepin' in a villa +song-159,run1,evidence,Cleansing my soul of addiction for now,Cleansin' my soul of addiction for now +song-159,run1,evidence,Tension\nBetween us just like picket fences,tension\nBetween us just like picket fences +song-159,run2,evidence,Cleansing my soul of addiction for now,Cleansin' my soul of addiction for now +song-159,run2,evidence,Tension\nBetween us just like picket fences,tension\nBetween us just like picket fences +song-159,run3,evidence,Cleansing my soul of addiction for now,Cleansin' my soul of addiction for now +song-159,run3,evidence,Tension\nBetween us just like picket fences,tension\nBetween us just like picket fences +song-161,run1,evidence,"Some things, only God can forgive","some things, only God can forgive" +song-161,run2,evidence,"Some things, only God can forgive","some things, only God can forgive" +song-161,run3,evidence,"Some things, only God can forgive","some things, only God can forgive" +song-162,run1,evidence,Back the fuck up off me,back the fuck up off me +song-162,run2,evidence,Back the fuck up off me,back the fuck up off me +song-162,run3,evidence,Back the fuck up off me,back the fuck up off me +song-165,run3,evidence,"What if I hurt you, what if I leave you","what if I hurt you, what if I leave you" +song-172,run2,evidence,Bitch can't stop me,bitch can't stop me +song-175,run2,evidence,But how you called the cops on me my nig? You grew up with me,But how you called the cops on me my nig?\nYou grew up with me +song-175,run3,evidence,But how you called the cops on me my nig? You grew up with me,But how you called the cops on me my nig?\nYou grew up with me +song-177,run1,evidence,All she wear is red bottom heels,all she wear is red bottom heels +song-177,run2,evidence,All she wear is red bottom heels,all she wear is red bottom heels +song-177,run3,evidence,All she wear is red bottom heels,all she wear is red bottom heels +song-184,run1,evidence,I do what I want 'cause I'm signed to me,I do what I want ‘cause I'm signed to me +song-184,run2,evidence,I do what I want 'cause I'm signed to me,I do what I want ‘cause I'm signed to me +song-184,run3,evidence,I do what I want 'cause I'm signed to me,I do what I want ‘cause I'm signed to me +song-187,run1,evidence,"Half of my heart is in Havana, ooh-na-na (ayy)","Half of my heart is in Havana, ooh-na-na (ayy" +song-187,run1,evidence,He said there's a lot of girls I can do with,He said there’s a lot of girls I can do with +song-187,run2,evidence,"Half of my heart is in Havana, ooh-na-na (ayy)","Half of my heart is in Havana, ooh-na-na (ayy" +song-187,run2,evidence,He said there's a lot of girls I can do with,He said there’s a lot of girls I can do with +song-187,run3,evidence,"Half of my heart is in Havana, ooh-na-na (ayy)","Half of my heart is in Havana, ooh-na-na (ayy" +song-187,run3,evidence,"Half of my heart is in Havana, ooh-na-na (ayy)\nHe took me back to East Atlanta, oh-na-na-na","Half of my heart is in Havana, ooh-na-na (ayy, ayy)\nHe took me back to East Atlanta, oh-na-na-na" +song-187,run3,evidence,He said there's a lot of girls I can do with,He said there’s a lot of girls I can do with +song-188,run1,evidence,Aren't we too grown to mess around? Yeah,Are we too grown to mess around? Yeah +song-188,run2,evidence,Aren't we too grown to mess around? Yeah,Are we too grown to mess around? Yeah +song-188,run3,evidence,Aren't we too grown to mess around? Yeah,Are we too grown to mess around? Yeah +song-189,run1,evidence,"So fuckin' done with you, girl","so fuckin' done with you, girl" +song-189,run2,evidence,Breaking glass on my Range Rover,breaking glass on my Range Rover +song-189,run2,evidence,"So fuckin' done with you, girl","so fuckin' done with you, girl" +song-189,run3,evidence,"So fuckin' done with you, girl","so fuckin' done with you, girl" +song-194,run2,evidence,My heart's been hurt a couple times,my heart's been hurt a couple times +song-194,run3,evidence,"Ain't gon' lie, ain't gon' lie","ain't gon' lie, ain't gon' lie" +song-194,run3,evidence,My heart's been hurt a couple times,my heart's been hurt a couple times +song-195,run1,evidence,Don't act like you my friend when I'm rollin' through my end zone,Don’t act like you my friend when I'm rollin' through my end zone +song-195,run2,evidence,Don't act like you my friend when I'm rollin' through my end zone,Don’t act like you my friend when I'm rollin' through my end zone +song-195,run3,evidence,Don't act like you my friend when I'm rollin' through my end zone,Don’t act like you my friend when I'm rollin' through my end zone +song-195,run3,evidence,Got diamonds by the boatload,got diamonds by the boatload +song-207,run1,evidence,"Just one hit of you, I knew I'll never ever, ever be the same","Just one hit of you, I knew I’ll never ever, ever be the same" +song-207,run2,evidence,"Just one hit of you, I knew I'll never ever, ever be the same","Just one hit of you, I knew I’ll never ever, ever be the same" +song-207,run3,evidence,"Just one hit of you, I knew I'll never ever, ever be the same","Just one hit of you, I knew I’ll never ever, ever be the same" +song-210,run1,evidence,"I just gotta tell you how I feel, look","Just gotta tell you how I feel, look" +song-210,run3,evidence,"I just gotta tell you how I feel, look","Just gotta tell you how I feel, look" +song-211,run1,evidence,Pull up with that Draco (huh?) / Play with Drake and I'ma shoot (that's on my mama),pull up with that Draco (huh?)\nPlay with Drake and I'ma shoot (that's on my mama +song-211,run3,evidence,"Pull up broad day with a K, now he shiverin' (he shiverin')","pull up broad day with a K, now he shiverin' (he shiverin')" +song-211,run3,evidence,Pull up with that Draco (huh?) / Play with Drake and I'ma shoot (that's on my mama),pull up with that Draco (huh?)\nPlay with Drake and I'ma shoot (that's on my mama +song-216,run2,evidence,Fuck what a nigga say,fuck what a nigga say +song-217,run1,evidence,Let's put my fake face on and pretend now,let's put my fake face on and pretend now +song-217,run3,evidence,Let's put my fake face on and pretend now,let's put my fake face on and pretend now +song-218,run1,evidence,Pussy poppin' on the charts,Pussy poppin’ on the charts +song-218,run2,evidence,Pussy poppin' on the charts,Pussy poppin’ on the charts +song-218,run3,evidence,Pussy poppin' on the charts,Pussy poppin’ on the charts +song-219,run1,evidence,Come through rockin' fashions,come through rockin' fashions +song-219,run2,evidence,"Come through rockin' fashions\nThat got all these bitches like ""Yo, what's that?""","come through rockin' fashions\nThat got all these bitches like ""Yo, what's that?""" +song-219,run3,evidence,Come through rockin' fashions,come through rockin' fashions +song-223,run1,evidence,So I'm just a dead man crawling tonight,So I’m just a dead man crawling tonight +song-223,run1,evidence,"So who you've been calling, baby? Nobody could take my place","So who you’ve been calling, baby? Nobody could take my place" +song-223,run2,evidence,So I'm just a dead man crawling tonight,So I’m just a dead man crawling tonight +song-223,run2,evidence,"So who you've been calling, baby? Nobody could take my place","So who you’ve been calling, baby? Nobody could take my place" +song-223,run2,evidence,You used to call me baby now you're calling me by name,you used to call me baby now you're calling me by name +song-223,run3,evidence,So I'm just a dead man crawling tonight,So I’m just a dead man crawling tonight +song-223,run3,evidence,"So who you've been calling, baby? Nobody could take my place","So who you’ve been calling, baby? Nobody could take my place" +song-223,run3,evidence,You used to call me baby now you're calling me by name,you used to call me baby now you're calling me by name +song-226,run1,evidence,"She left me with a broken heart, yeah","she left me with a broken heart, yeah" +song-226,run3,evidence,"She left me with a broken heart, yeah","she left me with a broken heart, yeah" +song-227,run1,evidence,If I gotta be sacrificed for the greater good\nThen that's what it gotta be,if I gotta be sacrificed for the greater good\nThen that's what it gotta be +song-227,run2,evidence,If I gotta be sacrificed for the greater good\nThen that's what it gotta be,if I gotta be sacrificed for the greater good\nThen that's what it gotta be +song-228,run1,evidence,And I gotta convince myself I don't want it even though I do,And I gotta convince myself I don’t want it even though I do +song-228,run2,evidence,And I gotta convince myself I don't want it even though I do,And I gotta convince myself I don’t want it even though I do +song-228,run3,evidence,And I gotta convince myself I don't want it even though I do,And I gotta convince myself I don’t want it even though I do +song-228,run3,evidence,Overthinking every word and I hate it 'cause it's not me,Overthinking every word and I hate it 'cause it’s not me +song-229,run2,evidence,"Checks over stripes, that's what I like",Checks over stripes (yeah)\nThat's what I like +song-229,run3,evidence,"Checks over stripes, that's what I like",Checks over stripes (yeah)\nThat's what I like +song-230,run2,evidence,"Take my shoes and walk a mile, Something that you can't do",Take my shoes and walk a mile\nSomething that you can't do +song-230,run2,evidence,"Think it came with stripes, But you ain't straight with the gang",Think it came with stripes\nBut you ain't straight with the gang +song-230,run3,evidence,"I bought a 'Plain Jane' Rollie, These niggas bought they fame",I bought a 'Plain Jane' Rollie\nThese niggas bought they fame +song-230,run3,evidence,Quadruple the profit (Profit),quadruple the profit (Profit) +song-230,run3,evidence,"Take my shoes and walk a mile, Something that you can't do",Take my shoes and walk a mile\nSomething that you can't do +song-230,run3,evidence,"Think it came with stripes, But you ain't straight with the gang (Gang, gang!)","Think it came with stripes\nBut you ain't straight with the gang (Gang, gang" +song-232,run1,evidence,"What the fuck is love with no pain, no suffer","what the fuck is love with no pain, no suffer" +song-232,run2,evidence,She gon' ride for me until this thing over,she gon' ride for me until this thing over +song-232,run2,evidence,We'd both go crazy (crazy) if we was to sever,we'd both go crazy (crazy) if we was to sever +song-232,run2,evidence,"What the fuck is love with no pain, no suffer","what the fuck is love with no pain, no suffer" +song-232,run3,evidence,She gon' ride for me until this thing over,she gon' ride for me until this thing over +song-232,run3,evidence,We'd both go crazy (crazy) if we was to sever,we'd both go crazy (crazy) if we was to sever +song-232,run3,evidence,"What the fuck is love with no pain, no suffer","what the fuck is love with no pain, no suffer" +song-235,run3,evidence,"Ichy Patek, check, yeah, boogers, they sit on my neck (ice)","Icy Patek, check, yeah, boogers, they sit on my neck (ice)" +song-238,run1,evidence,I get 2 million a pop and that's standard for me,I get 2 million a pop and that’s standard for me +song-238,run1,evidence,"I'm a bar spitta, I'm a hard hitta","I'm a bar spitta, I’m a hard hitta" +song-238,run2,evidence,I get 2 million a pop and that's standard for me,I get 2 million a pop and that’s standard for me +song-238,run2,evidence,"I'm a bar spitta, I'm a hard hitta","I'm a bar spitta, I’m a hard hitta" +song-238,run3,evidence,I get 2 million a pop and that's standard for me,I get 2 million a pop and that’s standard for me +song-238,run3,evidence,"I'm a bar spitta, I'm a hard hitta","I'm a bar spitta, I’m a hard hitta" +song-242,run1,evidence,"Fuck 12, I'm a G, ain't no stoppin' me (ain't no stoppin' me)","Fuck 12, I’m a G, ain't no stoppin' me (ain't no stoppin' me)" +song-242,run2,evidence,"Fuck 12, I'm a G, ain't no stoppin' me (ain't no stoppin' me)","Fuck 12, I’m a G, ain't no stoppin' me (ain't no stoppin' me)" +song-242,run3,evidence,"Fuck 12, I'm a G, ain't no stoppin' me (ain't no stoppin' me)","Fuck 12, I’m a G, ain't no stoppin' me (ain't no stoppin' me)" +song-247,run1,evidence,You love it how I move you,you love it how I move you +song-247,run2,evidence,You love it how I move you,you love it how I move you +song-247,run3,evidence,You love it how I move you,you love it how I move you +song-252,run1,evidence,face up 'cause you're a natural,face up 'cause you're a...\n\nNatural +song-252,run2,evidence,Will somebody let me see the light within the dark trees' shadows,Will somebody\nLet me see the light within the dark trees' shadows +song-252,run2,evidence,"Will you hold the line when every one of them is giving up or giving in, tell me","Will you hold the line\nWhen every one of them is giving up or giving in, tell me" +song-252,run2,evidence,You gotta be so cold to make it in this world,You gotta be so cold\nTo make it in this world +song-252,run2,evidence,face up 'cause you're a natural,face up 'cause you're a...\n\nNatural +song-252,run3,evidence,"I can taste it, the end is upon us, I swear gonna make it","I can taste it, the end is upon us, I swear\nGonna make it" +song-252,run3,evidence,Will somebody let me see the light within the dark trees' shadows and,Will somebody\nLet me see the light within the dark trees' shadows and +song-252,run3,evidence,You gotta be so cold to make it in this world,You gotta be so cold\nTo make it in this world +song-252,run3,evidence,face up 'cause you're a natural,face up 'cause you're a...\n\nNatural +song-258,run1,evidence,Every day she found a way out of the window to sneak out late,every day she found a way out of the window to sneak out late +song-258,run2,evidence,Every day she found a way out of the window to sneak out late,every day she found a way out of the window to sneak out late +song-258,run3,evidence,Every day she found a way out of the window to sneak out late,every day she found a way out of the window to sneak out late +song-259,run1,evidence,"Call out my name, and I'll be on my way","call out my name, and I'll be on my way" +song-261,run1,evidence,It's eating me up inside,it's eating me up inside +song-262,run1,evidence,"De mi vida te saqué, yo te saqué","de mi vida te saqué, yo te saqué" +song-262,run1,evidence,Pa'l carajo te mandé; hoy me voy a beber,pa'l carajo te mandé; hoy me voy a beber +song-262,run2,evidence,"De mi vida te saqué, yo te saqué","de mi vida te saqué, yo te saqué" +song-262,run3,evidence,"De mi vida te saqué, yo te saqué","de mi vida te saqué, yo te saqué" +song-263,run1,evidence,It's safe to say it ain't our style,it's safe to say it ain't our style +song-263,run3,evidence,It's safe to say it ain't our style,it's safe to say it ain't our style +song-264,run2,evidence,Once a nigga graduate,once a nigga graduate +song-264,run3,evidence,Once a nigga graduate,once a nigga graduate +song-269,run3,evidence,Cuéntale parte por parte,cuéntale parte por parte +song-271,run1,evidence,You take the bullet tryna save me,you take the bullet tryna save me +song-271,run2,evidence,You take the bullet tryna save me,you take the bullet tryna save me +song-276,run1,evidence,"Big balling like Mutombo, yeah","big balling like Mutombo, yeah" +song-276,run2,evidence,"Just had a ménage, back seat of my Benz","Just had a ménage (hey), back seat of my Benz" +song-276,run3,evidence,"Just had a ménage, back seat of my Benz","Just had a ménage (hey), back seat of my Benz" +song-281,run1,evidence,Maybe it's 'cause I'm wearing your cologne,maybe it's 'cause I'm wearing your cologne +song-281,run3,evidence,Maybe it's 'cause I'm wearing your cologne,maybe it's 'cause I'm wearing your cologne +song-282,run1,evidence,"See the igloo in my mouth when I be grinnin' (I be grinnin'), yeah","See the igloo in my mouth when I be grinnin' (I be grinnin’), yeah" +song-282,run2,evidence,"All the housewives pullin' up (up, up)","All the housewives pullin’ up (up, up)" +song-282,run2,evidence,"See the igloo in my mouth when I be grinnin' (I be grinnin'), yeah","See the igloo in my mouth when I be grinnin' (I be grinnin’), yeah" +song-282,run3,evidence,"See the igloo in my mouth when I be grinnin' (I be grinnin'), yeah","See the igloo in my mouth when I be grinnin' (I be grinnin’), yeah" +song-283,run1,evidence,Breakfast at Tiffany's and bottles of bubbles,breakfast at Tiffany's and bottles of bubbles +song-283,run2,evidence,Breakfast at Tiffany's and bottles of bubbles,breakfast at Tiffany's and bottles of bubbles +song-283,run3,evidence,Breakfast at Tiffany's and bottles of bubbles,breakfast at Tiffany's and bottles of bubbles +song-287,run2,evidence,I've learned from the pain\nTurned out amazing,I've learned from the pain (pain)\nTurned out amazing +song-287,run3,evidence,Look what I got\nLook what you taught me,look what I got\nLook what you taught me +song-291,run1,evidence,But I'm told its where I'm supposed to be,But I’m told its where I’m supposed to be +song-291,run1,evidence,Coz I don't care when I'm with my baby yeah,Coz I don’t care when I’m with my baby yeah +song-291,run1,evidence,Don't think I fit in at this party,Don’t think I fit in at this party +song-291,run1,evidence,I always feel like I'm nobody,I always feel like I’m nobody +song-291,run1,evidence,I can deal with the bad nights when I'm with my baby yeah,I can deal with the bad nights when I’m with my baby yeah +song-291,run1,evidence,I don't like 'bout nobody but you,I don’t like ‘bout nobody but you +song-291,run1,evidence,I'm at a party I don't wanna be at,I’m at a party I don’t wanna be at +song-291,run1,evidence,"With all these people all around, I'm crippled with anxiety","With all these people all around, I’m crippled with anxiety" +song-291,run1,evidence,You can take me anywhere and you making me feel like I'm loved by somebody,You can take me anywhere and you making me feel like I’m loved by somebody +song-291,run2,evidence,But I'm told its where I'm supposed to be,But I’m told its where I’m supposed to be +song-291,run2,evidence,Coz I don't care when I'm with my baby yeah,Coz I don’t care when I’m with my baby yeah +song-291,run2,evidence,Don't think I fit in at this party,Don’t think I fit in at this party +song-291,run2,evidence,I always feel like I'm nobody,I always feel like I’m nobody +song-291,run2,evidence,I can deal with the bad nights when I'm with my baby yeah,I can deal with the bad nights when I’m with my baby yeah +song-291,run2,evidence,I'm at a party I don't wanna be at,I’m at a party I don’t wanna be at +song-291,run2,evidence,"With all these people all around, I'm crippled with anxiety","With all these people all around, I’m crippled with anxiety" +song-291,run2,evidence,You can take me anywhere and you making me feel like I'm loved by somebody,You can take me anywhere and you making me feel like I’m loved by somebody +song-291,run3,evidence,But I'm told its where I'm supposed to be,But I’m told its where I’m supposed to be +song-291,run3,evidence,Coz I don't care when I'm with my baby yeah,Coz I don’t care when I’m with my baby yeah +song-291,run3,evidence,Don't think I fit in at this party,Don’t think I fit in at this party +song-291,run3,evidence,I always feel like I'm nobody,I always feel like I’m nobody +song-291,run3,evidence,I can deal with the bad nights when I'm with my baby yeah,I can deal with the bad nights when I’m with my baby yeah +song-291,run3,evidence,I'm at a party I don't wanna be at,I’m at a party I don’t wanna be at +song-291,run3,evidence,"With all these people all around, I'm crippled with anxiety","With all these people all around, I’m crippled with anxiety" +song-291,run3,evidence,You can take me anywhere and you making me feel like I'm loved by somebody,You can take me anywhere and you making me feel like I’m loved by somebody +song-292,run1,evidence,Lot of Murakami in the hallway (What?),lot of Murakami in the hallway (What?) +song-292,run2,evidence,Lot of Murakami in the hallway (What?),lot of Murakami in the hallway (What?) +song-292,run3,evidence,Lot of Murakami in the hallway (What?),lot of Murakami in the hallway (What?) +song-293,run1,evidence,Ain't it hard keeping it so hardcore?,Ain’t it hard keeping it so hardcore? +song-293,run1,evidence,Aren't you tired tryin' to fill that void?,Aren’t you tired tryin' to fill that void? +song-293,run1,evidence,"Crash through the surface, where they can't hurt us","Crash through the surface, where they can’t hurt us" +song-293,run1,evidence,We're far from the shallow now,We’re far from the shallow now +song-293,run2,evidence,Ain't it hard keeping it so hardcore?,Ain’t it hard keeping it so hardcore? +song-293,run2,evidence,Aren't you tired tryin' to fill that void?,Aren’t you tired tryin' to fill that void? +song-293,run2,evidence,"Crash through the surface, where they can't hurt us","Crash through the surface, where they can’t hurt us" +song-293,run2,evidence,"I'm off the deep end, watch as I dive in","I’m off the deep end, watch as I dive in" +song-293,run2,evidence,We're far from the shallow now,We’re far from the shallow now +song-293,run3,evidence,Ain't it hard keeping it so hardcore?,Ain’t it hard keeping it so hardcore? +song-293,run3,evidence,Aren't you tired tryin' to fill that void?,Aren’t you tired tryin' to fill that void? +song-293,run3,evidence,"Crash through the surface, where they can't hurt us","Crash through the surface, where they can’t hurt us" +song-293,run3,evidence,"I'm off the deep end, watch as I dive in","I’m off the deep end, watch as I dive in" +song-293,run3,evidence,We're far from the shallow now,We’re far from the shallow now +song-297,run3,evidence,That lil' nigga ain't gon' shoot shit with that gun\nHe just pull it out in his pictures,that lil' nigga ain't gon' shoot shit with that gun\nHe just pull it out in his pictures +song-303,run1,evidence,There's no way I could save you\n'Cause I need to be saved too,There's no way I could save you (Save you)\n'Cause I need to be saved too +song-303,run3,evidence,There's no way I could save you\n'Cause I need to be saved too,There's no way I could save you (Save you)\n'Cause I need to be saved too +song-313,run1,evidence,"But I'm 21 4L, ain't no way I'ma switch","But I'm 21 4L, ain’t no way I'ma switch" +song-313,run1,evidence,"Every day that I'm alive, I'ma ride with the stick","Every day that I'm alive, I’ma ride with the stick" +song-313,run1,evidence,It's got to the point that these rappers don't even like rappin' with me,It’s got to the point that these rappers don't even like rappin' with me +song-313,run1,evidence,This is a marathon and I'm aware,This is a marathon and I’m aware +song-313,run2,evidence,"But I'm 21 4L, ain't no way I'ma switch","But I'm 21 4L, ain’t no way I'ma switch" +song-313,run2,evidence,"Every day that I'm alive, I'ma ride with the stick","Every day that I'm alive, I’ma ride with the stick" +song-313,run2,evidence,It's got to the point that these rappers don't even like rappin' with me,It’s got to the point that these rappers don't even like rappin' with me +song-313,run2,evidence,This is a marathon and I'm aware,This is a marathon and I’m aware +song-313,run3,evidence,"But I'm 21 4L, ain't no way I'ma switch","But I'm 21 4L, ain’t no way I'ma switch" +song-313,run3,evidence,"Every day that I'm alive, I'ma ride with the stick","Every day that I'm alive, I’ma ride with the stick" +song-313,run3,evidence,It's got to the point that these rappers don't even like rappin' with me,It’s got to the point that these rappers don't even like rappin' with me +song-313,run3,evidence,This is a marathon and I'm aware,This is a marathon and I’m aware +song-316,run1,evidence,"Diamonds in the rollie, they in hd like it's blu-ray","Diamonds in the rollie, they in hd like it’s blu-ray" +song-316,run2,evidence,"Diamonds in the rollie, they in hd like it's blu-ray","Diamonds in the rollie, they in hd like it’s blu-ray" +song-316,run3,evidence,"Diamonds in the rollie, they in hd like it's blu-ray","Diamonds in the rollie, they in hd like it’s blu-ray" +song-316,run3,evidence,Every single dollar in these bands got a blue face,every single dollar in these bands got a blue face +song-317,run2,evidence,Ain't afraid to take chances,ain't afraid to take chances +song-319,run1,evidence,"Sheck Wes, I ain't a mo'fuckin' joke","Sheck Wes, I ain’t a mo'fuckin' joke" +song-319,run1,evidence,Young Sheck Wes and I'm getting really rich,Young Sheck Wes and I’m getting really rich +song-319,run2,evidence,"I'm the best drug dealer, nigga, come and cop it","I’m the best drug dealer, nigga, come and cop it" +song-319,run2,evidence,"Sheck Wes, I ain't a mo'fuckin' joke","Sheck Wes, I ain’t a mo'fuckin' joke" +song-319,run2,evidence,Young Sheck Wes and I'm getting really rich,Young Sheck Wes and I’m getting really rich +song-319,run3,evidence,"Sheck Wes, I ain't a mo'fuckin' joke","Sheck Wes, I ain’t a mo'fuckin' joke" +song-319,run3,evidence,Young Sheck Wes and I'm getting really rich,Young Sheck Wes and I’m getting really rich +song-325,run1,evidence,You got the bag but can't afford it (Give me the bag),"You got the bag, but can't afford it (Give me the bag" +song-327,run1,evidence,"I'ma hoe, rich bitch and work like I'm broke still (Cardi)","I'ma hoe, rich bitch and work like I’m broke still (Cardi)" +song-327,run1,evidence,"Pорque i am the party, yo soy fiesta","Porque i am the party, yo soy fiesta" +song-327,run2,evidence,"I'ma hoe, rich bitch and work like I'm broke still (Cardi)","I'ma hoe, rich bitch and work like I’m broke still (Cardi)" +song-327,run3,evidence,"I'ma hoe, rich bitch and work like I'm broke still (Cardi)","I'ma hoe, rich bitch and work like I’m broke still (Cardi)" +song-335,run1,evidence,Desde que te vi supe que eras pa' mi,Desde que te vi supe que eras pa’ mi +song-335,run1,evidence,Ese un asesina cuando baila quiero que to' el mundo la vea,Ese un asesina cuando baila quiero que to’ el mundo la vea +song-335,run1,evidence,"I like your ""poom poom"" girl",I like your “poom poom” girl +song-335,run1,evidence,Zúmbale dj otra vez pa' que dance,Zúmbale dj otra vez pa’ que dance +song-335,run2,evidence,Desde que te vi supe que eras pa' mi,Desde que te vi supe que eras pa’ mi +song-335,run2,evidence,Ese un asesina cuando baila quiero que to' el mundo la vea,Ese un asesina cuando baila quiero que to’ el mundo la vea +song-335,run2,evidence,"I like your ""poom poom"" girl",I like your “poom poom” girl +song-335,run3,evidence,Desde que te vi supe que eras pa' mi,Desde que te vi supe que eras pa’ mi +song-335,run3,evidence,"I like your ""poom poom"" girl",I like your “poom poom” girl +song-340,run1,evidence,"'Cause you different, you can't play your part (no damn, ay)","'Cause you different, you can’t play your part (no damn, ay)" +song-340,run1,evidence,How could you\nMoving like you're crazy\nI ain't call you back (damn),How could you\nMoving like you’re crazy\nI ain’t call you back (damn) +song-340,run1,evidence,How you just gon' play me\nI ain't fine with that,How you just gon’ play me\nI ain’t fine with that +song-340,run1,evidence,I can't sweat you I'm like who dat?,I can’t sweat you I’m like who dat? +song-340,run1,evidence,I wanted you but I can't fuck with you,I wanted you but I can’t fuck with you +song-340,run1,evidence,Play me you're my lady\nGot no time for that,Play me you’re my lady\nGot no time for that +song-340,run1,evidence,Tell you the truth\nI ain't want you to depart (ay),Tell you the truth\nI ain’t want you to depart (ay) +song-340,run1,evidence,Thinking 'bout you daily\nSmoking crazy while I'm off the tac (damn),Thinking ‘bout you daily\nSmoking crazy while I’m off the tac (damn) +song-340,run1,evidence,"You can't play me, I'm just wavy","You can’t play me, I’m just wavy" +song-340,run2,evidence,Hit my bop like I'm Lil Kodak,Hit my bop like I’m Lil Kodak +song-340,run2,evidence,How you just gon' play me\nI ain't fine with that,How you just gon’ play me\nI ain’t fine with that +song-340,run2,evidence,I cannot fuck on no bitch\nI can't love when the bitch is not playing her part (like damn),I cannot fuck on no bitch\nI can’t love when the bitch is not playing her part (like damn) +song-340,run2,evidence,"I wanted you but I can't fuck with you\n'Cause you different, you can't play your part (no damn, ay)","I wanted you but I can’t fuck with you\n'Cause you different, you can’t play your part (no damn, ay)" +song-340,run2,evidence,Moving like you're crazy\nI ain't call you back (damn),Moving like you’re crazy\nI ain’t call you back (damn) +song-340,run2,evidence,Tell you the truth\nI ain't want you to depart (ay),Tell you the truth\nI ain’t want you to depart (ay) +song-340,run2,evidence,Thinking 'bout you daily,Thinking ‘bout you daily +song-340,run2,evidence,"You can't play me, I'm just wavy","You can’t play me, I’m just wavy" +song-340,run3,evidence,"'Cause you different, you can't play your part (no damn, ay)","'Cause you different, you can’t play your part (no damn, ay)" +song-340,run3,evidence,Hit my bop like I'm Lil Kodak,Hit my bop like I’m Lil Kodak +song-340,run3,evidence,How you just gon' play me\nI ain't fine with that,How you just gon’ play me\nI ain’t fine with that +song-340,run3,evidence,I ain't fine with that,I ain’t fine with that +song-340,run3,evidence,I cannot fuck on no bitch\nI can't love when the bitch is not playing her part (like damn),I cannot fuck on no bitch\nI can’t love when the bitch is not playing her part (like damn) +song-340,run3,evidence,I wanted you but I can't fuck with you,I wanted you but I can’t fuck with you +song-340,run3,evidence,Leave and I'm gone (yah),Leave and I’m gone (yah) +song-340,run3,evidence,Moving like you're crazy\nI ain't call you back (damn),Moving like you’re crazy\nI ain’t call you back (damn) +song-340,run3,evidence,Tell you the truth\nI ain't want you to depart (ay),Tell you the truth\nI ain’t want you to depart (ay) +song-340,run3,evidence,Thinking 'bout you daily,Thinking ‘bout you daily +song-340,run3,evidence,Thinking 'bout you daily\nSmoking crazy while I'm off the tac (damn),Thinking ‘bout you daily\nSmoking crazy while I’m off the tac (damn) +song-340,run3,evidence,"You can't play me, I'm just wavy","You can’t play me, I’m just wavy" +song-344,run1,evidence,"It's the end, doo doo doo doo doo doo","It’s the end, doo doo doo doo doo doo" +song-344,run1,evidence,"Let's go hunt, doo doo doo doo doo doo","Let’s go hunt, doo doo doo doo doo doo" +song-344,run2,evidence,"Let's go hunt, doo doo doo doo doo doo","Let’s go hunt, doo doo doo doo doo doo" +song-344,run3,evidence,"It's the end, doo doo doo doo doo doo","It’s the end, doo doo doo doo doo doo" +song-344,run3,evidence,"Let's go hunt, doo doo doo doo doo doo","Let’s go hunt, doo doo doo doo doo doo" +song-345,run1,evidence,"Bitch please, Lamborghini keys","Bitch please (Bitch), Lamborghini keys" +song-345,run2,evidence,"Bitch please, Lamborghini keys","Bitch please (Bitch), Lamborghini keys" +song-345,run3,evidence,"Bitch please, Lamborghini keys","Bitch please (Bitch), Lamborghini keys" +song-347,run1,evidence,'Cause leaving now just don't feel right,'Cause leaving now just don’t feel right +song-347,run1,evidence,I'm praying you don't change your mind,I’m praying you don’t change your mind +song-347,run1,evidence,"It's closing time, so leave with me again (Yeah)","It’s closing time, so leave with me again (Yeah)" +song-347,run2,evidence,'Cause leaving now just don't feel right,'Cause leaving now just don’t feel right +song-347,run2,evidence,I'm praying you don't change your mind,I’m praying you don’t change your mind +song-347,run2,evidence,"It's closing time, so leave with me again (Yeah)","It’s closing time, so leave with me again (Yeah)" +song-347,run3,evidence,'Cause leaving now just don't feel right,'Cause leaving now just don’t feel right +song-347,run3,evidence,I'm praying you don't change your mind,I’m praying you don’t change your mind +song-347,run3,evidence,"It's closing time, so leave with me again (Yeah)","It’s closing time, so leave with me again (Yeah)" +song-348,run1,evidence,And ice needs whiskey,and ice needs whiskey +song-348,run1,evidence,Back seats need I want you so bad,back seats need I want you so bad +song-348,run1,evidence,Birds need bees and ice needs whiskey,birds need bees and ice needs whiskey +song-348,run1,evidence,Small town nights need both ends burnin',small town nights need both ends burnin' +song-348,run2,evidence,And ice needs whiskey,and ice needs whiskey +song-348,run2,evidence,Back seats need I want you so bad,back seats need I want you so bad +song-348,run2,evidence,Birds need bees and ice needs whiskey,birds need bees and ice needs whiskey +song-348,run2,evidence,Friday nights need to do what Friday nights need to do,Friday nights need to do\nWhat Friday nights need to do +song-348,run2,evidence,Small town nights need both ends burnin',small town nights need both ends burnin' +song-348,run3,evidence,And ice needs whiskey,and ice needs whiskey +song-348,run3,evidence,Back seats need I want you so bad,back seats need I want you so bad +song-348,run3,evidence,Birds need bees and ice needs whiskey,birds need bees and ice needs whiskey +song-348,run3,evidence,Friday nights need to do what Friday nights need to do,Friday nights need to do\nWhat Friday nights need to do +song-348,run3,evidence,Small town nights need both ends burnin',small town nights need both ends burnin' +song-350,run1,evidence,"I swear I ain't no killer, but test me if you want","I swear I ain’t no killer, but test me if you want" +song-350,run1,evidence,"I thought everything was right, that's when you left, yeah","I thought everything was right, that’s when you left, yeah" +song-350,run1,evidence,"New Louboutin, you would think I'm bleedin' from my toes","New Louboutin, you would think I’m bleedin’ from my toes" +song-350,run2,evidence,"I swear I ain't no killer, but test me if you want","I swear I ain’t no killer, but test me if you want" +song-350,run2,evidence,"I thought everything was right, that's when you left, yeah","I thought everything was right, that’s when you left, yeah" +song-350,run2,evidence,"New Louboutin, you would think I'm bleedin' from my toes","New Louboutin, you would think I’m bleedin’ from my toes" +song-350,run3,evidence,"I swear I ain't no killer, but test me if you want","I swear I ain’t no killer, but test me if you want" +song-350,run3,evidence,"I thought everything was right, that's when you left, yeah","I thought everything was right, that’s when you left, yeah" +song-350,run3,evidence,"New Louboutin, you would think I'm bleedin' from my toes","New Louboutin, you would think I’m bleedin’ from my toes" +song-353,run2,evidence,Those eyes can hypnotize,those eyes can hypnotize +song-356,run1,evidence,I've cheated and I've lied,I've cheated and I’ve lied +song-356,run1,evidence,I've got nothing to hide no more,I’ve got nothing to hide no more +song-356,run2,evidence,I've cheated and I've lied,I've cheated and I’ve lied +song-356,run2,evidence,I've got nothing to hide no more,I’ve got nothing to hide no more +song-356,run2,evidence,"When I was gettin' crazy, reckless, and wild\nActin' like my mama's little devilish child\nIt took a heart like yours to find its place","When I was gettin' crazy, reckless, and wild\nActin’ like my mama's little devilish child\nIt took a heart like yours to find its place" +song-356,run3,evidence,I've cheated and I've lied,I've cheated and I’ve lied +song-356,run3,evidence,I've got nothing to hide no more,I’ve got nothing to hide no more +song-357,run1,evidence,"and that's why every time you see me, I got some new shoes","And that's why every time you see me, I got some new shoes" +song-357,run2,evidence,"and that's why every time you see me, I got some new shoes","And that's why every time you see me, I got some new shoes" +song-357,run3,evidence,"and that's why every time you see me, I got some new shoes","And that's why every time you see me, I got some new shoes" +song-359,run2,evidence,"College girl, but a freak on the weekend (On the weekend)","college girl, but a freak on the weekend (On the weekend)" +song-360,run1,evidence,"I talked you into taking up my time, making up your mind","Talked you into taking up my time, making up your mind" +song-360,run1,evidence,There's a look in your eyes\nLooks like we ain't leavin' now,there's a look in your eyes\nLooks like we ain't leavin' now +song-360,run2,evidence,There's a look in your eyes\nLooks like we ain't leavin' now,there's a look in your eyes\nLooks like we ain't leavin' now +song-360,run3,evidence,There's a look in your eyes\nLooks like we ain't leavin' now,there's a look in your eyes\nLooks like we ain't leavin' now +song-362,run1,keyword,travel-and-adventure,**REMOVE** +song-369,run2,evidence,"Aren't you the guy who tried to hurt me with the word ""goodbye""?","Aren't you the guy who tried to\nHurt me with the word ""goodbye""?" +song-370,run2,evidence,She know that her youngest son was always guaranteed to get the money,she know that her youngest son was always guaranteed to get the money +song-374,run1,evidence,"But we built this right, so nothing's ever gonna move it","but\nWe built this right, so nothing's ever gonna move it" +song-374,run1,evidence,The wolves came and went and we're still standing,the wolves came and went and we're still standing +song-374,run2,evidence,The wolves came and went and we're still standing,the wolves came and went and we're still standing +song-374,run3,evidence,The wolves came and went and we're still standing,the wolves came and went and we're still standing +song-376,run2,evidence,I hope you make me smile the way you made me smile on the other end of a phone,I hope she makes you smile\nThe way you made me smile on the other end of a phone +song-390,run2,evidence,Shit hit different when it's Thursday night,shit hit different when it's Thursday night +song-397,run2,evidence,"I should've stayed at home, 'cause I was doing better alone","I whould've stayed at home, 'cause I was doing better alone" +song-398,run1,evidence,Chasing that feeling that got gone too soon,chasing that feeling that got gone too soon +song-399,run1,evidence,"Your savage love\nDid somebody, did somebody break your heart?\nLookin' like an angel but your savage love","your\n\nSavage love\nDid somebody, did somebody break your heart?\nLookin' like an angel but your savage love" +song-400,run1,evidence,She drop a pin and I'd come met her,she drop a pin and I'd come met her +song-400,run2,evidence,She drop a pin and I'd come met her,she drop a pin and I'd come met her +song-406,run2,evidence,"Yeah, we still young, there's so much we haven't done","yeah, we still young, there's so much we haven't done" +song-406,run3,evidence,"Yeah, we still young, there's so much we haven't done","yeah, we still young, there's so much we haven't done" +song-416,run1,evidence,"Nothing on me from Saks, everything Revive","Nothin' on me from Saks, everything Revive" +song-423,run1,evidence,"I ain't never do you wrong, so tell me why you don't trust me","I ain’t never do you wrong, so tell me why you don’t trust me" +song-423,run1,evidence,"I been tryna reach for it, but it's too far above me","I been tryna reach for it, but it’s too far above me" +song-423,run1,evidence,I'm tryna be with you so you don't be without me,I’m tryna be with you so you don’t be without me +song-423,run1,evidence,"She boo'd up off the meth like, she can't breathe without it","She boo’d up off the meth like, she can’t breathe without it" +song-423,run1,evidence,She don't want nobody,She don’t want nobody +song-423,run1,evidence,"She drinkin' Four Lokos, I can't get with those","She drinkin' Four Lokos, I can’t get with those" +song-423,run1,evidence,"She say: You say you love me, but I don't know what love means","She say: You say you love me, but I don’t know what love means" +song-423,run1,evidence,"She tote 'em just like me, no, we can't leave without it","She tote ’em just like me, no, we can’t leave without it" +song-423,run1,evidence,"They say you ain't wifey type, but I don't care, I want you","They say you ain’t wifey type, but I don’t care, I want you" +song-423,run2,evidence,"(Woah, don't be scared to party, don't be scared to party)","(Woah, don’t be scared to party, don’t be scared to party)" +song-423,run2,evidence,"I ain't never do you wrong, so tell me why you don't trust me","I ain’t never do you wrong, so tell me why you don’t trust me" +song-423,run2,evidence,"I been tryna reach for it, but it's too far above me","I been tryna reach for it, but it’s too far above me" +song-423,run2,evidence,I'm tryna be with you so you don't be without me,I’m tryna be with you so you don’t be without me +song-423,run2,evidence,"She boo'd up off the meth like, she can't breathe without it","She boo’d up off the meth like, she can’t breathe without it" +song-423,run2,evidence,She don't want nobody,She don’t want nobody +song-423,run2,evidence,"She drinkin' Four Lokos, I can't get with those","She drinkin' Four Lokos, I can’t get with those" +song-423,run2,evidence,"She say: You say you love me, but I don't know what love means","She say: You say you love me, but I don’t know what love means" +song-423,run2,evidence,"She tote 'em just like me, no, we can't leave without it","She tote ’em just like me, no, we can’t leave without it" +song-423,run2,evidence,"They say you ain't wifey type, but I don't care, I want you","They say you ain’t wifey type, but I don’t care, I want you" +song-423,run3,evidence,"I ain't never do you wrong, so tell me why you don't trust me","I ain’t never do you wrong, so tell me why you don’t trust me" +song-423,run3,evidence,"I been tryna reach for it, but it's too far above me","I been tryna reach for it, but it’s too far above me" +song-423,run3,evidence,I'm tryna be with you so you don't be without me,I’m tryna be with you so you don’t be without me +song-423,run3,evidence,"She boo'd up off the meth like, she can't breathe without it","She boo’d up off the meth like, she can’t breathe without it" +song-423,run3,evidence,She don't want nobody,She don’t want nobody +song-423,run3,evidence,"She drinkin' Four Lokos, I can't get with those","She drinkin' Four Lokos, I can’t get with those" +song-423,run3,evidence,"She say: You say you love me, but I don't know what love means","She say: You say you love me, but I don’t know what love means" +song-423,run3,evidence,"They say you ain't wifey type, but I don't care, I want you","They say you ain’t wifey type, but I don’t care, I want you" +song-425,run1,evidence,"Shawty with the long text, I don't talk, ayy","shawty with the long text, I don't talk, ayy" +song-426,run2,evidence,Make my wish come true\nBaby all I want for Christmas is you,Make my wish come true\nBaby all I want for Christmas is\nYou +song-427,run1,evidence,You broke every heart in your hometown,"You one of them girls, broke every heart in your hometown" +song-427,run1,evidence,You're one of them girls that ain't tryna meet nobody,you're one of them girls that ain't tryna meet nobody +song-427,run2,evidence,You're one of them girls that ain't tryna meet nobody,you're one of them girls that ain't tryna meet nobody +song-427,run3,evidence,You broke every heart in your hometown,"You one of them girls, broke every heart in your hometown" +song-427,run3,evidence,You're one of them girls that ain't tryna meet nobody,you're one of them girls that ain't tryna meet nobody +song-428,run2,evidence,It's driving me out of mine,it's driving me out of mine +song-428,run3,evidence,It's driving me out of mine,it's driving me out of mine +song-431,run2,evidence,"I hope you get moving on, all figured out","Hope you get moving on, all figured out" +song-434,run1,evidence,But it's time for a change,but it's time for a change +song-434,run2,evidence,But it's time for a change,but it's time for a change +song-434,run3,evidence,But it's time for a change,but it's time for a change +song-435,run1,evidence,"She only liked the guap, red light these hoes","she only liked the guap, red light these hoes" +song-435,run1,evidence,"The Bentley came with the wings like a number nine, yeah","the Bentley came with the wings like a number nine, yeah" +song-435,run2,evidence,"She only liked the guap, red light these hoes","she only liked the guap, red light these hoes" +song-435,run3,evidence,"The Bentley came with the wings like a number nine, yeah","the Bentley came with the wings like a number nine, yeah" +song-436,run1,evidence,"Peep all the moves I been makin', by time I get forty, I gotta be one of them greats","Peep all the moves I been makin', by time I get forty\nI gotta be one of them greats" +song-436,run1,evidence,"Wake up every day, somebody harassin' me","Wake up every day, somebody harrassin' me" +song-436,run2,evidence,"Peep all the moves I been makin', by time I get forty, I gotta be one of them greats","Peep all the moves I been makin', by time I get forty\nI gotta be one of them greats" +song-436,run2,evidence,"Wake up every day, somebody harassin' me","Wake up every day, somebody harrassin' me" +song-436,run3,evidence,"Peep all the moves I been makin', by time I get forty, I gotta be one of them greats","Peep all the moves I been makin', by time I get forty\nI gotta be one of them greats" +song-437,run1,evidence,Lock the door and throw out the key,lock the door and throw out the key +song-437,run2,evidence,Lock the door and throw out the key,lock the door and throw out the key +song-437,run2,evidence,"You never let me down, no, no","you never let me down, no, no" +song-437,run3,evidence,Lock the door and throw out the key,lock the door and throw out the key +song-445,run3,evidence,"Sometimes when you thought you found the love of your life (Ooh, ooh, ooh)","Sometimes, when you thought you found the love of your life (Ooh, ooh, ooh" +song-446,run1,evidence,It says Kane Brown on a sign with a line out the door,it says Kane Brown on a sign with a line out the door +song-446,run2,evidence,It says Kane Brown on a sign with a line out the door,it says Kane Brown on a sign with a line out the door +song-446,run3,evidence,It says Kane Brown on a sign with a line out the door,it says Kane Brown on a sign with a line out the door +song-448,run1,evidence,Don't like where I'm at,Don't like where I'm at +song-448,run2,evidence,Don't like where I'm at,Don't like where I'm at +song-448,run3,evidence,Don't like where I'm at,Don't like where I'm at +song-450,run1,evidence,And I stand up for what I believe,I stand up for what I believe +song-450,run2,evidence,And I stand up for what I believe,I stand up for what I believe +song-450,run3,evidence,And I stand up for what I believe,I stand up for what I believe +song-456,run1,evidence,Nothing matters when we one on one,Nothin' matters when we one on one +song-456,run2,evidence,Nothing matters when we one on one,Nothin' matters when we one on one +song-456,run3,evidence,Nothing matters when we one on one,Nothin' matters when we one on one +song-460,run3,evidence,Your apathy's like a wound in salt,your apathy's like a wound in salt +song-465,run1,evidence,"I can't, I can't pretend, I can't ignore you're right for me","I can't, I can’t pretend, I can't ignore you're right for me" +song-465,run1,evidence,"I left my girl, I'm in my Yorker","I left my girl, I’m in my Yorker" +song-465,run1,evidence,"It's the way you lift me up, yeah","It’s the way you lift me up, yeah" +song-465,run1,evidence,Remember when I couldn't hold her,Remember when I couldn’t hold her +song-465,run2,evidence,"I can't, I can't pretend, I can't ignore you're right for me","I can't, I can’t pretend, I can't ignore you're right for me" +song-465,run2,evidence,"I left my girl, I'm in my Yorker","I left my girl, I’m in my Yorker" +song-465,run2,evidence,"It's the way you lift me up, yeah","It’s the way you lift me up, yeah" +song-465,run3,evidence,"I can't, I can't pretend, I can't ignore you're right for me","I can't, I can’t pretend, I can't ignore you're right for me" +song-465,run3,evidence,"I left my girl, I'm in my Yorker","I left my girl, I’m in my Yorker" +song-465,run3,evidence,"It's the way you lift me up, yeah","It’s the way you lift me up, yeah" +song-465,run3,evidence,Remember when I couldn't hold her,Remember when I couldn’t hold her +song-467,run1,evidence,'Cause you ain't ever left me empty-handed,'Cause you ain’t ever left me empty-handed +song-467,run2,evidence,'Cause you ain't ever left me empty-handed,'Cause you ain’t ever left me empty-handed +song-467,run3,evidence,'Cause you ain't ever left me empty-handed,'Cause you ain’t ever left me empty-handed +song-468,run1,evidence,"So when you gonna tell her that we did that, too?","So when you gonna tell her\nThat we did that, too?" +song-468,run2,evidence,"Play her piano, but she doesn't know that I was the one who taught you Billy Joel","Play her piano, but she doesn't know (oh, oh)\nThat I was the one who taught you Billy Joel" +song-468,run2,evidence,"So when you gonna tell her that we did that, too?","So when you gonna tell her\nThat we did that, too?" +song-468,run3,evidence,I made the jokes you tell to her when she's with you,I made the jokes you tell to her\nWhen she's with you +song-468,run3,evidence,"Play her piano, but she doesn't know that I was the one who taught you Billy Joel","Play her piano, but she doesn't know (oh, oh)\nThat I was the one who taught you Billy Joel" +song-468,run3,evidence,"So when you gonna tell her that we did that, too?","So when you gonna tell her\nThat we did that, too?" +song-468,run3,evidence,"That was the show we talked about, played you the songs she's singing now",That was the show we talked about\nPlayed you the songs she's singing now +song-478,run2,evidence,"I turn my haters to consumers, I make vets feel like they juniors","Turn my haters to consumers, I make vets feel like they juniors" +song-480,run1,evidence,Bitches ain't fucking with me now and I can see why,Bitches ain’t fucking with me now and I can see why +song-480,run1,evidence,Broke boys don't deserve no pussy,Broke boys don’t deserve no pussy +song-480,run1,evidence,"He nutted on my butt, I said: I'm glad that you came","He nutted on my butt, I said: I’m glad that you came" +song-480,run1,evidence,"If it ain't no ring on my finger, you ain't goin' on my 'Gram","If it ain’t no ring on my finger, you ain’t goin' on my 'Gram" +song-480,run2,evidence,Bitches ain't fucking with me now and I can see why,Bitches ain’t fucking with me now and I can see why +song-480,run2,evidence,Broke boys don't deserve no pussy,Broke boys don’t deserve no pussy +song-480,run2,evidence,"He nutted on my butt, I said: I'm glad that you came","He nutted on my butt, I said: I’m glad that you came" +song-480,run2,evidence,"If it ain't no ring on my finger, you ain't goin' on my 'Gram","If it ain’t no ring on my finger, you ain’t goin' on my 'Gram" +song-480,run3,evidence,Broke boys don't deserve no pussy,Broke boys don’t deserve no pussy +song-480,run3,evidence,"He nutted on my butt, I said: I'm glad that you came","He nutted on my butt, I said: I’m glad that you came" +song-480,run3,evidence,"If it ain't no ring on my finger, you ain't goin' on my 'Gram","If it ain’t no ring on my finger, you ain’t goin' on my 'Gram" +song-483,run1,evidence,"Best friend, you the baddest and you know it (You know)","best friend, you the baddest and you know it (You know)" +song-483,run2,evidence,"Best friend, you the baddest and you know it (You know)","best friend, you the baddest and you know it (You know)" +song-485,run3,evidence,Like when you walked out my life,like when you walked out my life +song-487,run1,evidence,I fill my nights with broken dreams,And fill my nights with broken dreams +song-487,run1,evidence,I'm the best you ever had and best you gon' get (Gon' get),I'm the best (I'm the best)\nBest you ever had and best you gon' get (Gon' get) +song-487,run2,evidence,I fill my nights with broken dreams,And fill my nights with broken dreams +song-487,run2,evidence,I'm the best you ever had and best you gon' get (Gon' get),I'm the best (I'm the best)\nBest you ever had and best you gon' get (Gon' get) +song-487,run3,evidence,I fill my nights with broken dreams,And fill my nights with broken dreams +song-487,run3,evidence,I'm the best you ever had and best you gon' get (Gon' get),I'm the best (I'm the best)\nBest you ever had and best you gon' get (Gon' get) +song-491,run1,evidence,Ain't it funny\nHow you said you were friends?\nNow it sure as hell don't look like it,ain't it funny\nHow you said you were friends?\nNow it sure as hell don't look like it +song-491,run2,evidence,Ain't it funny\nHow you said you were friends?\nNow it sure as hell don't look like it,ain't it funny\nHow you said you were friends?\nNow it sure as hell don't look like it +song-491,run3,evidence,Ain't it funny\nHow you said you were friends?\nNow it sure as hell don't look like it,ain't it funny\nHow you said you were friends?\nNow it sure as hell don't look like it +song-492,run1,evidence,"All that wolfin' on the net, nigga, I thought you was a thug","All that wolfin' on the net (Ugh), nigga, I thought you was a thug" +song-492,run2,evidence,"All that wolfin' on the net, nigga, I thought you was a thug","All that wolfin' on the net (Ugh), nigga, I thought you was a thug" +song-492,run3,evidence,"All that wolfin' on the net, nigga, I thought you was a thug","All that wolfin' on the net (Ugh), nigga, I thought you was a thug" +song-492,run3,evidence,"Hit his lil' ass with that switch, I bet that switch switch up his nerves","Hit his lil' ass with that switch (Grrah), I bet that switch switch up his nerves" +song-493,run3,evidence,Coming through a hunnid thou,Comin' through a hunnid thou +song-494,run1,evidence,But you still hesitate 'cause you choose loyalty,But you still hesitate (Oh) 'cause you choose loyalty +song-497,run2,evidence,"She came for me twice, I didn't even nut for her once, you know I'm a pleaser","She came for me twice, I didn’t even nut for her once, you know I'm a pleaser" +song-500,run1,keyword,alcohol-and-substance-use,**REMOVE** +song-500,run3,keyword,alcohol-and-substance-use,**REMOVE** +song-501,run1,evidence,Kicked the PJs on a PJ (a PJ),"Kickin' my feet up, left the PJs on a PJ (a PJ)" +song-513,run2,evidence,love-as-fleeting-and-transient,**REMOVE** +song-513,run3,evidence,love-as-fleeting-and-transient,**REMOVE** +song-516,run1,evidence,"So put your loving hand out, baby",So put your loving hand out baby +song-520,run1,evidence,"And she said, ""Take me to the country\nShow me where you from""","And she said, “Take me to the country\nShow me where you from”" +song-520,run2,evidence,"And she said, ""Take me to the country\nShow me where you from""","And she said, “Take me to the country\nShow me where you from”" +song-520,run3,evidence,"And she said, ""Take me to the country\nShow me where you from""","And she said, “Take me to the country\nShow me where you from”" +song-521,run1,evidence,None of these hoes finna see me at the bank,none of these hoes finna see me at the bank +song-521,run1,evidence,"Order '42 for the table, let's pop shit","Order '42 for the table, let’s pop shit" +song-521,run1,evidence,Why the fuck you in the club when niggas wildin'?,Why the fuck you in the club when niggas wildin’? +song-521,run2,evidence,None of these hoes finna see me at the bank,none of these hoes finna see me at the bank +song-521,run2,evidence,"Order '42 for the table, let's pop shit","Order '42 for the table, let’s pop shit" +song-521,run2,evidence,Why the fuck you in the club when niggas wildin'?,Why the fuck you in the club when niggas wildin’? +song-521,run3,evidence,None of these hoes finna see me at the bank,none of these hoes finna see me at the bank +song-521,run3,evidence,"Order '42 for the table, let's pop shit","Order '42 for the table, let’s pop shit" +song-521,run3,evidence,Why the fuck you in the club when niggas wildin'?,Why the fuck you in the club when niggas wildin’? +song-524,run1,evidence,Forever's not enough time to love you the way that I want,Forever's not enough time to\nLove you the way that I want +song-524,run2,evidence,Forever's not enough time to love you the way that I want,Forever's not enough time to\nLove you the way that I want +song-524,run3,evidence,Forever's not enough time to love you the way that I want,Forever's not enough time to\nLove you the way that I want +song-532,run2,evidence,"si me da' tu cuenta de banco, un millón de peso'","Si me da' tu cuenta de banco, un millón de peso'" +song-532,run3,evidence,"si me da' tu cuenta de banco, un millón de peso'","Si me da' tu cuenta de banco, un millón de peso'" +song-538,run1,evidence,"Girl, I don't want to be the one who pays the price","Girl, I don’t want to be the one who pays the price" +song-538,run1,evidence,"It's like a dream, what she feels with me","It’s like a dream, what she feels with me" +song-538,run1,evidence,You're offering yourself to me like sacrifice,You’re offering yourself to me like sacrifice +song-538,run1,evidence,You're way too young to end your life,You’re way too young to end your life +song-538,run2,evidence,"Girl, I don't want to be the one who pays the price","Girl, I don’t want to be the one who pays the price" +song-538,run2,evidence,"It's like a dream, what she feels with me","It’s like a dream, what she feels with me" +song-538,run2,evidence,You're offering yourself to me like sacrifice,You’re offering yourself to me like sacrifice +song-538,run2,evidence,You're way too young to end your life,You’re way too young to end your life +song-538,run3,evidence,"Girl, I don't want to be the one who pays the price","Girl, I don’t want to be the one who pays the price" +song-538,run3,evidence,"It's like a dream, what she feels with me","It’s like a dream, what she feels with me" +song-538,run3,evidence,You're offering yourself to me like sacrifice,You’re offering yourself to me like sacrifice +song-538,run3,evidence,You're way too young to end your life,You’re way too young to end your life +song-539,run1,evidence,How can I judge you when you're with somebody else as long as you swear,How can I judge you when you're with\nSomebody else as long as you swear +song-539,run2,evidence,How can I judge you when you're with somebody else,How can I judge you when you're with\nSomebody else +song-539,run3,evidence,How can I judge you when you're with somebody else as long as you swear,How can I judge you when you're with\nSomebody else as long as you swear +song-540,run1,evidence,But I was your first and your last ticket outta there,But I was your first and your\nLast ticket outta there +song-540,run1,evidence,Go out like shooting stars chasing what's in our hearts,Go out like shooting stars\nChasing what's in our hearts +song-540,run1,evidence,I caught your wings on fire when I smoked my Bronco tires outta that town,I caught your wings on fire\nWhen I smoked my Bronco tires\nOutta that town +song-540,run1,evidence,"We're livin' wreckless, nothin' to catch us, baby","We're livin' wreckless\nNothin' to catch us, baby" +song-540,run1,evidence,"You holdin' me holdin' you, it's a hell of a view",You holdin' me holdin' you\nIt's a hell of a view +song-540,run1,evidence,You liked the thought of chasin' life instead of dollar bills,You liked the thought of chasin'\nLife instead of dollar bills +song-543,run3,evidence,You only listen to your fucking friends,you only listen to your fucking friends +song-544,run1,evidence,But damn if I didn't find what I wasn't even looking for,But damn if I didn’t find what I wasn't even looking for +song-544,run1,evidence,I wasn't looking for love when I walked through the door,I wasn’t looking for love when I walked through the door +song-544,run2,evidence,I wasn't looking for love when I walked through the door,I wasn’t looking for love when I walked through the door +song-544,run3,evidence,But damn if I didn't find what I wasn't even looking for,But damn if I didn’t find what I wasn't even looking for +song-544,run3,evidence,I wasn't looking for love when I walked through the door,I wasn’t looking for love when I walked through the door +song-545,run1,evidence,How to fix it 'fore it's too late,how to fix it 'fore it's too late +song-545,run2,evidence,How to fix it 'fore it's too late,how to fix it 'fore it's too late +song-545,run3,evidence,How to fix it 'fore it's too late,how to fix it 'fore it's too late +song-547,run1,evidence,Just talked to pops about the feds,just talked to pops about the feds +song-547,run1,evidence,"This shit comes with a lot, it's a lot of pressure, I'm a young nigga though","This shit comes with a lot, it’s a lot of pressure, I’m a young nigga though" +song-547,run2,evidence,Just talked to pops about the feds,just talked to pops about the feds +song-547,run2,evidence,"This shit comes with a lot, it's a lot of pressure, I'm a young nigga though","This shit comes with a lot, it’s a lot of pressure, I’m a young nigga though" +song-547,run3,evidence,I'm a young nigga though,I’m a young nigga though +song-547,run3,evidence,Just talked to pops about the feds,just talked to pops about the feds +song-547,run3,evidence,"This shit comes with a lot, it's a lot of pressure, I'm a young nigga though","This shit comes with a lot, it’s a lot of pressure, I’m a young nigga though" +song-548,run1,evidence,EVEN THOUGH IT'S A FRIDAY NIGHT,EVEN THOUGH IT’S A FRIDAY NIGHT +song-548,run1,evidence,I AIN'T NEVER\nBEEN THE CHURCH GOING TYPE,I AIN’T NEVER\nBEEN THE CHURCH GOING TYPE +song-548,run1,evidence,IF IT'S LIKE DOWN HERE UP THERE TONIGHT,IF IT’S LIKE DOWN HERE UP THERE TONIGHT +song-548,run1,evidence,"SITTIN' HERE, DRINKIN' BEER, TALKIN' GOD, AMEN","SITTIN’ HERE, DRINKIN’ BEER, TALKIN’ GOD, AMEN" +song-548,run1,evidence,WHEN THE WORLD'S GONE CRAZY MAN IT ALL MAKES SENSE,WHEN THE WORLD’S GONE CRAZY MAN IT ALL MAKES SENSE +song-548,run2,evidence,EVEN THOUGH IT'S A FRIDAY NIGHT,EVEN THOUGH IT’S A FRIDAY NIGHT +song-548,run2,evidence,I AIN'T NEVER\nBEEN THE CHURCH GOING TYPE,I AIN’T NEVER\nBEEN THE CHURCH GOING TYPE +song-548,run2,evidence,IF IT'S LIKE DOWN HERE UP THERE TONIGHT,IF IT’S LIKE DOWN HERE UP THERE TONIGHT +song-548,run2,evidence,"SITTIN' HERE, DRINKIN' BEER, TALKIN' GOD, AMEN","SITTIN’ HERE, DRINKIN’ BEER, TALKIN’ GOD, AMEN" +song-548,run2,evidence,WHEN THE WORLD'S GONE CRAZY MAN IT ALL MAKES SENSE,WHEN THE WORLD’S GONE CRAZY MAN IT ALL MAKES SENSE +song-548,run3,evidence,EVEN THOUGH IT'S A FRIDAY NIGHT,EVEN THOUGH IT’S A FRIDAY NIGHT +song-548,run3,evidence,GOTTA COUNTRY ANGEL I DON'T DESERVE\nTHE KIND THAT YOU NEVER LET GO OF,GOTTA COUNTRY ANGEL I DON’T DESERVE\nTHE KIND THAT YOU NEVER LET GO OF +song-548,run3,evidence,I AIN'T NEVER\nBEEN THE CHURCH GOING TYPE,I AIN’T NEVER\nBEEN THE CHURCH GOING TYPE +song-548,run3,evidence,IF IT'S LIKE DOWN HERE UP THERE TONIGHT,IF IT’S LIKE DOWN HERE UP THERE TONIGHT +song-548,run3,evidence,"SITTIN' HERE, DRINKIN' BEER, TALKIN' GOD, AMEN","SITTIN’ HERE, DRINKIN’ BEER, TALKIN’ GOD, AMEN" +song-548,run3,evidence,WHEN THE WORLD'S GONE CRAZY MAN IT ALL MAKES SENSE,WHEN THE WORLD’S GONE CRAZY MAN IT ALL MAKES SENSE +song-550,run1,evidence,Nothing to say\nAnd everything gets in the way,Nothin' to say\nAnd everything gets in the way +song-560,run1,evidence,"Tell me: That's life, when I'm stressin' at night","tell me: That's life, when I'm stressin' at night" +song-560,run3,evidence,"Tell me: That's life, when I'm stressin' at night","tell me: That's life, when I'm stressin' at night" +song-563,run1,evidence,All of the these sorries I don't owe you honey,All of the these sorries I don’t owe you honey +song-563,run1,evidence,It's all my fault,It’s all my fault +song-563,run1,evidence,"Like the pile of your stuff that's packed up in the back, right down to the strike of this match","Like the pile of your stuff that’s packed up in the back, right down to the strike of this match" +song-563,run1,evidence,Looks like I'm learning the hard way again,Looks like I’m learning the hard way again +song-563,run1,evidence,My heart wouldn't listen to my head and these boots on my feet,My heart wouldn’t listen to my head and these boots on my feet +song-563,run1,evidence,Sure as hell can't keep leanin' on you,Sure as hell can’t keep leanin’ on you +song-563,run1,evidence,You're gone and I've gone 3 sheets to the wind,You’re gone and I’ve gone 3 sheets to the wind +song-563,run2,evidence,All of the these sorries I don't owe you honey,All of the these sorries I don’t owe you honey +song-563,run2,evidence,It's all my fault,It’s all my fault +song-563,run2,evidence,"Like the pile of your stuff that's packed up in the back, right down to the strike of this match","Like the pile of your stuff that’s packed up in the back, right down to the strike of this match" +song-563,run2,evidence,Looks like I'm learning the hard way again,Looks like I’m learning the hard way again +song-563,run2,evidence,Sure as hell can't keep leanin' on you,Sure as hell can’t keep leanin’ on you +song-563,run2,evidence,You're gone and I've gone 3 sheets to the wind,You’re gone and I’ve gone 3 sheets to the wind +song-563,run3,evidence,All of the these sorries I don't owe you honey,All of the these sorries I don’t owe you honey +song-563,run3,evidence,"Like the pile of your stuff that's packed up in the back, right down to the strike of this match","Like the pile of your stuff that’s packed up in the back, right down to the strike of this match" +song-563,run3,evidence,Looks like I'm learning the hard way again,Looks like I’m learning the hard way again +song-563,run3,evidence,My heart wouldn't listen to my head and these boots on my feet,My heart wouldn’t listen to my head and these boots on my feet +song-563,run3,evidence,Sure as hell can't keep leanin' on you,Sure as hell can’t keep leanin’ on you +song-563,run3,evidence,You're gone and I've gone 3 sheets to the wind,You’re gone and I’ve gone 3 sheets to the wind +song-566,run2,evidence,Las de PR que todita' son mía',las de PR que todita' son mía' +song-567,run1,evidence,"And if I only could, I'd make a deal with God,","And if I only could,\nI'd make a deal with God," +song-567,run2,evidence,"And if I only could, I'd make a deal with God,","And if I only could,\nI'd make a deal with God," +song-570,run1,evidence,"Stolen the pussy, you ain't get sued for that (Sued)","Stole the pussy, you ain't get sued for that (Sued)" +song-570,run3,evidence,"Stolen the pussy, you ain't get sued for that (Sued)","Stole the pussy, you ain't get sued for that (Sued)" +song-575,run1,evidence,Guess I'm just broken and broke,Guess I’m just broken and broke +song-575,run2,evidence,Guess I'm just broken and broke,Guess I’m just broken and broke +song-575,run3,evidence,Guess I'm just broken and broke,Guess I’m just broken and broke +song-581,run1,evidence,To me you're all I am,to me you're all I am +song-581,run2,evidence,To me you're all I am,to me you're all I am +song-582,run1,evidence,I hope that your triflin' ass\nIs walkin' 'round barefoot in these streets,I also hope that your triflin' ass\nIs walkin' 'round barefoot in these streets +song-582,run2,evidence,I hope that your triflin' ass\nIs walkin' 'round barefoot in these streets,I also hope that your triflin' ass\nIs walkin' 'round barefoot in these streets +song-582,run3,evidence,I hope that your triflin' ass\nIs walkin' 'round barefoot in these streets,I also hope that your triflin' ass\nIs walkin' 'round barefoot in these streets +song-584,run1,evidence,Aún te debo una noche en la suite,aún te debo una noche en la suite +song-584,run1,evidence,"Hoy tú no va' a trabajar, jeje, no","hoy tú no va' a trabajar, jeje, no" +song-584,run1,evidence,"Yo no sé tú, pero yo quisiera amanecer esnú'","yo no sé tú, pero yo quisiera amanecer esnú'" +song-584,run2,evidence,"Hoy tú no va' a trabajar, jeje, no","hoy tú no va' a trabajar, jeje, no" +song-584,run3,evidence,"Hoy tú no va' a trabajar, jeje, no","hoy tú no va' a trabajar, jeje, no" +song-584,run3,evidence,"Yo no sé tú, pero yo quisiera amanecer esnú'","yo no sé tú, pero yo quisiera amanecer esnú'" +song-587,run1,evidence,"Bought her a P, not a pill, a Porsche","bought her a P, not a pill, a Porsche" +song-587,run2,evidence,"Bought her a P, not a pill, a Porsche","bought her a P, not a pill, a Porsche" +song-587,run3,evidence,"Bought her a P, not a pill, a Porsche","bought her a P, not a pill, a Porsche" +song-588,run1,evidence,'Cause the truth about it is\nIt all goes by real quick,‘Cause the truth about it is\nIt all goes by real quick +song-588,run1,evidence,Find the one you can't live without,Find the one you can’t live without +song-588,run1,evidence,You can't buy happiness\nBut you can buy dirt,You can’t buy happiness\nBut you can buy dirt +song-588,run2,evidence,'Cause the truth about it is\nIt all goes by real quick,‘Cause the truth about it is\nIt all goes by real quick +song-588,run2,evidence,Find the one you can't live without,Find the one you can’t live without +song-588,run2,evidence,You can't buy happiness\nBut you can buy dirt,You can’t buy happiness\nBut you can buy dirt +song-588,run3,evidence,'Cause the truth about it is\nIt all goes by real quick,‘Cause the truth about it is\nIt all goes by real quick +song-588,run3,evidence,Find the one you can't live without,Find the one you can’t live without +song-588,run3,evidence,You can't buy happiness\nBut you can buy dirt,You can’t buy happiness\nBut you can buy dirt +song-590,run1,evidence,He's not with you,he's not with you +song-593,run1,evidence,Love's a smoke ring wrapped around your finger,love's a smoke ring wrapped around your finger +song-593,run2,evidence,Love's a smoke ring wrapped around your finger,love's a smoke ring wrapped around your finger +song-593,run3,evidence,"It waved you gone, goodbye","it waved you gone, goodbye" +song-593,run3,evidence,Love's a smoke ring wrapped around your finger,love's a smoke ring wrapped around your finger +song-597,run1,evidence,Now I'm dodging potholes in my sunburnt Silverado,now I'm dodging potholes in my sunburnt Silverado +song-597,run2,evidence,Now I'm dodging potholes in my sunburnt Silverado,now I'm dodging potholes in my sunburnt Silverado +song-597,run3,evidence,Now I'm dodging potholes in my sunburnt Silverado,now I'm dodging potholes in my sunburnt Silverado +song-598,run1,evidence,El tercero lo conozco esta noche,el tercero lo conozco esta noche +song-598,run3,evidence,El tercero lo conozco esta noche,el tercero lo conozco esta noche +song-599,run2,evidence,Tryna keep my wife from figuring out,tryna keep my wife from figuring out +song-601,run2,evidence,"En mi cama, la recompensa","en mi cama, la recompensa" +song-606,run1,evidence,So I'd rather ride it out for better weather,So I’d rather ride it out for better weather +song-606,run1,evidence,We're caught in-between,we're caught in-between +song-606,run1,evidence,We've been swingin' and missin',We've been swingin’ and missin' +song-606,run2,evidence,So I'd rather ride it out for better weather,So I’d rather ride it out for better weather +song-606,run2,evidence,We're caught in-between,we're caught in-between +song-606,run2,evidence,We've been swingin' and missin',We've been swingin’ and missin' +song-606,run3,evidence,"It ain't broke yet, but damn, it needs fixin'","It ain't broke yet, but damn, it needs fixin’" +song-606,run3,evidence,So I'd rather ride it out for better weather,So I’d rather ride it out for better weather +song-606,run3,evidence,We've been swingin' and missin',We've been swingin’ and missin' +song-616,run1,evidence,She's puttin' her number in my phone (Broadway girls alone),She's puttin’ her number in my phone (Broadway girls alone) +song-616,run1,evidence,"Two Bud Lights deep, and she's sayin' things she don't mean","Two Bud Lights deep, and she's sayin' things she don’t mean" +song-616,run2,evidence,She's puttin' her number in my phone,She's puttin’ her number in my phone +song-616,run2,evidence,"Two Bud Lights deep, and she's sayin' things she don't mean","Two Bud Lights deep, and she's sayin' things she don’t mean" +song-616,run3,evidence,She's puttin' her number in my phone,She's puttin’ her number in my phone +song-616,run3,evidence,"Two Bud Lights deep, and she's sayin' things she don't mean","Two Bud Lights deep, and she's sayin' things she don’t mean" +song-617,run3,evidence,"Hold up a minute, don't go","hold up a minute, don't go" +song-622,run1,evidence,"Iба por mi camino y me perdí (Ey, ey)","Iba por mi camino y me perdí (Ey, ey)" +song-622,run2,evidence,"Iба por mi camino y me perdí (Ey, ey)","Iba por mi camino y me perdí (Ey, ey)" +song-622,run3,evidence,"Iба por mi camino y me perdí (Ey, ey)","Iba por mi camino y me perdí (Ey, ey)" +song-625,run1,evidence,When I already know\nWhat she's thinkin'\nShe don't have to say it yeah,When I already know\n\nWhat she's thinkin'\nShe don't have to say it yeah +song-625,run2,evidence,When I already know\nWhat she's thinkin'\nShe don't have to say it yeah,When I already know\n\nWhat she's thinkin'\nShe don't have to say it yeah +song-625,run3,evidence,When I already know\nWhat she's thinkin'\nShe don't have to say it yeah,When I already know\n\nWhat she's thinkin'\nShe don't have to say it yeah +song-627,run1,evidence,"Damn Strait, you're killing me man","Damn Strait, you’re killing me man" +song-627,run1,evidence,I couldn't turn it off fast enough,I couldn’t turn it off fast enough +song-627,run1,evidence,I know it ain't your fault\nThat she left me,I know it ain’t your fault\nThat she left me +song-627,run1,evidence,Now I can't even listen\n'Cause I'll get to missin' her,Now I can’t even listen\n‘Cause I’ll get to missin’ her +song-627,run2,evidence,'Cause I'll get to missin' her\nThen thehurt gets worse,‘Cause I’ll get to missin’ her\nThen thehurt gets worse +song-627,run2,evidence,I know it ain't your fault\nThat she left me,I know it ain’t your fault\nThat she left me +song-627,run2,evidence,Now I can't even listen\n'Cause I'll get to missin' her\nThen thehurt gets worse,Now I can’t even listen\n‘Cause I’ll get to missin’ her\nThen thehurt gets worse +song-627,run3,evidence,'Cause I'll get to missin' her\nThen thehurt gets worse,‘Cause I’ll get to missin’ her\nThen thehurt gets worse +song-627,run3,evidence,"Damn Strait, you're killing me man","Damn Strait, you’re killing me man" +song-627,run3,evidence,I know it ain't your fault\nThat she left me,I know it ain’t your fault\nThat she left me +song-627,run3,evidence,Now I can't even listen\n'Cause I'll get to missin' her\nThen thehurt gets worse,Now I can’t even listen\n‘Cause I’ll get to missin’ her\nThen thehurt gets worse +song-630,run1,evidence,It's all gone to hell she's gone to her mom's,it's all gone to hell she's gone to her mom's +song-630,run3,evidence,It's a bad day for love but a good day for flower shops,it's a bad day for love but a good day for flower shops +song-630,run3,evidence,It's all gone to hell she's gone to her mom's,it's all gone to hell she's gone to her mom's +song-630,run3,evidence,There's tears in her blue and bloodshot in mine,there's tears in her blue and bloodshot in mine +song-635,run1,evidence,I can't remember everything we said but we said too much,I can’t remember everything we said but we said too much +song-635,run1,evidence,I know you said this time you really weren't coming back again,I know you said this time you really weren’t coming back again +song-635,run2,evidence,I can't remember everything we said but we said too much,I can’t remember everything we said but we said too much +song-635,run2,evidence,I know you said this time you really weren't coming back again,I know you said this time you really weren’t coming back again +song-635,run2,evidence,You know you love to fight,you know you love to fight +song-635,run3,evidence,I can't remember everything we said but we said too much,I can’t remember everything we said but we said too much +song-635,run3,evidence,I know you said this time you really weren't coming back again,I know you said this time you really weren’t coming back again +song-637,run1,evidence,How'd I get here?,how'd I get here? +song-637,run1,evidence,"I just killed my ex, not the best idea","I just killed my ex (My ex, oops), not the best idea" +song-637,run2,evidence,How'd I get here?,how'd I get here? +song-637,run2,evidence,"I just killed my ex, not the best idea","I just killed my ex (My ex, oops), not the best idea" +song-637,run3,evidence,How'd I get here?,how'd I get here? +song-639,run1,evidence,"Gal, you used to ride in the rinky dink","Girl, you used to ride in the rinky dink" +song-639,run2,evidence,"Youwas rockin' coach bags, got you Chane'-ne'","You was rockin' coach bags, got you Chane'-ne'" +song-641,run2,evidence,I'm findin' ways to manipulate the feelin' you're goin' through,I'm finding ways to manipulate the feelin' you're goin' through +song-641,run3,evidence,I'm findin' ways to manipulate the feelin' you're goin' through,I'm finding ways to manipulate the feelin' you're goin' through +song-645,run1,evidence,I'm a Slaughter Gang CEO,It's a Slaughter Gang CEO +song-645,run2,evidence,I'm a Slaughter Gang CEO,It's a Slaughter Gang CEO +song-650,run1,evidence,See you're tired thinkin' 'bout if he cheat,see you're tired thinkin' 'bout if he cheat +song-650,run1,evidence,Somebody who can open up those gates to your heart,Somebody who can open up those gates\nOpen up those gates to your heart +song-650,run1,evidence,"Someone to bring you peace, uh","someone to bring you peace, uh" +song-650,run2,evidence,See you're tired thinkin' 'bout if he cheat,see you're tired thinkin' 'bout if he cheat +song-650,run2,evidence,Somebody who can open up those gates to your heart,Somebody who can open up those gates\nOpen up those gates to your heart +song-650,run2,evidence,"Someone to bring you peace, uh","someone to bring you peace, uh" +song-650,run3,evidence,See you're tired thinkin' 'bout if he cheat,see you're tired thinkin' 'bout if he cheat +song-650,run3,evidence,"Someone to bring you peace, uh","someone to bring you peace, uh" +song-654,run1,evidence,All my life\nThey been tryin' to keep me down,All my life)\nThey been tryin' to keep me down +song-654,run2,evidence,All my life\nThey been tryin' to keep me down,All my life)\nThey been tryin' to keep me down +song-654,run3,evidence,All my life\nThey been tryin' to keep me down,All my life)\nThey been tryin' to keep me down +song-655,run3,evidence,"Le dije\n""Voy a conquistar tu familia""","Le dije\n""Voy a conquistar tu familia" +song-661,run1,evidence,All they keep asking me\nIs if I'm gonna be your bride,all they keep asking me)\nIs if I'm gonna be your bride +song-661,run1,evidence,The only kind of girl they see\nIs a one-night or a wife,the only kind of girl they see)\nIs a one-night or a wife +song-661,run2,evidence,All they keep asking me is if I'm gonna be your bride,all they keep asking me)\nIs if I'm gonna be your bride +song-661,run2,evidence,The only kind of girl they see is a one-night or a wife,the only kind of girl they see)\nIs a one-night or a wife +song-661,run3,evidence,All they keep asking me is if I'm gonna be your bride,all they keep asking me)\nIs if I'm gonna be your bride +song-661,run3,evidence,The only kind of girl they see is a one-night or a wife,the only kind of girl they see)\nIs a one-night or a wife +song-666,run3,evidence,If you want me to stop some of that\nOr you want me to stop lovin' you?,You want me to stop some of that\nOr you want me to stop lovin' you? +song-671,run1,evidence,Your lovin' so deep,your lovin' so deep +song-671,run2,evidence,Your lovin' so deep,your lovin' so deep +song-672,run1,evidence,I'm feeling lonely (lonely),I’m feeling lonely (lonely) +song-672,run1,evidence,I'm gonna make it mineI'm gonna make it mine,I’m gonna make it mineI’m gonna make it mine +song-672,run2,evidence,I'm feeling lonely (lonely)I'm feeling lonely (lonely),I’m feeling lonely (lonely)I’m feeling lonely (lonely) +song-672,run3,evidence,I'm feeling lonely (lonely)I'm feeling lonely (lonely),I’m feeling lonely (lonely)I’m feeling lonely (lonely) +song-675,run1,evidence,Your left hand's gettin' used to that ring,your\nLeft hand's gettin' used to that ring +song-675,run2,evidence,Your left hand's gettin' used to that ring,your\nLeft hand's gettin' used to that ring +song-680,run1,evidence,I'm goin' to glow up one more time,I’m goin’ to glow up one more time +song-680,run1,evidence,You gon' see me sleepin' in courtside,You gon' see me sleepin’ in courtside +song-680,run2,evidence,I'm goin' to glow up one more time,I’m goin’ to glow up one more time +song-680,run2,evidence,You gon' see me sleepin' in courtside,You gon' see me sleepin’ in courtside +song-680,run3,evidence,I'm goin' to glow up one more time,I’m goin’ to glow up one more time +song-680,run3,evidence,You gon' see me sleepin' in courtside,You gon' see me sleepin’ in courtside +song-690,run2,evidence,So I'll keep dancing with my eyes closed,"So I'll keep dancing with my\nEy-ey-ey-eyes, ey-ey-ey-eyes closed" +song-691,run2,evidence,Lo que ella no sabe es que tú todavía\nMe estás viendo toa' la' historia',Lo que ella no sabe es que tú todavía (au)\nMe estás viendo toa' la' historia' +song-691,run3,evidence,Lo que ella no sabe es que tú todavía\nMe estás viendo toa' la' historia',Lo que ella no sabe es que tú todavía (au)\nMe estás viendo toa' la' historia' +song-693,run2,evidence,He's got a smile that makes me forget,he's got a smile that makes me forget +song-694,run1,evidence,and I just fell in love with a gangsta (like),And I just fell in love with a gangsta (like) +song-694,run1,evidence,"and I'm young, still gettin' money my pockets is chubby, nothin' was the same (huh)","And I'm young, still gettin' money my pockets is chubby, nothin' was the same (huh)" +song-694,run1,evidence,and my name in her mouth so I bet she gon' choke (bitch),And my name in her mouth so I bet she gon' choke (bitch) +song-694,run1,evidence,and they hype that I'm up on them banners,And they hype that I'm up on them banners +song-694,run1,evidence,bitches not takin' shit from me but notes,Bitches not takin' shit from me but notes +song-694,run1,evidence,but I don't let him come to the crib (grrah),But I don't let him come to the crib (grrah) +song-694,run1,evidence,"callin' my phone, but they know I don't answer (why?)","Callin' my phone, but they know I don't answer (why?)" +song-694,run1,evidence,hottest bitch out and they know what I mean (know what I mean),Hottest bitch out and they know what I mean (know what I mean) +song-694,run1,evidence,"in the hood, I'm like princess diana (grrah)","In the hood, I'm like princess diana (grrah)" +song-694,run1,evidence,"like flexin' on niggas and bitches addictive, feenin' for me like they usually do (usually do)","Like flexin' on niggas and bitches addictive, feenin' for me like they usually do (usually do)" +song-694,run1,evidence,lookin' at me like who bigger than she? (who?),Lookin' at me like who bigger than she? (who?) +song-694,run1,evidence,makin' it rain (makin' it rain),Makin' it rain (makin' it rain) +song-694,run1,evidence,one book a flight and go chill in tulum,One book a flight and go chill in tulum +song-694,run1,evidence,so he put my name in a tatt' (damn),So he put my name in a tatt' (damn) +song-694,run1,evidence,they be chattin' I don't give a damn and I'm still gettin' money I know who I am (grrah),They be chattin' I don't give a damn and I'm still gettin' money I know who I am (grrah) +song-694,run1,evidence,"to her man, l'm the girl of his dreams","To her man, l'm the girl of his dreams" +song-694,run1,evidence,"wanna be me, so she do my emotes","Wanna be me, so she do my emotes" +song-694,run2,evidence,Book a flight and go chill in tulum,book a flight and go chill in tulum +song-694,run2,evidence,"like flexin' on niggas and bitches addictive, feenin' for me like they usually do (usually do)","Like flexin' on niggas and bitches addictive, feenin' for me like they usually do (usually do)" +song-694,run3,evidence,"like flexin' on niggas and bitches addictive, feenin' for me like they usually do (usually do)","Like flexin' on niggas and bitches addictive, feenin' for me like they usually do (usually do)" +song-695,run1,evidence,"All they doin' is talkin' down, 'cause they can't get up with me","all they doin' is talkin' down, 'cause they can't get up with me" +song-695,run2,evidence,"All they doin' is talkin' down, 'cause they can't get up with me","all they doin' is talkin' down, 'cause they can't get up with me" +song-695,run2,evidence,"Ridin' with my twin and 'nem, and we all look good as fuck","Ridin' with my twin and 'nem (Skrrt), and we all look good as fuck" +song-695,run2,evidence,"She say she don't fuck with me, who said that you can, ho?","She say she don't fuck with me (Who?), who said that you can, ho?" +song-695,run3,evidence,"All they doin' is talkin' down, 'cause they can't get up with me","all they doin' is talkin' down, 'cause they can't get up with me" +song-695,run3,evidence,"I can't put you in my business, you might wish me dead tomorrow","I can't put you in my business (No), you might wish me dead tomorrow" +song-695,run3,evidence,"Ridin' with my twin and 'nem, and we all look good as fuck","Ridin' with my twin and 'nem (Skrrt), and we all look good as fuck" +song-696,run3,evidence,"Desde que nos vimo' pienso en cómo nos comimo', ey","desde que nos vimo' pienso en cómo nos comimo', ey" +song-697,run1,evidence,No quisiera que\nPase otro día y no te vea al amanecer,no quisiera que\nPase otro día y no te vea al amanecer +song-697,run2,evidence,No quisiera que\nPase otro día y no te vea al amanecer,no quisiera que\nPase otro día y no te vea al amanecer +song-697,run3,evidence,No quisiera que\nPase otro día y no te vea al amanecer,no quisiera que\nPase otro día y no te vea al amanecer +song-703,run3,evidence,"Looks so alive, turns out, I'm not real","Looked so alive, turns out, I'm not real" +song-705,run1,evidence,But if you kissed me now I know you'd fool me again,But if you kissed me now\nI know you'd fool me again +song-705,run1,evidence,Last Christmas I gave you my heart,Last Christmas\nI gave you my heart +song-705,run1,evidence,Maybe next year I'll give it to someone special,Maybe next year I'll give it to someone\nI'll give it to someone special +song-705,run2,evidence,Last Christmas I gave you my heart,Last Christmas\nI gave you my heart +song-705,run2,evidence,Maybe next year I'll give it to someone special,Maybe next year I'll give it to someone\nI'll give it to someone special +song-705,run3,evidence,Last Christmas I gave you my heart,Last Christmas\nI gave you my heart +song-705,run3,evidence,Maybe next year I'll give it to someone special,Maybe next year I'll give it to someone\nI'll give it to someone special +song-708,run3,evidence,"We'd never fade, never fade","we'd never fade, never fade" +song-709,run1,evidence,He designered down (down),he designered down (down) +song-711,run1,evidence,Y bien jalados con La Doble P,y bien jalados con La Doble P +song-711,run2,evidence,Y bien jalados con La Doble P,y bien jalados con La Doble P +song-711,run3,evidence,Y bien jalados con La Doble P,y bien jalados con La Doble P +song-717,run2,evidence,"Cuando te necesitaba, diste tu peor versión","cuando te necesitaba, diste tu peor versión" +song-718,run3,evidence,Melt down the chains that I bought from yo' boss,melt down the chains that I bought from yo' boss +song-721,run2,evidence,Being brave as eighteen gets,Bein' brave as eighteen gets +song-737,run1,evidence,When you wake up next to him in the middle of the night,when you wake up next to him in the middle of the night +song-737,run1,evidence,You don't wanna call it love,you don't wanna call it love +song-737,run2,evidence,When you wake up next to him in the middle of the night,when you wake up next to him in the middle of the night +song-737,run2,evidence,You don't wanna call it love,you don't wanna call it love +song-737,run3,evidence,When you wake up next to him in the middle of the night,when you wake up next to him in the middle of the night +song-737,run3,evidence,You don't wanna call it love,you don't wanna call it love +song-744,run2,evidence,She got a cold heart but she got a warm smile,she got a cold heart but she got a warm smile +song-744,run3,evidence,She got a cold heart but she got a warm smile,she got a cold heart but she got a warm smile +song-746,run1,evidence,Rugged whiskey\n'Cause we survivin',rugged whiskey)\n'Cause we survivin +song-746,run2,evidence,Rugged whiskey\n'Cause we survivin',rugged whiskey)\n'Cause we survivin +song-746,run3,evidence,Rugged whiskey\n'Cause we survivin',rugged whiskey)\n'Cause we survivin +song-747,run1,evidence,Before it called you a lying traitor,before it called you a lying traitor +song-747,run2,evidence,"Oh, lord, I think about jumpin' / Off of very tall somethings","Oh, lord, I think about jumpin'\nOff of very tall somethings" +song-747,run2,evidence,You called you a lying traitor,You dream of my mouth before it called you a lying traitor +song-750,run1,keyword,alcohol-and-substance-use,alcohol-and-substance-abuse +song-750,run2,keyword,alcohol-and-substance-use,alcohol-and-substance-abuse +song-750,run3,keyword,alcohol-and-substance-use,**REMOVE** +song-753,run1,evidence,You're never gon' see me\nCaught sleepin',you're never gon' see me\nCaught sleepin' +song-753,run3,evidence,"You debate who the best, but opps, I'm white chalkin' when","you debate who the best, but opps, I'm white chalkin' when" +song-755,run2,keyword,guilt-and-remorse,**REMOVE** +song-755,run2,evidence,I'm\nIn my head right now,I'm\n\nIn my head right now +song-759,run1,evidence,You just might get that G-Wagon out of me,You just might\nJust might get that G-Wagon out of me +song-759,run2,evidence,You just might get that G-Wagon out of me,You just might\nJust might get that G-Wagon out of me +song-759,run3,evidence,You just might get that G-Wagon out of me,You just might\nJust might get that G-Wagon out of me +song-763,run1,evidence,It wasn't no thing to give you up,it wasn't no thing to give you up +song-775,run1,evidence,"Fuck y'all niggas, I don't trust y'all niggas","fuck y'all niggas, I don't trust y'all niggas" +song-777,run1,evidence,They said he hit that guardrail at half past three,they said he hit that guardrail at half past three +song-777,run2,evidence,They said he hit that guardrail at half past three,they said he hit that guardrail at half past three +song-777,run3,evidence,They said he hit that guardrail at half past three,they said he hit that guardrail at half past three +song-782,run2,evidence,"Hey, I think I might've found my future love","Hey, I think I might’ve found my future love" +song-782,run3,evidence,"Hey, I think I might've found my future love","Hey, I think I might’ve found my future love" +song-784,run1,evidence,"I'll be shooting that shot like 2K, girl, I know","I’ll be shooting that shot like 2K, girl, I know" +song-784,run1,evidence,"So I don't give a hoot what your dude say, girl, I know","So I don’t give a hoot what your dude say, girl, I know" +song-784,run2,evidence,"I'll be shooting that shot like 2K, girl, I know","I’ll be shooting that shot like 2K, girl, I know" +song-784,run2,evidence,"So I don't give a hoot what your dude say, girl, I know","So I don’t give a hoot what your dude say, girl, I know" +song-784,run3,evidence,"I'll be shooting that shot like 2K, girl, I know","I’ll be shooting that shot like 2K, girl, I know" +song-784,run3,evidence,"So I don't give a hoot what your dude say, girl, I know","So I don’t give a hoot what your dude say, girl, I know" +song-785,run3,evidence,You always been a real one\nEven though we ain't together,you always been a real one\nEven though we ain't together +song-787,run1,evidence,"If I catch you with her, you gon' catch me with him","If I catch you with her, you gon’ catch me with him" +song-787,run1,evidence,Since the day that we met\nIt's always who cut first and never who bleeds last,Since the day that we met\nIt’s always who cut first and never who bleeds last +song-787,run1,evidence,"You think I don't hear about it, you better think again","You think I don’t hear about it, you better think again" +song-787,run2,evidence,"If I catch you with her, you gon' catch me with him","If I catch you with her, you gon’ catch me with him" +song-787,run2,evidence,Since the day that we met\nIt's always who cut first and never who bleeds last,Since the day that we met\nIt’s always who cut first and never who bleeds last +song-787,run2,evidence,"You think I don't hear about it, you better think again","You think I don’t hear about it, you better think again" +song-787,run3,evidence,"If I catch you with her, you gon' catch me with him","If I catch you with her, you gon’ catch me with him" +song-787,run3,evidence,It's always who cut first and never who bleeds last,It’s always who cut first and never who bleeds last +song-787,run3,evidence,Since the day that we met\nIt's always who cut first and never who bleeds last,Since the day that we met\nIt’s always who cut first and never who bleeds last +song-787,run3,evidence,"You think I don't hear about it, you better think again","You think I don’t hear about it, you better think again" +song-791,run1,evidence,"Singin' 'bout it don't mean I care\nYeah, I know I've been known to share","singin' 'bout it don't mean I care\nYeah, I know I've been known to share" +song-791,run2,evidence,"Singin' 'bout it don't mean I care\nYeah, I know I've been known to share","singin' 'bout it don't mean I care\nYeah, I know I've been known to share" +song-793,run1,evidence,Who wanna play with Nicki?,who wanna play with Nicki? +song-793,run2,evidence,Who wanna play with Nicki?,who wanna play with Nicki? +song-794,run1,evidence,Fell out of love and you both let go,fell out of love and you both let go +song-794,run1,evidence,She couldn't be more different from me\nHappy and free in leather,she couldn't be more different from me\nHappy and free in leather +song-794,run2,evidence,"Every time you touch me, I just wonder how she felt","every time you touch me, I just wonder how she felt" +song-801,run1,evidence,"Pistols all in the kitchen, can't give the zip code up, hold up, yeah (Wow)","pistols all in the kitchen, can't give the zip code up, hold up, yeah (Wow)" +song-802,run3,evidence,I don't remember life before she came into the picture,I don't remember\nLife before she came into the picture +song-807,run2,evidence,I'm gonna keep on dancing at the Pink Pony Club,I'm gonna keep on dancing at the\nPink Pony Club +song-807,run3,evidence,I'm gonna keep on dancing at the Pink Pony Club,I'm gonna keep on dancing at the\nPink Pony Club +song-812,run2,evidence,"They'll play it one day, it's a hell of a show","They'll play it one day (Yeah), it's a hell of a show" +song-812,run3,evidence,"They'll play it one day, it's a hell of a show","They'll play it one day (Yeah), it's a hell of a show" +song-818,run1,evidence,We got sticks in the club illegally,we got sticks in the club illegally +song-818,run2,evidence,We got sticks in the club illegally,we got sticks in the club illegally +song-818,run3,evidence,We got sticks in the club illegally,we got sticks in the club illegally +song-819,run2,evidence,Given the throne i don't know\nHow to believe,Given the throne i don't know (hah)\nHow to believe +song-819,run3,evidence,Given the throne i don't know\nHow to believe,Given the throne i don't know (hah)\nHow to believe +song-819,run3,evidence,Waisted so long to break these walls down,Waited so long to break these walls down +song-819,run3,evidence,Waisted so long to break these walls down\nTo make up and feel like me,Waited so long to break these walls down\nTo make up and feel like me +song-821,run1,evidence,"okay, so yeah, I smoke like a chimney","Okay, so yeah, I smoke like a chimney" +song-821,run2,evidence,"okay, so yeah, I smoke like a chimney","Okay, so yeah, I smoke like a chimney" +song-821,run3,evidence,"okay, so yeah, I smoke like a chimney","Okay, so yeah, I smoke like a chimney" +song-824,run2,evidence,"Said you'd never leave, we would fight 'til it's due","Said that you'd never leave, we would fight 'til it's due" +song-829,run1,evidence,"It's my anxiety, can't let it conquer me","it's my anxiety, can't let it conquer me" +song-829,run2,evidence,"It's my anxiety, can't let it conquer me","it's my anxiety, can't let it conquer me" +song-829,run3,evidence,"It's my anxiety, can't let it conquer me","it's my anxiety, can't let it conquer me" +song-833,run3,evidence,You met someone\nYour dad says he's okay,you met someone\nYour dad says he's okay +song-842,run1,evidence,Pull off in a Lam',pull off in a Lam' +song-847,run3,evidence,"You got me all, all, now I'm nodding my head","you got me all, all, now I'm nodding my head" +song-849,run3,evidence,How could I ever miss something\nThat I'd never had?,How could I ever miss something (go)\nThat I'd never had? +song-850,run1,evidence,Made it clear you didn't wanna see the sequel,Made it clear you didn’t wanna see the sequel +song-850,run2,evidence,Can't recall my mornings ever being this faded,Can’t recall my mornings ever being this faded +song-850,run2,evidence,Made it clear you didn't wanna see the sequel,Made it clear you didn’t wanna see the sequel +song-850,run3,evidence,Made it clear you didn't wanna see the sequel,Made it clear you didn’t wanna see the sequel +song-852,run2,evidence,"He walked in\nLike a 6'2"" dream, heaven-sent","he walked in\nLike a 6'2"" dream, heaven-sent" +song-853,run3,evidence,"Nothing to us, run up, you're done up, we come up from sunup to sundown, so come out to play","Nothin' to us, run up, you're done up, we come up from sunup to sundown, so come out to play" +song-854,run2,evidence,She's in here chasing tequila with High Noon,she's in here chasing tequila with High Noon +song-854,run2,evidence,"We did that ""What's your name"" thing\nWhere you from and what's your favorite drink","we did that ""What's your name"" thing\nWhere you from and what's your favorite drink" +song-856,run1,evidence,If it was a different time,if it was a different time +song-856,run2,evidence,If it was a different time,if it was a different time +song-856,run3,evidence,If it was a different time,if it was a different time +song-857,run1,evidence,Might be a lot of things\nBut I ain't your savin' grace,might be a lot of things\nBut I ain't your savin' grace +song-857,run1,evidence,"The night I said, ""I'm leavin',"" I turned into Richard Petty","the night I said, ""I'm leavin',"" I turned into Richard Petty" +song-857,run2,evidence,Might be a lot of things\nBut I ain't your savin' grace,might be a lot of things\nBut I ain't your savin' grace +song-857,run2,evidence,"The night I said, ""I'm leavin',"" I turned into Richard Petty","the night I said, ""I'm leavin',"" I turned into Richard Petty" +song-857,run3,evidence,Might be a lot of things\nBut I ain't your savin' grace,might be a lot of things\nBut I ain't your savin' grace +song-857,run3,evidence,"The night I said, ""I'm leavin',"" I turned into Richard Petty","the night I said, ""I'm leavin',"" I turned into Richard Petty" +song-861,run2,evidence,All I ask is don't make my pull up and get to dumping,All I ask is don't make me pull up and get to dumping +song-863,run1,evidence,"And I'm gonna love you, yeah","I'm gonna love you, yeah" +song-867,run1,evidence,The struggle keeps me honest\nAnd it breaks down the walls of my pride,the struggle keeps me honest\nAnd it breaks down the walls of my pride +song-867,run2,evidence,The struggle keeps me honest\nAnd it breaks down the walls of my pride,the struggle keeps me honest\nAnd it breaks down the walls of my pride +song-872,run1,evidence,"Con reggaetón y dembow, sí, con reggaetón y dembow","con reggaetón y dembow, sí, con reggaetón y dembow" +song-872,run2,evidence,"Con reggaetón y dembow, sí, con reggaetón y dembow","con reggaetón y dembow, sí, con reggaetón y dembow" +song-872,run2,evidence,Pasan los año' y sigo dando palo',pasan los año' y sigo dando palo' +song-872,run3,evidence,"Con reggaetón y dembow, sí, con reggaetón y dembow","con reggaetón y dembow, sí, con reggaetón y dembow" +song-874,run2,evidence,She wanna break and I get that,She want a break and I get that diff --git a/docs/decision-log.md b/docs/decision-log.md index a991503..5ddef24 100644 --- a/docs/decision-log.md +++ b/docs/decision-log.md @@ -554,3 +554,25 @@ 代價,換得人工判定時證據在手。版權一項先前寫得不準: 這些引述早已隨三份執行歸檔 commit,寫入定案表不增加 任何新的歌詞重製。 + +## 2026-08-07 + +- **計票前套用人工校定的更正表,並驗證標籤在詞彙表內**: + 模型對定義檔的每一條明確要求都有非零的違規率,且 + temperature=0 未消除之(量測見 `output-validation.md`)。 + 違規本身不是本研究的量測對象——模型的機率性屬方法層, + 研究問題是編碼;而引述存在的目的是讓人看見編碼的文本 + 依據,一句在歌詞裏找不到的引述無法履行該目的。故凡 + 可辨識其正確文本者一律還原。 + 判準:**可據紀錄證明者才還原,僅依研究者判斷推知者 + 不還原。** 更正一律不自行組字——替代必為該首歌詞的 + 逐字子字串;標籤的改名須有同一筆紀錄的內證(模型於 + 同一份輸出並列了正確與錯誤的拼寫),否則刪去。依此, + 跨行拼接與平行句混合共 13 筆指派無唯一來源,不予更正, + 於定案表中呈現為 6 列引述無法逐字對回歌詞,據實保留。 + 更正表 936 列中,僅 13 筆 `keyword` 能改變票數,其餘 + 923 筆只改變呈現的證據。效果:詞彙表外的碼 13 筆歸零, + 定案編碼 14,665 降為 14,664(`song-750` 的三票因拼寫 + 更正而合流),逐字可對回的引述由 43,098 升至 44,122。 + 更正表為外部參數而非寫死於程式——研究者的介入因此 + 出現在重現命令上,且逐列可審、可 diff。 diff --git a/docs/methodology.md b/docs/methodology.md index 708702b..73f92ac 100644 --- a/docs/methodology.md +++ b/docs/methodology.md @@ -45,7 +45,8 @@ 組內一致性 0.41,成員橫跨籃球、海灘、外星人綁架); k 太大則人工難以通覽。定於 100,理由是實測顯示雜物櫃 組於此始裂解為有主題的組,且編碼實測未見碼數過多的 - 副作用(詞彙表外的碼歸零、僅一個碼零使用)。 + 副作用——全量三次執行下 101 個碼全數用到;模型另行 + 造出的碼共 13 筆,佔 44,149 筆標籤指派的 0.03%。 - **組名**:取 medoid——與該組中心(成員向量均值後 正規化)餘弦相似度最高的成員詞。組名因此必為模型 自己產出過的關鍵字,非任何人事後撰寫。已知限制: @@ -148,18 +149,34 @@ 依歌曲 ID 升序。碼表以參數傳入而非填進定義檔——定義 檔只規定任務形狀,換詞彙表、換演算法都不必改它。 - **步驟 3 定案**:`tally-codings <執行歸檔 1> <執行歸檔 - 2> <執行歸檔 3> <輸出 CSV>` 讀三份執行歸檔的 - `output.jsonl`,逐首取標籤鍵集合(引述不參與計票)。 - 某首歌的某個標籤於三份中出現至少兩次即寫出一列,產出 - `results/codings.csv`,欄位 `Song`、`Artist Credit`、 - `Keyword`、`Quote`,一列一個標籤。歌名與演出者名銜 - 逐首查工作儲存取得,故本子命令須在 `build-db` 之後 - 執行。`Quote` 收該標籤在計票中的各份執行所給的歌詞 - 引述:各份的引述串接後逐字去重,按 Unicode 碼位排序, - 以單一 `|` 相接(三份執行彼此無先後主從之別,引述之序 - 取決於引述本身)。列序依印出的前三欄依序排:歌名、 - 演出者名銜、標籤,一律以 Unicode 碼位比較,換行為 - CRLF(同專案其他 CSV)。 + 2> <執行歸檔 3> <輸出 CSV> --corrections <更正表> + --valid-keywords <合法碼清單>` 讀三份執行歸檔的 + `output.jsonl`,依序套用更正表、驗證所有標籤皆在合法碼 + 清單之內、計票。 +- **更正表**:`data/manual/coding-corrections.csv`,研究者 + 逐列校定的人工著作,欄位 `Song ID`、`Run`、`Type`、 + `To Be Replaced`、`Correct Term`。`Type` 為 `keyword` + 或 `evidence`,分別更正標籤與引述;`Correct Term` 為 + 替代字串,或 `**REMOVE**` 表示刪去該筆標籤指派(`keyword`) + 或該句引述(`evidence`)。一筆 `evidence` 更正套用於該 + 首歌該次執行的所有出現處。兩個文字欄以兩字元 `\n` 表示 + 換行,故一列一行,純文字工具可逐列處理。表中任一列若 + 在資料中找不到對應者,即中止;校定的判準記於 + `decision-log.md`。 +- **合法碼清單**:純文字、一行一個碼,自詞彙表產出: + `{ cat runs/02-cluster/result-keywords.txt; echo + women-power; } | sort`。 +- **定案表**:`results/codings.csv`,欄位 `Song`、 + `Artist Credit`、`Keyword`、`Quote`,一列一個標籤。歌名 + 與演出者名銜逐首查工作儲存取得,故本子命令須在 + `build-db` 之後執行。`Quote` 為該標籤在計票中各份執行 + 所引的歌詞行:各份的引述串接後逐字去重,按 Unicode + 碼位排序,以單一 `|` 相接(三份執行彼此無先後主從之 + 別,引述之序取決於引述本身);`Quote` 欄以兩字元 `\n` + 表示換行,故一列一行,還原 `\n` 後即為該首歌歌詞的逐字 + 片段。列序依印出的前三欄依序排:歌名、演出者名銜、 + 標籤,一律以 Unicode 碼位比較,換行為 CRLF(同專案 + 其他 CSV)。 - **序列化通則**:所有中間檔為 UTF-8,欄序、鍵序與元素 序皆依上列規則明定,無時間戳、無隨機成分;JSON 解析 一律偵測重複鍵,違規即失敗。人讀為主的產物採純文字或 diff --git a/tools/src/pop_fem_audit_tools/commands/tally_codings.py b/tools/src/pop_fem_audit_tools/commands/tally_codings.py index b969089..519afc4 100644 --- a/tools/src/pop_fem_audit_tools/commands/tally_codings.py +++ b/tools/src/pop_fem_audit_tools/commands/tally_codings.py @@ -2,7 +2,7 @@ # Copyright 2026 imacat. All rights reserved. # Authors: # imacat@mail.imacat.idv.tw (imacat), 2026/8/6 -"""The majority tally of the three coding runs. +r"""The majority tally of the three coding runs. Settles the coding step: the same coding definition file is run three times independently, and this command counts the votes and @@ -15,12 +15,31 @@ three runs assign it, so three votes never tie, and it carries the lyric quotes of every run that assigned it, pooled, deduplicated, sorted by Unicode code point, and joined with a single ``|``: the three runs are peers, so the quote order -follows the text alone. The three +follows the text alone. The written quote carries the two +characters ``\n`` where the lyric has a newline, the mirror of +the unescaping the correction table loader does, so the coding +table holds one row per line. The three archives must cover exactly the same set of song IDs, every record must be a successful result, and every record's "text" must parse to a JSON object; otherwise the tally fails and nothing is written. +Two optional inputs guard the tally. ``--corrections`` names a +CSV file of researcher-reviewed repairs, applied to each run's +records before anything else happens: a keyword row renames or +drops one keyword assignment of one song in one run, and an +evidence row rewrites or drops one lyric quote string wherever it +appears in that song's record for that run. Its two text fields +carry the two characters ``\n`` where the text has a newline, so +the file holds one row per line. Every row must match, so a +stale row fails the run. ``--valid-keywords`` names a +plain text file of the allowed keywords, one per line; once the +corrections are in, every keyword left in any record must appear +in it. The order is fixed and matters: the corrections come +first, so a repair may reunite the votes of a misspelled keyword +that the check would otherwise reject. With neither option, no +record is touched and no vocabulary is checked. + The archives identify a song as ``song-``, where ```` is the song's ID in the SQLite working store. The output table does not carry that ID: every song is looked up in the working store @@ -49,6 +68,266 @@ class TallyError(Exception): """An error that fails the tally.""" +@dataclass(frozen=True) +class Correction: + """One researcher-reviewed repair of one run's record.""" + + KEYWORD: ClassVar[str] = "keyword" + """The type of a row that repairs a keyword assignment.""" + EVIDENCE: ClassVar[str] = "evidence" + """The type of a row that repairs a lyric quote.""" + REMOVE: ClassVar[str] = "**REMOVE**" + """The correct term that drops what the row names instead of + replacing it.""" + __MAX_QUOTED: ClassVar[int] = 40 + """The number of characters of the replaced text an error + message shows before cutting it short.""" + + line: int + """The line of the corrections file the row ends on.""" + song_id: int + """The numeric part of the song ID the row repairs.""" + run: str + """The basename of the run directory the row repairs.""" + type: str + """The type of the row, :attr:`KEYWORD` or :attr:`EVIDENCE`.""" + to_be_replaced: str + """The keyword or the lyric quote string the row replaces.""" + correct_term: str + """The replacement, or :attr:`REMOVE` to drop what the row + names.""" + + @property + def is_removal(self) -> bool: + """Whether the row drops what it names. + + :return: True when the correct term is :attr:`REMOVE`, + False otherwise. + """ + return self.correct_term == self.REMOVE + + @property + def label(self) -> str: + """The identity of the row, for an error message. + + :return: The song ID, the run, the type, and the replaced + text, the text cut short when it is long. + """ + text: str = self.to_be_replaced + if len(text) > self.__MAX_QUOTED: + text = f"{text[:self.__MAX_QUOTED]}..." + return (f"song-{self.song_id} {self.run} {self.type}" + f" \"{text}\"") + + +@dataclass +class CorrectionTable: + """The researcher-reviewed repairs of the runs' records.""" + + MANUAL_CORRECTIONS_CSV: ClassVar[str] \ + = "coding-corrections.csv" + """The correction table CSV file's conventional name under + ``data/manual/``.""" + + path: Path + """The correction table CSV file the repairs came from.""" + corrections: list[Correction] + """The repairs, in file order.""" + + +class CorrectionsLoader: + """The loader of the researcher-reviewed correction table.""" + + __HEADER: tuple[str, str, str, str, str] = ( + "Song ID", "Run", "Type", "To Be Replaced", "Correct Term") + """The header row the correction table CSV file must carry.""" + + def __init__(self, path: Path, run_names: list[str]) -> None: + """Set up the loader of the correction table. + + :param path: The correction table CSV file. + :param run_names: The basenames of the run directories the + command was given, in the given order. + """ + self.__path: Path = path + """The correction table CSV file.""" + self.__run_names: set[str] = set(run_names) + """The basenames of the given run directories.""" + + def run(self) -> CorrectionTable: + r"""Load and validate the correction table. + + Every row must name a song in the ``song-`` form, one + of the runs the command was given, and a known type. The + file is read with the CSV reader, so a quoted field may + hold a comma or a double quote. No field holds a line + break: the two text fields carry the two characters + ``\n`` where the text has a newline, so the file holds one + row per line, and each of them is unescaped to a single LF + before the repair is matched or applied, as that is what + the archived records carry. Nothing is written. + + :return: The repairs, in file order. + :raises TallyError: When the file cannot be read, the + header row is not the expected one, a row does not + have the expected number of fields, a song ID is not + in the ``song-`` form, a row names a run the + command was not given, or a row has an unknown type. + """ + try: + return CorrectionTable( + path=self.__path, + corrections=self.__load( + self.__path, self.__run_names)) + except (OSError, ValueError) as error: + raise TallyError(str(error)) from error + + @classmethod + def __load(cls, path: Path, run_names: set[str]) \ + -> list[Correction]: + """Read the rows of the correction table CSV file. + + :param path: The correction table CSV file. + :param run_names: The basenames of the given run + directories. + :return: The repairs, in file order. + :raises OSError: When the file cannot be read. + :raises ValueError: When the file is empty, the header row + is not the expected one, or a row is invalid. + """ + corrections: list[Correction] = [] + with open(path, encoding="utf-8", newline="") as file: + reader: Any = csv.reader(file) + header: list[str] | None = None + row: list[str] + for row in reader: + if len(row) == 0: + continue + if header is None: + header = row + if tuple(row) != cls.__HEADER: + raise ValueError( + f"{path}: the header row is not" + f" \"{','.join(cls.__HEADER)}\"") + continue + corrections.append(cls.__parse_row( + row, reader.line_num, path, run_names)) + if header is None: + raise ValueError(f"{path}: no header row") + return corrections + + @classmethod + def __parse_row(cls, row: list[str], line: int, path: Path, + run_names: set[str]) -> Correction: + """Validate one row of the correction table. + + :param row: The row's fields, in file order. + :param line: The line the row ends on. + :param path: The correction table CSV file, for the error + message. + :param run_names: The basenames of the given run + directories. + :return: The repair the row states, its two text fields + unescaped. + :raises ValueError: When the row does not have the + expected number of fields, its song ID is not in the + ``song-`` form, it names a run the command was not + given, or its type is unknown. + """ + label: str = f"{path}: line {line}" + if len(row) != len(cls.__HEADER): + raise ValueError( + f"{label}: expected {len(cls.__HEADER)} fields," + f" got {len(row)}") + song_id: int = cls.__parse_song_id(row[0], label) + if row[1] not in run_names: + given: str = ", ".join(sorted(run_names)) + raise ValueError( + f"{label}: run \"{row[1]}\" is not among the given" + f" runs {given}") + if row[2] not in (Correction.KEYWORD, Correction.EVIDENCE): + raise ValueError(f"{label}: unknown type \"{row[2]}\"") + return Correction( + line=line, song_id=song_id, run=row[1], type=row[2], + to_be_replaced=cls.__unescape(row[3]), + correct_term=cls.__unescape(row[4])) + + @staticmethod + def __unescape(text: str) -> str: + r"""Unescape the newlines of a text field. + + The mirror of the escaping :meth:`CodingTable.write` does + to the ``Quote`` field it writes out. + + :param text: The field as the CSV reader gave it. + :return: The field with every two-character ``\n`` + sequence turned into a single LF. + """ + return text.replace("\\n", "\n") + + @staticmethod + def __parse_song_id(item_id: str, label: str) -> int: + """Parse the integer song ID out of a song ID field. + + :param item_id: The song ID field, expected as + ``song-``. + :param label: The location of the field, for the error + message. + :return: The parsed song ID. + :raises ValueError: When the field is not ``song-``. + """ + prefix: str = "song-" + if not item_id.startswith(prefix) \ + or not item_id[len(prefix):].isdigit(): + raise ValueError( + f"{label}: song ID \"{item_id}\": not in" + " \"song-\" form") + return int(item_id[len(prefix):]) + + +@dataclass +class ValidKeywords: + """The keywords the coding records may carry.""" + + path: Path + """The keyword list file the keywords came from.""" + keywords: set[str] + """The allowed keywords.""" + + +class ValidKeywordsLoader: + """The loader of the valid keyword list.""" + + def __init__(self, path: Path) -> None: + """Set up the loader of the valid keyword list. + + :param path: The keyword list text file, one keyword per + line. + """ + self.__path: Path = path + """The keyword list text file.""" + + def run(self) -> ValidKeywords: + """Load the valid keyword list. + + Blank lines are ignored and every keyword is stripped of + its surrounding whitespace; the file order carries no + meaning. Nothing is written. + + :return: The allowed keywords. + :raises TallyError: When the file cannot be read. + """ + text: str + try: + text = self.__path.read_text(encoding="utf-8") + except OSError as error: + raise TallyError(str(error)) from error + return ValidKeywords( + path=self.__path, + keywords={x.strip() for x in text.split("\n") + if x.strip() != ""}) + + @dataclass class TalliedCodings: """The codes settled by a majority of the three coding runs.""" @@ -84,7 +363,9 @@ class CodingTallier: settled code.""" def __init__(self, run_dir_1: Path, run_dir_2: Path, - run_dir_3: Path) -> None: + run_dir_3: Path, + valid_keywords_txt: Path | None = None, + corrections_csv: Path | None = None) -> None: """Set up the tallier of the three coding runs. :param run_dir_1: The first run's archive directory, @@ -93,11 +374,21 @@ class CodingTallier: containing ``output.jsonl``. :param run_dir_3: The third run's archive directory, containing ``output.jsonl``. + :param valid_keywords_txt: The valid keyword list text + file, or None to check no keyword. + :param corrections_csv: The researcher-reviewed correction + table CSV file, or None to repair no record. """ self.__run_dirs: list[Path] = [ run_dir_1, run_dir_2, run_dir_3] """The three runs' archive directories, in the given order.""" + self.__valid_keywords_txt: Path | None = valid_keywords_txt + """The valid keyword list text file, or None to check no + keyword.""" + self.__corrections_csv: Path | None = corrections_csv + """The correction table CSV file, or None to repair no + record.""" def run(self) -> TalliedCodings: """Load the three coding runs and tally their votes. @@ -105,9 +396,13 @@ class CodingTallier: Every record of every run must be a successful result whose "text" parses to a JSON object of keywords mapped to their lyric quote lists, and the three runs must cover - exactly the same set of song IDs. Only the keyword keys - are counted; the quotes of a settled code are pooled for - the output. Nothing is written. + exactly the same set of song IDs. The researcher-reviewed + repairs, when given, are applied to the records first, and + every one of them must match something; the valid keyword + list, when given, is checked against the repaired records + next. Only the keyword keys are counted; the quotes of a + settled code are pooled for the output. Nothing is + written. :return: The keywords at least two of the three runs assign, with their joined quotes, of every song the @@ -117,17 +412,192 @@ class CodingTallier: record is not a successful result, a "text" does not parse to a JSON object of quote string lists, a JSON document has a duplicate key, a run has two records of - one song, or the three runs do not cover the same - songs. + one song, the three runs do not cover the same songs, + the correction table or the valid keyword list cannot + be read or is invalid, a correction matches nothing, + or a keyword is not in the valid keyword list. """ + corrections: CorrectionTable | None = self.__load_corrections() + valid: ValidKeywords | None = self.__load_valid_keywords() runs: list[dict[int, dict[str, list[str]]]] try: runs = [self.__load_run(x) for x in self.__run_dirs] self.__check_same_songs(self.__run_dirs, runs) + if corrections is not None: + self.__correct(runs, self.__run_dirs, corrections) + if valid is not None: + self.__check_keywords(self.__run_dirs, runs, valid) except (OSError, ValueError) as error: raise TallyError(str(error)) from error return TalliedCodings(codings=self.__tally(runs)) + def __load_corrections(self) -> CorrectionTable | None: + """Load the researcher-reviewed correction table. + + :return: The repairs, or None when the caller gave no + correction table. + :raises TallyError: When the correction table cannot be + read or is invalid. + """ + if self.__corrections_csv is None: + return None + return CorrectionsLoader( + self.__corrections_csv, + [x.name for x in self.__run_dirs]).run() + + def __load_valid_keywords(self) -> ValidKeywords | None: + """Load the valid keyword list. + + :return: The allowed keywords, or None when the caller + gave no keyword list. + :raises TallyError: When the keyword list cannot be read. + """ + if self.__valid_keywords_txt is None: + return None + return ValidKeywordsLoader(self.__valid_keywords_txt).run() + + @classmethod + def __correct(cls, runs: list[dict[int, dict[str, list[str]]]], + run_dirs: list[Path], + corrections: CorrectionTable) -> None: + """Apply the researcher-reviewed repairs to the records. + + Each repair is applied to the runs whose directory + basename it names, in file order. The table is + hand-curated and is expected to be reconciled with the + records, so a repair that matches nothing fails the run. + + :param runs: The runs' records, in the given order, + repaired in place. + :param run_dirs: The runs' archive directories, in the + same order. + :param corrections: The repairs to apply. + :return: None. + :raises ValueError: When a repair matches nothing. + """ + applied: set[int] = set() + index: int + records: dict[int, dict[str, list[str]]] + for index, records in enumerate(runs): + position: int + correction: Correction + for position, correction \ + in enumerate(corrections.corrections): + if correction.run != run_dirs[index].name: + continue + if cls.__correct_one(records, correction): + applied.add(position) + for position, correction in enumerate( + corrections.corrections): + if position not in applied: + raise ValueError( + f"{corrections.path}: line {correction.line}:" + f" {correction.label}: matches nothing") + + @classmethod + def __correct_one( + cls, records: dict[int, dict[str, list[str]]], + correction: Correction) -> bool: + """Apply one repair to one run's records. + + :param records: The run's records, keyed by the numeric + part of the song ID, repaired in place. + :param correction: The repair to apply. + :return: Whether the repair matched anything. + """ + if correction.song_id not in records: + return False + keywords: dict[str, list[str]] = records[correction.song_id] + if correction.type == Correction.KEYWORD: + return cls.__correct_keyword(keywords, correction) + return cls.__correct_evidence(keywords, correction) + + @staticmethod + def __correct_keyword(keywords: dict[str, list[str]], + correction: Correction) -> bool: + """Rename or drop one keyword assignment of one record. + + A rename onto a keyword the record already carries pools + the two quote lists under the one keyword, which casts the + one vote the record now states. + + :param keywords: The song's assigned keywords and their + lyric quotes, repaired in place. + :param correction: The keyword repair to apply. + :return: Whether the record carries the named keyword. + """ + if correction.to_be_replaced not in keywords: + return False + quotes: list[str] = keywords.pop(correction.to_be_replaced) + if not correction.is_removal: + keywords.setdefault( + correction.correct_term, []).extend(quotes) + return True + + @staticmethod + def __correct_evidence(keywords: dict[str, list[str]], + correction: Correction) -> bool: + """Rewrite or drop one lyric quote of one record. + + The quote string is repaired under every keyword of the + record that carries it, as one quote often grounds several + keywords. Dropping the last quote of a keyword leaves the + assignment standing with no quote at all. + + :param keywords: The song's assigned keywords and their + lyric quotes, repaired in place. + :param correction: The evidence repair to apply. + :return: Whether any keyword of the record carries the + named quote. + """ + matched: bool = False + keyword: str + quotes: list[str] + for keyword, quotes in keywords.items(): + if correction.to_be_replaced not in quotes: + continue + matched = True + if correction.is_removal: + keywords[keyword] = [ + x for x in quotes + if x != correction.to_be_replaced] + continue + keywords[keyword] = [ + correction.correct_term + if x == correction.to_be_replaced else x + for x in quotes] + return matched + + @staticmethod + def __check_keywords( + run_dirs: list[Path], + runs: list[dict[int, dict[str, list[str]]]], + valid: ValidKeywords) -> None: + """Check every keyword against the valid keyword list. + + :param run_dirs: The runs' archive directories, in the + given order. + :param runs: The runs' records, in the same order, the + repairs already applied. + :param valid: The allowed keywords. + :return: None. + :raises ValueError: When a record carries a keyword the + list does not have. + """ + index: int + records: dict[int, dict[str, list[str]]] + for index, records in enumerate(runs): + song_id: int + for song_id in sorted(records): + keyword: str + for keyword in records[song_id]: + if keyword in valid.keywords: + continue + raise ValueError( + f"{run_dirs[index]}: song-{song_id}:" + f" keyword \"{keyword}\": not in" + f" {valid.path}") + @classmethod def __load_run(cls, run_dir: Path) \ -> dict[int, dict[str, list[str]]]: @@ -362,13 +832,18 @@ class CodingTable: keyword, by Unicode code point.""" def write(self, output_csv: Path) -> None: - """Write the coding table CSV file. + r"""Write the coding table CSV file. Writes an RFC 4180 CSV file, UTF-8, with CRLF line endings, carrying the header row ``Song,Artist Credit,Keyword,Quote`` and one row per - settled keyword, in the row order. The parent directory - is created when it does not exist. + settled keyword, in the row order. The ``Quote`` field + carries the two characters ``\n`` where the quotes have a + newline, so no field holds a line break and the file + holds one row per line; the correction table loader + unescapes its own two text fields the same way, and + restoring a single LF gives the lyric text back. The + parent directory is created when it does not exist. :param output_csv: The output CSV file. :return: None. @@ -379,7 +854,22 @@ class CodingTable: newline="") as file: writer: Any = csv.writer(file) writer.writerow(self.__HEADER) - writer.writerows(self.rows) + writer.writerows( + (*x[:3], self.__escape(x[3])) for x in self.rows) + + @staticmethod + def __escape(text: str) -> str: + r"""Escape the newlines of the quote field. + + The mirror of the unescaping the correction table loader + does to its own two text fields. + + :param text: The joined lyric quotes of one settled + keyword. + :return: The quotes with every LF turned into the two + characters ``\n``. + """ + return text.replace("\n", "\\n") class CodingTableBuilder: @@ -503,11 +993,23 @@ def parse_args(argv: list[str] | None) -> argparse.Namespace: "output_csv", type=Path, help="the output CSV file, by convention" f" results/{CodingTable.RESULT_CODINGS_CSV}") + parser.add_argument( + "--valid-keywords", type=Path, default=None, + help="a plain text file of the allowed keywords, one per" + " line, that every keyword left after the" + " corrections must appear in (default: no check)") + parser.add_argument( + "--corrections", type=Path, default=None, + help="the researcher-reviewed correction table CSV file," + " by convention" + f" data/manual/{CorrectionTable.MANUAL_CORRECTIONS_CSV}," + " applied to the runs' records before the tally" + " (default: no repair)") return parser.parse_args(argv) def main(argv: list[str] | None = None) -> int: - """Settle the coding by a majority of the three coding runs. + r"""Settle the coding by a majority of the three coding runs. Writes the final coding table as the given CSV file, holding the header row ``Song,Artist Credit,Keyword,Quote`` and one @@ -515,11 +1017,17 @@ def main(argv: list[str] | None = None) -> int: song named by its title and its stored artist credit from the SQLite working store, and the keyword carrying the pooled, deduplicated, and sorted lyric quotes of the runs that - assigned it, joined with a single ``|``. Nothing is written - when the three archives do not cover the same songs, a record - is not a successful result, a record's "text" does not parse - to a JSON object of quote string lists, or a song is not in - the working store; the error message names what failed. + assigned it, joined with a single ``|`` and written with the + two characters ``\n`` where the quotes have a newline, so the + table holds one row per line. The records are + repaired from the ``--corrections`` table and then checked + against the ``--valid-keywords`` list, when either is given. + Nothing is written when the three archives do not cover the + same songs, a record is not a successful result, a record's + "text" does not parse to a JSON object of quote string lists, + a correction is invalid or matches nothing, a keyword is not + in the valid keyword list, or a song is not in the working + store; the error message names what failed. :param argv: The command-line arguments, or None for ``sys.argv``. @@ -529,7 +1037,8 @@ def main(argv: list[str] | None = None) -> int: args: argparse.Namespace = parse_args(argv) try: codings: TalliedCodings = CodingTallier( - args.run_dir_1, args.run_dir_2, args.run_dir_3).run() + args.run_dir_1, args.run_dir_2, args.run_dir_3, + args.valid_keywords, args.corrections).run() table: CodingTable = CodingTableBuilder( codings, args.output_csv).run() elapsed: str = format_duration(time.monotonic() - started) diff --git a/tools/tests/test_tally_codings.py b/tools/tests/test_tally_codings.py index 27cc2ef..15f5fb0 100644 --- a/tools/tests/test_tally_codings.py +++ b/tools/tests/test_tally_codings.py @@ -114,19 +114,48 @@ class TestTallyCodings(unittest.TestCase): self.__write_output(self.__runs[index], [ self.__record(x, songs[x]) for x in songs]) - def __run_tally(self) -> tuple[int, str]: + def __run_tally(self, *options: str) -> tuple[int, str]: """Run the tally over the three run directories. + :param options: The optional command-line arguments. :return: A tuple of the exit status and the standard error. """ argv: list[str] = [ - *(str(x) for x in self.__runs), str(self.__output_csv)] + *(str(x) for x in self.__runs), str(self.__output_csv), + *options] stderr: io.StringIO = io.StringIO() with redirect_stderr(stderr): status: int = tally_codings.main(argv) return status, stderr.getvalue() + def __write_corrections( + self, rows: list[tuple[str, str, str, str, str]]) \ + -> str: + """Write the correction table CSV file. + + :param rows: The data rows, in file order. + :return: The path of the correction table CSV file. + """ + path: Path = self.__dir / "corrections.csv" + with open(path, "w", encoding="utf-8", newline="") as file: + writer: Any = csv.writer(file) + writer.writerow(( + "Song ID", "Run", "Type", "To Be Replaced", + "Correct Term")) + writer.writerows(rows) + return str(path) + + def __write_valid_keywords(self, text: str) -> str: + """Write the valid keyword list text file. + + :param text: The whole content of the file. + :return: The path of the valid keyword list text file. + """ + path: Path = self.__dir / "valid-keywords.txt" + path.write_text(text, encoding="utf-8") + return str(path) + def __read_rows(self) -> list[list[str]]: """Read the coding table CSV file. @@ -222,6 +251,47 @@ class TestTallyCodings(unittest.TestCase): b"Alpha,A Singer,kw," b"\"she said \"\"no\"\", twice\"\r\n") + def test_newline_in_quote_written_as_two_characters( + self) -> None: + r"""Test that a quote spanning two lyric lines is written + with the two characters ``\n`` where the newline is, + needing no RFC 4180 quoting.""" + self.__seed([("Alpha", "A Singer")]) + codings: dict[int, dict[str, list[str]]] = { + 1: {"kw": ["You needed me\nTo feel a little more"]}} + self.__write_codings([codings, codings, codings]) + status: int + status, _ = self.__run_tally() + self.assertEqual(status, 0) + self.assertEqual( + self.__output_csv.read_bytes(), + b"Song,Artist Credit,Keyword,Quote\r\n" + b"Alpha,A Singer,kw," + b"You needed me\\nTo feel a little more\r\n") + + def test_multi_line_quotes_keep_one_row_per_line(self) -> None: + r"""Test that the file holds exactly one line per row, no + field carrying a line break, and that turning the two + characters ``\n`` back into a single LF gives the quotes + as the runs wrote them.""" + self.__seed([("Alpha", "A Singer")]) + codings: dict[int, dict[str, list[str]]] = { + 1: {"kw1": ["one line"], + "kw2": ["first line\nsecond line"], + "kw3": ["a\nb\nc", "d\ne"]}} + self.__write_codings([codings, codings, codings]) + status: int + status, _ = self.__run_tally() + self.assertEqual(status, 0) + data: bytes = self.__output_csv.read_bytes() + self.assertEqual(data.count(b"\n"), 4) + self.assertEqual(data.count(b"\r\n"), 4) + rows: list[list[str]] = self.__read_rows() + self.assertEqual(len(rows), 4) + self.assertEqual( + [x[3].replace("\\n", "\n") for x in rows[1:]], + ["one line", "first line\nsecond line", "a\nb\nc|d\ne"]) + def test_empty_quote_lists_yield_an_empty_cell(self) -> None: """Test that a settled keyword whose runs all gave an empty quote list carries an empty quote cell.""" @@ -541,3 +611,395 @@ class TestTallyCodings(unittest.TestCase): codings, self.__output_csv).run() self.assertIn("song-9", str(context.exception)) self.assertFalse(self.__output_csv.exists()) + + def test_keyword_correction_reunites_the_votes(self) -> None: + """Test that renaming a misspelled keyword in two runs + joins the third run's vote and settles the code.""" + self.__seed([("Alpha", "A Singer")]) + self.__write_codings([ + {1: {"womens-power": ["one"]}}, + {1: {"womens-power": ["two"]}}, + {1: {"women-power": ["three"]}}, + ]) + corrections: str = self.__write_corrections([ + ("song-1", "run1", "keyword", "womens-power", + "women-power"), + ("song-1", "run2", "keyword", "womens-power", + "women-power"), + ]) + status: int + status, _ = self.__run_tally("--corrections", corrections) + self.assertEqual(status, 0) + self.assertEqual(self.__read_rows()[1:], [ + ["Alpha", "A Singer", "women-power", + "one|three|two"]]) + + def test_keyword_correction_removal_drops_the_vote( + self) -> None: + """Test that removing a keyword assignment leaves it + casting no vote, so the code no longer settles.""" + self.__seed([("Alpha", "A Singer")]) + self.__write_codings([ + {1: {"kw": ["one"], "kept": ["one"]}}, + {1: {"kw": ["two"], "kept": ["two"]}}, + {1: {"kept": ["three"]}}, + ]) + corrections: str = self.__write_corrections([ + ("song-1", "run2", "keyword", "kw", "**REMOVE**")]) + status: int + status, _ = self.__run_tally("--corrections", corrections) + self.assertEqual(status, 0) + self.assertEqual(self.__read_rows()[1:], [ + ["Alpha", "A Singer", "kept", "one|three|two"]]) + + def test_keyword_correction_merges_into_the_existing_one( + self) -> None: + """Test that renaming a keyword onto one the same record + already carries pools their quotes into a single vote.""" + self.__seed([("Alpha", "A Singer")]) + self.__write_codings([ + {1: {"womens-power": ["one"], "women-power": ["two"]}}, + {1: {"women-power": ["three"]}}, + {1: {"other": ["four"]}}, + ]) + corrections: str = self.__write_corrections([ + ("song-1", "run1", "keyword", "womens-power", + "women-power")]) + status: int + status, _ = self.__run_tally("--corrections", corrections) + self.assertEqual(status, 0) + self.assertEqual(self.__read_rows()[1:], [ + ["Alpha", "A Singer", "women-power", + "one|three|two"]]) + + def test_evidence_correction_repairs_every_keyword( + self) -> None: + """Test that one evidence row repairs the quote under + every keyword of that song and run that carries it, and + leaves the other runs alone.""" + self.__seed([("Alpha", "A Singer")]) + self.__write_codings([ + {1: {"one": ["Shared line", "own"], + "two": ["Shared line"]}}, + {1: {"one": ["shared line"], "two": ["shared line"]}}, + {1: {"one": ["shared line"], "two": ["shared line"]}}, + ]) + corrections: str = self.__write_corrections([ + ("song-1", "run1", "evidence", "Shared line", + "shared line")]) + status: int + status, _ = self.__run_tally("--corrections", corrections) + self.assertEqual(status, 0) + self.assertEqual(self.__read_rows()[1:], [ + ["Alpha", "A Singer", "one", "own|shared line"], + ["Alpha", "A Singer", "two", "shared line"]]) + + def test_evidence_correction_removal_keeps_the_assignment( + self) -> None: + """Test that removing a quote leaves the keyword + assignments standing, even with no quote left at all.""" + self.__seed([("Alpha", "A Singer")]) + codings: dict[int, dict[str, list[str]]] \ + = {1: {"kw": ["hallucinated"]}} + self.__write_codings([codings, codings, codings]) + corrections: str = self.__write_corrections([ + ("song-1", x, "evidence", "hallucinated", "**REMOVE**") + for x in ("run1", "run2", "run3")]) + status: int + status, _ = self.__run_tally("--corrections", corrections) + self.assertEqual(status, 0) + self.assertEqual(self.__read_rows()[1:], [ + ["Alpha", "A Singer", "kw", ""]]) + + def test_correction_with_an_escaped_newline(self) -> None: + r"""Test that a correction whose two text fields carry the + two characters ``\n`` matches and replaces a quote that + genuinely spans two lines, the file itself holding one row + per line.""" + self.__seed([("Alpha", "A Singer")]) + quote: str = "You needed me\nTo feel a little more" + codings: dict[int, dict[str, list[str]]] \ + = {1: {"kw": [quote]}} + self.__write_codings([codings, codings, codings]) + path: Path = self.__dir / "corrections.csv" + path.write_bytes( + b"Song ID,Run,Type,To Be Replaced,Correct Term\r\n" + b"song-1,run1,evidence," + b"You needed me\\nTo feel a little more," + b"you needed me\\nTo feel a little more\r\n") + self.assertEqual(len(path.read_bytes().split(b"\r\n")), 3) + status: int + status, _ = self.__run_tally("--corrections", str(path)) + self.assertEqual(status, 0) + self.assertEqual(self.__read_rows()[1:], [ + ["Alpha", "A Singer", "kw", + "You needed me\\nTo feel a little more" + "|you needed me\\nTo feel a little more"]]) + + def test_stale_correction_row_rejected(self) -> None: + """Test that a correction matching nothing fails the run, + naming the row, without writing the CSV file.""" + self.__seed([("Alpha", "A Singer")]) + codings: dict[int, dict[str, list[str]]] \ + = {1: {"kw": ["the line"]}} + self.__write_codings([codings, codings, codings]) + corrections: str = self.__write_corrections([ + ("song-1", "run2", "evidence", "a line no run gave", + "repaired")]) + status: int + stderr: str + status, stderr = self.__run_tally( + "--corrections", corrections) + self.assertEqual(status, 1) + self.assertIn("matches nothing", stderr) + self.assertIn("song-1 run2 evidence", stderr) + self.assertIn("a line no run gave", stderr) + self.assertFalse(self.__output_csv.exists()) + + def test_correction_of_a_song_no_run_covers_rejected( + self) -> None: + """Test that a correction naming a song outside the runs + fails the run without writing the CSV file.""" + self.__seed([("Alpha", "A Singer")]) + codings: dict[int, dict[str, list[str]]] \ + = {1: {"kw": ["the line"]}} + self.__write_codings([codings, codings, codings]) + corrections: str = self.__write_corrections([ + ("song-7", "run1", "keyword", "kw", "**REMOVE**")]) + status: int + stderr: str + status, stderr = self.__run_tally( + "--corrections", corrections) + self.assertEqual(status, 1) + self.assertIn("song-7 run1 keyword", stderr) + self.assertIn("matches nothing", stderr) + self.assertFalse(self.__output_csv.exists()) + + def test_correction_of_an_unknown_run_rejected(self) -> None: + """Test that a correction naming a run the command was not + given fails the run without writing the CSV file.""" + self.__seed([("Alpha", "A Singer")]) + codings: dict[int, dict[str, list[str]]] \ + = {1: {"kw": ["the line"]}} + self.__write_codings([codings, codings, codings]) + corrections: str = self.__write_corrections([ + ("song-1", "run4", "keyword", "kw", "**REMOVE**")]) + status: int + stderr: str + status, stderr = self.__run_tally( + "--corrections", corrections) + self.assertEqual(status, 1) + self.assertIn("run4", stderr) + self.assertIn("run1, run2, run3", stderr) + self.assertFalse(self.__output_csv.exists()) + + def test_correction_of_an_unknown_type_rejected(self) -> None: + """Test that a correction of an unknown type fails the run + without writing the CSV file.""" + self.__seed([("Alpha", "A Singer")]) + codings: dict[int, dict[str, list[str]]] \ + = {1: {"kw": ["the line"]}} + self.__write_codings([codings, codings, codings]) + corrections: str = self.__write_corrections([ + ("song-1", "run1", "quote", "kw", "**REMOVE**")]) + status: int + stderr: str + status, stderr = self.__run_tally( + "--corrections", corrections) + self.assertEqual(status, 1) + self.assertIn("unknown type \"quote\"", stderr) + self.assertFalse(self.__output_csv.exists()) + + def test_correction_with_a_malformed_song_id_rejected( + self) -> None: + """Test that a correction whose song ID is not in the + ``song-`` form fails the run without writing the CSV + file.""" + self.__seed([("Alpha", "A Singer")]) + codings: dict[int, dict[str, list[str]]] \ + = {1: {"kw": ["the line"]}} + self.__write_codings([codings, codings, codings]) + corrections: str = self.__write_corrections([ + ("track-1", "run1", "keyword", "kw", "**REMOVE**")]) + status: int + stderr: str + status, stderr = self.__run_tally( + "--corrections", corrections) + self.assertEqual(status, 1) + self.assertIn("song-", stderr) + self.assertFalse(self.__output_csv.exists()) + + def test_correction_table_header_rejected(self) -> None: + """Test that a correction table carrying another header + row fails the run without writing the CSV file.""" + self.__seed([("Alpha", "A Singer")]) + codings: dict[int, dict[str, list[str]]] \ + = {1: {"kw": ["the line"]}} + self.__write_codings([codings, codings, codings]) + path: Path = self.__dir / "corrections.csv" + path.write_text( + "Song,Run,Type,Old,New\r\n", encoding="utf-8") + status: int + stderr: str + status, stderr = self.__run_tally( + "--corrections", str(path)) + self.assertEqual(status, 1) + self.assertIn("header row", stderr) + self.assertFalse(self.__output_csv.exists()) + + def test_correction_row_of_the_wrong_width_rejected( + self) -> None: + """Test that a correction row without all five fields + fails the run without writing the CSV file.""" + self.__seed([("Alpha", "A Singer")]) + codings: dict[int, dict[str, list[str]]] \ + = {1: {"kw": ["the line"]}} + self.__write_codings([codings, codings, codings]) + path: Path = self.__dir / "corrections.csv" + path.write_text( + "Song ID,Run,Type,To Be Replaced,Correct Term\r\n" + "song-1,run1,keyword\r\n", encoding="utf-8") + status: int + stderr: str + status, stderr = self.__run_tally( + "--corrections", str(path)) + self.assertEqual(status, 1) + self.assertIn("expected 5 fields", stderr) + self.assertFalse(self.__output_csv.exists()) + + def test_missing_correction_table_rejected(self) -> None: + """Test that an unreadable correction table fails the run + without writing the CSV file.""" + self.__seed([("Alpha", "A Singer")]) + codings: dict[int, dict[str, list[str]]] \ + = {1: {"kw": ["the line"]}} + self.__write_codings([codings, codings, codings]) + status: int + stderr: str + status, stderr = self.__run_tally( + "--corrections", str(self.__dir / "absent.csv")) + self.assertEqual(status, 1) + self.assertIn("absent.csv", stderr) + self.assertFalse(self.__output_csv.exists()) + + def test_off_vocabulary_keyword_rejected(self) -> None: + """Test that a keyword outside the valid keyword list + fails the run, naming the run, the song and the keyword, + without writing the CSV file.""" + self.__seed([("Alpha", "A Singer")]) + self.__write_codings([ + {1: {"women-power": ["one"]}}, + {1: {"women-power": ["two"], + "womens-power": ["three"]}}, + {1: {"women-power": ["four"]}}, + ]) + valid: str = self.__write_valid_keywords("women-power\n") + status: int + stderr: str + status, stderr = self.__run_tally("--valid-keywords", valid) + self.assertEqual(status, 1) + self.assertIn("run2", stderr) + self.assertIn("song-1", stderr) + self.assertIn("womens-power", stderr) + self.assertFalse(self.__output_csv.exists()) + + def test_valid_keyword_list_read_loosely(self) -> None: + """Test that the valid keyword list ignores blank lines + and surrounding whitespace and carries no order.""" + self.__seed([("Alpha", "A Singer")]) + codings: dict[int, dict[str, list[str]]] \ + = {1: {"zulu": ["q"], "alpha": ["q"]}} + self.__write_codings([codings, codings, codings]) + valid: str = self.__write_valid_keywords( + "\n zulu \n\nalpha\n\t\n") + status: int + status, _ = self.__run_tally("--valid-keywords", valid) + self.assertEqual(status, 0) + self.assertEqual(self.__read_rows()[1:], [ + ["Alpha", "A Singer", "alpha", "q"], + ["Alpha", "A Singer", "zulu", "q"]]) + + def test_corrections_checked_before_the_keyword_check( + self) -> None: + """Test that the corrections are applied before the valid + keyword check, so a misspelling the corrections repair + does not fail the run.""" + self.__seed([("Alpha", "A Singer")]) + self.__write_codings([ + {1: {"womens-power": ["one"]}}, + {1: {"womens-power": ["two"]}}, + {1: {"women-power": ["three"]}}, + ]) + corrections: str = self.__write_corrections([ + ("song-1", x, "keyword", "womens-power", "women-power") + for x in ("run1", "run2")]) + valid: str = self.__write_valid_keywords("women-power\n") + status: int + stderr: str + status, stderr = self.__run_tally( + "--valid-keywords", valid, + "--corrections", corrections) + self.assertEqual(status, 0) + self.assertEqual(self.__read_rows()[1:], [ + ["Alpha", "A Singer", "women-power", + "one|three|two"]]) + self.assertIn( + "Done. Tallied 1 codes across 1 songs.", stderr) + + def test_keyword_check_covers_the_unsettled_keywords( + self) -> None: + """Test that a keyword only one run assigns, which never + reaches the output table, is checked all the same.""" + self.__seed([("Alpha", "A Singer")]) + self.__write_codings([ + {1: {"kw": ["q"], "stray": ["q"]}}, + {1: {"kw": ["q"]}}, {1: {"kw": ["q"]}}, + ]) + valid: str = self.__write_valid_keywords("kw\n") + status: int + stderr: str + status, stderr = self.__run_tally("--valid-keywords", valid) + self.assertEqual(status, 1) + self.assertIn("stray", stderr) + self.assertFalse(self.__output_csv.exists()) + + def test_missing_valid_keyword_list_rejected(self) -> None: + """Test that an unreadable valid keyword list fails the + run without writing the CSV file.""" + self.__seed([("Alpha", "A Singer")]) + codings: dict[int, dict[str, list[str]]] \ + = {1: {"kw": ["q"]}} + self.__write_codings([codings, codings, codings]) + status: int + stderr: str + status, stderr = self.__run_tally( + "--valid-keywords", str(self.__dir / "absent.txt")) + self.assertEqual(status, 1) + self.assertIn("absent.txt", stderr) + self.assertFalse(self.__output_csv.exists()) + + def test_corrections_loader_reads_the_rows(self) -> None: + """Test that the corrections loader alone parses the rows + and writes no file.""" + corrections: str = self.__write_corrections([ + ("song-1", "run1", "keyword", "kw", "**REMOVE**"), + ("song-2", "run3", "evidence", "a line", "A line"), + ]) + table: tally_codings.CorrectionTable \ + = tally_codings.CorrectionsLoader( + Path(corrections), + ["run1", "run2", "run3"]).run() + self.assertEqual(len(table.corrections), 2) + first: tally_codings.Correction = table.corrections[0] + self.assertEqual(first.song_id, 1) + self.assertEqual(first.run, "run1") + self.assertEqual(first.type, tally_codings.Correction.KEYWORD) + self.assertEqual(first.to_be_replaced, "kw") + self.assertTrue(first.is_removal) + second: tally_codings.Correction = table.corrections[1] + self.assertEqual(second.song_id, 2) + self.assertEqual( + second.type, tally_codings.Correction.EVIDENCE) + self.assertEqual(second.correct_term, "A line") + self.assertFalse(second.is_removal) + self.assertFalse(self.__output_csv.exists())