From 1b3480b2e4b13b8045bac7f864fc43b4ea25f96f Mon Sep 17 00:00:00 2001 From: Liz Date: Fri, 2 Aug 2024 10:07:06 -0400 Subject: [PATCH] circuitpython day countdowns Code for the two CP countdown projects. One for Feather DVI and another for ESP32-S3 TFT --- .../Helvetica-Bold-16.pcf | Bin 0 -> 145784 bytes .../Feather_DVI_Countdown/code.py | 98 ++++++++++++++++++ .../Feather_DVI_Countdown/cpday_dvi.bmp | Bin 0 -> 76892 bytes .../Helvetica-Bold-16.pcf | Bin 0 -> 145784 bytes .../Feather_TFT_NTP_Countdown/code.py | 86 +++++++++++++++ .../Feather_TFT_NTP_Countdown/cpday_tft.bmp | Bin 0 -> 32496 bytes 6 files changed, 184 insertions(+) create mode 100644 CircuitPython_Day_2024_Projects/Feather_DVI_Countdown/Helvetica-Bold-16.pcf create mode 100644 CircuitPython_Day_2024_Projects/Feather_DVI_Countdown/code.py create mode 100644 CircuitPython_Day_2024_Projects/Feather_DVI_Countdown/cpday_dvi.bmp create mode 100644 CircuitPython_Day_2024_Projects/Feather_TFT_NTP_Countdown/Helvetica-Bold-16.pcf create mode 100644 CircuitPython_Day_2024_Projects/Feather_TFT_NTP_Countdown/code.py create mode 100644 CircuitPython_Day_2024_Projects/Feather_TFT_NTP_Countdown/cpday_tft.bmp diff --git a/CircuitPython_Day_2024_Projects/Feather_DVI_Countdown/Helvetica-Bold-16.pcf b/CircuitPython_Day_2024_Projects/Feather_DVI_Countdown/Helvetica-Bold-16.pcf new file mode 100644 index 0000000000000000000000000000000000000000..deb9092d11e0e0c9c4367805319f72ef3a01681d GIT binary patch literal 145784 zcmeI5dwf*qeW!oAfoZ_Tm$$Wcin8-WH;mD2B&djH*s6qCho8#CfQ9L+D%f@V6@No zT!yhMjDq)%wx8cgo_X)L=Y7x78QDrIHh1)$XJ!>}K76OzY&T(LobDv-t1%L#;gar)y`X3xE=(tVLOH(x zzpI=t!n2C}HT)pF&qV^!~0q>IS9IEQHa?ak}ftZ3O_x955X zZqMbr(sp~p9Zjn@Y+TcDN29GuXSbvWG94+qtFdY2sH(!-^FfTiZ6QZj5qmZPWV3)f-!z?ryZT%}s0CqG(HFYxC-LZB5N< zHm;4fS2eUS;Kr85l})W}OuMPIc|rZnH{M(- zXYavE{kGt@%t>_dwls9q+7LuxQ~;*X#3^@Nsq(=52Sng>zaBy za{0boJ~fc;yrHhHA)BphQ4jrfE$RMrehay$hs*TWrRoOqsm^pyDt}L1Zgbu0OmA*r zYhSvqVP##axAWb(d|igN{ezqOGo6`KK9lahA(XHYhpnvD>gyNWP+xzGvE_{|tDDv| zZd}{k+9VBSS#7JDmVaPPV{5Ce-?%E=bz9!BHi@=0+_kZxb$O%qp6H6kD88n-<&KTo zwMI5_bwgXzoorduxRg##inXp=%Y>Gm|vi?A*Rn z%MW8?dqy8b>=;hR_H1V^;e;L;CWdy^(+qY7qniCb{3*6=`|h#ba{ur{N!}w{=y|WU zn`w-W?%fuC>`=3ClIm|K>ll477#R&l_z0`ST?P9dWxK0^7vWw&{KG=%nBR(4x?A>>UkMOW+m7EgwH{l~1gHr8aXy`Q`VP5j_ zSh!o#UOLK2j4C6$SmiE0m|yr2cgo7c7^Qpmoc=gnI<}nx?W#)4KcWeZXlfb~FC)9y zig2dk{T2$_zn`|Dt8jl6qY59pqx(%~S34bl?A@X}eo(jb7CzXwa6@;i%GlWGw&3x{ z!+Vh4Sm&6za|S$z>8+n&V$9!2cLq&X44sO z`ZA#X^e5pPymQTl6)*&!h9a+4%xMPW%wQce7-Pn_c$KP!)eyilaDsO+`hQCstcP|O zfzJW`&ZOU&H$pdj99}S+RSonzi+*R(@2nSre$Jl*Yk~IXKMBtP`4^CX0rS0}6L!NF zfced?1IC^G5qJXVd-h4*i|c{8Tu9vuse2)L7cu5V3*kdB1bd+X&%j}z&c$KPJ=VJQ3__*06mjHcV(hmE9vP;N+D|v72g9AYNQqq?W0BgAPduBg-J!Ik2K)RN6 zE$Ld)wWKer1Nyw|2`HLfPWp1vmy^D{06#Fh;zpp)E1m+w$Jx zegvKc`kq?{YasyUH}_j+^DY6_IBx)$-59*-}M&K!+{o89{ zJuvp$i)QbrhJ}y?+P>o%v#ZFv>P8p<+FeDvtFHt4yPCRJGuG9spba{KwpUa4>TNIr zAA?WB7vKd@`x9o@+z8aWW-ojMo&n~6%@543y$a~}TKc_~ey%;hIeC)3`w{V{_y*N& zT!pg`P@Y@`B4Ym}TtS|=7>0ugzRTFnFiv`$@R}GVX0w4w8Q+`iFX69%h1qdX{#@XD zmwg>nM|o-^`j(lUD46XH%=W>L%`6XjZkY=8#yRId407>P#x7x#?-vk-!zyRGlx)~wB`i0(R?(f zcp0{V@{+z4Dy{saOm)l4$4SeH##EW=4?!V@;5Ao)R5`CHEGt_U#{)urJyHL2;RF=m zI4l9>t6cLC$(5vwWN1EWD>vFtt)&P7EC$X07#xMfpZ0zZ)IxG8EiMS~SmbPT&{wWC zd;SHp!-ru%zY>DKqbyh8eAUrEan;v6HFgN;E8#Lxpf6Y|inM|DcIMX?uZjF4P>jQH zpUd(}`Q)i=o<(Q+UeYQnk|rooBt!Ws9}c4W;}*3|#tG{bsh3cQ=AiO$e2c>%>c2=@ zgk`~N^TPZBWr8wMw9|xRm!-?g6xVv>=3Wxvd`OeDgQP{VJ<3 zHQM}?=&ZaEM=2LwFbq1cM~dVXIB!98=3XK1B%F#lMtC%c>KrLVYb%mBRT9U?k8_WR z1Kcz4<1)Tm&u=W@`!UA|Uk1529&>_Fd@tr@LZP_}%}tc{hj_6F?d(q(N-JOIP5Y?& z<07EFD8vvC=Wf)WgtLuvq@8)uFdTS&LK;b>s?G!%(z ze};+cKCUQ`51PC3R6jXe$@6w9;Su#Q1uuXCXf`I0u^7(I9&FxsN`y#Z`EZw;j_DsFmZgGxG0lvcjVHC{OnkXC!uIar3$%2)Xk7>163yqIE~R=&y?#`F=2#7B~zEWDL^ zYJaA&Rj#=n14 z0m*kpJp*rsxiBZ@SS{}Zbl6qTKZZPDHVE%4Ml2+(1@-wdXwI6a#utj~JRE{EjkScb z^6@n8P|Pr)NPa%3O#N!T<1xut?W8ACB(DJNlb}A-wr~yHg!`ngoE2_%SJeC%tar7?x<^Aw6<^*4_SE9O}zL#V4Y9C;OFz%1bWoTL4;P7PNobGu7P< z_3ezaj4NCj9TI$#1e;M^@GgQaF z57JH^>4gQ#1I{0HzOvBl{`Jvs>#NzE^T?|e7C}&oFC@+oq4R@;+J|9S40B)_=$a1U z_jiTC)V{-4QSZ&P*LXANL)W>Ce|`}Ce)U}2UrBqR>s-dy+GoI% z(0GSI*SUql>v$phoyrM9akk&5 zXwQ=~qcgdbHaer>d2Q$XmQf_Ge3h%7>Q{lzovw3fuk(LJ*!tYs&kLe|2BR*{WqghO zX2w5A`(yABERIoJdAGs5`ske@aeAbk@8IwZJPXG~F>mNOr@!aiLZ3@ObJW?Lj3W7BTm(`3 z(mY5jPi4h2)aNi9gQIcy3ZdT7j|Q(rc`927wV*3$-$7jW#8OaPeW~9Eg6KX;_GK#d zwZ`OmI+glzegh=eRN9n3v(;`YZM24qViccBnp3>HkVUTKE<`5vnc0BgVVpeIY>OYAGDW0 z2Mp7o8PdQ>m{y*MzmFR)69erZUDB`WMMH zl{Q-QLP*vwPeNCD+2Y`|lS9P60$&F?QT;DKxkKeo#<95m1BB%cC#$Qx^7`ctr&52S zkEygNzmLm*KJ+se{fy9ksIxd1=9Do+TofiyI(xzCbCjG{c~f~|0vbak*SXB2NaM3H z@tz%^%{EZ}@iJ@D^b1AeGz;Hd^c}aN5REIB!=U|st|Nd|Vedx^VN_&L|_Q#>(g&4K#gwMe% z@EnW>F+|3poxB1RCt(?RB7kDdGD5Kec7ytyh{`6GEBy@Ud0jgJc@h)zr;SCa$^E!7?bot6$~!5((S{3&dw5k~Jp(+*bQ7ejG&H zOL!)dHc9zZ+R$}$?^J}_^%HjOO=Saw{(j@8jXK6v+*Ikz3ATZR9VYR@y3SviI|6TdVC3Tf?7t zt+fy8uZpbA*4dqQm#w!A{9)72+lTo3tzUdoOOG4dMsC2AZQ^yglfNX}Y+crE8T;_~ zxZT5}vB!EX$Clp9KbGjX0UPAi;yxY$TkU>(fXCs3JR*lJuNw%@V;VxP9p*zel!*#Y}~`>*!j>?!*L`>g$U9w&cje`KGxFZ};7@J4;u z|9GQP9Q{xG;#q1G?CCSr;2)PCJX6_Z`SwhbYky*2O5$%E+Mzct_fj|T<_+*-@a41h z!Vj~r@Pqo#?5pX0cQ`Ndch`Tx|7Ff!5gz9Mwe)Y|vcG-(8tfYr^X!}U(!@Oa z`McNWdCtEE16KUkFiW4~xf$Sp{M0Wu;0D})8*l?|zzw(oH{b@`fE#cFZomz=0XN_V z+<+T!18%?#xB)ld2Hb!fa070@4Y&a};0D})8*l?|zzw(oH{b@`fE#cFZomz=0XN_V z+<+T!18%?#xB)ld2Hb!fa070@4Y&a};0D})8*l?|zzw(oH{b@`fE#cFZomz=0XN_V z+<+T!18%?#xB)ld2Hb!fa070@4Y&a};0D})8*l?|zzw(oH{b@`fE#cFZomz=0XN_V z+<+T!18%?#xB)ld2Hb!fa070@4Y&a};0D})8*l?|zzw(oH{b@`fE#cFZomz=0XN_V z+<+T!18%?#xB)ld2Hb!fa070@4Y&a};0D})8*l?|zzw(oH{b@`fE#cFZomz=0XN_V z+<+T!18%?#xB)ld2Hb!fa070@4Y&a};0D})8*l?|zzw(oH{b@`fE#cFZomz=0XN_V z+<+T!18%?#xB)ld2Hb!fa070@4Y&a};0D})8*l?|zzw(oH{b@`fE#cFZomz=0XN_V z+<+T!18%?#xB)ld2Hb!fa070@4Y&a};0D})8*l?|zzw(oH{b@`fE#cFZomz=0XN_V z+<+T!18%?#xB)ld2Hb!fa070@4Y&a};0D})8*l?|zzw(oH{b@`fE#cFZomz=0XN_V z+<+T!18%?#xB)ld2Hb!fa070@4Y&a};0D})8*l?|zzw(oH{b@`fE#cFZomz=0XN_V z+<+T!18%?#xB)ld2Hb!fa070@4Y&a};0D})8*l?|zzw(oH{b@`fE#cFZomz=0XN_V z+<+T!18%?#xB)ld2Hb!fa070@4Y&a};0D})8*l?|zzw(oH{b@`fE#cFZomz=0XN_V z+<+T!18%?#xB)ld2Hb!fa070@4Y&a};0D})8*l?|zzw(oH{b@`z`r>I_P^}tzqv*E zf~IJ|?0gHaZ<|$I3U|QYm{ndMQMHxuYt(opE>rm~@>UTh^%X+W=4@d&2K}gy5*=n$ z&y!}X*YInkRrWJcerX)lQ+`8~AC^-$saF}d3;R<30qQ9)&JX7h&p(_4>s4Mjcls?4 z!+hmIxaN4RiidvUGL?sQrU&%fsjwcIM zM|~u73q$R7OtQv`UyR36-FVOJx1+ppZ{s;vTzdN64DZote9i*qYHx$Zilt- z^Uw(y$iWtP5O%_D*bAH)`zWwJdjdWMzXJ#058(6gC-A560vra;n|%vj2Ig)58@>lT z7wkCvBd|{U5uAX3hLdoLH4;=*LN&04it~W;QZW-)V#RE@2rdEE7Ty8#;W4pufjpq1HgDy zkHW{`lkg-kZq;XjajTw#uftyhV^=YD)jtAbSJ%J=z#6M-fw8L@yZYV0K2Rx@@rV^=eFHLj}}yZTq)6YyK`8F&gl4~O8-;V`@e-vQiKpMY_*no3{}H8bI2 zxDu`cT-V^b=6!(cnkHZlHS2+S)TAK~{4A>pfIY5Z4mF>G--j;(>#kwlH8`(f-8Fv? zKQ@~-9WI4=@J?W@(->>oP4K?{zEnrr(nB5DRFB;|m>WoUZpvEkV9%y>zCY8|Yn{1l zHkG%&biO0qJ7B3EV*RP!&Zu&Krnf7bw!Tz8-J4Bs9*AQ3OjkEm`v=nbO#eOBmmTc4 zj$BVq%DT7qb*FpPTPD|O{n=E1x80x4=PcKowt@R{Hqf0;&%*R+XfG}SmaSzkvc z(~-${4EESyZzozha``kfNHOn}ZL$s?W30uxtec0~hwUEAT95VeQ0udMEpPocV1qo~ z?z17=YWIg@rsEOwQL1dDflRhD*{ROleZ3a$ha6|w1nU^gvj-hpZ7Z%e<#YF>dpEIf z{ppTSLuV$PPxoiE4}DvsUUT`*%_t0wb`55-*>q1XT5vYkmFY-jdvgPpPj_WBM!M5_ zQXP4OcBXO6mb0leW@p*9{=slZ^U?N|QmKx?fwc7u>Qtog($^jDyrv%Z*^%yK;FPw% z)QWlar20DsSr#^viN$m7)i&p~!!+qmWj9Ad#+m)4eGd&aM0?Q?&7&dOtIgT;kTpa$ z8%kOl@{-ulXv>o+HAamaqsEP8jT=j?nxZ;QQJto;I!&cIjRW1bCK|3es@@z`Z!W9e z99Jl{>KV)qWcspOtvNb*>!POXqNeN0nyxFg*$@@Bb?5TE)|JlpaGP$*_M6n}NJhn} zvbL#c*i@;DRHz}vEtY6tx79cuHBOf`X6xcJm5J(PqB`+C5qi#)>ZH-o8x5C>s^_BW zxw0;EafMQ=&din!r#=@+7>pVYMhyqc8V;6PY>f&BLJ3<-*_}Gt{rwqR9d(tBg62lc zrLDCirIXzs1sh6@?v66w3)gpb_to)2TuDG#IJqjgiNKV5n(pRUHXmenK`*6U1lvFjEE zdW>%x>Tn=`gK pYd7#@=uGo-x%AyjQC<98w<@R{f0dV}D!#(~P$|1G{7<#n{{srG@_7IN literal 0 HcmV?d00001 diff --git a/CircuitPython_Day_2024_Projects/Feather_DVI_Countdown/code.py b/CircuitPython_Day_2024_Projects/Feather_DVI_Countdown/code.py new file mode 100644 index 000000000..c20761273 --- /dev/null +++ b/CircuitPython_Day_2024_Projects/Feather_DVI_Countdown/code.py @@ -0,0 +1,98 @@ +# SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import time +import displayio +import picodvi +import board +import framebufferio +from adafruit_bitmap_font import bitmap_font +from adafruit_display_text import label +from adafruit_pcf8523.pcf8523 import PCF8523 +from adafruit_ticks import ticks_ms, ticks_add, ticks_diff + +EVENT_YEAR = 2024 +EVENT_MONTH = 8 +EVENT_DAY = 16 +EVENT_HOUR = 0 +EVENT_MINUTE = 0 +# we'll make a python-friendly structure +event_time = time.struct_time((EVENT_YEAR, EVENT_MONTH, EVENT_DAY, + EVENT_HOUR, EVENT_MINUTE, 0, # we don't track seconds + -1, -1, False)) # we dont know day of week/year or DST + +# check for DVI Feather with built-in display +if 'DISPLAY' in dir(board): + display = board.DISPLAY + +# check for DVI feather without built-in display +elif 'CKP' in dir(board): + displayio.release_displays() + fb = picodvi.Framebuffer(320, 240, + clk_dp=board.CKP, clk_dn=board.CKN, + red_dp=board.D0P, red_dn=board.D0N, + green_dp=board.D1P, green_dn=board.D1N, + blue_dp=board.D2P, blue_dn=board.D2N, + color_depth=8) + display = framebufferio.FramebufferDisplay(fb) +# otherwise assume Pico +else: + displayio.release_displays() + fb = picodvi.Framebuffer(320, 240, + clk_dp=board.GP12, clk_dn=board.GP13, + red_dp=board.GP10, red_dn=board.GP11, + green_dp=board.GP8, green_dn=board.GP9, + blue_dp=board.GP6, blue_dn=board.GP7, + color_depth=8) + display = framebufferio.FramebufferDisplay(fb) + +i2c = board.I2C() +rtc = PCF8523(i2c) +set_clock = False +if set_clock: + # year, mon, date, hour, min, sec, wday, yday, isdst + t = time.struct_time((2024, 8, 1, 16, 26, 00, 0, -1, -1)) + print("Setting time to:", t) + rtc.datetime = t + print() +# variable to hold RTC datetime +t = rtc.datetime + +pink = 0xf1078e +purple = 0x673192 +aqua = 0x19beed +group = displayio.Group() +my_font = bitmap_font.load_font("/Helvetica-Bold-16.pcf") +clock_area = label.Label(my_font, text="00:00:00:00", color=pink) +clock_area.anchor_point = (0.0, 1.0) +clock_area.anchored_position = (display.width / 2 - clock_area.width / 2, + display.height - (clock_area.height + 20)) +text1 = label.Label(my_font, text="Starting In:", color=aqua) +text1.anchor_point = (0.0, 0.0) +text1.anchored_position = (display.width / 2 - text1.width / 2, + display.height - (clock_area.height + text1.height + 35)) + +blinka_bitmap = displayio.OnDiskBitmap("/cpday_dvi.bmp") +blinka_grid = displayio.TileGrid(blinka_bitmap, pixel_shader=blinka_bitmap.pixel_shader) +group.append(blinka_grid) +group.append(text1) +group.append(clock_area) +display.root_group = group + +clock_clock = ticks_ms() +clock_timer = 1000 +while True: + if ticks_diff(ticks_ms(), clock_clock) >= clock_timer: + t = rtc.datetime + remaining = time.mktime(event_time) - time.mktime(t) + secs_remaining = remaining % 60 + remaining //= 60 + mins_remaining = remaining % 60 + remaining //= 60 + hours_remaining = remaining % 24 + remaining //= 24 + days_remaining = remaining + clock_area.text = (f"{days_remaining:0>2}:{hours_remaining:0>2}" + + f":{mins_remaining:0>2}:{secs_remaining:0>2}") + clock_clock = ticks_add(clock_clock, clock_timer) diff --git a/CircuitPython_Day_2024_Projects/Feather_DVI_Countdown/cpday_dvi.bmp b/CircuitPython_Day_2024_Projects/Feather_DVI_Countdown/cpday_dvi.bmp new file mode 100644 index 0000000000000000000000000000000000000000..097bbbf0ef97741451943085d3efc5e814602f2d GIT binary patch literal 76892 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 literal 0 HcmV?d00001 diff --git a/CircuitPython_Day_2024_Projects/Feather_TFT_NTP_Countdown/code.py b/CircuitPython_Day_2024_Projects/Feather_TFT_NTP_Countdown/code.py new file mode 100644 index 000000000..562845c0b --- /dev/null +++ b/CircuitPython_Day_2024_Projects/Feather_TFT_NTP_Countdown/code.py @@ -0,0 +1,86 @@ +# SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +import os +import time +import wifi +import board +import displayio +import socketpool +import microcontroller +from adafruit_bitmap_font import bitmap_font +from adafruit_display_text import bitmap_label +import adafruit_ntp +from adafruit_ticks import ticks_ms, ticks_add, ticks_diff + +timezone = -4 +# The time of the thing! +EVENT_YEAR = 2024 +EVENT_MONTH = 8 +EVENT_DAY = 16 +EVENT_HOUR = 0 +EVENT_MINUTE = 0 +# we'll make a python-friendly structure +event_time = time.struct_time((EVENT_YEAR, EVENT_MONTH, EVENT_DAY, + EVENT_HOUR, EVENT_MINUTE, 0, # we don't track seconds + -1, -1, False)) # we dont know day of week/year or DST + +wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD")) +pool = socketpool.SocketPool(wifi.radio) +ntp = adafruit_ntp.NTP(pool, tz_offset=timezone, cache_seconds=3600) + +display = board.DISPLAY +group = displayio.Group() +font = bitmap_font.load_font("/Helvetica-Bold-16.pcf") +blinka_bitmap = displayio.OnDiskBitmap("/cpday_tft.bmp") +blinka_grid = displayio.TileGrid(blinka_bitmap, pixel_shader=blinka_bitmap.pixel_shader) +scrolling_label = bitmap_label.Label(font, text=" ", y=display.height - 15) + +group.append(blinka_grid) +group.append(scrolling_label) +display.root_group = group +display.auto_refresh = False + +refresh_clock = ticks_ms() +refresh_timer = 3600 * 1000 +clock_clock = ticks_ms() +clock_timer = 1000 +scroll_clock = ticks_ms() +scroll_timer = 50 +first_run = True + +while True: + # only query the online time once per hour (and on first run) + if ticks_diff(ticks_ms(), refresh_clock) >= refresh_timer or first_run: + try: + print("Getting time from internet!") + now = ntp.datetime + print(now) + total_seconds = time.mktime(now) + first_run = False + refresh_clock = ticks_add(refresh_clock, refresh_timer) + except Exception as e: # pylint: disable=broad-except + print("Some error occured, retrying! -", e) + time.sleep(2) + microcontroller.reset() + + if ticks_diff(ticks_ms(), clock_clock) >= clock_timer: + remaining = time.mktime(event_time) - total_seconds + secs_remaining = remaining % 60 + remaining //= 60 + mins_remaining = remaining % 60 + remaining //= 60 + hours_remaining = remaining % 24 + remaining //= 24 + days_remaining = remaining + scrolling_label.text = (f"{days_remaining} DAYS, {hours_remaining} HOURS," + + f"{mins_remaining} MINUTES & {secs_remaining} SECONDS") + total_seconds += 1 + clock_clock = ticks_add(clock_clock, clock_timer) + if ticks_diff(ticks_ms(), scroll_clock) >= scroll_timer: + scrolling_label.x -= 1 + if scrolling_label.x < -(scrolling_label.width + 5): + scrolling_label.x = display.width + 2 + display.refresh() + scroll_clock = ticks_add(scroll_clock, scroll_timer) diff --git a/CircuitPython_Day_2024_Projects/Feather_TFT_NTP_Countdown/cpday_tft.bmp b/CircuitPython_Day_2024_Projects/Feather_TFT_NTP_Countdown/cpday_tft.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9cef1b374ea1271db9fbd25878d74fa260c345df GIT binary patch literal 32496 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 IG~RCi5B#624*&oF literal 0 HcmV?d00001