Adds the `:NitExecute` command (or `:NitE` as shortcut) to interpret the current file with `nit`.
This is very similar to the manual `:!nit %` but it saves modified buffers to a temp file to execute the content of the current buffer and not the last saved content.
This is completely up to you but I recommend mapping this to `ctrl-f` to fit between `ctrl-d -> Nitdoc` and `ctrl-g -> NitGitGrep`. Here are the required lines for `.vimrc`:
~~~
" Map the Nitdoc command to Ctrl-D
map <C-d> :Nitdoc<enter>
" Map the NitGitGrep function to Ctrl-G
map <C-g> :call NitGitGrep()<enter>
" Map the NitExecute function to Ctrl-F <------- The new one
map <C-f> :NitExecute<enter>
~~~
Pull-Request: #1717
Reviewed-by: Jean Privat <jean@pryen.org>
mkdir -p bin
../../bin/nitc -o bin/moles src/moles_linux.nit
+android: bin/moles.apk
bin/moles.apk: android-icons $(shell ../../bin/nitls -M src/moles_android.nit) assets/images/drawing.png
mkdir -p bin
../../bin/nitc -o bin/moles.apk src/moles_android.nit
-android: bin/moles.apk
+android-release: android-icons $(shell ../../bin/nitls -M src/moles_android.nit) assets/images/drawing.png
+ mkdir -p bin
+ ../../bin/nitc -o bin/moles.apk src/moles_android.nit --release
../inkscape_tools/bin/svg_to_icons:
$(MAKE) -C ../inkscape_tools
mkdir -p bin
../../bin/nitc -o bin/friendz src/friendz_linux.nit
-android:
- mkdir -p bin res
- ../inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/
+android: res/drawable-hdpi/icon.png
+ mkdir -p bin
../../bin/nitc -o bin/friendz.apk src/friendz_android.nit
+android-release: res/drawable-hdpi/icon.png
+ mkdir -p bin
+ ../../bin/nitc -o bin/friendz.apk src/friendz_android.nit --release
+
+res/drawable-hdpi/icon.png: art/icon.svg
+ mkdir -p res
+ ../inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/
+
doc:
mkdir -p doc
../../bin/nitdoc -d doc/ src/friendz.nit src/friendz_linux.nit
../../bin/nitc -o bin/complete.apk src/complete_simple_android.nit --semi-global
../../bin/nitc -o bin/minimal.apk src/simple_android.nit --semi-global
+android-release:
+ mkdir -p bin
+ ../../bin/nitc -o bin/complete.apk src/complete_simple_android.nit --semi-global --release
+ ../../bin/nitc -o bin/minimal.apk src/simple_android.nit --semi-global --release
+
clean:
rm -rf bin
module opportunity_controller
import nitcorn
-import sha1
import templates
import opportunity_model
redef fun commit(db) do
if id == "" then
var time = get_time
- var tmpid = (name + date + place + time.to_s).sha1_to_s
+ var tmpid = (name + date + place + time.to_s).sha1.hexdigest
if not db.execute("INSERT INTO meetups (id, name, date, place, answer_mode) VALUES({tmpid.to_sql_string}, {name.html_escape.to_sql_string}, {date.html_escape.to_sql_string}, {place.html_escape.to_sql_string}, {answer_mode});") then
print "Error recording entry Meetup {self}"
print db.error or else "Null error"
../../bin/nitserial -o src/server/server_serialize.nit src/server/dedicated.nit
# Android
+android: bin/tinks.apk
bin/tinks.apk: assets/images/drawing.png src/client/client_serialize.nit res/drawable-ldpi/icon.png $(shell ../../bin/nitls -M src/client/android_client.nit)
- ../../bin/nitc -o bin/tinks.apk src/client/android_client.nit -m src/client/client_serialize.nit --compile-dir nit_compile
- adb install -r bin/tinks.apk
+ ../../bin/nitc -o bin/tinks.apk src/client/android_client.nit -m src/client/client_serialize.nit
+
+android-release: assets/images/drawing.png src/client/client_serialize.nit res/drawable-ldpi/icon.png $(shell ../../bin/nitls -M src/client/android_client.nit)
+ ../../bin/nitc -o bin/tinks.apk src/client/android_client.nit -m src/client/client_serialize.nit --release
res/drawable-ldpi/icon.png: art/icon.svg
../inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
- inkscape:cx="107.98668"
- inkscape:cy="65.759563"
+ inkscape:cx="357.89925"
+ inkscape:cy="19.247995"
inkscape:document-units="px"
inkscape:current-layer="0splash"
showgrid="false"
transform="matrix(0.9571749,0,0,0.9571749,14.241487,126.08446)">
<path
style="font-size:52.50814056px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:-1px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Armalite Rifle;-inkscape-font-specification:Armalite Rifle"
- d="m 258.625,595.8125 c -4.89966,1.4313 -12.56953,-1.70866 -15.1875,4.5625 -0.4775,5.90634 -3.5509,14.50575 2.71875,18.6875 2.28891,1.18746 5.12,1.54986 7.5625,0.59375 0.52227,3.72431 1.0541,7.99473 -2.03125,10.59375 -3.51238,6.69348 3.86364,14.87896 10.90625,12.96875 6.54546,1.2404 16.20527,-0.87285 16.34375,-9 1.15076,-4.65522 -4.58661,-6.69297 -3.46875,-11.1875 -0.95739,-2.94159 3.31489,-1.69978 4.46875,-3.78125 5.83868,-2.11249 5.55685,-9.07334 5.53125,-14.34375 1.81324,-6.47371 -5.8435,-9.85183 -11.15625,-8.5625 -4.34595,0.15294 -9.06169,-1.83389 -13.21875,-0.125 0.0516,-2.21144 -1.36209,-0.68823 -2.46875,-0.40625 z"
+ d="m 258.625,595.8125 c -4.89966,1.4313 -12.56953,-1.70866 -15.1875,4.5625 -0.4775,5.90634 -3.5509,14.50575 2.71875,18.6875 2.28891,1.18746 5.12,1.54986 7.5625,0.59375 0.52227,3.72431 1.0541,7.99473 -2.03125,10.59375 -3.51238,6.69348 3.86364,14.87896 10.90625,12.96875 6.54546,1.2404 16.20527,-0.87285 16.34375,-9 1.15076,-4.65522 0.20769,-5.09487 1.32555,-9.5894 -0.95739,-2.94159 -1.47941,-3.29788 -0.32555,-5.37935 5.83868,-2.11249 5.55685,-9.07334 5.53125,-14.34375 1.81324,-6.47371 -5.8435,-9.85183 -11.15625,-8.5625 -4.34595,0.15294 -9.06169,-1.83389 -13.21875,-0.125 0.0516,-2.21144 -1.36209,-0.68823 -2.46875,-0.40625 z"
id="path3211"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccc" />
<path
style="font-size:52.50814056px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:-1px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Armalite Rifle;-inkscape-font-specification:Armalite Rifle"
d="m 286.25,592.6875 c -2.39783,0.63195 -3.74457,2.90332 -6.59375,2.8125 -5.4632,2.29227 -6.35616,10.35289 -2.0625,14.25 -0.60542,4.15669 0.70607,8.39731 0.4375,12.3125 -0.0599,3.57375 -1.98208,6.31549 -3.3125,9.34375 -1.62554,5.38708 2.55698,12.80186 8.96875,10.96875 6.47834,0.22337 16.30714,2.49861 19.125,-5.53125 1.23942,-3.73894 -0.38135,-7.90712 -3.59375,-10.09375 0.3082,-5.37065 -0.71586,-11.3191 0.59375,-16.375 6.74005,-4.69817 1.76294,-18.17585 -6.625,-15.0625 -2.79844,0.69065 -4.06188,-3.31293 -6.9375,-2.625 z"
inkscape:connector-curvature="0" />
<path
style="font-size:52.50814056px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:-1px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Armalite Rifle;-inkscape-font-specification:Armalite Rifle"
- d="m 362.71875,595.53125 c -4.88629,0.1191 -10.06204,0.70685 -14.78125,0.75 -5.47787,-0.76679 -11.36437,-0.40783 -16.78125,-0.15625 -5.17104,2.08849 -5.75771,9.90066 -1.65625,13.3125 -0.73815,5.29915 0.55713,11.35287 -0.28125,16.21875 -1.57391,2.43976 0.0174,5.43494 -1.9375,7.65625 -1.21338,8.01052 8.60308,12.27891 15.15625,10.1875 4.10866,1.15111 8.03361,-0.96492 11.90625,0.75 4.70244,-0.0919 9.41322,-0.76127 13.9375,-1.21875 6.34357,-2.47232 7.27867,-12.62071 1.1875,-15.90625 -2.84504,-3.85906 -6.71699,-8.25024 -7.5,-12.8125 2.57537,-4.33547 10.38664,-3.74912 10.125,-10.0625 0.19504,-4.87459 -4.47645,-9.43549 -9.375,-8.71875 z"
+ d="m 362.71875,595.53125 c -4.88629,0.1191 -10.06204,0.70685 -14.78125,0.75 -5.47787,-0.76679 -11.36437,-0.40783 -16.78125,-0.15625 -5.17104,2.08849 -5.75771,9.90066 -1.65625,13.3125 -0.73815,5.29915 0.55713,11.35287 -0.28125,16.21875 -1.57391,2.43976 0.0174,5.43494 -1.9375,7.65625 -1.21338,8.01052 8.60308,12.27891 15.15625,10.1875 4.10866,1.15111 8.03361,-0.96492 11.90625,0.75 4.70244,-0.0919 9.41322,-0.76127 13.9375,-1.21875 6.34357,-2.47232 7.27867,-12.62071 1.1875,-15.90625 -2.84504,-3.85906 -3.69836,-8.25024 -4.48137,-12.8125 2.57537,-4.33547 7.36801,-3.74912 7.10637,-10.0625 0.19504,-4.87459 -4.47645,-9.43549 -9.375,-8.71875 z"
id="path3217"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccc" />
<path
style="font-size:52.50814056px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:-1px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Armalite Rifle;-inkscape-font-specification:Armalite Rifle"
d="m 387.9375,595.15625 c -4.67722,2.02978 -9.78906,-1.62403 -14.46875,1.25 -9.65979,4.02935 -13.06716,17.5954 -7.09375,25.71875 -5.60204,3.65765 -3.86108,11.71823 -2.5625,17.15625 1.89135,4.23664 7.4795,4.74734 11.125,3.125 3.94271,1.07416 7.9082,-0.0824 11.78125,1.1875 12.90654,0.16282 22.05847,-17.35307 13.34375,-27.46875 4.21701,-4.46396 3.58479,-12.34862 1.53125,-17.90625 -3.12179,-4.23683 -8.89538,-1.69513 -13.1875,-3.09375 l -0.46875,0.0312 z"
inkscape:connector-curvature="0" />
<path
style="font-size:52.50814056px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:-1px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Armalite Rifle;-inkscape-font-specification:Armalite Rifle"
- d="m 413.09375,593.625 c -5.989,0.79809 -12.31873,3.77439 -13.59375,10.28125 -2.37552,6.92367 2.58427,13.98287 3.0625,20.28125 -6.66505,6.69348 -1.32209,20.82556 8.75,19.25 7.10297,0.39661 12.84047,-7.75209 9.8125,-14.21875 0.3156,-2.89071 -3.70654,-4.76237 -1.46875,-7.53125 2.44848,-7.39695 6.24638,-18.36454 -1.53125,-23.75 -0.23875,-2.6484 -2.19852,-4.85675 -5.03125,-4.3125 z"
+ d="m 413.09375,593.625 c -5.989,0.79809 -12.31873,3.77439 -13.59375,10.28125 -2.77433,6.83505 1.00514,13.63195 3.0625,20.28125 -6.66505,6.69348 -1.32209,20.82556 8.75,19.25 7.10297,0.39661 12.84047,-7.75209 9.8125,-14.21875 0.3156,-2.89071 -3.70654,-4.76237 -1.46875,-7.53125 2.44848,-7.39695 6.24638,-18.36454 -1.53125,-23.75 -0.23875,-2.6484 -2.19852,-4.85675 -5.03125,-4.3125 z"
id="path3221"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
</g>
<g
style="stroke:#000000;stroke-width:3.85294461;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
x="251.05626"
id="tspan2996"
sodipodi:role="line">TINKS!</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:50.25947571px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#e6e6e6;fill-opacity:1;stroke:none;font-family:Sans"
+ x="251.05626"
+ y="809.98505"
+ id="text3032"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3034"
+ x="251.05626"
+ y="809.98505"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;letter-spacing:-0.9571749px;fill:#e6e6e6;fill-opacity:1;font-family:Armalite Rifle;-inkscape-font-specification:Armalite Rifle">TINKS!</tspan></text>
</g>
</g>
</svg>
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
- inkscape:zoom="0.9899495"
- inkscape:cx="58.64005"
- inkscape:cy="380.00465"
+ inkscape:zoom="1.4"
+ inkscape:cx="160.56125"
+ inkscape:cy="282.40083"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
width="211.42856"
id="rect2995"
style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none" />
- <text
- xml:space="preserve"
+ <g
style="font-size:269.1137085px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
- x="299.74573"
- y="770.06946"
- id="text2997"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan2999"
- x="299.74573"
- y="770.06946">+</tspan></text>
+ id="text2997">
+ <path
+ d="m 364.00188,685.0516 -50.85303,0 0,-19.71047 50.85303,0 0,-51.11584 19.71048,0 0,51.11584 50.85303,0 0,19.71047 -50.85303,0 0,50.59023 -19.71048,0 0,-50.59023"
+ style=""
+ id="path2996" />
+ </g>
<path
inkscape:connector-curvature="0"
id="path3018"
id="path2997"
style="font-size:202.30386353px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
d="m 179.68975,735.88154 c -1e-5,-2.50244 0.32926,-4.60977 0.98782,-6.32199 0.65852,-1.77805 1.54755,-3.19391 2.66709,-4.2476 1.1195,-1.11949 2.43658,-1.90974 3.95125,-2.37074 1.51462,-0.52681 3.16097,-0.79023 4.93905,-0.79025 1.71218,2e-5 3.32561,0.26344 4.84028,0.79025 1.58047,0.461 2.93048,1.25125 4.05003,2.37074 1.11948,1.05369 2.00851,2.46955 2.66709,4.2476 0.65851,1.71222 0.98778,3.81955 0.98782,6.32199 -4e-5,2.43661 -0.32931,4.54394 -0.98782,6.322 -0.65858,1.71221 -1.54761,3.12807 -2.66709,4.24759 -1.11955,1.11952 -2.46956,1.94269 -4.05003,2.46953 -1.51467,0.52683 -3.1281,0.79024 -4.84028,0.79025 -1.77808,-10e-6 -3.42443,-0.26342 -4.93905,-0.79025 -1.51467,-0.52684 -2.83175,-1.35001 -3.95125,-2.46953 -1.11954,-1.11952 -2.00857,-2.53538 -2.66709,-4.24759 -0.65856,-1.77806 -0.98783,-3.88539 -0.98782,-6.322" />
- <text
- xml:space="preserve"
+ <g
style="font-size:269.1137085px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
- x="64.031456"
- y="1006.8839"
- id="text3013"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3015"
- x="64.031456"
- y="1006.8839">=</tspan></text>
+ id="text3013">
+ <path
+ d="m 77.43458,894.9284 0,-19.57907 121.41654,0 0,19.57907 -121.41654,0 m 0,53.87531 0,-19.71048 121.41654,0 0,19.71048 -121.41654,0"
+ style=""
+ id="path2999" />
+ </g>
</g>
</svg>
mkdir -p bin
../../bin/nitc -o bin/ballz.apk src/ballz_android.nit
+android-release: icon
+ mkdir -p bin
+ ../../bin/nitc -o bin/ballz.apk src/ballz_android.nit --release
+
linux:
mkdir -p bin
../../bin/nitc -o bin/ballz src/ballz_linux.nit
mkdir -p bin
../../bin/nitc -o bin/dino.apk src/dino_android.nit
+android-release: android-icons
+ mkdir -p bin
+ ../../bin/nitc -o bin/dino.apk src/dino_android.nit --release
+
../../contrib/inkscape_tools/bin/svg_to_icons:
$(MAKE) -C ../../contrib/inkscape_tools
import sha1
-print "Rosetta Code".sha1_to_s
+print "Rosetta Code".sha1.hexdigest
mkdir -p bin
../../bin/nitc -o bin/shoot.apk src/shoot_android.nit
+android-release:
+ mkdir -p bin
+ ../../bin/nitc -o bin/shoot.apk src/shoot_android.nit --release
+
null:
mkdir -p bin
../../bin/nitc -o bin/shoot_null src/shoot_null.nit
# Offers the base 64 encoding and decoding algorithms
module base64
-redef class String
-
+redef class NativeString
# Alphabet used by the base64 algorithm
- private fun base64_chars : String
+ private fun base64_chars : SequenceRead[Byte]
do
- return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+ return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".bytes
end
+
+ # Reversed alphabet for base64
private fun inverted_base64_chars : HashMap[Byte, Byte]
do
var inv_base64_chars = new HashMap[Byte, Byte]
- for k in [0..base64_chars.bytelen[ do
- inv_base64_chars[base64_chars.bytes[k]] = k.to_b
+ var l = base64_chars.length
+ for k in [0 .. l[ do
+ inv_base64_chars[base64_chars[k]] = k.to_b
end
return inv_base64_chars
end
- # Encodes the receiver string to base64.
+ # Encodes `self` to base64.
+ #
# By default, uses "=" for padding.
- fun encode_base64 : String do return encode_base64_custom_padding('='.ascii.to_b)
-
- # Encodes the receiver string to base64 using a custom padding character.
#
- # If using the default padding character `=`, see `encode_base64`.
- fun encode_base64_custom_padding(padding : Byte) : String
- do
- var base64_bytes = once base64_chars.bytes
- var length = bytelen
-
+ # assert "string".encode_base64 == "c3RyaW5n"
+ private fun encode_base64(length: Int, padding: nullable Byte): Bytes do
+ var base64_bytes = once base64_chars
+ if padding == null then padding = '='.ascii.to_b
var steps = length / 3
var bytes_in_last_step = length % 3
var result_length = steps * 4
if bytes_in_last_step > 0 then result_length += 4
- var result = new NativeString(result_length + 1)
- var bytes = self.bytes
- result[result_length] = 0u8
-
- var mask_6bit = 0b0011_1111
+ var result = new Bytes.with_capacity(result_length)
+ var in_off = 0
for s in [0 .. steps[ do
- var e = 0
- for ss in [0 .. 3[ do
- e += bytes[s * 3 + ss].to_i << ((2 - ss) * 8)
- end
- for ss in [0..4[ do
- result[s * 4 + 3 - ss] = base64_bytes[(e >> (ss * 6)) & mask_6bit]
- end
+ var ind = ((self[in_off] & 0b1111_1100u8) >> 2).to_i
+ result.add base64_bytes[ind]
+ ind = ((self[in_off] & 0b0000_0011u8) << 4).to_i | ((self[in_off + 1] & 0b1111_0000u8) >> 4).to_i
+ result.add base64_bytes[ind]
+ ind = ((self[in_off + 1] & 0b0000_1111u8) << 2).to_i | ((self[in_off + 2] & 0b1100_0000u8) >> 6).to_i
+ result.add base64_bytes[ind]
+ ind = (self[in_off + 2] & 0b0011_1111u8).to_i
+ result.add base64_bytes[ind]
+ in_off += 3
end
-
- var out_off = result_length - 4
- var in_off = length - bytes_in_last_step
if bytes_in_last_step == 1 then
- result[out_off] = base64_bytes[((bytes[in_off] & 0b1111_1100u8) >> 2).to_i]
- result[out_off + 1] = base64_bytes[((bytes[in_off] & 0b0000_0011u8) << 4).to_i]
- out_off += 2
+ result.add base64_bytes[((self[in_off] & 0b1111_1100u8) >> 2).to_i]
+ result.add base64_bytes[((self[in_off] & 0b0000_0011u8) << 4).to_i]
else if bytes_in_last_step == 2 then
- result[out_off] = base64_bytes[((bytes[in_off] & 0b1111_1100u8) >> 2).to_i]
- result[out_off + 1] = base64_bytes[(((bytes[in_off] & 0b0000_0011u8) << 4) | ((bytes[in_off + 1] & 0b1111_0000u8) >> 4)).to_i]
- result[out_off + 2] = base64_bytes[((bytes[in_off + 1] & 0b0000_1111u8) << 2).to_i]
- out_off += 3
- end
- if bytes_in_last_step > 0 then
- for i in [out_off .. result_length[ do result[i] = padding
+ result.add base64_bytes[((self[in_off] & 0b1111_1100u8) >> 2).to_i]
+ result.add base64_bytes[(((self[in_off] & 0b0000_0011u8) << 4) | ((self[in_off + 1] & 0b1111_0000u8) >> 4)).to_i]
+ result.add base64_bytes[((self[in_off + 1] & 0b0000_1111u8) << 2).to_i]
end
+ var rempad = if bytes_in_last_step > 0 then 3 - bytes_in_last_step else 0
+ for i in [0 .. rempad[ do result.add padding
- return result.to_s_with_length(result_length)
+ return result
end
- # Decodes the receiver string from base64.
- # By default, uses "=" for padding.
- fun decode_base64 : String do return decode_base64_custom_padding('='.ascii.to_b)
-
- # Decodes the receiver string to base64 using a custom padding character.
+ # Decodes `self` from base64
#
- # If using the default padding character `=`, see `decode_base64`.
- fun decode_base64_custom_padding(padding : Byte) : String
- do
+ # assert "c3RyaW5n".decode_base64 == "string"
+ #
+ # REQUIRE: `length % 4 == 0`
+ private fun decode_base64(length: Int, padding: nullable Byte): Bytes do
+ if padding == null then padding = '='.ascii.to_b
var inv = once inverted_base64_chars
- var length = bytelen
- if length == 0 then return ""
+ if length == 0 then return new Bytes.empty
assert length % 4 == 0 else print "base64::decode_base64 only supports strings of length multiple of 4"
- var bytes = self.bytes
+ var bytes = self
var steps = length / 4
var result_length = steps * 3
if padding_len == 1 then result_length -= 1
if padding_len == 2 then result_length -= 2
- var result = new NativeString(result_length + 1)
- result[result_length] = 0u8
+ var result = new Bytes.with_capacity(result_length + 1)
for s in [0 .. steps[ do
var c0 = inv[bytes[s * 4]]
var c1 = inv[bytes[s * 4 + 1]]
var c2 = inv[bytes[s * 4 + 2]]
var c3 = inv[bytes[s * 4 + 3]]
- result[s * 3] = ((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4)
- result[s * 3 + 1] = ((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2)
- result[s * 3 + 2] = ((c2 & 0b0000_0011u8) << 6) | (c3 & 0b0011_1111u8)
+ result.add (((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4))
+ result.add (((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2))
+ result.add (((c2 & 0b0000_0011u8) << 6) | (c3 & 0b0011_1111u8))
end
var last_start = steps * 4
var c0 = inv[bytes[last_start]]
var c1 = inv[bytes[last_start + 1]]
var c2 = inv[bytes[last_start + 2]]
- result[result_length - 2] = ((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4)
- result[result_length - 1] = ((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2)
+ result.add (((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4))
+ result.add (((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2))
else if padding_len == 2 then
var c0 = inv[bytes[last_start]]
var c1 = inv[bytes[last_start + 1]]
- result[result_length - 1] = ((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4)
+ result.add (((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4))
end
- return result.to_s_with_length(result_length)
+ return result
+ end
+end
+
+redef class Bytes
+
+ # Encodes the receiver string to base64 using a custom padding character.
+ #
+ # If using the default padding character `=`, see `encode_base64`.
+ fun encode_base64(padding: nullable Byte): Bytes
+ do
+ return items.encode_base64(length, padding)
+ end
+
+ # Decodes the receiver string to base64 using a custom padding character.
+ #
+ # Default padding character `=`
+ fun decode_base64(padding : nullable Byte) : Bytes
+ do
+ return items.decode_base64(length, padding)
+ end
+end
+
+redef class String
+
+ # Encodes the receiver string to base64 using a custom padding character.
+ #
+ # If using the default padding character `=`, see `encode_base64`.
+ fun encode_base64(padding: nullable Byte): String
+ do
+ return to_cstring.encode_base64(bytelen, padding).to_s
+ end
+
+ # Decodes the receiver string to base64 using a custom padding character.
+ #
+ # Default padding character `=`
+ fun decode_base64(padding : nullable Byte) : String
+ do
+ return to_cstring.decode_base64(bytelen, padding).to_s
end
end
import collection::array
intrude import text::flat
+redef class Byte
+ # Write self as a string into `ns` at position `pos`
+ private fun add_digest_at(ns: NativeString, pos: Int) do
+ var tmp = (0xF0u8 & self) >> 4
+ ns[pos] = if tmp >= 0x0Au8 then tmp + 0x37u8 else tmp + 0x30u8
+ tmp = 0x0Fu8 & self
+ ns[pos + 1] = if tmp >= 0x0Au8 then tmp + 0x37u8 else tmp + 0x30u8
+ end
+
+ # Is `self` a valid hexadecimal digit (in ASCII)
+ #
+ # ~~~nit
+ # intrude import core::bytes
+ # assert not '/'.ascii.to_b.is_valid_hexdigit
+ # assert '0'.ascii.to_b.is_valid_hexdigit
+ # assert '9'.ascii.to_b.is_valid_hexdigit
+ # assert not ':'.ascii.to_b.is_valid_hexdigit
+ # assert not '@'.ascii.to_b.is_valid_hexdigit
+ # assert 'A'.ascii.to_b.is_valid_hexdigit
+ # assert 'F'.ascii.to_b.is_valid_hexdigit
+ # assert not 'G'.ascii.to_b.is_valid_hexdigit
+ # assert not '`'.ascii.to_b.is_valid_hexdigit
+ # assert 'a'.ascii.to_b.is_valid_hexdigit
+ # assert 'f'.ascii.to_b.is_valid_hexdigit
+ # assert not 'g'.ascii.to_b.is_valid_hexdigit
+ # ~~~
+ private fun is_valid_hexdigit: Bool do
+ return (self >= 0x30u8 and self <= 0x39u8) or
+ (self >= 0x41u8 and self <= 0x46u8) or
+ (self >= 0x61u8 and self <= 0x66u8)
+ end
+
+ # `self` as a hexdigit to its byte value
+ #
+ # ~~~nit
+ # intrude import core::bytes
+ # assert 0x39u8.hexdigit_to_byteval == 0x09u8
+ # assert 0x43u8.hexdigit_to_byteval == 0x0Cu8
+ # ~~~
+ #
+ # REQUIRE: `self.is_valid_hexdigit`
+ private fun hexdigit_to_byteval: Byte do
+ if self >= 0x30u8 and self <= 0x39u8 then
+ return self - 0x30u8
+ else if self >= 0x41u8 and self <= 0x46u8 then
+ return self - 0x37u8
+ else if self >= 0x61u8 and self <= 0x66u8 then
+ return self - 0x57u8
+ end
+ # Happens only if the requirement is not met.
+ # i.e. this abort is here to please the compiler
+ abort
+ end
+end
+
# A buffer containing Byte-manipulation facilities
#
# Uses Copy-On-Write when persisted
super AbstractArray[Byte]
# A NativeString being a char*, it can be used as underlying representation here.
- private var items: NativeString
+ var items: NativeString
# Number of bytes in the array
redef var length
return items[i]
end
+ # Returns self as a hexadecimal digest
+ fun hexdigest: String do
+ var elen = length * 2
+ var ns = new NativeString(elen)
+ var i = 0
+ var oi = 0
+ while i < length do
+ self[i].add_digest_at(ns, oi)
+ i += 1
+ oi += 2
+ end
+ return new FlatString.full(ns, elen, 0, elen - 1, elen)
+ end
+
# var b = new Bytes.with_capacity(1)
# b[0] = 101u8
# assert b.to_s == "e"
redef fun to_s do
persisted = true
var b = self
- if not is_utf8 then
- b = clean_utf8
- persisted = false
- end
- return new FlatString.with_infos(b.items, b.length, 0, b.length -1)
+ var r = b.items.to_s_with_length(length)
+ if r != items then persisted = false
+ return r
end
redef fun iterator do return new BytesIterator.with_buffer(self)
- # Is the byte collection valid UTF-8 ?
- fun is_utf8: Bool do
- var charst = once [0x80u8, 0u8, 0xE0u8, 0xC0u8, 0xF0u8, 0xE0u8, 0xF8u8, 0xF0u8]
- var lobounds = once [0, 0x80, 0x800, 0x10000]
- var hibounds = once [0x7F, 0x7FF, 0xFFFF, 0x10FFFF]
- var pos = 0
- var len = length
- var mits = items
- while pos < len do
- var nxst = mits.length_of_char_at(pos)
- var charst_index = (nxst - 1) * 2
- if mits[pos] & charst[charst_index] == charst[charst_index + 1] then
- var c = mits.char_at(pos)
- var cp = c.ascii
- if cp <= hibounds[nxst - 1] and cp >= lobounds[nxst - 1] then
- if cp >= 0xD800 and cp <= 0xDFFF or
- cp == 0xFFFE or cp == 0xFFFF then return false
- else
- return false
- end
- else
- return false
- end
- pos += nxst
- end
- return true
- end
-
- # Cleans the bytes of `self` to be UTF-8 compliant
- private fun clean_utf8: Bytes do
- var charst = once [0x80u8, 0u8, 0xE0u8, 0xC0u8, 0xF0u8, 0xE0u8, 0xF8u8, 0xF0u8]
- var badchar = once [0xEFu8, 0xBFu8, 0xBDu8]
- var lobounds = once [0, 0x80, 0x800, 0x10000]
- var hibounds = once [0x7F, 0x7FF, 0xFFFF, 0x10FFFF]
- var pos = 0
- var len = length
- var ret = new Bytes.with_capacity(len)
- var mits = items
- while pos < len do
- var nxst = mits.length_of_char_at(pos)
- var charst_index = (nxst - 1) * 2
- if mits[pos] & charst[charst_index] == charst[charst_index + 1] then
- var c = mits.char_at(pos)
- var cp = c.ascii
- if cp <= hibounds[nxst - 1] and cp >= lobounds[nxst - 1] then
- if cp >= 0xD800 and cp <= 0xDFFF or
- cp == 0xFFFE or cp == 0xFFFF then
- ret.append badchar
- pos += 1
- else
- var pend = pos + nxst
- for i in [pos .. pend[ do ret.add mits[i]
- pos += nxst
- end
- else
- ret.append badchar
- pos += 1
- end
- else
- ret.append badchar
- pos += 1
- end
- end
- return ret
- end
end
private class BytesIterator
var max: Int
- init with_buffer(b: Bytes) do init(b.items, 0, b.length - 1)
+ init with_buffer(b: Bytes) do init(b.items, 0, b.length)
redef fun is_ok do return index < max
return b
end
+ # Is `self` a valid hexdigest ?
+ #
+ # assert "0B1d3F".is_valid_hexdigest
+ # assert not "5G".is_valid_hexdigest
+ fun is_valid_hexdigest: Bool do
+ for i in bytes do if not i.is_valid_hexdigit then return false
+ return true
+ end
+
# Appends `self.bytes` to `b`
fun append_to_bytes(b: Bytes) do
for s in substrings do
b.append_ns_from(s.items, s.bytelen, from)
end
end
+
+ # Returns a new `Bytes` instance with the digest as content
+ #
+ # assert "0B1F4D".hexdigest_to_bytes == [0x0Bu8, 0x1Fu8, 0x4Du8]
+ #
+ # REQUIRE: `self` is a valid hexdigest and hexdigest.length % 2 == 0
+ fun hexdigest_to_bytes: Bytes do
+ var b = bytes
+ var pos = 0
+ var max = bytelen
+ var ret = new Bytes.with_capacity(max / 2)
+ while pos < max do
+ ret.add((b[pos].hexdigit_to_byteval << 4) |
+ b[pos + 1].hexdigit_to_byteval)
+ pos += 2
+ end
+ return ret
+ end
end
redef class FlatText
# ~~~
fun read_all: String do
var s = read_all_bytes
- if not s.is_utf8 then s = s.clean_utf8
var slen = s.length
if slen == 0 then return ""
var rets = ""
var pos = 0
- var sits = s.items
+ var str = s.items.clean_utf8(slen)
+ slen = str.bytelen
+ var sits = str.items
var remsp = slen
while pos < slen do
# The 129 size was decided more or less arbitrarily
redef fun to_s_with_length(length): FlatString
do
assert length >= 0
- var str = new FlatString.with_infos(self, length, 0, length - 1)
- return str
+ return clean_utf8(length)
end
redef fun to_s_full(bytelen, unilen) do
redef fun to_s_with_copy: FlatString
do
var length = cstring_length
+ var r = clean_utf8(length)
+ if r.items != self then return r
var new_self = new NativeString(length + 1)
copy_to(new_self, length, 0, 0)
var str = new FlatString.with_infos(new_self, length, 0, length - 1)
return str
end
+ # Cleans a NativeString if necessary
+ fun clean_utf8(len: Int): FlatString do
+ var replacements: nullable Array[Int] = null
+ var end_length = len
+ var pos = 0
+ var chr_ln = 0
+ while pos < len do
+ var b = self[pos]
+ var nxst = length_of_char_at(pos)
+ var ok_st: Bool
+ if nxst == 1 then
+ ok_st = b & 0x80u8 == 0u8
+ else if nxst == 2 then
+ ok_st = b & 0xE0u8 == 0xC0u8
+ else if nxst == 3 then
+ ok_st = b & 0xF0u8 == 0xE0u8
+ else
+ ok_st = b & 0xF8u8 == 0xF0u8
+ end
+ if not ok_st then
+ if replacements == null then replacements = new Array[Int]
+ replacements.add pos
+ end_length += 2
+ pos += 1
+ chr_ln += 1
+ continue
+ end
+ var ok_c: Bool
+ var c = char_at(pos)
+ var cp = c.ascii
+ if nxst == 1 then
+ ok_c = cp >= 0 and cp <= 0x7F
+ else if nxst == 2 then
+ ok_c = cp >= 0x80 and cp <= 0x7FF
+ else if nxst == 3 then
+ ok_c = cp >= 0x800 and cp <= 0xFFFF
+ ok_c = ok_c and not (cp >= 0xD800 and cp <= 0xDFFF) and cp != 0xFFFE and cp != 0xFFFF
+ else
+ ok_c = cp >= 0x10000 and cp <= 0x10FFFF
+ end
+ if not ok_c then
+ if replacements == null then replacements = new Array[Int]
+ replacements.add pos
+ end_length += 2
+ pos += 1
+ chr_ln += 1
+ continue
+ end
+ pos += c.u8char_len
+ chr_ln += 1
+ end
+ var ret = self
+ if end_length != len then
+ ret = new NativeString(end_length)
+ var old_repl = 0
+ var off = 0
+ var repls = replacements.as(not null)
+ var r = repls.items.as(not null)
+ var imax = repls.length
+ for i in [0 .. imax[ do
+ var repl_pos = r[i]
+ var chkln = repl_pos - old_repl
+ copy_to(ret, chkln, old_repl, off)
+ off += chkln
+ ret[off] = 0xEFu8
+ ret[off + 1] = 0xBFu8
+ ret[off + 2] = 0xBDu8
+ old_repl = repl_pos + 1
+ off += 3
+ end
+ copy_to(ret, len - old_repl, old_repl, off)
+ end
+ return new FlatString.full(ret, end_length, 0, end_length - 1, chr_ln)
+ end
+
# Sets the next bytes at position `pos` to the value of `c`, encoded in UTF-8
#
# Very unsafe, make sure to have room for this char prior to calling this function.
end
i += 1
end
- return ns.to_s_with_length(sl)
+ return new FlatString.with_infos(ns, sl, 0, sl - 1)
end
end
end
i += 1
end
- return ns.to_s_with_length(sl)
+ return new FlatString.with_infos(ns, sl, 0, sl - 1)
end
end
# This file is part of NIT (http://www.nitlanguage.org).
#
-# Copyright 2014 Lucas Bajolet <r4pass@hotmail.com>
-#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
}
`}
-redef class String
-
- # Computes the SHA1 of the receiver
- #
- # Returns a digest of 20 bytes as a String,
- # note that all the characters are not necessarily ASCII.
- # If you want the hex string version of the digest, use
- # sha1_to_s.
- #
- # import base64
- # assert "The quick brown fox jumps over the lazy dog".sha1.encode_base64 == "L9ThxnotKPzthJ7hu3bnORuT6xI="
- fun sha1: String import String.to_cstring, String.length, NativeString.to_s_with_length `{
+redef class NativeString
+ private fun sha1_intern(len: Int): NativeString `{
sha1nfo s;
sha1_init(&s);
- sha1_write(&s, String_to_cstring(self), String_length(self));
+ sha1_write(&s, self, len);
uint8_t* digest = sha1_result(&s);
char* digested = malloc(21);
digested[20] = '\0';
- return NativeString_to_s_with_length(digested, 20);
+ return digested;
`}
+end
+
+redef class String
+
+ # Computes the SHA1 of the receiver
+ #
+ # Returns a digest of 20 bytes as a NativeString,
+ # note that all the characters are not necessarily ASCII.
+ # If you want the hex string version of the digest, use
+ # sha1_hexdigest.
+ #
+ # import base64
+ # assert "The quick brown fox jumps over the lazy dog".sha1 == [0x2Fu8, 0xD4u8, 0xE1u8, 0xC6u8, 0x7Au8, 0x2Du8, 0x28u8, 0xFCu8, 0xEDu8, 0x84u8, 0x9Eu8, 0xE1u8, 0xBBu8, 0x76u8, 0xE7u8, 0x39u8, 0x1Bu8, 0x93u8, 0xEBu8, 0x12u8]
+ fun sha1: Bytes do
+ return new Bytes(to_cstring.sha1_intern(bytelen), 20, 20)
+ end
# Computes the SHA1 of the receiver.
#
# Returns a 40 char String containing the Hexadecimal
# Digest in its Char form.
#
- # assert "The quick brown fox jumps over the lazy dog".sha1_to_s == "2FD4E1C67A2D28FCED849EE1BB76E7391B93EB12"
- fun sha1_to_s: String import String.to_cstring, String.length, NativeString.to_s_with_length `{
- sha1nfo s;
-
- sha1_init(&s);
- sha1_write(&s, String_to_cstring(self), String_length(self));
- uint8_t* digest = sha1_result(&s);
-
- char* ret_str = malloc(41);
- char* hexmap = "0123456789ABCDEF";
-
- int i;
- for(i=0;i<20;i++){
- uint8_t q = digest[i];
- ret_str[i*2] = hexmap[q >> 4];
- ret_str[(i*2)+1] = hexmap[q & 0x0F];
- }
- ret_str[40] = '\0';
-
- return NativeString_to_s_with_length(ret_str, 40);
- `}
-
+ # assert "The quick brown fox jumps over the lazy dog".sha1_hexdigest == "2FD4E1C67A2D28FCED849EE1BB76E7391B93EB12"
+ fun sha1_hexdigest: String do return sha1.hexdigest
end
-
resp_map["Connection:"] = "Upgrade"
var key = heads["Sec-WebSocket-Key"]
key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
- key = key.sha1.encode_base64
+ key = key.sha1.encode_base64.to_s
resp_map["Sec-WebSocket-Accept:"] = key
var resp = resp_map.join("\r\n", " ")
resp += "\r\n\r\n"
# Placeholder to include additional things before the `</head>`.
var more_head = new Template
+ # Relative path to the root directory (with the index file).
+ #
+ # Use "" for pages in the root directory
+ # Use ".." for pages in a subdirectory
+ var rootpath: String
+
redef init
do
add """
<head>
<meta charset="utf-8">
<link rel="stylesheet" media="all" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
- <link rel="stylesheet" media="all" href="style.css">
+ <link rel="stylesheet" media="all" href="{{{rootpath / "style.css"}}}">
"""
add more_head
</div>
<div class='collapse navbar-collapse' id='topmenu-collapse'>
<ul class='nav navbar-nav'>
- <li><a href="index.html">Catalog</a></li>
+ <li><a href="{{{rootpath / "index.html"}}}">Catalog</a></li>
</ul>
</div>
</div>
# Compute information and generate a full HTML page for a package
fun package_page(mpackage: MPackage): Writable
do
- var res = new CatalogPage
+ var res = new CatalogPage("..")
var score = score[mpackage].to_f
var name = mpackage.name.html_escape
res.more_head.add """<title>{{{name}}}</title>"""
if cat == null then cat = t
tag2proj[t].add mpackage
t = t.html_escape
- ts2.add "<a href=\"index.html#tag_{t}\">{t}</a>"
+ ts2.add "<a href=\"../index.html#tag_{t}\">{t}</a>"
end
res.add_list(ts2, ", ", ", ")
end
var t = "none"
cat = t
tag2proj[t].add mpackage
- res.add "<a href=\"index.html#tag_{t}\">{t}</a>"
+ res.add "<a href=\"../index.html#tag_{t}\">{t}</a>"
end
if cat != null then cat2proj[cat].add mpackage
score += ts2.length.score
fun li_package(p: MPackage): String
do
var res = ""
- var f = "{p.name}.html"
+ var f = "p/{p.name}.html"
res += "<a href=\"{f}\">{p}</a>"
var d = p.mdoc_or_fallback
if d != null then res += " - {d.html_synopsis.write_to_string}"
res.add "</tr></thead>"
for p in mpackages do
res.add "<tr>"
- res.add "<td><a href=\"{p.name}.html\">{p.name}</a></td>"
+ res.add "<td><a href=\"p/{p.name}.html\">{p.name}</a></td>"
var maint = "?"
if p.maintainers.not_empty then maint = p.maintainers.first
res.add "<td>{maint}</td>"
end
var out = opt_dir.value or else "catalog.out"
-out.mkdir
+(out/"p").mkdir
# Generate the css (hard coded)
var css = """
for p in model.mpackages do
# print p
- var f = "{p.name}.html"
+ var f = "p/{p.name}.html"
catalog.package_page(p).write_to_file(out/f)
end
# INDEX
-var index = new CatalogPage
+var index = new CatalogPage("")
index.more_head.add "<title>Packages in Nit</title>"
index.add """
# PEOPLE
-var page = new CatalogPage
+var page = new CatalogPage("")
page.more_head.add "<title>People of Nit</title>"
page.add """<div class="content">\n<h1>People of Nit</h1>\n"""
page.add "<h2>By Maintainer</h2>\n"
# TABLE
-page = new CatalogPage
+page = new CatalogPage("")
page.more_head.add "<title>Projets of Nit</title>"
page.add """<div class="content">\n<h1>People of Nit</h1>\n"""
page.add "<h2>Table of Projets</h2>\n"
FlatString = 18
Calls to first_byte on FlatString 153
Calls to last_byte on FlatString 103
-FlatStrings allocated with length 81 (85.417%)
+FlatStrings allocated with length 82 (86.458%)
Length of travel for index distribution:
* null = 20 => occurences 83.333%, cumulative 83.333%
* 1 = 8 => occurences 21.053%, cumulative 73.684%
if name == "Array[nullable Object]" then return new Array[nullable Object].from_deserializer(self)
if name == "Array[Serializable]" then return new Array[Serializable].from_deserializer(self)
if name == "Array[Object]" then return new Array[Object].from_deserializer(self)
+ if name == "Array[Int]" then return new Array[Int].from_deserializer(self)
if name == "Array[Match]" then return new Array[Match].from_deserializer(self)
if name == "Array[nullable Match]" then return new Array[nullable Match].from_deserializer(self)
return super
--- /dev/null
+0x0b
+0x1f
+0x4d
FlatString = 18
Calls to first_byte on FlatString 153
Calls to last_byte on FlatString 103
-FlatStrings allocated with length 81 (85.417%)
+FlatStrings allocated with length 82 (86.458%)
Length of travel for index distribution:
* 0 = 20 => occurences 83.333%, cumulative 83.333%
* 1 = 8 => occurences 21.053%, cumulative 73.684%
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+var s = "0B1F4D".hexdigest_to_bytes
+
+for i in s do print i