richqueue 1.6__tar.gz → 1.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: richqueue
3
- Version: 1.6
3
+ Version: 1.7
4
4
  Summary: RichQueue
5
5
  Project-URL: Homepage, https://github.com/mwinokan/RichQueue/issues
6
6
  Project-URL: Bug Tracker, https://github.com/mwinokan/RichQueue/issues
@@ -3,7 +3,7 @@ requires = ["hatchling"]
3
3
  build-backend = "hatchling.build"
4
4
  [project]
5
5
  name = "richqueue"
6
- version = "1.6"
6
+ version = "1.7"
7
7
  authors = [
8
8
  { name = "Max Winokan", email = "max@winokan.com" },
9
9
  ]
@@ -8,6 +8,9 @@ def dual_layout(function, **kwargs):
8
8
 
9
9
  layout = Layout()
10
10
 
11
+ if "console_height" in kwargs:
12
+ layout.size = kwargs["console_height"]
13
+
11
14
  upper, lower = function(**kwargs)
12
15
 
13
16
  upper = Layout(renderable=upper, name="upper")
@@ -40,7 +40,9 @@ def show_log(
40
40
  if user is None:
41
41
  user = get_user()
42
42
 
43
- if job is None:
43
+ job_id = job
44
+
45
+ if job_id is None:
44
46
 
45
47
  def job_getter():
46
48
  return guess_current_job(user=user)
@@ -48,7 +50,7 @@ def show_log(
48
50
  else:
49
51
 
50
52
  def job_getter():
51
- return get_specific_job(job=job, user=None)
53
+ return get_specific_job(job=job_id, user=None)
52
54
 
53
55
  job = job_getter()
54
56
 
@@ -90,7 +92,10 @@ def log_layout_pair(job_getter, **kwargs):
90
92
  limit = console.size.height - 2 * PANEL_PADDING - upper.renderable.row_count
91
93
 
92
94
  lower = log_table(
93
- stdout=job.standard_output, stderr=job.standard_error, limit=limit
95
+ job_id=job.job_id,
96
+ stdout=job.standard_output,
97
+ stderr=job.standard_error,
98
+ limit=limit,
94
99
  )
95
100
  lower = Panel(lower, expand=False)
96
101
 
@@ -144,7 +149,13 @@ def get_specific_job(job: int, user: str, **kwargs):
144
149
  console.print("[red bold]Could not find job with ID {job_id=}")
145
150
  return None
146
151
 
147
- assert len(matches) == 1
152
+ elif len(matches) > 1:
153
+
154
+ matches = matches[matches["command"].notna()]
155
+
156
+ if len(matches) > 1:
157
+ console.print(matches.to_dict(orient="records"))
158
+ raise ValueError("Multiple job matches")
148
159
 
149
160
  return matches.iloc[0]
150
161
 
@@ -31,9 +31,9 @@ def show(
31
31
  ] = None,
32
32
  long: Annotated[bool, Option("-v", "--long", help="More detailed output")] = False,
33
33
  idle: Annotated[bool, Option("-i", "--idle", help="Show available nodes")] = False,
34
- loop: Annotated[
35
- bool, Option("-l", "--loop", help="Show a live-updating screen")
36
- ] = True,
34
+ no_loop: Annotated[
35
+ bool, Option("-nl", "--no-loop", help="Don't show a live-updating screen")
36
+ ] = False,
37
37
  hist: Annotated[
38
38
  int, Option("-h", "--hist", help="Show historical jobs from the last X weeks")
39
39
  ] = None,
@@ -49,6 +49,7 @@ def show(
49
49
  ] = False,
50
50
  ):
51
51
 
52
+ loop = True
52
53
  screen = True
53
54
  disappear = not screen
54
55
 
@@ -56,7 +57,7 @@ def show(
56
57
  "user": user,
57
58
  "long": long,
58
59
  "idle": idle,
59
- "loop": loop,
60
+ "no_loop": no_loop,
60
61
  "hist": hist,
61
62
  "hist_unit": hist_unit,
62
63
  "screen": screen,
@@ -66,6 +67,9 @@ def show(
66
67
 
67
68
  # console.print(kwargs)
68
69
 
70
+ if no_loop:
71
+ loop = False
72
+
69
73
  match (bool(idle), bool(hist), bool(job)):
70
74
  case (True, False, False):
71
75
  loop = False
@@ -110,6 +114,8 @@ def show(
110
114
  # static layout
111
115
  else:
112
116
 
117
+ kwargs["console_height"] = 500
118
+
113
119
  layout = layout_func(**kwargs)
114
120
  console.print(layout)
115
121
 
@@ -0,0 +1 @@
1
+ gAAAAABnEpbvOgLsVhspN5M4SH7oIIjr2t8BaSv96xKOIeaZfAOABpiQdZiLzMWre3LD14ZH-i0VeydLW6JSaepYtOW6qhnOtZMUh5LvXBubEhPPQkR6w3F7rMOLQQOsBHxHBsYktVf9-733DnWH7KgSMrUT5StcpFmM9mPG--hcJMWfFi5YsOkmlcMBn5elcku9AJRkgyYKzcxdZnX1uWdPJk3C2j-lzysAhecW4sLb7ygvFwvqsz2GFlYebf2JUHjTulYGuU7UuSh-N2NG1X5dZX3mRi9Pn8IDRvidVowdUdQq7IcAxSp8AxdF4OqS1IhIcUJ1xVlRe8qRvu5jtxP3NyBV39zBgfAp1AZInm2CoxLAzGL1_Lb5EeO0ev9PGu6eMSvHfenBLWS_WnB24z0dwfWF9bQPeyOoKbm-0GSBQPSjIJPOaCBfhkFxH0SaRdYVuwgqzCGZXQL_j8OjpDHi_XSWMXCFWuswE4WS2kiu4g46M4mQP-HOR4EuwibdxiPxhvuHwibnEoK0pgxG9wyQeowejaOm-Au7avwd2x_M_S1aY3c4TtI_Immx4BqBuBMFWDOgdwLzHuNgagU5NvYNsXElow0bwlIERjboNvq3Pn3m4kHRF3-RoxmiXuhNkN0Ho11GKGaylbFSTXHrIJUIDKSjzeQnVOPLYOb9JvqL9RI7HrikFIUASJTogH4whfLKNikTaHrSkDOpR5PiZhVTNARkZI9xZ6vEcmDemFTLsQ8RZ22a5w-dG03i7dpnjAnfL9at7fcno56Fz83tev_pb8EIY32SoaEGKjbz_jLIO2nKM238LttWfIefy93Q6Uk_W7Jc3gtmcWj1sQ-KEJ7qmk4QAC--lGNnF8AD1HvD6jyroKzGzRJCbef76kG_6m_zlsZXVSIctA2var1vIpHWMa459jIxpzNiydldvh9NxcP3GiLsFbUDVs3MtzxWz7Onqy2KlnDCFWS76fZIvwuHzdryKEEYEUebfEIxwFLK4dAH9gx6lK0HQY1_Q0NV3MEi5jTcc_I3vpLeiu3xTjmPAt14s_UESjjOoXqxgtG7EQwxX8j2NJdqNNf1NeeHN1Hz4ZKy1XB27hjFqI_bF_f-bW4UgZEddGdbwhjDH8AefKuOTXoi764xlhklvhBLBTfpnqzGK6Qy1tjG-QbbdllEzKlYyMHqQwXvUrYjmy3OnmkkxVN03eYNyeH8tXhx8TSOSouQK7lX31SSK9Oo05H1XQLt6XbmZlXLOo7Yu3zeHBj5MADW7AqLyAk6WDmtGP-UJZviy1anetLqWEV862WuZFEcVSQAylPDgSLF9AZexb0YYQ3soPHeRsiwsjFeFeCLJeq_fN8mZ8CRRIn9bTulhWiYGJurq58XOzvZPiIjdOjY3F9sGRw6vetfFD9STKo_CUlvf_rYrUzUl5Z5S9PEC-yxUrDI4D25d-pCyum_nO9YtQlsv1f4MPwpwzFQvgdqBk43FVKmy8j2N0WHXg_aUVukKYV882ECvq1JT9kIp70yr1fZMKcDEDmgSrExBUoXI7hoN5HkDTKzbe_Mq76-OKH_1xLk4s4Hvn5Zd_v9s0ArshK5W9shQ10SltzHhegT_H9hSWrXQLi3BJx1OE77RRzXoa_eBIFSnnSNQeerbbuK08QsdAtYuk7ikmwg5gKy-8dnX73c9hYu5Au1f_7ZBH5OrlJJe2mU18dX1-uVsyfqYQsUNZSS9YVmeVfcvKFl_dyxVyzfSCQLTizeslpbs8SH9p2iDTL5d2D4ybF3_4AVUiBA_Am7Ael2mM0UZCth4zUyirePiGYXrcxXjQtSHyb_kcnwDYIg2WGhfe99A6EZ51755HTkQHtlLUlCv8zEo57Mz7ljAPH6E0f-fcyhpOJQshe7PV3xsBZL_sHrI5VnNkIQmP7onXQNVY86FphNgKcXCuTkw65I9TEAOEN5_y_YkQGT4Swm0xc83cS0h9jlvVLaBHLOecKXFCbVLCziHghD0Z9bNiuh-Mf7R0iJGDzzRN9AW3oMpcWoPTGuC0QNJWsQN9fXX783LkyxbsxtjFGli4USNhWnes4CNFFMbA5JaLhFPlERxRFMUUB6Du7kSQAvAB9ooxjYNvNSAgRQBc9EaKCVXVc8gDCGvfZcIdI90ysDbeERBJ1gnfKUtO5kf-ar7D1N5X5loOdW0oZ340fd84eHYBEKRJ7kFlr66bHMeEk8nUxjQ_ZUTcHjxDCnhYRrZkCw86zNiWriMKm4Nw7ErZ6kCQqQ3Zr1zZW1IkiMZSmv7qxBviZvAU_LsCeRfm1lqx3rlIIw9J4vfIUwTb5yZ-jtq_BBX6eYxXGCfnuZMm9pcAlWjAjFGOvGQp6JolkBckDNk6RimLaW33WCssEEntVTqiJYFFpXKmD57pfN0hoWEzslnESWS4xTOIxG1U-aJfC5VNzYwgZkMpaZeTuVGQNKUMk2zcHuXWBCtRi0uN3dO7JfgCn2Oeaa6ZPUAWz241VBzg1ka_2pENH5Eki4BKNyw9h928gIiDVVFnaKJydU-GGWuVXtdkhA-xMIuS7H8Mnqtgv2LVpNJyDu1FYKIT_zme1MLScLbuoiIi-ZcTC3Vs-vcroHUMdFPJjscvKZ5XtFQelzLiURcQ9DDzehmf-2Py_pgg5-pWGnNxhaYbV7Nzf68Xfoe5guQzjyGBSjR3Fzk7rIx9p1OfnRLD7zC9HNGy35CqA0K0Gzjym573rUkJ2QaircGt4BNRMqTbKr7dmt6xPIv7dOpK3eBNJvk-HVnz8hKqZTtYt9Kr9qivMuk3eOXjPaeSd6Ih4gUYDnIoU9V3nca-QQhYeaMt8ujfRHl1oE2eod23cZWpecqPitbaJRJQ5Bwmx-PeyjxIlYEby4WO8zr75A7NlVUu4kADDK8XtpQJDkyGMRZzuiqx5rhldyspmkP2zXtMV9tn-KQGZbUM1BW5ldXZZjdVrL3TZabM0vLbpnN_Pf8_3TYWMYOkc5TlNJ9NHbgo7epucW2wGV6O_dytO4TpLEDf4SXR2t7sE8ClJXrYbRvDJlOi3NK_799S7lHzNqw1RU_SnGPujgDRht2wWVUSSXOWijkwFLgdEkHomyKhMBIAwUIDPw_PBxyTZJJW54IWlaGudy9Wxpgi_EszuhuG0IJdC6ynNL-VBUwHZCGkiM8RmQOQdV3UKlcp0MozknS9lVrlenBnGjSK4eJxA1w5dQHssDVW6iK4Dm8SBFDE3B1EwBFd5ck9knoZpnr3e6Wqd2cXyGrPR2axEnjUhwaH0woZi9sXmBS6lbTTG7YfFhFStBqo6v0qvWW3eGyHE9Uzdef1x6WDTtX3TQd1OonX6wrRPv1ne75EhD8gbS3Zat41o264ivzTVbK_6X7htAAHrPbd1_nxoDgT4ezHlOtN1jOzqShCPuwgOaZCowGdbJtQZI2i9GlIAlwYIj-OTpTZGAeYpx35c7jGgIl5h1ALNpAguM-MEF4nnsJDb9j2rqOZkJjacMVORQQuHtUX7iogsdpLR-_dwIjca5H0aM5o0aIrQQ6prwVTZzpb8SoAQq9uFJXfSWO3JpTMo_3jH6oI4d8UpMXApy-QK9hQHTh8dNvM5uZmmirrpFBfTE409BvuYhcojjwXaT7KHKUNlG9hm6-WpPK2WrUD7PeTCHI_s6rW55Tb8bhhvmW0SEiGM2TN9ymrKZ_16GQlVmNiepsl9Ox4AROgYNqcuX95X9JbgwzhKuekfIfdY-c_C4EdY4AtkNl7X3idRNjJWZJwftUzkEXKj9bCvKeaBsZ4rkV-7yETAnNykoWnjAcS2uPpEro_ryr-H47AkXuxlDPGaZgLKAnutyEJz0nDjV2LCmk5M5ApqnjRS5c1jAQpypWIeUa1e6O0NyYVhkY95LLHAcWC_1YsRy63t51ntvl9POZKO7wlwu5UJ8z0QEfWb_4Schs2RX_bSEFgYY0QVWLXP-DoeFudYiaK2m1e661-LfTz07lwROQQ8xiDNuuiuOzdm1bTr4FIQxulQlxcjQJH0H1IwqhcydnkUWCa5-us65flEUhGay5YqI0hPN3XB675xm7_o2Xps3spFy6U0bWv737GUC39KboVDKIcHvwNS72udwy8XW5ggNEyyUkRvXj82LNo88sk38j_A-dYR0nKOKA1j9FktkA_EPJJ8gfkAGOKzDx4B8FA_yQ_yo3IFr4ge52EuKInVsyx7gmRJp4oaZdskQFHIs7eR3qs_TN_eLQohoY-mv4bi7E_Z-OjCi-DEPEjTXt-DgHRG_GOjzvdVYbee1ZJu1BHO2TY8uXAq_vxcno59VvFRVhfcThd9OyFl7Z7ckAG1fbpD5OD_WuGD_1CKYQcqW5PsfKyb2YVrBPKV_GtHLix2fFufH134RrSoBxUSBqcejnP_k7QsG-qrJjG8hDw7-_Us07L8gMbC-s72sd21LBgoQ9wawrrYHyd9Ml46eFF0UDMQXoo1cAp4xMYwhJhQ58FNrH0KuqoZedYlDjc6u9aTGRTZMGy6lvZlyl_sN9N9LDa1FQnKEh3cjNVPOmDflNLshX_Q4ctg0zEhk7TGkrhcvLszfda7-bDt79YdIrjGCEQTn9yjzHjWtL1PbgA8gbIAu0ZL6wjkYk6BH9d6esShFRHsp1anqAd2U9kwvltQnpUkOogPiHBz41__ZrMk2FLiX8F8Ztr_wAFlHmb1Bii3nyGTVj6bvEoXEenxy_UYCZIXtP9-3fR-xSAKQFbKVcZn0C4cY9W2BQOlVP0ZDYL7kDajI5yDXFQeT49WGyq3i_JuNYVb11aUEnP4ghWh2t2WKUsD1L4qS8uw6jQiHPt219V3wnstwoOa1e1y6I9zyT3FpGpg-SPm7LgyQ-JnyBwkwaU7YVkCeEAH8dJX6vgzECqUcNGXSFrpYyYBiPUh70rOs8CYA_FLcj3c5WvC0ChZU7DWbiz3vp4Rx9ApQm2ErI-78s631wINQalqItcEAVU6OLpvmESgrokmyhShciTTu2EM8OHvcQjxsO8A8NhjUw91uCNoU8MjF7gZnItrtuNJc1fKzMdYSeWvf6YrJbfPvR22naeTDlAqex7n-amuNDWDsf-ltV7E4t2-FQc5d8rBYMK9CTQtlVxzBc57OGa-R5cmOaTW8Zq9LzyH2hrEnONYzHWaqlx0m2W9Hiu7hVvQFqxlfsdlvTT4PmKsn0Y-ehiIpMN-3XEUruFzqCoGuU2nbdC08lGLnK5CKGIeYmcWH8InE_rIEf4lvxHpH3w0dn0tUJM094pdhNfniE-dZmPkQJvRjvEVLiQAYfakoacT1PsRfV2D4AxlC38q4Bol-SqpHpJQZ16Rf40cyucZXYzF_6mBFadHSrWqvk8VyhiLPaQVNGmuNoCue1_6qSAU4-d74ywXP_j_e5QWks4fbrXOBlh3ZqFnH_QEZVi-qNMESjgZ52GmjIqtY1IjPH0jZJNk5WXQRmEoMAwsPFT82QltTpopO8EswrsFLL_zuG2kD1tK3TVz_0GYiIGthiZp5ysIekpXgNi6Wd6Ura7nuD4MmwDzLfW8Qyn4ZzOdK94ylv91zEgUlyQu7qRyixvWjQ4Vuf0Jb6FaHb39bm_PL42belMXIerpqly8SOOxG48L9m43s85f51oAC7ZiSJj2Xp5-6oxjwCZ9LGm1yEkVOlg7MBH2WT1bzDDvdZgmXvEt0pbWPWP5SGH9Tmjr6kOQsgBFbj2fse2dvkr8DFTdvauUfT4bDpC5UmmWXNDaDKUmZuLSZPj1dWw6o1lB5_GF2XOJCOeIXZfc48a-jPO0p4PfqKGDoFK7bEDErnD1-0TvzkZu98w-z0Rd21g2qzjePx58e9RoSoX-xUS1OoUvJdrTKlk10YGh5YTRUE09GnLGsah9IWzlv4a6TE7o4QOK881Jks0nb3TVtt2Z8fuROndfIndlXBvHqAwu38va5mYn5UQdxHKTsW1KwsyiHEyygqN--v_6OSVMWAVD-IvZCSW6a69IIJKTtJTWwB-5_w1tDGl_vVlbx-ePlF2h_odqujQRvlAOGvqn_vFuuuUd9kD_MB7aUKegQa5IRs0SvOp43iBLpmYP6sht8qdHzLdluzFWx51VCYMzWp2cZjGhGyHN2UjHhkgFVoRPltwL0LLihC6heXdk4rmBdoezQe8SbzDvMOD0CCI_U0gad8GotaAUgsV95XQeBuUsd6OtpddsEFIgJRtcytH8qlZMt0eGTfe_Gcob6Ss8wzRNvwISINQ29AidZ4jYb2DUYQUF-4f4Eg0KT-Ohi_F4QcQ4OE6VnyDZkYGLrrDT6KaA44cFmmWeQjuglMMKGtZRszs77W0AiGDwelXHlNTUQrmgmJ9x5b9xdw20FcEkKP1JG7jCSomjcQqDbur1ZXf8djuKCFMk17hVXtpcsAdXLpKuly8wZwDeUXmy_vApouIllQoZplBMI1oZZFy8VS98W_vOow6mlXIgyORpYwDcWmTac5bSSI1riek-DXJiEfY4snpzkc-Wy3XLbsDTBr47Q86bjeHMVFgOPpoyYUwj_ueOzxH0fAJiZjww2tPyKIiKJz3-2GXWJG4DCneVE2rECGYTsQDqjxMLST6xZDDFajaB5uolj4khtZd8ufMW7rXlXd0Ec-2sfv51AZXzkSmJCwID4nE_rUpHNKaHPav4GE-P-yAqkpuutslnTm7ZirXm8UTc1GxZmOJ1GGT7gAgNLQGjnp9h6Cq8UT7lah9MZqy9Wy9ID5lHoWcgZYTcxH2fejlOxzEaT7wicbZRDW-bZXx_FN7PUr-b-XqqBjqCyu722Io2iKsvM7_MdQF1O75mujFpTFsnSHEUgYFqwsAfpktuUE_rVZuQ9vkfV0GBvAUvu-w6qPnl6B1QfWapmNzoyQBhlRdTklR5gZtxdo_6lCJtjveuoSa7JCh10mAyOy8mAy57lp74WvZaOXr4abn0xfF9K3bCQeIS8TrAP8U3J6Vmd-W7vaTAtRHc2t-VNxkpHDpgP6U7s4-keNGyuMB4_IXIoqOSfVRKZsFfH9Cdn11Umh2gSJl9V_n3TPoQhqk7w-H0bL7kUwHZ0sScOijLQDxrSH-ZGbDjR2P1qb-isbAgqnUXDo5EdfanA3f5rXYoAqocaOG0cwLCDVbUhRtwoEha35HIViPGa4ZzEh_5Wwr4FveqvsiazYUg-11qKNJYkmPjiD-jbo7AhHWxwGqdTMlSDn7nWveZ2s_35aqW8yHiY9QSzYUA-RwQF32VVTQOHwmAavMOrM1MMFR4isGV2yRZ06xoNn5QlZpgxFLXWY-yHHJ4lYK7gLvS_XN_QmQVZBhEjDRsoJndD8KmXS1OtzMrUpXlUx1QlFcdgfNzdtcPKlNlg1F7xTR9s8_pB2Dd1YH6sk_G2ekoGOmZFDXMOY0B20HPXjAXSbwPvMuCJ4VN7RbwS-nblKKNpLj5WSMYUbmCS6o_sH-YyWxcZ2RlaEWmAM1gwKsofgY0RKlT1h309khqzLSNyqN8h81mXN0VDR0ZlZAdbZyP3BUUrpX5PmEQLxAkjH5CQZbeprFqHWNaUTC4mRKKtSr40LXJljRwF6PIfLat3DE_JrS8gg0XF34CMsi-u_amMl5OyvpsHWbTYYPgoe9S0HEHT41Jz0ENUdkoITCd3TIwJCJ1Jx5-N24sngC9mUcwz_rdsDO136vrPcM4Le63VYkXWA2OacgTrQArPCUAsJyK5gEt-CJF9UZW7HvwBOkZYazbDg3Hw8-ws2T22qjcJzc-wKxGUl5ZRTKAYWotTnk9YZYeaHCrSugepzj4H5fOtV5jdoWrpPHiuBr39QysGd2ahkdxSi9p93mlbjyT5EZL53cI7EX8JXHoRq02SuriPjU6cUE4VPo5JPHmM1LZXc2m4n3LGTlbOyZctk5xaR9xwhe3YzIdgYByEWzvi_pVHwNHNB5PUJvPS2_32SqNI_PHpL1QmfxHoQq5-QDI0uM6XHXr6Fq5JFI04374cPjzRiWNSzDGs7SZ6NpDnMredX7oz7uyuL4D--AkEtc6pUUHnTStetpaHS66l6sNctC2M9ST6NFNMbMHFg8M9PH9bxmC7zy-Mk_iMlMw4W-ACiSFlptwnHkTBcaR0eZdSVtGenjF3qO9VkUuLVk1Y3GbCBxTB5PNHF0c3vBU5rtSG-HzbBA4RUyI7v7ca6QWtzfxOzdtAM8Va5gNCwqmaq8LKYa_gb8rgmcjaKAcJ4feMDGBaugBJ9bzb83q1SFk-4sExA8QEfQDHyc-SQG2AmGaalIJD_pC4QMPfkv03bcIcVmiyeS0zGeaVHzd76udmvxxsQus5k2FVxQEfXddB8T_4O5ZKB8ibL5yO0PL7SC-WuFqydXmLJ_i3szFtH3C5XAMgWW1OSa1EbdNmmvVOquo31DirlLeYXysQ6kIVe94_Es6_sK52hewhogagy0MH610sBzEUpfFTyVe_WNzABjq4Q0k8rEb1vPx3DknceDb-WJqW2-pNtEq0L8-ER_Xqrx8TE2JS7uJkG2GqdviT0KF0mKJt2dz9b8ZjOG6HTSUk3t0jwhA_FrBPwLJoLnwEE5Ynq-mwgsAxWVXUw_WZx--t3byxHefGmtIOQulbSjwJL7tfRXnY9vBHGMEV2EB8fYRDH4syiUNmHuedX91SAsy3q3joAlmNdND4PmsJ63dIRlyrBx_BLONlNuTO3uDk33hjloToQ9ssIDM_v1ylwWj60yvJHnbm28WXZiTuRtqjZMGQlkRLoxXVGFeTU0xXZaaCS_xI1LfOLh5khikjYuu_ZRyxTHwO_LdYx2Yut2nXtjzVPwgR87qJBHYugGpWi3BClAPv3Q__7Mz6onkNUL_HC7tmxF6AdnHz1fopaKIPCWyLht_PMf2JPp_fveBw0G1ybu25aK_yD_ieoJgMjomysdtmYiedFXHpqNPRXHtJ7XYaNQyMiQAvy-JBKdzw5uwSDgMqKwoIgRMFAV_Ybl0qjFLnv_C1E5Bfvf2jLUR_OFk8exU17--jk5LifIpRVd7so7AS-JNmzYf0-RQe8rWU7fEtKcN7zqCI_n6IE2J4COb6IoZk4V2nv9wyMGo4LqL9s_aoBfSbHe1WiZYG8B0OO1Jecjcr-98ZZEgnjOQApfdkLHzz0357Z3NqEOPpZejo17_urndLrvKMWKXOcVL7SDr_7VcYpq4am-jpNb7e4JdiqYsetYd6oWlFDwoCCW0gBUAkQ3NL466XvPcJLnmGMECdJuWwDYQ_N4ODIcwcHew03aetbKdK0TejnZ1ZEbgmOBYbuUyHPl0_USHw_gZH-YsA9gCWtAxgse4MkoiFMdyqWgvThROUHyDziyPG-bHjLpHwqgC6thSX0cLY1LEYQj3Xzab2z4qYo083roHpiB9QJnuuB65z4hRuyjqaQm7Ep81ms3Pqdq6czPhwOIKubovjbv-zCckJXS589v8UpxEJFUi4Q615dcaNUFcuTtkjpMeRYyNhuzHytjL5L7Zw4qsNdxhLtNnPT5KSi25eA-LQWGZOtg50fkWfPf-hyqTzpnUUr4dJsLUDvTDaNGloGP1H1HQHiBhODvKSirBJFZU2gs4v117KiJnF7y75_kVad33OcbAcK3a3svhxtfC9q62BiPAJVfb6s0_85Od88L7TBmlW4-iF0RDc6qeO-0ivmNCFukxxxze48TvsyqEU5DFWaSvwvRbRzOSt-xIqJFQH-fP1slcFooK4yHrNQdBDEF4LNKxJyOytMvELETE4M4Tn91I5C0zUs_JUftf85d6GJDvWWfVc19KsmAu0aLbd2jN6g7Z-TifhNyudDQ3NCiTPaouLNzcggzYoJaZNCtA_aOdlckk7X-wjBWGtw9TEtKNGfET5xktFdhA69_dV3GVfQ5I-7LkW4UaQ2gZ-h4eDAvX0YWZz6CISElmPw50IZPOz1P8-wS3a0AdusbJ2C2PMbyc0rogQdca9y3uPHJq4F57jKGLZeLZroaV5fyTmyfpG3Dxqc8Z8GUB6AX1q0Nme7pbRiLrForjfq5B8ESFsyR-xUMMMQ4kXhHGD2L9Ko-EdfqAUuQ49NsP0zsAiaU6EQ-Jvy1F9bzBsjc3Iv6gXh-l6hAej6CQxR3mefYA6zuUXEx-zz56G2DALVtxNY3UBoXOZ4MVsVBrKCz4ZG7FdbkdgYV9LWobPmQNkjyxgmb_yBj2ezF7WQkuBwFcKWZsR9wzkph0kvBFbaDjqWMg3E4cVTROiKO6RWP0rQI1Le2c-fRAKe4O2VVM9ZqBOHxA-9Lj01xIq-JaB4qjw-zfQTiyFvckKgMS7bY7Yct0DM0xjSNpwgm6OozGxogyOD28TSVg1C6MENnINRruX5utM3gIK5nFoQLE6cBWxuEzeMhJJSpETC73hEYm2EXTIzcfCQwCiO4lFooMCuk4w58Fd-AYwwtUUS9rGKLjC9xlklmegRct0akyEfhO_kHJ7cCp-P035Ld-EkLRBkxriFMN8j1b9os8pGFUI0oTajEdebghpYKP1fq77P7-5aX8pLC7D3sqozhHhOC4Ih8qoLOr_YEuKoepkvzEETO_hY3k4ZCZcGo_5O9czD98RLxf5wibfqKvom2LUIrv_HjPyDI840txzkewxSqaxIB9J9iqRddZwLNYuL2RLDqy8aTMgOpcgYYpQVgijU1qPUG59MoJG9STJVxRqi6XEg68Imh5kP_NApI3Il7p6zRzJWAbML73UrurbQENN1buc2QALcL_upeAXyWQKnD9rHsCxTZbszV1QQwQKq4RojO7OZQwLjCUjpRnoOG1OjDiBvosBmuv2XHlkB6rQHElbmSsKAoTXvvu-MQpUp74TAoqb0G3JqfZgDoYMzizrB_sxZJbJtAWy-L0Yy5Kp5u6o4H1eB1KfH4IhQVEnMlDElY7jgmyjgSnwN9bEndR7NcZBaUklQpW00mbpY1_oQjXn8dfw5PIs-zEwCh2mkCvQCn5AEYYhuKz9hjlN_RcoDpuWkNDoheypO2pk_9ign-wdzd7LjcgEfjUrRqSW3REFI63CEZXEHPi38SrYotxyhRdXkUiIt04Zt12G4hTqAx2NJ4m0Z_0SY9VulyzGlsGb7hPQtw2OXIR40zXXMcWhIfiScq8QPDRTxpw705OwNA_UAWFVPHgli8OJ3IYT15GqEP1MS9UhAfFzhHwr1lCURpra09IKeZwNu8PVv6uTOCxGnTK1EL4AUFBqNUJt0Kg6-uD1LxrHxNDGjU_RwqLwIOrzrr9_QUveV4XTS7-4C5Wl7aazREzopWe78tMQqJ9Z2SQZoAEKQirmnhtVAcsnv8EmHJUc7vOul1xzKC56ysyeM066v9VmY8lE-pMUmxuybfDGJUMCKENCQ1oeEazIA11j0vzX4cAar4A--qpBCJXYt6LkA9ycMVurz55KzsyxJimuCH1-SW5EahcZ-VlEZS6euYrAzUH8kPJRlyRFX22RVqidaLHLEtqEvsq7d4XJxCa72PcXvzFnU3TVwbVNiotjbSAPeoWF75DHGi9CnN6hy-yTMhVek2hXpne-Uxc5mK_zdYv29WiRX0ZQR8bizWeuHIumFsQTDuM0dHcr7Tf6-o1pBqYTv_LepCBErCARVCIRBNIMloalkMirDnfSMhfwOrR27tAzgjeMS81dBdJuuALUTlWrgzcXxcmK_4IL8ts0GaZ8A15jAWyhX1K0zJkB73D_2NiN0OsTY-cvJeotu1cD2mQ7gi45tCsWJ5fzskBxVOHzkaxRa6GUxVgPfvZX6pSjjx0vtbHyYs9_v1EqXLvCM_Kyf942dIsH09Zyg2vbDwDdGYbgq2Mo9wH30szj215fsZevU5vGhHnLqbBkNG9l9A_ufNUdLR2afWTC1WZtsjONua2A06kHN1OhSDr_DTia0dniKd9-JPsDHBwtCmI5ziRSszBCqhE5uY5c_yUmJsxRvPr6MoL1wGe3k8tXjztZFirRSuEnCFwtxWbaajP8ChW4P2uliG1WSNdjiLw-CP6Z2pBPXOkRyZPEi8rl_sg9aCFRLRB0JGT-E1_vYTnZlBUGgpQoQ2nF8_92zAuNPJPEsw4PF1l0cH9oQXUfSenw0kWsmxEW7X0xfM_WEKJuJPcVYfhzvAF0qkNjEdAexy9z0E313boRwZfC3D-iFjkjx1g_A-PKbcMddQSIn2XKc35FFKq_M2X87EpmLoJETajHYmbxV8AKL-ZvfU7fbuTcafEr61UOQB_6Xk6m77xzfDCifbZtpJFtrt_hL20HZjrKgtRbRjPl7StQONMmI0IzcEuFN_WkXq9mfIC8hUzPt1oAVu4BuU4Xuk2uoXz_ePdx_je_HC-nZPpFUz1_M5PVOOy5hFV3yjNquiOQ9RRgqiZ920K8SLJ0Ri-uzqAgJG2bBEUSgHedd4dGkfbhKUZrpDlpIEPKOW4Ltz6PCq4T2yll4A-RVpP1KA3peXhexZIJCwwJSmc1g_NzR9jrCFY61SWpvO1V_tTfKfLXMCgGutwsP4RBgi6fPp2H97OU5rFCA3NWTGy43WmWVysdYue9YWmgwde0wvWfOcgVrJZ2dxYYJZfWBeaiCCuORmrWplKytlcI9cCO_qEHvCyUh7aXnwB4Ffo3Tww2vrJTvZqhKRCnOOVdfTn01wXa5G4JgzxEwDxI0xjdMVedNlTHlU7z3Ix_KVVplvF01Md0Y6U54lbagJSCL3xjbMB4gFL92vDSgDXM816F1NTXJAEsQkJ5WO2bZRt5wNRSkaypMYSgw4_1rtCePLhsUuz4PUz48TmjkxqQs99_DxTeol1-4r42o_3-f74zZQINooNSZBrgaLLIjEsXKYjx7_tPjSByI1uwIWz1lHNP--aNo8c0TH29Mlb2AE5oWMeVTr5WDmE6djkCsna49FOFmXu3y3Vva1sFQEVPlbE1c_zL5ECllnrRbw3PEeIsNwpzbf2R53RQ1DSuegDTEqnENGH1PZ_fM_56oBSFpaV5TGMUgpwyClqIZjsXRx4IqFwYqN2sFS3u2fOAzGE58cu0puL3_IF_UTCWErvW3BM6PTl1icF4bF_DYwDeZMja3Y4eqHK-x5pud3hCVeDpg6rs-2ANrRx354DNSsmweHQgEMz_GUy36bfem7ABcr-YF2okVhT4SLXYtpN0hXYWm108VXia2CXvo6QZp0H2-JusAWjSSPJGo_QnpsYa3Taii_IBgy_1PpFuvzDeZ9QKTE-acckQEzMq4jr2-x09-6-JqFI61AU1XctnomxXgK_KOVbtHXIJQjFS8oEoddqSABi7IhxkwctNHsenm4zdic9UQcxa9UgXF4GtYmktrjKQt7WKdKUbxYn_QZzaC3NY3bubv3pF5UB6FDEOpbhehIjMaQa65zp38rFBJ9q3R12ZhnZHrReBqH0WqmKNLlmL1IU9sXaMXTFmntj2B0VJzt-7BIwRVkoX27ny5OharThw-qCGxM3LWPOhkkTIxhyRRCDwemwb3D4QVUX9XYkmo_FFUWxMUPyZENv89Q6600QvJvOMSg_5XwXbHJWQO59nsuouBS1Le9JLJ3-J3rPAI4b6HEyI3Rh8PkLrePD12VOtKIWTXxvct3qF4ZVf7sRrEqGkymmSTOlxxwD1oQuoXIa-ZlCRnlf86JbzEIef2de3y6fF9EpatQZYZgwtH5eu-b1MP2BfoAxKRdnsxaW2n-7uOlKYalB2r640oka0hyRK4rk1mUFq7x3sdOuXuVqh40fIaieL41CLZOEIi8SLk6ZViDZKPU4hm_67RzWSnKszJH0iGtwutbVf3gRhz_gyunhwHUMXJZJkBtO3CqUBS9OWx-HTFgtwpLpGkIBn7_SC9XmKMSge45mnhMy12YPdrQ_2RX7ei9UR4IU1b9uvfP-krLDbwvrSd3nQb2DDc6_PJ6mfGvUy_vab_SD9o0jWZbNFdmqP4gVAn_MSW-LwefvcrWS5uTNInmkcl22pzfLmhjpvzrUo1uI4uNTyAdjTPVrU7-EOLPYi7QxHBfzIE-NyE4qU_8c3ZEu3LSwHTAuQPwqbqgbWu-sDwzgiRtqOLtPCbJxHpkbLFabZ1kBCgfbDEmijXd2ZjHXr9_PKNAyqijYm_BvS1fUpfkp7DbqZjVsz0I4Aye88DSNE3lrZY_WPNXRr4Bw_DVjav3hKFebib4RkwNWSpwe74NNFVpniVTmmzNsSk2t8N12wIlQbK3jwa6DvrWU03cNvqKdNJYXpNgJf8nAGmkLFUUPekoWlJKLrm8FhwTbGPCoTvXz0KVR6jA3ZaM7iibKYJeJyuGgrG5G8uIyKd8_vxl_0-ixJ_Cqe0swITZOd0QWWkkCpVeuZh8TE5g5QTCqCjRC53xhP5fSRiokmYhlUyGMe7Oj0TCZnep9C4wGAKWyDejTPg_4EF77K4I2XunjKntumh9E6HbryOv3YVcbjmhX8GszPzrkzmRataaCrONmw4noQUjCASI3q56kbiFdx1j0yZL9mfQiiVNF8zo6h2EVLUeliiYnJX5C3S1cY-TVpWGlZxUt0ZxjJfXpOfciRgEfVEPPuTZENGp9cEEEaBdmkTEbBGfwzm_Z1INB9qdJXkKlTnxyDAKi6hCDF8-FaRG2h75aNKWoBqiqTMQCld9AmDLlgx1ajYl78ksnPdAaprQ_fgLbZVXE7H2qFW3FYMsTLOZI6UD07YqeByYBtzdvFZNsxGNw1t9gZ8wnw4qDHWQteWCxK-YcQpm2AXGk64FIbRHeLNblAHCfCsVrPPgf79DP-0tu2dv6Pe2DNifndz3jkaFAzVK0LCS9WMBBG_XwKzQ3Om7HqjW-5MUhqFRvy7j1aD-szAvhUFTG8qqA-VpQVocS75tWltzyOZ9JKaxfDrliTboYGxQ3dwBslkvePWyOSNXm_OzU2aTcbJBAIBocIhHXGRQLQzbjKnYl0rloEJeSSw_fkL-JtIhaCm_7tA5kZYd-1xYAPfly0PjZu6Wwly6jAPRfQt7y8b5L_mG0xovQXwW-0PCtXT_HP3QlvmGf5-INCc2FQNtTpYWPgdK2kIsHK3DPv0TvwCFNE_9fXpkPq-0VvvVdOIJYFhg_cd3zhWzdP11ofDYSVyvGVDWBv-JqIO2esZD5g8H2ixVkNCE1rZl1akOIz7Iu-_rAFzLFGQLVJNwDIrJXV2Si8WRK6zRLKAZFYYOUcB7GFypJo5ByJMZKIBPcfkrU8oK520nn_DgUlMhjx6vEyBVJPgsjlar7eTWfc8d04CvHX_GfQpl-AGnfTvmaWSW_q-g-kvTN7hJrQanbxAlzMU71Eezg4QVZ19VPqGB3Dx3I_oHB2gfRs07FLGW5E4TJ4CiY5rb806EjVnwM2NWeDMbdKMQYGZsBEvVwjoNE9nVWhGoTnx0k5KH-L6yU1zHf2zCv_1h-a6zKPHCJol4mYmtrAl0Kb69uk8G5ax7-TURt_0SWZdyxGTEUcKx0GFGd872ydT9sjh6bpQkdO0SZUUNC7j-z390sVvmM8DPOXPpZXDPN41gdzhdDpvVu3IZ9ZhqIgI4B6YwoO9bt4VBdeR7aXGOGD68dnrfGG-JHcmxM0f3uwAuf9VVvvZg9xRAxR3L1Gbz3h_0UhMZNIGgo_12LXb0itJzQT4RkcCrD5h6pAq23_1d91lPIXeiIr710rGjebQ0fH8Lgyaqb4tKqCQxApx6YKeZktAOQ6Qkhlxsuq7OBVAgGGwnaMZ0mL1NOCpEW9naoVhq2e3kjiIfkz0aNbO5vrUFtVrWZm24mPNdcO-ErDoirFHiOJ_TZ2exmi0Ce1NXPXIFY9_1knOuMGvFPOTI1GVUP3Mu0y9CYlvf68rlYu-ktpLTUvHi0ec0W1T50Rc6-e7A_ZU0U3dwHyFQz5ictEtV4jg0YhCRVvKZMA6tKYpPf8nckUrtnv8HnjcaRK-R6ICLC9CCVD90zt2oMDLZ1tKohgepjwCU7kKCKPl7OJM-o42xBHei1PRaXK4rA7TVtVQhqGflu4cKKQDTrsWy4UkYukdZQon-YGWamAzJHmAVscCrvSOPpa5vb7EOK9lDKsNBsFEHWget1FUkEAe93sHXUcO1EcdfQOYYb1MrLq4-Wg0o0LZPxkIZnRchAW5GZaTPWJ80oLMxOCJQ_lZLHI_sYPiFgJnWb6esrvXKufUrJSgBK-XvmKQbLbkqRVQE07RtQj8aG4oguksskG6De0egc0kM_sl5nO5EoaWjlnfkEkwTjxpvsxp_lMKE3Z2dQjaaW_v15kzTYAS2AOOhWzMlP6s3PEh9W57K8txoYdUwjhwkcXtsA2DkWEDitVTIvFHX2DvKIVAQ==
@@ -24,7 +24,7 @@ def get_user() -> str:
24
24
  return output[0].strip().decode("utf-8")
25
25
 
26
26
 
27
- def get_layout_pair(user: str | None, **kwargs):
27
+ def get_layout_pair(user: str | None, console_height=None, **kwargs):
28
28
 
29
29
  if user == "all":
30
30
  user = None
@@ -43,7 +43,14 @@ def get_layout_pair(user: str | None, **kwargs):
43
43
 
44
44
  hide_pending = False
45
45
 
46
- console_height = console.size.height
46
+ # print(console_height)
47
+
48
+ if console_height is None:
49
+ console_height = console.size.height
50
+
51
+ # print(console_height)
52
+ # print(n_running)
53
+ # print(n_pending)
47
54
 
48
55
  history_df = df[~df["job_state"].isin(["RUNNING", "PENDING"])]
49
56
 
@@ -207,11 +214,15 @@ def get_squeue(
207
214
  if not len(df):
208
215
  return DataFrame(columns=columns)
209
216
 
217
+ if "exclusive" not in df.columns:
218
+ columns = [c for c in columns if c != "exclusive"]
219
+
210
220
  try:
211
221
  df = df[columns]
212
222
  except KeyError:
213
223
  for key in columns:
214
224
  if key not in df.columns:
225
+ print(df.iloc[0].to_dict())
215
226
  raise KeyError(key)
216
227
 
217
228
  extract_inner(df, "cpus", "number")
@@ -228,7 +239,9 @@ def get_squeue(
228
239
  extract_time_limit(df, "time_limit")
229
240
 
230
241
  extract_list(df, "job_state")
231
- extract_list(df, "exclusive")
242
+
243
+ if "exclusive" in columns:
244
+ extract_list(df, "exclusive")
232
245
  # extract_json(df, "exclusive")
233
246
 
234
247
  return df
@@ -1,8 +1,12 @@
1
+ from rich.layout import Layout
1
2
  from rich.table import Table
2
3
  from .tools import human_datetime
3
4
  from pandas import isnull
4
5
  from .console import console
5
6
  import subprocess
7
+ from pandas import isna
8
+ from os import environ
9
+ from pathlib import Path
6
10
 
7
11
  ### TABLES
8
12
 
@@ -20,15 +24,17 @@ def running_job_table(
20
24
  pending_df = df[df["job_state"] == "PENDING"]
21
25
  df = df[df["job_state"] == "RUNNING"]
22
26
 
27
+ count = len(df)
28
+
23
29
  if limit:
24
30
  df = df[-limit:]
25
31
 
26
32
  from .slurm import METADATA
27
33
 
28
34
  if not user:
29
- title = f"[bold]all running jobs on {METADATA['cluster_name']}"
35
+ title = f"[bold]{count} running jobs on {METADATA['cluster_name']}"
30
36
  else:
31
- title = f"[bold]{user}'s running jobs on {METADATA['cluster_name']}"
37
+ title = f"[bold]{user}'s {count} running jobs on {METADATA['cluster_name']}"
32
38
 
33
39
  table = Table(title=title, box=None, header_style="")
34
40
 
@@ -77,6 +83,8 @@ def history_job_table(
77
83
  **kwargs,
78
84
  ):
79
85
 
86
+ count = len(df)
87
+
80
88
  if limit:
81
89
  df = df[-limit:]
82
90
 
@@ -91,9 +99,9 @@ def history_job_table(
91
99
  hist_string = f"last {hist} {hist_unit}"
92
100
 
93
101
  if not user:
94
- title = f"[bold]all previous jobs on {METADATA['cluster_name']} ({hist_string})"
102
+ title = f"[bold]{count} previous jobs on {METADATA['cluster_name']} ({hist_string})"
95
103
  else:
96
- title = f"[bold]{user}'s previous jobs on {METADATA['cluster_name']} ({hist_string})"
104
+ title = f"[bold]{user}'s {count} previous jobs on {METADATA['cluster_name']} ({hist_string})"
97
105
 
98
106
  table = Table(title=title, box=None, header_style="")
99
107
 
@@ -201,18 +209,48 @@ def job_table(row, job: int, long: bool = True, **kwargs):
201
209
  return table
202
210
 
203
211
 
204
- def log_table(stdout, stderr, limit):
212
+ def log_table(job_id, stdout, stderr, limit):
205
213
 
206
214
  from rich.text import Text
207
215
 
208
- dual = stdout != stderr
216
+ if isna(stdout) or isna(stderr):
217
+ log_dir = Path(environ.get("LOGS", "."))
218
+ matches = list(log_dir.glob(f"*{job_id}*.*"))
219
+
220
+ if len(matches) == 1:
221
+ stdout = matches[0]
222
+ stderr = matches[0]
223
+ elif len(matches) == 2:
224
+ raise NotImplementedError("separate log files not supported")
225
+
226
+ if stdout != stderr:
227
+
228
+ # layout = Layout()
229
+
230
+ # layout.split_column(
231
+ # Layout(name="upper"),
232
+ # Layout(name="lower")
233
+ # )
234
+
235
+ # table = Table(title="stdout", box=None, header_style="")
236
+
237
+ # table.add_column("[bold underline]#", style="bold")
238
+ # table.add_column("[bold underline]Log", no_wrap=True)
239
+
240
+ # lines = tail(stdout, limit)
241
+
242
+ # for i, line in enumerate(lines):
243
+ # line = line.decode("utf-8")
244
+
245
+ # line = line.split("\r")[-1]
246
+
247
+ # table.add_row(str(i), Text.from_ansi(line))
209
248
 
210
- if dual:
211
249
  raise NotImplementedError("separate log files not yet supported")
212
250
 
213
251
  else:
214
252
 
215
- table = Table(title="stdout", box=None, header_style="")
253
+ table = Table(title=str(stdout), box=None, header_style="")
216
254
 
217
255
  table.add_column("[bold underline]#", style="bold")
218
256
  table.add_column("[bold underline]Log", no_wrap=True)
@@ -245,6 +283,8 @@ def color_by_state(state):
245
283
  elif state == "IDLE":
246
284
  return "[bold bright_green]Idle"
247
285
  elif state == "PENDING":
286
+ return "[bright_red]Preempted"
287
+ elif state == "PREEMPTED":
248
288
  return "[bright_yellow]Pending"
249
289
  elif state == "MIXED":
250
290
  return "[bright_yellow]Mixed"
@@ -254,6 +294,8 @@ def color_by_state(state):
254
294
  return "[orange3]Cancelled"
255
295
  elif state == "FAILED":
256
296
  return "[bold bright_red]Failed"
297
+ elif state == "OUT_OF_MEMORY":
298
+ return "[bold bright_red]Out Of Memory"
257
299
  elif state == "COMPLETED":
258
300
  return "[bold bright_green]Completed"
259
301
  else:
@@ -1,7 +1,7 @@
1
1
  import datetime
2
2
 
3
3
 
4
- def curry(function, payload):
4
+ def curry(function, payload, *args, **kwargs):
5
5
  def f(*args, **kwargs):
6
6
  return function(payload, *args, **kwargs)
7
7
 
@@ -66,3 +66,22 @@ def human_datetime(dt):
66
66
  bits = (str(b) for b in bits)
67
67
 
68
68
  return " ".join(bits)
69
+
70
+
71
+ def human_timedelta_to_seconds(s):
72
+
73
+ values = s.split()
74
+
75
+ seconds = 0
76
+
77
+ for value in values:
78
+ if value.endswith("s"):
79
+ seconds += int(value[:-1])
80
+ elif value.endswith("m"):
81
+ seconds += 60 * int(value[:-1])
82
+ elif value.endswith("h"):
83
+ seconds += 60 * 60 * int(value[:-1])
84
+ elif value.endswith("d"):
85
+ seconds += 24 * 60 * 60 * int(value[:-1])
86
+
87
+ return seconds
@@ -0,0 +1,112 @@
1
+ from random import sample
2
+ from .console import console
3
+ from rich.table import Table
4
+ from rich.text import Text
5
+ from rich.panel import Panel
6
+ from rich.layout import Layout
7
+ from rich.padding import Padding
8
+ from typer import Typer
9
+
10
+ import textwrap
11
+
12
+ app = Typer()
13
+
14
+
15
+ def get_quotes():
16
+ import json
17
+ from pathlib import Path
18
+
19
+ root = Path(__file__).parent
20
+ if not (root / "quotes_decrypted.json").exists():
21
+ from cryptography.fernet import Fernet
22
+
23
+ key = console.input("[bold]Enter passkey:\n")
24
+
25
+ with open(root / "quotes_encrypted.py", "rb") as f:
26
+ encrypted = f.read()
27
+
28
+ fernet = Fernet(key)
29
+ decrypted = fernet.decrypt(encrypted)
30
+
31
+ with open(root / "quotes_decrypted.json", "wt") as f:
32
+ encrypted = f.write(decrypted.decode())
33
+
34
+ payload = json.loads(decrypted.decode())
35
+ return payload
36
+
37
+ else:
38
+ return json.load(open(root / "quotes_decrypted.json", "rt"))
39
+
40
+
41
+ @app.callback(invoke_without_command=True)
42
+ def print_random_quote():
43
+
44
+ width = console.size.width
45
+
46
+ if width < 12 + PADDING * 2:
47
+ return
48
+
49
+ quote = sample(QUOTES, 1)[0]
50
+ index = QUOTES.index(quote)
51
+
52
+ lines = [""]
53
+
54
+ paragraphs = [""]
55
+ for c in quote:
56
+ if c == "\n":
57
+ paragraphs.append("")
58
+ else:
59
+ paragraphs[-1] += c
60
+
61
+ for i, paragraph in enumerate(paragraphs):
62
+
63
+ if len(paragraph) == 0:
64
+ lines.append("")
65
+ continue
66
+
67
+ if i == 0:
68
+ first_padding = " " * PADDING
69
+ else:
70
+ first_padding = " " * (PADDING + 1)
71
+
72
+ subsequent_padding = " " * (PADDING + 1)
73
+
74
+ if i == 0:
75
+ paragraph = f'"{paragraph}'
76
+
77
+ if i + 1 == len(paragraphs):
78
+ paragraph = f'{paragraph}"'
79
+
80
+ lines += textwrap.wrap(
81
+ paragraph,
82
+ width=width - PADDING,
83
+ replace_whitespace=False,
84
+ initial_indent=first_padding,
85
+ subsequent_indent=subsequent_padding,
86
+ )
87
+
88
+ lines.append("")
89
+
90
+ longest = max(len(l) for l in lines)
91
+ signoff = f"-CONFUCIUS #{index+1}"
92
+ lines.append(" " * (longest - len(signoff)) + f"[italic]{signoff}[reset]")
93
+
94
+ lines.append("")
95
+
96
+ for line in lines:
97
+ console.print(line, highlight=False)
98
+
99
+
100
+ PADDING = 6
101
+
102
+
103
+ def main():
104
+ global QUOTES
105
+ QUOTES = get_quotes()
106
+ app()
107
+
108
+
109
+ if __name__ == "__main__":
110
+ global QUOTES
111
+ QUOTES = get_quotes()
112
+ app()
@@ -1,341 +0,0 @@
1
- from random import sample
2
- from .console import console
3
- from rich.table import Table
4
- from rich.text import Text
5
- from rich.panel import Panel
6
- from rich.layout import Layout
7
- from rich.padding import Padding
8
- from typer import Typer
9
-
10
- import textwrap
11
-
12
- app = Typer()
13
-
14
-
15
- @app.callback(invoke_without_command=True)
16
- def print_random_quote():
17
-
18
- width = console.size.width
19
-
20
- if width < 12 + PADDING * 2:
21
- return
22
-
23
- quote = sample(QUOTES, 1)[0]
24
- index = QUOTES.index(quote)
25
-
26
- lines = [""]
27
-
28
- paragraphs = [""]
29
- for c in quote:
30
- if c == "\n":
31
- paragraphs.append("")
32
- else:
33
- paragraphs[-1] += c
34
-
35
- for i, paragraph in enumerate(paragraphs):
36
-
37
- if len(paragraph) == 0:
38
- lines.append("")
39
- continue
40
-
41
- if i == 0:
42
- first_padding = " " * PADDING
43
- else:
44
- first_padding = " " * (PADDING + 1)
45
-
46
- subsequent_padding = " " * (PADDING + 1)
47
-
48
- if i == 0:
49
- paragraph = f'"{paragraph}'
50
-
51
- if i + 1 == len(paragraphs):
52
- paragraph = f'{paragraph}"'
53
-
54
- lines += textwrap.wrap(
55
- paragraph,
56
- width=width - PADDING,
57
- replace_whitespace=False,
58
- initial_indent=first_padding,
59
- subsequent_indent=subsequent_padding,
60
- )
61
-
62
- lines.append("")
63
-
64
- longest = max(len(l) for l in lines)
65
- signoff = f"-CONFUCIUS #{index+1}"
66
- lines.append(" " * (longest - len(signoff)) + f"[italic]{signoff}[reset]")
67
-
68
- lines.append("")
69
-
70
- for line in lines:
71
- console.print(line, highlight=False)
72
-
73
-
74
- PADDING = 6
75
-
76
- QUOTES = [
77
- "DO IT TOMORROW",
78
- "DO DFT TOMORROW",
79
- "HOW 'BOUT NAH",
80
- "STYLE OVER SUBSTANCE",
81
- "I'M NOT CHINESE",
82
- "TO DRIVE A TANK SIMPLY USE DRUIDRY TO TRANSFORM INTO A TANK DRIVER",
83
- "IF THE GAUSSIAN FAILS TWICE CONSECUTIVELY, GIVE UP",
84
- "THE FEWER HOURS YOU WORK ON A FIXED SALARY THE HIGHER YOUR HOURLY PAY", # MW
85
- "COMP. CHEM IS TEMPORARY. CONFUCIUS IS FOREVER",
86
- "BETTER TO ASK FOR FORGIVENESS THAN PERMISSION",
87
- "DO YOU THINK I WANT TO BE HERE?",
88
- "READ THE FUCKING MANUAL",
89
- "NEVER GIVE A COW FREE MILK",
90
- "FOR BETTER OR FOR WORSE I'LL ALWAYS HAVE ANOTHER COFFEE", # MW
91
- "I'M A BIG PROPONENT FOR HAVING FUN", # MW
92
- "I WOULDN'T BET MY LIFE ON IT",
93
- "DEATH DOES NOT PROTECT YOU FROM CRITICISM",
94
- "SOMETIMES YOU HAVE TO SPEND MONEY TO MAKE MONEY.\n\nSOMETIMES YOU HAVE TO SPEND MONEY TO LOSE MONEY.\n\nONE THING'S FOR SURE, YOU HAVE TO SPEND MONEY.", # Rust Valley Restorers
95
- "PREMATURE JOB FAILURE IS NOTHING TO BE ASHAMED OF",
96
- "LOUIE TOLD ME WHAT TO DO AND I DID MY BEST TO FUCK IT UP",
97
- "IT IS IMPOSSIBLE TO REVERSE THE CREATION OF A CAKE",
98
- "CAKE CAN BE CREATED AND DESTROYED",
99
- "I CAN HEAR BUT I CAN'T LISTEN",
100
- "I'M BETTER THAN THE MANUAL",
101
- "BEFORE TRYING, CONSULT ME",
102
- "CODE FIRST, THINK LATER",
103
- "WHEN IN DOUBT, CROSS PRODUCT",
104
- "CHEMIS[bold]DO[/bold] OR CHEMIS[bold]DON'T[/bold] THERE IS NO CHEMIS[bold]TRY[/bold]",
105
- "I HATE IT HERE",
106
- "I DIDN'T SIGN UP FOR THIS",
107
- "I DON'T UNDERSTAND WHY PEOPLE WOULD CHOOSE TO BE A BIOLOGIST",
108
- "I HATE PAST ME",
109
- "SOUNDS LIKE A FUTURE ME PROBLEM",
110
- "I STRUGGLE TO FIND PEACE",
111
- "I HEREBY CLASSIFY THIS AS A ROYAL BALL ACHE",
112
- "I'M ALL OUT OF PASSION",
113
- "WHAT IS A DECIMAL PLACE BETWEEN FRIENDS?",
114
- "[bold italic]OF COURSE",
115
- "[dodger_blue2 bold] 🇬🇷 OF COURSE [/bold /dodger_blue2]",
116
- "ΩΦ KΩΥΡΣΕ",
117
- "FRENCH? SO YOU'RE EASY TO SATISFY",
118
- "YOU DON'T WANT TO FINISH TOO EARLY",
119
- "BOLD AND UNPROVEN",
120
- "WHERE IS MY GIRAFFE??", # CV
121
- "THIS IS A HIPPOPOTAMUS",
122
- "MONOGAMOUS ENTANGLEMENT",
123
- "INVEST IN A STRAP-ON",
124
- "[bold italic]FRIZZ OFF", # AC
125
- "I'M FRIZZED OFF", # AC
126
- "I'M GONNA GO TO THAT BUS STATION TOMORROW AND KICK MIKE'S ASS",
127
- "STRUGGLING FROM SUCCESS",
128
- "I'D SHOW YOU MINE; BUT I DON'T THINK YOU'D LIKE IT",
129
- "I'M SEVERAL RAKI'S DEEP",
130
- "DON'T ASK ME QUESTIONS THAT COULD HAVE CONSEQUENCES",
131
- "ENORMOUS DRAGON OF FAECES, DANCING INSIDE ME", # FB
132
- "I HAD A CRISIS OF FAITH IN MY RESEARCH, BUT THEN I REALISED THAT IT'S FINE",
133
- "IT DEPENDS",
134
- "KIND OF A PROOF",
135
- "THE DEAD CAT CAN BE A RESOURCE",
136
- "WITH A TALK LIKE THAT YOU CAN EXPECT TO MEET A PERSON\nWHO TOTALLY DISAGREES WITH EVERYTHING YOU SAID.\nYOU WILL FIND THAT PERSON IN ME", # Moritz @ QuEBS 2022
137
- "MIDNIGHT MEAT",
138
- "EXISTENCE IS CANCER",
139
- "IT'S A PITY THEY FOUND A CURE FOR LEPROSY", # QuEBS 2022 Excursion
140
- "[bold italic]MEOW", # RG
141
- "DON’T KNOW DON’T CARE",
142
- "INTERESTING TRANSFER DOWN THESE RODS",
143
- # "DISSEMINATE THROUGHOUT THE UK",
144
- "DUMPING MY PUMP ON",
145
- "KINDA TOXIC, BUT DON’T WORRY ABOUT THAT",
146
- "WHACKING GREAT ABSORBER", # AM
147
- "I KNOW YOU’RE THEORISTS, AND THIS IS VERY MUDDY",
148
- "I HAVE A PROPENSITY FOR THE DENSITY", # AB @ QuEBS 2022
149
- "OH MY [bold]GOODNESS[/bold]", # GF
150
- "YOU ARE UNDERMINING MY AUTHORITY", # unknown @ QuEBS 2022
151
- "TO BE WEAK, IS ACTUALLY AN ADVANTAGE ",
152
- "SPEEDY BOARDING",
153
- "THE PHILOSOPHICAL SIGNIFICANCE OF POO",
154
- "THE CAFFEINE IS A MATTER OF LIFE AND DEATH ",
155
- "IT’S ALMOST CERTAINLY WRONG, BUT FUN",
156
- "THAT WOULD HAVE BEEN WISE, HOWEVER, I AM NOT A WISE MAN",
157
- "THAT MAKES YOU THINK SOFT",
158
- "I WOULD ARGUE THAT BARE LEGS IS BETTER",
159
- "ANYTHING IS MICROSCOPIC IF IT’S FAR AWAY ENOUGH",
160
- "AN ERROR OCCURRED, HOW IS THAT EVEN SCIENTIFICALLY POSSIBLE",
161
- "YOU HEAR THAT? THAT’S A TARDIGRADE",
162
- "I SEEM TO HAVE LOST CONTROL [OF MY MOUSE]",
163
- "THERE’S NO ANSWER, BY THE WAY",
164
- "BECAUSE OF SOME PHYSICS ",
165
- "PSEUDO-WEAK",
166
- "THESE BALLS ARE JUST REGULAR SHINY", # MW
167
- "THE LAST COUP KIND OF FIZZLED OUT",
168
- "I THINK IT’S STRAIGHT SO IT MUST BE ERADICATED",
169
- "KOBE BEEF IS ALSO FAMOUSLY DEAD COW",
170
- "I’VE ALSO DECIDED I AM NOT A MORAL PERSON",
171
- "IT WAS ONLY AN EMPTY THREAT", # JJMF
172
- "THREATS ARE A PART OF WORKING LIFE", # JJMF
173
- "WELL THE THREAT WORKED!", # JJMF
174
- "AN EMPTY THREAT IS STILL A THREAT",
175
- "WHAT DO YOU THINK I’M SOME SORT OF PEPSI CRACK WHORE?",
176
- "LOW IMPACT FACTOR? I WANT LOW IMPACT ON MY LIFE!",
177
- "NOT F*CK YO MAMA F*CK YO-YO MA!",
178
- "I FORGOT ABOUT THE PASSAGE OF TIME",
179
- "EVERYTHING IS JUST A BIG WEIRD LIGAND",
180
- "IT NEEDS TO TASTE GOOD, AND KILL YOU", # CV
181
- "MY ABILITY TO SEE FUNKINESS REQUIRES EXPERIENCE", # ISQBP 2022
182
- "HISTIDINE IS A PROBLEM",
183
- "I HATE THE FACT THAT THEY SPENT SO MUCH TIME ON THESE QUOTES, INSTEAD OF IMPROVING THEIR SIMULATION SOFTWARE", # Gromacs
184
- "BUTTER MUSS SEIN",
185
- "I DON’T NEED A CONTROL BECAUSE I DON’T HAVE ANY RESULTS",
186
- "LET THE ANIMAL EAT FIBRE, AND THEN EAT THE ANIMAL",
187
- "THAT’S NOT A SHOT MATE!!",
188
- "FUCK AROUND AND FIND OUT",
189
- "♫♬♪[bold]OH MON BEBE[/bold]", # Les Kaira
190
- "WHY DID TOM CHEATHAM KILL US LAST NIGHT?", # ISQBP 2022
191
- "NOSE-HOOVER? SO LIKE A COCAINE ADDICT?",
192
- "YOU CAN SLEEP ON A BANANA",
193
- "AMBER AND I BROKE UP", # MW
194
- "WE WENT TOO FAR",
195
- "THEY GOT JIGGLY PHYSICS?",
196
- "DO YOU WANT TO SEE MY STUFF JIGGLING?",
197
- "WE DON’T SEE COLOURS HERE, WE JUST SEE BALLS",
198
- "IN MY OPINION THIS IS EXACTLY WHAT IS WRONG WITH SCIENCE",
199
- "I DIDN’T REALISE YOU WERE A NONCE",
200
- "I HEARD YOU LIKE FINISHING EARLY",
201
- "JOIN THE QUANTUM BIOLOGY DISCORD SERVER! #GAMERSRISEUP",
202
- "WE SHOULD GET SOMETHING VENOMOUS LIKE A PLATYPUS",
203
- "THERE IS TOO MUCH ON YOUTUBE ABOUT PLATYPUS CUSTARD",
204
- "I DON'T BELIEVE IN GRANDCHILDREN",
205
- "WINNING IS NEVER AN OPTION, ONLY REVENGE",
206
- "FEDERICO’S ALLEYWAY BOUQUET", # MW
207
- "SENT FROM MY GALAXY",
208
- " _______\n / 12 \\ \n| | |\n|9 | 3|\n| \\ |\n| |\n \\___6___/\n\nGOOD HEAVENS, LOOK AT THE TIME!",
209
- # "Har🌳-Frick ✝️ ",
210
- "BRANEURISM\n\nSymptoms:\tlight-headed, delirium, dyslexic, autism, chicken sounds, flowcharts",
211
- f" LISTEN TO PHAT BRAHMS\n | \\\n V \\\n EAT KATSU \\ IS IT FRIDAY? ----> WAIT\n | \\ | Yes ^ No |\n V \\ V L-----------\n SPIN MESMERISING SPIN ORB | IS HILLSIDE OPEN? ---> KATSU\n | | | \n V ^ V \n [bold]BRANEURYSM[/bold] | IS YOUNG'S OPEN ---> KATSU\n / \\ | | \n /YES \\ | V\n L NO------->--------| IS MAX IN THE OFFICE?\nKATSU COMA | | Yes \\ No\n ----<---- \\\n END THE DAY\n",
212
- "I WOULDN’T PAY £100 FOR A WET DREAM,\nFOR £100 I CAN GET A WET REALITY",
213
- "I KNOW YOUR FUTURE… BUT I’LL TELL YOU AFTER I GO TO THE LOO",
214
- "YOU ARE HEADING FOR A SMACK",
215
- "[bold]F*CK!!! WHY ARE THESE GUYS SUCH *$#@'S?![/bold]\n\n...\n\nI NEED ANOTHER COFFEE, I'M NOT ON EDGE ENOUGH.", # MW
216
- "RESULTS ARE A SOCIAL CONSTRUCT",
217
- "AUTISOMANCY",
218
- "IS A HANGING MAN STANDING ON A BOX THAT HE IS HOLDING BENEATH HIS FEET A PERPETUAL MOTION MACHINE?",
219
- "HAVE YOU READ KARL MARX'S LATEST TWEET?",
220
- "WE NEED MORE GAY SCIENCE",
221
- "IF WE OVERCOME THIS I WILL JERK FROM NOW UNTIL THE NEXT YEAR", # FB
222
- "DO LOOK A THIEVING STUFFED DOUGHNUT IN THE ASS",
223
- "YOU'RE NOT HUMAN UNTIL YOU'VE BEEN CITED", # LS
224
- "TRUE [bold]AND[/bold] FALSE",
225
- "EINSTEIN? LARGELY A B*TCH",
226
- "I’M SCARED TO GO TO TEXAS, PEOPLE JUST SHOOTING ME", # MS
227
- "YOU’RE WRONG WITH THAT, YOU’RE ABSOLUTELY WRONG WITH THAT", # MS, supervisory meeting
228
- "WE SHOULD GET AN OFFICE DILDO",
229
- "AIDS SALIVA IS A-OK, SO YOU CAN GIVE THAT WHISTLE A SUCK",
230
- "NO ONE EVER SAID NOT TO EAT YELLOW RICE",
231
- "WALRUSES RAPING PENGUINS FOR REASONS THAT ARE NOT YET CLEAR",
232
- "THEY NEVER SAID DON'T EAT YELLOW RICE",
233
- "RUINING PEOPLE'S CAREERS BY KEEPING THEM IN THE SAME PLACE JUST BECAUSE I DID", # JAK
234
- "WHEN I FIRST STARTED LECTURING I DID A LOT OF BUM WIGGLING", # JAK
235
- "I DON'T UNDERSTAND HAVING VALUES",
236
- "PISS",
237
- "THAT'S THE ONLY REASON I'M NOT EATING YOUR FACE OFF RIGHT NOW",
238
- "DOUBLE-TEAMED BY GERIATRICS",
239
- "LIMPINGCHAN",
240
- "LET'S HAVE A QUICK CHAT? I NEED TO VENT SOME ANGER!",
241
- "THE FRENCHMAN BURNS EASILY",
242
- "WHY IS THE BROWN ALWAYS CAUSING PROBLEMS",
243
- "QUANTUM NATIONALISM",
244
- "THERE IS NO SUCH THING AS TIME",
245
- "IS OUR BANANA CORRECT?",
246
- "WOULD YOU RATHER:\n\nWALLACE HAMMERING FOR AN HOUR\n\nOR\n\nA BRIEF AL-QAEDA MOMENT?",
247
- "THE CONSPIRACY GROWS",
248
- "YOU'RE LOOKING GUILTIER BY THE SECOND",
249
- "I HAD TO MAKE SOMETHING, BUT I ONLY DESTROY",
250
- "QUANTUM CRY FOR HELP",
251
- "QB SOS",
252
- "UNFORUNATELY THE JAVA VERSION ON EUREKA IS TOO OLD TO RUN MINECRAFT", # MW
253
- "NOBODY CARES, ESPECIALLY ME",
254
- "GEOGRAPHICALLY-CHALLENGED",
255
- "I GUESS THAT'S ONE GOOD THING ABOUT FASCISTS",
256
- "TESTICLES HAVE SO MUCH POTENTIAL",
257
- "WHENEVER IN DOUBT, GIVE LOUIE A SHOUT",
258
- "IF IN MOGADISHU, TELL LOUIE 'I MISS YOU'",
259
- "IF YOU'RE IN A PICKLE, GIVE LOUIE A TICKLE",
260
- "DOORS - UNLIKE PEOPLE - CAN BE UNFUCKED", # MW
261
- "ARE YOU GOING TO GO TO HIS OFFICE, LIFT HIS ARMS UP AND GET YOUR FINGERS IN THERE?",
262
- "I CANNOT RIPEN MY OWN BANANA",
263
- "I DO BELIEVE!",
264
- "GREAT MINDS THINK THE SAME JUNK",
265
- """HI EVERYONE. HOW DO YOU KEEP WORKING WITH A COLLABORATOR IF YOUR LAST MEETING ENDED WITH YOU SAYING "SPARE ME THIS USELESS AND AGGRESSIVE RHETORIC, 'CAUSE I DON'T NEED IT, OR CARE ABOUT IT"?""",
266
- "LUCKILY SCIENCE AND DFT CALCULATIONS, DO NOT CARE ABOUT YOUR IMPRESSION OF THEM", # FB
267
- "I WAS ONLY DOING AN IMPRESSION OF A NONCE!",
268
- "I GUESS WE ALL LEAVE AS FLESH",
269
- "SHOULD I BUY AN END OF LIFE PLANNER FOR MY PHD?", # EN
270
- "WE NEED MORE MONEY TO MAKE STUDENTS SUFFER",
271
- "I WON'T TELL YOU WHAT TO DO, I'LL JUST JUDGE YOU",
272
- "NO, YOU DO NOT NEED TO STAY IN QB.\nAND YOU MIGHT NOT WANT TO DO SO",
273
- "SHIT CODE IS THE FIRST STEP TO NOT SHIT CODE", # MW
274
- "GRANTS MAKE IT RAIN!",
275
- "YOU CAN'T GET DRUNK ON PISS",
276
- "CAN'T GET CANCELLED IF YOU'RE NOT FAMOUS",
277
- "I'M STARTING TO BELIEVE THESE ARE NOT REAL CONFUCIUS QUOTES", # MS
278
- "WOULD YOU RATHER MAKE LOVE TO AN EYE OR A FOOT?", # unknown @ MMC 2023
279
- "QUANTUM PHYSICS MEANS THAT ANYTHING CAN HAPPEN AT ANY TIME, FOR NO REASON", # Futurama
280
- "I WOULD BE SCHLOBBIN ON SOMEONE'S KNOB FOR THAT", # LS
281
- "THERE IS NO GREAT LOVE, WITHOUT GREAT JEALOUSY", # Futurama
282
- "THE BAD BOYS WON'T WAIT ALL NIGHT", # MW @ ABC 2023
283
- "YOU WON'T BELIEVE WHAT THIS OLD ITALIAN MAN PUT IN MY MIND",
284
- "THERE'S NOTHING NATURAL ABOUT AVERAGING COORDINATES", # ABC 2023
285
- "ONIONS DON'T HURT ME",
286
- "THAT WAS BEFORE I DISCOVERED TURKISH MEN", # RG @ ABC 2023
287
- "ALL COSTS ARE SUBSTANTIAL",
288
- "ALWAYS A GOOD IDEA TO BLAME THE FRENCH",
289
- "CHEESE, SEX AND ALIENS", # about a museum in Basel
290
- "YOU HAVE TO ACCEPT YOUR MISERY",
291
- "COSTA RICA WAS A SIMULATION WITH THE WRONG FORCE FIELD", # Leandro @ ABC 2023
292
- "LOW ENTROPY REGION OF NERDS",
293
- "THANK YOU FOR BEING WILLING", # MW @ ABC 2023
294
- "HELLO STALKERS, COME TO ME",
295
- "YOU'RE ALWAYS ON THE RECEIVING END OF THE MOOSE SHAFTING",
296
- "IT'S A COCKTAIL OF SHIT",
297
- "F*CK HIM, CARVE YOUR OWN PATH", # LS about Löwdin
298
- "I AM A STRAIGHT WHITE WHALE",
299
- "TO KILL A MONKEYBIRD",
300
- "LAZINESS LEADS TO THE ULTIMATE CREATIVITY",
301
- "DO YOU KNOW HOW TO READ [bold]FACIAL[/bold] LIPS?",
302
- "THERE'S TOO MANY BALD BASTARDS",
303
- "MAYBE YOU'RE THE D&D CHARACTER OF SOMEONE ELSE, AND THEY ARE DOING A REALLY BAD JOB",
304
- "THIS IS NOT AN ACT OF GOD, IT IS PITY",
305
- "FREUD'S THEORY ON GRAPEFRUITING YOUR DAD",
306
- "NORMALLY IT'S SHIT. BUT TODAY, IT'S [bold]EXCEPTIONALLY[/bold] SHIT",
307
- "WHAT ARE THESE REVOLUTIONARY LOOKING FIGURES? AH YES, HEXAGONS",
308
- "IF YOU ABUSE THEM, THEY'LL MOVE",
309
- "IT'S NOT SEXUAL HARASSMENT, IT'S A COMPLIMENT",
310
- "NOT A GOOD CRAZY",
311
- "EVENTUALLY YOU HAVE TO CARE ABOUT [bold]SOMETHING[/bold]",
312
- "DON'T PUSH THE RIVER", # MW
313
- "THE DILDO OF CONSEQUENCES RARELY ARRIVES PRE-LUBED", # REDDIT
314
- "IT'S ALL UNDER CONTROL", # TH
315
- "THERE IS NO FUN WITHOUT VIOLENCE", # GF
316
- "AN UBER IS TRANSIENT BUT SWIM TRUNKS ARE FOREVER", # MW
317
- "IT'S NOT STEALING IF YOU PIONEER SOMETHING", # MW
318
- "THE SUFFERING IS OPTIONAL",
319
- "THAT'S THANKS TO LOUIE, AIMEE, AND - IT PAINS ME TO SAY IT - GEORGE", # alex jones @ QuEBS 2023
320
- "HOME IS WHERE YOUR CHEEKS IMPRESS", # MW
321
- "YOUR NUTS ARE DOING A REAL JOB ON MY THROAT", # MW
322
- "VICIOUS CIRCLE OF BOLLOCKING", # RL, XChem, Aug 2023
323
- "CROWDS GATHER TO WITNESS THE FIRST PANINI ARRIVE IN IRELAND", # Waterford Whispers News
324
- "BLESSED ARE THE TOASTED SANDWICH MAKERS", # Waterford Whispers News
325
- "BEEF JESUS DIED FOR OUR SINS", # MW
326
- "I'M NOT IN A PICKLE, I'M IN A POTENTIAL WELL",
327
- "THE ELECTRON IDENTITY CRISIS",
328
- "TOY STORY IS A SOCIAL COMMENTARY ON THE MEASUREMENT PROBLEM",
329
- "DO YOU THINK SOME STUDENTS JUST AREN'T INTELLIGENT ENOUGH?",
330
- "YOU DON'T NEED A DEBUGGER. YOU NEED A PRIEST", # MW
331
- "IF THE PAPER YOU WANT TO READ DOESN'T EXIST, WRITE IT", # MW
332
- "THE WORLD IS YOUR HOSTAGE", #
333
- ]
334
-
335
-
336
- def main():
337
- app()
338
-
339
-
340
- if __name__ == "__main__":
341
- app()
File without changes
File without changes
File without changes
File without changes
File without changes