Last active
May 24, 2017 06:48
-
-
Save elrikdante/dd0e9d80c48082da1227c340b2cfc3c1 to your computer and use it in GitHub Desktop.
Quick and Dirty I18n Dictionary from Grep Results
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
run via: grep -R -e "[^']\+'" -e '[^"]\+"' mapwarper-master/app/controllers | ./Parser.hs | |
--autogenerated | |
mapwarper-master/app/controllers/sessions: | |
Logged_In_Successfully: Logged in successfully | |
Resend_Activation_Email?: Resend activation email? | |
You_Have_Been_Logged_Out: You have been logged out. | |
Your_Account_Has_Been_Disabled: Your account has been disabled. | |
Your_Email_Or_Password_Is_Incorrect: Your email or password is incorrect. | |
mapwarper-master/app/controllers/users: | |
Activation_Email_Has_Been_Resent,_Check_Your_Email: Activation email has been resent, check your email. | |
Activation_Email_Was_Not_Sent,_Either_Because_The_Email_Was_Not_The_Same_As_You_Gave_When_You_Signed_Up,_Or_You_Have_Already_Been_Activated!: Activation email was not sent, either because the email was not the same as you gave when you signed up, or you have already been activated! | |
Edit_User_Profile_-_: Edit User Profile - | |
Thanks_For_Signing_Up!_Please_Check_Your_Email_To_Activate_Your_Account_Before_Logging_In_If_You_Dont_Recieve_An_Email,_Then_%S: Thanks for signing up! Please check your email to activate your account before logging in. If you dont recieve an email, then %s | |
There_Was_A_Problem_Activating_This_User: There was a problem activating this user. | |
There_Was_A_Problem_Creating_Your_Account: There was a problem creating your account. | |
There_Was_A_Problem_Disabling_This_User: There was a problem disabling this user. | |
There_Was_A_Problem_Enabling_This_User: There was a problem enabling this user. | |
User_Activated: User activated | |
User_Already_Active: User already active | |
User_Disabled: User disabled | |
User_Enabled: User enabled | |
User_Updated: User updated | |
Your_Account_Has_Been_Activated: Your account has been activated. | |
Updated_At_Desc: updated_at DESC | |
mapwarper-master/app/controllers/my_maps: | |
Map_Coudn'T_Be_Deleted: Map coudn't be deleted | |
Map_Removed_From_List!: Map removed from list! | |
Map_Saved_To_My_Maps: Map saved to My Maps | |
My_Maps: My Maps | |
You_Cannot_Add_A_Map_To_Another_User!: You cannot add a map to another user! | |
You_Cannot_Remove_Other_People'S_Maps!: You cannot remove other people's maps! | |
Updated_At_Desc: updated_at DESC | |
mapwarper-master/app/controllers/passwords: | |
A_Password_Reset_Link_Has_Been_Sent_To_Your_Email_Address: A password reset link has been sent to your email address. | |
Could_Not_Find_A_User_With_That_Email_Address: Could not find a user with that email address. | |
Invalid_Reset_Code_Entered: Invalid Reset Code entered | |
Invalid_Reset_Code_Entered: Invalid Reset Code entered. | |
Password_Field_Cannot_Be_Blank: Password field cannot be blank. | |
Password_Mismatch: Password mismatch. | |
Password_Not_Reset: Password not reset | |
Password_Not_Reset: Password not reset. | |
Sorry_-_That_Is_An_Invalid_Password_Reset_Code_Please_Check_Your_Code_And_Try_Again_(Perhaps_Your_Email_Client_Inserted_A_Carriage_Return?): Sorry - That is an invalid password reset code. Please check your code and try again. (Perhaps your email client inserted a carriage return?) | |
Sorry_-_That_Is_An_Invalid_Password_Reset_Code_Please_Check_Your_Code_And_Try_Again_(Perhaps_Your_Email_Client_Inserted_A_Carriage_Return?): Sorry - That is an invalid password reset code. Please check your code and try again. (Perhaps your email client inserted a carriage return?) | |
mapwarper-master/app/controllers/audits: | |
Activity: Activity | |
Map: Map | |
Map: Map | |
Recent_Activity_For_Everything: Recent Activity For Everything | |
Recent_Activity_For_All_Maps: Recent Activity for All Maps | |
Recent_Activity_For_Map_: Recent Activity for Map | |
Recent_Activity_For_User_: Recent Activity for User | |
Auditable_Type_=_?_And_Auditable_Id_=_?: auditable_type = ? AND auditable_id = ? | |
Created_At_Desc: created_at DESC | |
Created_At_Desc: created_at DESC | |
Created_At_Desc: created_at DESC | |
Created_At_Desc: created_at DESC | |
mapwarper-master/app/controllers/maps: | |
_It_May_Resize_The_Image_If_It'S_Too_Large_(#{MapMax_Dimension}X#{MapMax_Dimension})_: It may resize the image if it's too large (#{Map.max_dimension}x#{Map.max_dimension}) | |
Align_Map_-_: Align Map - | |
Coverage",_"Image: COVERAGE", "image | |
Crop_Map_-_: Crop Map - | |
Epsg:4326_Epsg:4269_Epsg:900913: EPSG:4326 EPSG:4269 EPSG:900913 | |
Edit_Metadata: Edit metadata | |
Editing_Map_-_: Editing Map - | |
Export_Map: Export Map | |
Geotiff: GEOTIFF | |
Http_Referer: HTTP_REFERER | |
Http_Referer: HTTP_REFERER | |
Http_Referer"][-8-1]==_"Maps: HTTP_REFERER"][-8..-1]== "maps | |
Layers",_"Image: LAYERS", "image | |
Map_-_: Map - | |
Map_Masked_And_Rectified!: Map masked and rectified! | |
Map_Masked,_But_It_Needs_More_Control_Points_To_Rectify_Click_The_Rectify_Tab_To_Add_Some: Map masked, but it needs more control points to rectify. Click the Rectify tab to add some. | |
Map_Rectified!: Map rectified! | |
Map_Was_Successfully_Created: Map was successfully created. | |
Map_Was_Successfully_Updated: Map was successfully updated. | |
Map_Will_Be_Published_(This_Functionality_Doesn'T_Do_Anything_At_The_Moment): Map will be published. (this functionality doesn't do anything at the moment) | |
Maps: Maps | |
New_Map: New Map | |
Proj_Lib: PROJ_LIB | |
Rectify_Map_-_: Rectify Map - | |
Status"]To_SDowncase_||_"Unwarped: STATUS"].to_s.downcase || "unwarped | |
Status"]To_SDowncase_||_"Unwarped: STATUS"].to_s.downcase || "unwarped | |
Styles",_": STYLES", " | |
Showing_Rectified_Map_-_: Showing rectified map - | |
Sorry,_The_Map_Needs_At_Least_Three_Control_Points_To_Be_Able_To_Rectify_It: Sorry, the map needs at least three control points to be able to rectify it | |
Sorry,_You_Cannot_Edit_Other_People'S_Maps: Sorry, you cannot edit other people's maps | |
This_Map_Has_Not_Been_Rectified_Yet: This map has not been rectified yet. | |
Viewing_Original_Map_: Viewing original map. | |
Viewing_Unrectified_Map: Viewing unrectified map. | |
Viewing_Warped_Map: Viewing warped map | |
Whoops,_You_Have_To_Rectify_A_Map_Before_You_Can_View_It: Whoops, you have to rectify a map before you can view it | |
Upper(#{@Field}_)__Like_?__And_Status_=_4_: upper(#{@field} ) LIKE ? AND status = 4 | |
Upper(#{@Field}_)_Like_?_: upper(#{@field} ) LIKE ? | |
mapwarper-master/app/controllers/home: | |
Home: Home | |
Status_=_4_Or_Status_In_(2,3,4)_: status = 4 OR status IN (2,3,4) | |
Status_=_4_Or_Status_In_(2,3,4)_: status = 4 OR status IN (2,3,4) | |
Updated_At_Desc: updated_at DESC | |
Updated_At_Desc: updated_at DESC | |
mapwarper-master/app/controllers/gcp: | |
Control_Point_Couldnt_Be_Updated: Control point couldnt be updated | |
This_Ground_Control_Point_Does_Not_Exist_Anymore: This ground control point does not exist anymore | |
mapwarper-master/app/controllers/user_accounts: | |
Activation_Code_Not_Found_Please_Try_Creating_A_New_Account_Or_We_Can_Try_To_%S: Activation code not found. Please try creating a new account. Or we can try to %s | |
Activation_Code_Not_Found_Please_Try_Creating_A_New_Account_Or_We_Can_Try_To_%S: Activation code not found. Please try creating a new account. Or we can try to %s | |
An_Error_Occured,_Your_Password_Was_Not_Changed: An error occured, your password was not changed. | |
Change_Password: Change Password | |
New_Password_Does_Not_Match_The_Password_Confirmation: New password does not match the password confirmation. | |
Password_Successfully_Updated: Password successfully updated. | |
Your_Account_Has_Already_Been_Activated_You_Can_Log_In_Below: Your account has already been activated. You can log in below. | |
Your_Account_Has_Been_Activated!_You_Can_Now_Login: Your account has been activated! You can now login. | |
Your_Old_Password_Is_Incorrect: Your old password is incorrect. | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
run on https://github.com/projectfedena/project_fedena using: | |
grep -R -e "[^']\+'" -e '[^"]\+"' project_fedena-master/app/controllers | ./Parser.hs | |
--autogenerated | |
project_fedena-master/app/controllers/reminder: | |
<B>Error:</B>Please_Enter_Both_Subject_And_Body: <b>ERROR:</b>Please enter both subject and body | |
<B>Error:</B>Please_Fill_The_Required_Fields_To_Create_This_Reminder: <b>ERROR:</b>Please fill the required fields to create this reminder | |
Reminder_Created: Reminder created... | |
Reminder_Deleted: Reminder deleted... | |
Reminder_Deleted: Reminder deleted... | |
Reminder_Marked_Unread: Reminder marked unread... | |
Your_Reply_Has_Been_Sent: Your reply has been sent | |
Created_At_Desc: created_at DESC | |
Created_At_Desc: created_at DESC | |
Created_At_Desc",_:Conditions=>"Is_Deleted_By_Sender_=_False: created_at DESC", :conditions=>"is_deleted_by_sender = false | |
project_fedena-master/app/controllers/holiday: | |
#{AcademicyearThisEnd_Date}: #{AcademicYear.this.end_date} | |
#{AcademicyearThisEnd_Date}: #{AcademicYear.this.end_date} | |
Holiday_Saved: Holiday saved | |
Holiday_Updated!: Holiday updated! | |
project_fedena-master/app/controllers/course: | |
Academicyearid: AcademicYearID | |
Course_Created: Course created. | |
Course_Deleted_Successfully: Course deleted successfully | |
Course_Updated: Course updated. | |
Course_Was_Not_Deleted_Because_It_May_Be_Used_Elsewhere!: Course was not deleted because it may be used elsewhere!. | |
Guardians: Guardians | |
Mail_Sent_To_#{Recipients}: Mail sent to #{recipients} | |
Students: Students | |
Students_&_Guardians: Students & Guardians | |
Date_>=_#{DateToday}_And_Date_<=_#{DateToday_+_60Days}: date >= #{Date.today} AND date <= #{Date.today + 60.days} | |
project_fedena-master/app/controllers/academic_year: | |
Academicyearid: AcademicYearID | |
Academicyearid: AcademicYearID | |
Academicyearid: AcademicYearID | |
Former: Former | |
Former\": Former\" | |
Former\": Former\" | |
Leaving_School: Leaving school | |
Date_>_#{DateToday}_And_Date_<_#{DateToday_+_60Days}: date > #{Date.today} AND date < #{Date.today + 60.days} | |
project_fedena-master/app/controllers/attendance: | |
_And_Attendance_Date_<=_'#{YearEnd_Date}: AND attendance_date <= '#{year.end_date} | |
Attendance_Registered: Attendance Registered | |
Attendance_Registered: Attendance registered. | |
Daily: Daily | |
Daily: Daily | |
Daily: Daily | |
Studentattendancetype: StudentAttendanceType | |
Studentattendancetype: StudentAttendanceType | |
Studentattendancetype: StudentAttendanceType | |
You_Did_Not_Mark_Any_Attendance,_All_Students_Of_The_Class__Seems_To_Be_Present: You did not mark any attendance, All students of the class seems to be present | |
Course_Id_Asc: course_id ASC | |
Course_Id_Asc: course_id ASC | |
project_fedena-master/app/controllers/application: | |
Fedena: Fedena | |
Sorry,_You_Are_Not_Allowed_To_Access_That_Page: Sorry, you are not allowed to access that page. | |
You_Are_Not_Allowed_To_View_That_Information: You are not allowed to view that information. | |
You_Are_Not_Allowed_To_View_That_Information: You are not allowed to view that information. | |
You_Are_Not_Allowed_To_View_That_Information: You are not allowed to view that information. | |
project_fedena-master/app/controllers/examination_result: | |
Active: Active | |
Distinct_Examination_Type_Id: DISTINCT examination_type_id | |
Schoolcollegename: SchoolCollegeName | |
Schoolcollegename: SchoolCollegeName | |
project_fedena-master/app/controllers/configuration: | |
Currencytype: CurrencyType | |
Schoolcollegename: SchoolCollegeName | |
Settings_Has_Been_Saved: Settings has been saved | |
Studentattendancetype: StudentAttendanceType | |
project_fedena-master/app/controllers/news: | |
_And_Content_Like_\"%#{Q}%\": AND content LIKE \"%#{q}%\" | |
_And_Title_Like_\"%#{Q}%\": AND title LIKE \"%#{q}%\" | |
(Title_Like_\"%#{Query_Terms1Pop}%\": (title LIKE \"%#{query_terms1.pop}%\" | |
)_Or_(Content_Like_\"%#{Query_Terms2Pop}%\": ) OR (content LIKE \"%#{query_terms2.pop}%\" | |
News_Added!: News added! | |
News_Item_Deleted_Succefully!: News item deleted succefully! | |
News_Updated!: News updated! | |
Created_At_Desc: created_at DESC | |
Created_At_Desc: created_at DESC | |
Title_Like_?",_"%#{Params[:Query]}%: title LIKE ?", "%#{params[:query]}% | |
project_fedena-master/app/controllers/class_timing: | |
Period_Timing_For_#{@Period_TimingName}_Deleted!: Period Timing for #{@period_timing.name} deleted! | |
Period_Timing_For_#{@Period_TimingName}_Updated!: Period Timing for #{@period_timing.name} updated! | |
Time_For_#{@Period_TimingName}_Saved_Successfully: Time for #{@period_timing.name} saved successfully | |
project_fedena-master/app/controllers/user: | |
#{UserEmail}#{TimeNowTo_SSplit(//)Sort_By_{Rand}Join}: #{user.email}#{Time.now.to_s.split(//).sort_by {rand}.join} | |
(First_Name_Like_\"#{Query}%\: (first_name LIKE \"#{query}%\ | |
,_Last_Name)_Like_\"#{Query}%\")): , last_name) LIKE \"#{query}%\")) | |
Admin: Admin | |
Invalid_Reset_Link: Invalid reset link | |
Invalid_Username_Or_Password_Combination: Invalid username or password combination | |
Logged_Out: Logged out | |
No_User_Exists_With_Email_Address_#{Params[:Reset_Password][:Email]}: No user exists with email address #{params[:reset_password][:email]} | |
Password_Changed_Successfully: Password changed successfully. | |
Password_Changed_Successfully: Password changed successfully. | |
Password_Confirmation_Failed_Please_Enter_Password_Again: Password confirmation failed. Please enter password again. | |
Password_Confirmation_Failed_Please_Try_Again: Password confirmation failed. Please try again. | |
Password_Confirmation_Failed_Please_Try_Again: Password confirmation failed. Please try again. | |
Password_Succesfully_Reset_Use_New_Password_To_Log_In: Password succesfully reset. Use new password to log in. | |
Reset_Password_Link_Emailed_To_#{UserEmail}: Reset Password link emailed to #{user.email} | |
Reset_Time_Expired: Reset time expired | |
Role_Updated: Role updated. | |
Student: Student | |
The_Old_Password_You_Entered_Is_Incorrect_Please_Enter_Valid_Password: The old password you entered is incorrect. Please enter valid password. | |
User_Account_Created!: User account created! | |
User_Account_Deleted!: User account deleted! | |
User_Account_Updated!: User account updated! | |
User_Profile_Not_Found: User profile not found. | |
Welcome,_#{UserFirst_Name}_#{UserLast_Name}!: Welcome, #{user.first_name} #{user.last_name}! | |
You_Do_Not_Have_Permission_To_Access_Forgot_Password!: You do not have permission to access forgot password! | |
You_Do_Not_Have_Permission_To_Change_Demo_Account_Password!: You do not have permission to change demo account password! | |
You_Have_Followed_An_Invalid_Link_Please_Try_Again: You have followed an invalid link. Please try again. | |
First_Name_Asc: first_name ASC | |
First_Name_Asc: first_name ASC | |
project_fedena-master/app/controllers/student: | |
#5E4725: #5E4725 | |
#5E4725: #5E4725 | |
#5E4725: #5E4725 | |
#5E4725: #5E4725 | |
(First_Name_Like_\"#{Query}%\: (first_name LIKE \"#{query}%\ | |
,_Last_Name)_Like_\"#{Query}%\: , last_name) LIKE \"#{query}%\ | |
Academic_Year: Academic year | |
Academic_Year: Academic year | |
Active: Active | |
Active\": Active\" | |
Add_More: Add more | |
Add_More: Add more | |
All_Records_Have_Been_Deleted_For_Student_With_Admission_No_#{StudentAdmission_No}: All records have been deleted for student with admission no. #{student.admission_no}. | |
Average_Marks: Average marks | |
Class_Average: Class average | |
Distinct_Examination_Type_Id: DISTINCT examination_type_id | |
Examination_Name: Examination name | |
Examination_Name: Examination name | |
Finish: Finish | |
Finish: Finish | |
Former: Former | |
Former\": Former\" | |
Guardian: Guardian | |
Guardian_Has_Been_Deleted: Guardian has been deleted | |
Guardian_Has_Been_Deleted: Guardian has been deleted | |
Line: Line | |
Mail_Sent_To_#{Recipients}: Mail sent to #{recipients} | |
Marks: Marks | |
Parent_Record_Updated!: Parent Record updated! | |
Parent_Details_Saved_For_#{@Parent_InfoStudent_Id}: Parent details saved for #{@parent_info.student_id} | |
Parent_Details_Saved_For_#{@StudentFirst_Name}: Parent details saved for #{@student.first_name} | |
Skip: Skip | |
Skip: Skip | |
Skipped: Skipped | |
Skipped: Skipped | |
Student: Student | |
Student: Student | |
Student_&_Guardian: Student & guardian | |
Student_Record_Updated!: Student Record updated! | |
Student_Record_Saved: Student record saved. | |
Student_Records_Saved_For_#{@StudentFirst_Name}_#{@StudentLast_Name}: Student records saved for #{@student.first_name} #{@student.last_name}. | |
Student'S_Marks: Student's marks | |
Title: Title | |
Total_Marks: Total marks | |
Total_Marks: Total marks | |
First_Name_Asc: first_name ASC | |
project_fedena-master/app/controllers/exam: | |
Distinct_Examination_Type_Id: DISTINCT examination_type_id | |
Exam_Has_Been_Saved: Exam has been saved. | |
Exam_Was_Deleted_Successfully: Exam was deleted successfully | |
Exam_Was_Not_Deleted_Because_It_Is_Being_Used_In_Examination_Results_Section!: Exam was not deleted because it is being used in examination results section! | |
Examination_Has_Been_Saved: Examination has been saved. | |
Examination_Type_Has_Been_Saved: Examination type has been saved. | |
Examination_Type_Has_Been_Updated: Examination type has been updated. | |
]Each_Pair_{_|G_Id,_Min_Scr|_GradingUpdate(G_Id,_:Min_Score_=>_Min_Scr["Name: ].each_pair { |g_id, min_scr| Grading.update(g_id, :min_score => min_scr["name | |
Min_Score_Desc: min_score DESC | |
Min_Score_Desc: min_score DESC | |
Min_Score_Desc: min_score DESC | |
Min_Score_Desc: min_score DESC | |
project_fedena-master/app/controllers/subject: | |
New_Subject_Created: New subject created | |
Subject_Deleted_Successfully: Subject deleted successfully | |
Subject_Updated!: Subject updated! | |
Subject_Was_Not_Deleted_Because_It_May_Be_Used_Elsewhere!: Subject was not deleted because it may be used elsewhere!. | |
project_fedena-master/app/controllers/timetable: | |
Cancelled: Cancelled. | |
Weekly_Subject_Limit_Reached: Weekly subject limit reached. | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env stack | |
{- --package text-1.2.2.1 --package foldl --package bytestring --package turtle-1.3.3 --pacakge lens --package unordered-containers --package containers runghc -} | |
{--| Author: Dante Elrik | |
This script will read from stdin and build a yaml tree of the the dangling text literals in a Rails project. | |
-} | |
{-# LANGUAGE OverloadedStrings #-} | |
module Main where | |
import Data.Text(Text) | |
import qualified Data.Text as Text | |
import qualified Data.Text.IO as Text | |
import qualified Turtle | |
import Turtle(stdout,stdin) | |
import Turtle.Line(Line(..)) | |
import Data.Monoid | |
import Control.Monad (guard) | |
import Control.Applicative | |
import Turtle.Pattern | |
import qualified Control.Foldl as Fold | |
import qualified Data.HashMap.Strict as Map | |
import Data.HashMap.Strict (HashMap) | |
import Data.Function | |
import Data.Maybe | |
import Data.List(sort) | |
import Data.List.NonEmpty(NonEmpty(..),intersperse) | |
type RubyFile = Text | |
type Msg = Text | |
type Key = Text | |
type Node = Either I18N I18N | |
type DList = [(Key,Msg)] -> [(Key,Msg)] | |
type I18NDict = HashMap RubyFile DList | |
data I18N = Plain RubyFile Msg | |
| Other Text | |
parseI18N' :: Line -> Node | |
parseI18N' raw = | |
case match parseI18N raw' of | |
[] -> Left (Other raw') | |
(x:_) -> Right x | |
where raw' = Turtle.lineToText raw | |
quoted c f = chars *> | |
(between (char c) (char c) f) | |
<* chars | |
parseI18N = | |
let parseMsg = | |
chars1 >>= \msg -> | |
guard (Text.toLower msg /= msg) *> | |
pure msg -- ^ we don't want i18n handles for rails | |
in do { | |
fileName <- plus (notChar ':') | |
;char ':' | |
;skip spaces1 | |
;msg <- choice [quoted '\'' parseMsg, quoted '"' parseMsg ] | |
;pure (Plain fileName msg) | |
} | |
updateDict :: I18NDict -> Node -> I18NDict | |
updateDict dic (Right (Plain rf msg)) = | |
Map.insertWith (.) rf ((msg,msg):) dic | |
updateDict dic _ = | |
dic | |
writeToFile :: Turtle.FilePath -> I18NDict -> IO () | |
writeToFile fp = | |
Turtle.writeTextFile fp . fmtDict | |
fmtDict :: I18NDict -> Text | |
fmtDict dict = | |
Map.foldlWithKey' combine start dict | |
where | |
combine blob fp = (blob <>) | |
. offset 3 . (clean fp <>) . (":\n" <>) | |
. mconcat . ((offset 4 . renderLine) <$>) | |
. sort . ($ []) | |
renderLine (k,v) = camelCase k <> ": " <> v <> "\n" | |
start = "--autogenerated\n\n" | |
offset n = (<>) $ Text.pack (take (2*n) (repeat ' ')) | |
camelCase = Text.replace "." "" | |
. Text.replace " " "_" | |
. Text.toTitle | |
clean fp = | |
(pure fp >>= Text.stripSuffix "_controller.rb") | |
<|> (pure fp >>= Text.stripSuffix ".rb") | |
<|> (pure fp) | |
& fromJust | |
main = stdout (Turtle.fold stdin (Fold.Fold step begin end)) | |
where | |
end x = foldl (<>) mempty (intersperse (Turtle.unsafeTextToLine "\n") (Turtle.textToLines (fmtDict x))) | |
step x a = updateDict x (parseI18N' a) | |
begin = Map.empty |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment