Compare commits
40 Commits
b70d452341
...
master
Author | SHA1 | Date | |
---|---|---|---|
4ecaa1a216 | |||
fcef1277f3 | |||
8507082995 | |||
e091a825ce | |||
8501f2f473 | |||
bfdc5dc93b | |||
d81425a781 | |||
62f9f2677d | |||
95918841b0 | |||
419e67f80a | |||
38135762f6 | |||
5c03647a4a | |||
3ee1155e1f | |||
efb36f83fc | |||
d28bd6ed1c | |||
45c5b94e63 | |||
0f1e8d5e36 | |||
57405f5aac | |||
8500f351fc | |||
268e3b6a47 | |||
a50f49d2c8 | |||
fb1a0435c1 | |||
490552f9bd | |||
07b1461635 | |||
d5c907859b | |||
f45f47b572 | |||
4daea2121b | |||
e18f58c0d0 | |||
9a62c4918f | |||
8f668a032f | |||
243b14b247 | |||
869e89188d | |||
ee767d8067 | |||
29d579b8ac | |||
542510f5d0 | |||
66b3b590b7 | |||
f22f52eebe | |||
138644d870 | |||
29dd89f729 | |||
5fe9b2c913 |
6
.gitattributes
vendored
Normal file
6
.gitattributes
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
# All line endings should be unix
|
||||
* text eol=lf
|
||||
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.exe binary
|
10
.gitignore
vendored
10
.gitignore
vendored
@ -1,2 +1,10 @@
|
||||
# Racket related files
|
||||
*.bak
|
||||
.nyc_output
|
||||
|
||||
# Javascript related files
|
||||
.nyc_output
|
||||
|
||||
# Python related files
|
||||
.pytest_cache
|
||||
.coverage
|
||||
__pycache__
|
92
assignments/A3/example1.json
Normal file
92
assignments/A3/example1.json
Normal file
@ -0,0 +1,92 @@
|
||||
[
|
||||
[
|
||||
[
|
||||
{
|
||||
"id": "20091117232137.GA7669@griffis1.net",
|
||||
"match": false,
|
||||
"excluded": false,
|
||||
"filename": [
|
||||
"/home/bremner/Maildir/unb/.list.notmuch/cur/1324645067.000017.mbox:2,"
|
||||
],
|
||||
"timestamp": 1258500098,
|
||||
"date_relative": "2009-11-17",
|
||||
"tags": [
|
||||
"unread"
|
||||
],
|
||||
"headers": {
|
||||
"Subject": "[notmuch] archive",
|
||||
"From": "Aron Griffis <agriffis@n01se.net>",
|
||||
"To": "notmuch <notmuch@notmuchmail.org>",
|
||||
"Date": "Tue, 17 Nov 2009 18:21:38 -0500"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"id": 1,
|
||||
"content-type": "text/plain",
|
||||
"content-disposition": "inline",
|
||||
"content": "Just subscribed, I'd like to catch up on the previous postings,\nbut the archive link seems to be bogus?\n\nThanks,\nAron\n\n"
|
||||
}
|
||||
]
|
||||
},
|
||||
[
|
||||
[
|
||||
{
|
||||
"id": "yunzl6kd1w0.fsf@aiko.keithp.com",
|
||||
"match": true,
|
||||
"excluded": false,
|
||||
"filename": [
|
||||
"/home/bremner/Maildir/unb/.list.notmuch/cur/1324645067.000028.mbox:2,S"
|
||||
],
|
||||
"timestamp": 1258509871,
|
||||
"date_relative": "2009-11-17",
|
||||
"tags": [],
|
||||
"headers": {
|
||||
"Subject": "Re: [notmuch] archive",
|
||||
"From": "Keith Packard <keithp@keithp.com>",
|
||||
"To": "Aron Griffis <agriffis@n01se.net>, notmuch <notmuch@notmuchmail.org>",
|
||||
"Date": "Tue, 17 Nov 2009 18:04:31 -0800"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"id": 1,
|
||||
"content-type": "text/plain",
|
||||
"content": "On Tue, 17 Nov 2009 18:21:38 -0500, Aron Griffis <agriffis@n01se.net> wrote:\n\n> Just subscribed, I'd like to catch up on the previous postings,\n> but the archive link seems to be bogus?\n\nYeah, the archive appears broken and will need to wait until Carl\narrives in Barcelona to get fixed.\n\n--\nkeith.packard@intel.com\n\n\n\n"
|
||||
}
|
||||
]
|
||||
},
|
||||
[
|
||||
[
|
||||
{
|
||||
"id": "87iqd8qgiz.fsf@yoom.home.cworth.org",
|
||||
"match": false,
|
||||
"excluded": false,
|
||||
"filename": [
|
||||
"/home/bremner/Maildir/unb/.list.notmuch/cur/1324645067.000042.mbox:2,"
|
||||
],
|
||||
"timestamp": 1258539732,
|
||||
"date_relative": "2009-11-18",
|
||||
"tags": [
|
||||
"unread"
|
||||
],
|
||||
"headers": {
|
||||
"Subject": "Re: [notmuch] archive",
|
||||
"From": "Carl Worth <cworth@cworth.org>",
|
||||
"To": "Keith Packard <keithp@keithp.com>, Aron Griffis <agriffis@n01se.net>, notmuch <notmuch@notmuchmail.org>",
|
||||
"Date": "Wed, 18 Nov 2009 02:22:12 -0800"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"id": 1,
|
||||
"content-type": "text/plain",
|
||||
"content": "On Tue, 17 Nov 2009 18:04:31 -0800, Keith Packard <keithp@keithp.com> wrote:\n> On Tue, 17 Nov 2009 18:21:38 -0500, Aron Griffis <agriffis@n01se.net> wrote:\n> \n> > Just subscribed, I'd like to catch up on the previous postings,\n> > but the archive link seems to be bogus?\n> \n> Yeah, the archive appears broken and will need to wait until Carl\n> arrives in Barcelona to get fixed.\n\nFixed it in transit in Frankfurt---with only moments to spare on my\nbattery and no outlets in sight.\n\nThanks for the report, Aron. And welcome to notmuch!\n\n-Carl (who wants to reply to a lot more mail, but will have to wait\n until later for that)\n\n"
|
||||
}
|
||||
]
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
346
assignments/A3/example2.json
Normal file
346
assignments/A3/example2.json
Normal file
@ -0,0 +1,346 @@
|
||||
[
|
||||
[
|
||||
[
|
||||
{
|
||||
"id": "20101026131106.3791.46291.reportbug@i7",
|
||||
"match": false,
|
||||
"excluded": false,
|
||||
"filename": [
|
||||
"/home/bremner/Maildir/unb/.list.debian-devel/cur/1288099996.28935.pivot.cs.unb.ca:2,S"
|
||||
],
|
||||
"timestamp": 1288098666,
|
||||
"date_relative": "2010-10-26",
|
||||
"tags": [],
|
||||
"headers": {
|
||||
"Subject": "Bug#601455: general: can't stop daemon using /etc/init.d/foo stop when disabled via /etc/default/foo",
|
||||
"From": "Mathias Kub <git@makubi.at>",
|
||||
"To": "Debian Bug Tracking System <submit@bugs.debian.org>",
|
||||
"Reply-To": "Mathias Kub <git@makubi.at>, 601455@bugs.debian.org",
|
||||
"Date": "Tue, 26 Oct 2010 15:11:06 +0200"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"id": 1,
|
||||
"content-type": "text/plain",
|
||||
"content": "Package: general\nSeverity: minor\nTags: patch\n\nWhen I try to stop a daemon after I disabled it in /etc/default/foo, I get an error-message that I can not stop it, because it is disabled.\n\nShouldn't I be able to stop it even if I disabled it first?\n\nThis happens if you disabled a daemon but didn't restart after that.\n\nIn my case it's MPD, I even tried it with icecast2, but I think this applies to more than these packages.\n\n-----------\nuser@sys:~$ sudo /etc/init.d/mpd stop\nNot stopping MPD: disabled by /etc/default/mpd. failed!\n\nuser@sys:~$ sudo /etc/init.d/icecast2 stop\nicecast2 daemon disabled - read /etc/default/icecast2.\n-----------\n\nE.g. in /etc/init.d/icecast2 I changed\n- if [ \"$ENABLE\" != \"true\" ]; then\nto\n+ if [ \"$ENABLE\" != \"true\" ] && [ \"$1\" != \"stop\" ]; then\n\nBest regards,\nMathias Kub\n\n-- System Information:\nDebian Release: lenny\n\n\n\n-- \nTo UNSUBSCRIBE, email to debian-devel-REQUEST@lists.debian.org\nwith a subject of \"unsubscribe\". Trouble? Contact listmaster@lists.debian.org\nArchive: http://lists.debian.org/20101026131106.3791.46291.reportbug@i7\n\n\n"
|
||||
}
|
||||
]
|
||||
},
|
||||
[
|
||||
[
|
||||
{
|
||||
"id": "20111017041202.GA6506@elie.hsd1.il.comcast.net",
|
||||
"match": false,
|
||||
"excluded": false,
|
||||
"filename": [
|
||||
"/home/bremner/Maildir/unb/.list.debian-devel/cur/1318824935.H635656P9975.tesseract.cs.unb.ca:2,"
|
||||
],
|
||||
"timestamp": 1318824722,
|
||||
"date_relative": "2011-10-17",
|
||||
"tags": [
|
||||
"unread"
|
||||
],
|
||||
"headers": {
|
||||
"Subject": "Bug#601455: general: can't stop daemon using /etc/init.d/foo stop when disabled via /etc/default/foo",
|
||||
"From": "Jonathan Nieder <jrnieder@gmail.com>",
|
||||
"To": "Mathias Kub <git@makubi.at>",
|
||||
"Cc": "601455@bugs.debian.org",
|
||||
"Reply-To": "Jonathan Nieder <jrnieder@gmail.com>, 601455@bugs.debian.org",
|
||||
"Date": "Sun, 16 Oct 2011 23:12:02 -0500"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"id": 1,
|
||||
"content-type": "text/plain",
|
||||
"content-disposition": "inline",
|
||||
"content": "tags 601455 - patch\nretitle 601455 multiple, annoyingly different ways to disable an init script\nquit\n\nHi Mathias,\n\nMathias Kub wrote:\n\n> When I try to stop a daemon after I disabled it in /etc/default/foo,\n> I get an error-message that I can not stop it, because it is\n> disabled.\n>\n> Shouldn't I be able to stop it even if I disabled it first?\n\nYes, I agree that this is a bug. Nowadays the appropriate way\nto disable an init script is to remove the 'S' links without removing\nthe 'K' links, for example by running\n\n\tupdate-rc.d foo disable\n\nUnfortunately:\n\n 1. That is not as well known is it ought to be. For example, section\n 4.6.3. \"Restricting access to some server services\"[1] of\n debian-reference could be clarified to emphasize this method.\n\n 2. Many packages seem to provide ENABLE/DISABLE variables in\n /etc/default/foo, providing a confusing red herring for this\n task --- a second method which does not work nearly as well,\n as you pointed out.\n\n 3. The tempting \"update-rc.d foo remove\" (which removes the 'K'\n links, too) might _seem_ to work, except that the next time the\n foo package is upgraded, the service is back again.\n\nOne possible way to move forward would be to write a patch to the\ndebian reference and any other pertinent documentation to address (1)\nand (3) and (once consensus that this is a good idea is reached) to\nfile bugs requesting removal of the ENABLE/DISABLE vars to address (2),\nblocking this bug by them. When the last such variable is eliminated\nfrom the default conffiles in /etc/default, this bug could be closed.\n\nA complicating factor is that the sysadmin may already have customized\nsome ENABLE/DISABLE settings and a move like this should not override\ntheir settings. So perhaps packages should stop advertising the\nENABLE/DISABLE vars in /etc/default/<package>, but continue to respect\nthem when set.\n\nSane?\n\nThanks,\nJonathan\n\n[1] http://www.debian.org/doc/manuals/debian-reference/ch04.en.html#_restricting_access_to_some_server_services\n\n\n\n-- \nTo UNSUBSCRIBE, email to debian-devel-REQUEST@lists.debian.org\nwith a subject of \"unsubscribe\". Trouble? Contact listmaster@lists.debian.org\nArchive: http://lists.debian.org/20111017041202.GA6506@elie.hsd1.il.comcast.net\n\n"
|
||||
}
|
||||
]
|
||||
},
|
||||
[
|
||||
[
|
||||
{
|
||||
"id": "handler.s.C.131882474613866.transcript@bugs.debian.org",
|
||||
"match": true,
|
||||
"excluded": false,
|
||||
"filename": [
|
||||
"/home/bremner/Maildir/unb/.list.debian-devel/cur/1318824952.H424691P9980.tesseract.cs.unb.ca:2,S"
|
||||
],
|
||||
"timestamp": 1318824912,
|
||||
"date_relative": "2011-10-17",
|
||||
"tags": [],
|
||||
"headers": {
|
||||
"Subject": "Processed: Re: general: can't stop daemon using /etc/init.d/foo stop when disabled via /etc/default/foo",
|
||||
"From": "owner@bugs.debian.org (Debian Bug Tracking System)",
|
||||
"To": "Jonathan Nieder <jrnieder@gmail.com>",
|
||||
"Cc": "general for {601455} <debian-devel@lists.debian.org>",
|
||||
"Date": "Mon, 17 Oct 2011 04:15:12 +0000"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"id": 1,
|
||||
"content-type": "text/plain",
|
||||
"content": "Processing commands for control@bugs.debian.org:\n\n> tags 601455 - patch\nBug #601455 [general] general: can't stop daemon using /etc/init.d/foo stop when disabled via /etc/default/foo\nRemoved tag(s) patch.\n> retitle 601455 multiple, annoyingly different ways to disable an init script\nBug #601455 [general] general: can't stop daemon using /etc/init.d/foo stop when disabled via /etc/default/foo\nChanged Bug title to 'multiple, annoyingly different ways to disable an init script' from 'general: can't stop daemon using /etc/init.d/foo stop when disabled via /etc/default/foo'\n> quit\nStopping processing here.\n\nPlease contact me if you need assistance.\n-- \n601455: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=601455\nDebian Bug Tracking System\nContact owner@bugs.debian.org with problems\n\n\n-- \nTo UNSUBSCRIBE, email to debian-devel-REQUEST@lists.debian.org\nwith a subject of \"unsubscribe\". Trouble? Contact listmaster@lists.debian.org\nArchive: http://lists.debian.org/handler.s.C.131882474613866.transcript@bugs.debian.org\n\n"
|
||||
}
|
||||
]
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
{
|
||||
"id": "87efrfvc5p.fsf@iris.silentflame.com",
|
||||
"match": false,
|
||||
"excluded": false,
|
||||
"filename": [
|
||||
"/home/bremner/Maildir/tethera/cur/1504989708.H253980P5302.fethera.tethera.net:2,S"
|
||||
],
|
||||
"timestamp": 1504989618,
|
||||
"date_relative": "September 09",
|
||||
"tags": [
|
||||
"signed"
|
||||
],
|
||||
"headers": {
|
||||
"Subject": "Bug#601455: Steps towards a patch to document disabling a daemon upon installation",
|
||||
"From": "Sean Whitton <spwhitton@spwhitton.name>",
|
||||
"To": "601455@bugs.debian.org",
|
||||
"Cc": "debian-devel@lists.debian.org",
|
||||
"Reply-To": "Sean Whitton <spwhitton@spwhitton.name>, 601455@bugs.debian.org",
|
||||
"Date": "Sat, 09 Sep 2017 13:40:18 -0700"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"id": 1,
|
||||
"content-type": "multipart/signed",
|
||||
"content": [
|
||||
{
|
||||
"id": 2,
|
||||
"content-type": "text/plain",
|
||||
"content": "Hello,\n\nThis is what I have so far; it is certainly inadequate. CCing -devel\nfor help answering my technical questions about this patch.\n\n> @@ -537,6 +537,21 @@ and in your ``postrm``\n> update-rc.d package remove\n> fi\n> \n> +The default behaviour is to enable autostarting your package's daemon.\n> +If the daemon should not be autostarted unless the local administrator\n> +has explicitly requested this, use instead add to your ``postinst``\n> +script\n> +\n> +::\n> +\n> + update-rc.d package defaults\n> + update-rc.d package disable\n> +\n> +An older practice, which should not be used, was to include a line\n> +like ``DISABLED=yes`` in the package's ``/etc/default`` file. The\n> +package's init script would not start the service until the local\n> +system administrator changed this to ``DISABLED=no``, or similar.\n> +\n> Note that if your package changes runlevels or priority, you may have to\n> remove and recreate the links, since otherwise the old links may\n> persist. Refer to the documentation of ``update-rc.d``.\n\n1. Is the 'should not' for the /etc/default practice too strong? I\n don't know an efficient way to find out how many packages this would\n make buggy. But given that we have very strong reasons against the\n old practice, we might want to use a 'should not' regardless.\n\n2. Do we need to include any text saying *why* the /etc/default practice\n is a bad idea? I couldn't come up with a succinct way to state it.\n In general, I think we can err on the side of not including the text,\n since we have policy bugs that document the reasons.\n\n3. The maintscript snippet I have added is not right because it will\n disable the daemon every time the package is updated. Unfortunately,\n the postinst doesn't know whether this is a new installation, or an\n upgrade.\n\n An alternative is to require the package maintainer to set the\n correct LSB headers and systemd unit file configuration values such\n that the daemon is not autostarted (in the former case, setting the\n daemon not to be started at any runlevel). But I think this would\n prevent the local system administrator from enabling the service with\n a simple `update-rc.d package enable`, which is the whole point of\n all this.\n\n I looked at dh_installinit(8) and update-rc.d(8) and I couldn't get\n them to generate a postinst that does what I want. It seems you're\n expected to use all three of these:\n\n dh_systemd_enable --no-enable\n dh_systemd_start --no-start\n dh_installinit --no-start\n\n but then after a reboot, a sysvinit system will start the daemon,\n AFAICT.\n\n-- \nSean Whitton\n"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"content-type": "application/pgp-signature",
|
||||
"filename": "signature.asc",
|
||||
"content-length": 832
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
{
|
||||
"id": "20170910074844.ncsj7ihhdmqsxob7@bongo.bofh.it",
|
||||
"match": false,
|
||||
"excluded": false,
|
||||
"filename": [
|
||||
"/home/bremner/Maildir/tethera/cur/1505053420.H579482P8345.fethera.tethera.net:2,S"
|
||||
],
|
||||
"timestamp": 1505029724,
|
||||
"date_relative": "September 10",
|
||||
"tags": [
|
||||
"signed"
|
||||
],
|
||||
"headers": {
|
||||
"Subject": "Bug#601455: Steps towards a patch to document disabling a daemon upon installation",
|
||||
"From": "md@Linux.IT (Marco d'Itri)",
|
||||
"To": "debian-policy@lists.debian.org",
|
||||
"Cc": "601455@bugs.debian.org, debian-devel@lists.debian.org",
|
||||
"Reply-To": "Marco d'Itri <md@Linux.IT>, 601455@bugs.debian.org",
|
||||
"Date": "Sun, 10 Sep 2017 09:48:44 +0200"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"id": 1,
|
||||
"content-type": "multipart/signed",
|
||||
"content-disposition": "inline",
|
||||
"content": [
|
||||
{
|
||||
"id": 2,
|
||||
"content-type": "text/plain",
|
||||
"content-disposition": "inline",
|
||||
"content": "On Sep 09, Sean Whitton <spwhitton@spwhitton.name> wrote:\n\n> 1. Is the 'should not' for the /etc/default practice too strong? I\nNo, because it cannot be supported in a sane way by systemd units.\nIt should even be \"must not\".\n\n-- \nciao,\nMarco\n"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"content-type": "application/pgp-signature",
|
||||
"filename": "signature.asc",
|
||||
"content-length": 659
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
{
|
||||
"id": "20170910111619.ak3co2pxx7w7ybwq@fatal.se",
|
||||
"match": false,
|
||||
"excluded": false,
|
||||
"filename": [
|
||||
"/home/bremner/Maildir/tethera/cur/1505042623.H930419P7859.fethera.tethera.net:2,S"
|
||||
],
|
||||
"timestamp": 1505042179,
|
||||
"date_relative": "September 10",
|
||||
"tags": [],
|
||||
"headers": {
|
||||
"Subject": "Bug#601455: Steps towards a patch to document disabling a daemon upon installation",
|
||||
"From": "Andreas Henriksson <andreas@fatal.se>",
|
||||
"To": "Sean Whitton <spwhitton@spwhitton.name>",
|
||||
"Cc": "601455@bugs.debian.org, debian-devel@lists.debian.org",
|
||||
"Reply-To": "Andreas Henriksson <andreas@fatal.se>, 601455@bugs.debian.org",
|
||||
"Date": "Sun, 10 Sep 2017 13:16:19 +0200"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"id": 1,
|
||||
"content-type": "text/plain",
|
||||
"content-disposition": "inline",
|
||||
"content": "Hello Sean Whitton,\n\nThanks for your work on this. Hopefully you'll find something in my\ncomments inlined below of any use...\n\nOn Sat, Sep 09, 2017 at 01:40:18PM -0700, Sean Whitton wrote:\n> Hello,\n> \n> This is what I have so far; it is certainly inadequate. CCing -devel\n> for help answering my technical questions about this patch.\n> \n> > @@ -537,6 +537,21 @@ and in your ``postrm``\n> > update-rc.d package remove\n> > fi\n> > \n> > +The default behaviour is to enable autostarting your package's daemon.\n> > +If the daemon should not be autostarted unless the local administrator\n> > +has explicitly requested this, use instead add to your ``postinst``\n> > +script\n> > +\n> > +::\n> > +\n> > + update-rc.d package defaults\n> > + update-rc.d package disable\n\nI can't help myself but repeat that I'd prefer seeing more passive\nwording eg. instead of \"instead add to your postinst\" use something\nlike \"the postinst should contain\" + a footnote about this normally\nbeing added by dh_...\nManually written maintainer scripts should be avoided and I've seen\npeople being \"fooled\" by taking policy literally before. (Maybe this\ndeserves a section of its own?)\n\n> > +\n> > +An older practice, which should not be used, was to include a line\n> > +like ``DISABLED=yes`` in the package's ``/etc/default`` file. The\n> > +package's init script would not start the service until the local\n> > +system administrator changed this to ``DISABLED=no``, or similar.\n> > +\n> > Note that if your package changes runlevels or priority, you may have to\n> > remove and recreate the links, since otherwise the old links may\n> > persist. Refer to the documentation of ``update-rc.d``.\n> \n> 1. Is the 'should not' for the /etc/default practice too strong?\n\nNot in my opinion, no.\n\n> I don't know an efficient way to find out how many packages this\n> would make buggy. But given that we have very strong reasons\n> against the old practice, we might want to use a 'should not'\n> regardless.\n\nAny maintainer being hit by policy extremists have two options:\n\n1. Take the opportunity to fix the package to follow best pracises.\n2. Postpone by saying \"should not\" is not \"must not\" (and lower severity),\n plus \"patches welcome\" ofcourse.\n\nI think that's good enough.\n\n> \n> 2. Do we need to include any text saying *why* the /etc/default practice\n> is a bad idea? I couldn't come up with a succinct way to state it.\n> In general, I think we can err on the side of not including the text,\n> since we have policy bugs that document the reasons.\n\nI don't think elaborating on all the ways something can be done\nincorrectly is nessessary. Should not be too hard for anyone interested\nin the reason to find out atleast one reason either by thinking it\nthrough by themselves or by googling for past discussions.\n\nIf anything I'd rather see helpful suggestions (in footnotes?) on how\na proper cleanup should be done. (Convert admin changes on upgrades,\nuse debian/*.maintscript to rm_conffile)\n\n> \n> 3. The maintscript snippet I have added is not right because it will\n> disable the daemon every time the package is updated. Unfortunately,\n> the postinst doesn't know whether this is a new installation, or an\n> upgrade.\n> \n> An alternative is to require the package maintainer to set the\n> correct LSB headers and systemd unit file configuration values such\n> that the daemon is not autostarted (in the former case, setting the\n> daemon not to be started at any runlevel). But I think this would\n> prevent the local system administrator from enabling the service with\n> a simple `update-rc.d package enable`, which is the whole point of\n> all this.\n> \n> I looked at dh_installinit(8) and update-rc.d(8) and I couldn't get\n> them to generate a postinst that does what I want. It seems you're\n> expected to use all three of these:\n> \n> dh_systemd_enable --no-enable\n> dh_systemd_start --no-start\n> dh_installinit --no-start\n> \n> but then after a reboot, a sysvinit system will start the daemon,\n> AFAICT.\n\nhttps://bugs.debian.org/cgi-bin/bugreport.cgi?bug=709384\n\nRegards,\nAndreas Henriksson\n\n"
|
||||
}
|
||||
]
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
{
|
||||
"id": "22966.37496.665485.820932@chiark.greenend.org.uk",
|
||||
"match": false,
|
||||
"excluded": false,
|
||||
"filename": [
|
||||
"/home/bremner/Maildir/tethera/cur/1505137301.H848769P17164.fethera.tethera.net:2,S"
|
||||
],
|
||||
"timestamp": 1505137272,
|
||||
"date_relative": "September 11",
|
||||
"tags": [],
|
||||
"headers": {
|
||||
"Subject": "Bug#601455: Steps towards a patch to document disabling a daemon upon installation",
|
||||
"From": "Ian Jackson <ijackson@chiark.greenend.org.uk>",
|
||||
"To": "Sean Whitton <spwhitton@spwhitton.name>",
|
||||
"Cc": "601455@bugs.debian.org, debian-devel@lists.debian.org",
|
||||
"Reply-To": "Ian Jackson <ijackson@chiark.greenend.org.uk>, 601455@bugs.debian.org",
|
||||
"Date": "Mon, 11 Sep 2017 14:41:12 +0100"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"id": 1,
|
||||
"content-type": "text/plain",
|
||||
"content": "Sean Whitton writes (\"Steps towards a patch to document disabling a daemon upon installation\"):\n...\n> [draft policy text]\n...\n> > +The default behaviour is to enable autostarting your package's daemon.\n> > +If the daemon should not be autostarted unless the local administrator\n> > +has explicitly requested this, use instead add to your ``postinst``\n> > +script\n> > +\n> > +::\n> > +\n> > + update-rc.d package defaults\n> > + update-rc.d package disable\n\nThis has a bug: after the first rune, but before this second, starting\nthe daemon is enabled. (This is a regression compared to the previous\napproach.)\n\nTo make this work correctly, I think we need a new update-rc.d\nmechanism which provides, in one go, the equivalent of\n update-rc.d DAEMON defaults && update-rc.d DAEMON disable\n\nSomething like\n update-rc.d DAEMON add-disabled\nmaybe.\n\n> > +An older practice, which should not be used, was to include a line\n> > +like ``DISABLED=yes`` in the package's ``/etc/default`` file. The\n> > +package's init script would not start the service until the local\n> > +system administrator changed this to ``DISABLED=no``, or similar.\n...\n> 1. Is the 'should not' for the /etc/default practice too strong? I\n> don't know an efficient way to find out how many packages this would\n> make buggy. But given that we have very strong reasons against the\n> old practice, we might want to use a 'should not' regardless.\n\nOn sysvinit systems, using update-rc.d disable/defaults are rather\nmore awkward:\n\n * Enabling and disabling cannot, in practice, be conveniently made\n without using the update-rc.d tool.\n\n * Enabling and disabling generates a tremendous amount of noise in\n /etc (especially visible when using etckeeper).\n\n> 2. Do we need to include any text saying *why* the /etc/default practice\n> is a bad idea? I couldn't come up with a succinct way to state it.\n> In general, I think we can err on the side of not including the text,\n> since we have policy bugs that document the reasons.\n\nHow about this text:\n\n Setting a value in /etc/default/PACKAGE is nowadays troublesome\n because supporting that pattern is very hard due to inflexibility in\n systemd, which is usually the default init system.\n\nThis also makes it clear that this pattern is perfectly fine if for\nany reason the package does not support systemd.\n\n> 3. The maintscript snippet I have added is not right because it will\n> disable the daemon every time the package is updated. Unfortunately,\n> the postinst doesn't know whether this is a new installation, or an\n> upgrade.\n\nThis should also be fixed with a new update-rc.d rune.\n\n> I looked at dh_installinit(8) and update-rc.d(8) and I couldn't get\n> them to generate a postinst that does what I want. It seems you're\n> expected to use all three of these:\n> \n> dh_systemd_enable --no-enable\n> dh_systemd_start --no-start\n> dh_installinit --no-start\n> \n> but then after a reboot, a sysvinit system will start the daemon,\n> AFAICT.\n\nI can't speak to the behaviour of systemd, but I think the\n\n update-rc.d add-disabled\n\noperation I propose would, for sysvinit systems, do the follow:\n\n1. Are there already rc*.d links for DAEMON ? If so, do nothing.\n\n2. If not, create them in the way that defaults && disable\n would have done.\n\nIan.\n\n"
|
||||
}
|
||||
]
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
{
|
||||
"id": "87poaupkdc.fsf@iris.silentflame.com",
|
||||
"match": false,
|
||||
"excluded": false,
|
||||
"filename": [
|
||||
"/home/bremner/Maildir/tethera/cur/1505324860.H792966P2543.fethera.tethera.net:2,S"
|
||||
],
|
||||
"timestamp": 1505324447,
|
||||
"date_relative": "September 13",
|
||||
"tags": [
|
||||
"signed"
|
||||
],
|
||||
"headers": {
|
||||
"Subject": "Bug#601455: Steps towards a patch to document disabling a daemon upon installation",
|
||||
"From": "Sean Whitton <spwhitton@spwhitton.name>",
|
||||
"To": "601455@bugs.debian.org",
|
||||
"Cc": "debian-devel@lists.debian.org",
|
||||
"Reply-To": "Sean Whitton <spwhitton@spwhitton.name>, 601455@bugs.debian.org",
|
||||
"Date": "Wed, 13 Sep 2017 10:40:47 -0700"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"id": 1,
|
||||
"content-type": "multipart/signed",
|
||||
"content": [
|
||||
{
|
||||
"id": 2,
|
||||
"content-type": "text/plain",
|
||||
"content": "control: block 601455 by 857452\n\nOn Mon, Sep 11 2017, Ian Jackson wrote:\n\n> This should also be fixed with a new update-rc.d rune.\n\nThank you, Ian and Felipe, for your feedback.\n\nI think the right thing is to wait on #857452.\n\n-- \nSean Whitton\n"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"content-type": "application/pgp-signature",
|
||||
"filename": "signature.asc",
|
||||
"content-length": 832
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
{
|
||||
"id": "handler.s.B601455.150532489815922.transcript@bugs.debian.org",
|
||||
"match": false,
|
||||
"excluded": false,
|
||||
"filename": [
|
||||
"/home/bremner/Maildir/tethera/new/1505324862.H799240P2547.fethera.tethera.net"
|
||||
],
|
||||
"timestamp": 1505325065,
|
||||
"date_relative": "September 13",
|
||||
"tags": [
|
||||
"unread"
|
||||
],
|
||||
"headers": {
|
||||
"Subject": "Processed: Re: Steps towards a patch to document disabling a daemon upon installation",
|
||||
"From": "owner@bugs.debian.org (Debian Bug Tracking System)",
|
||||
"To": "Sean Whitton <spwhitton@spwhitton.name>",
|
||||
"Cc": "debian-policy@lists.debian.org, pkg-systemd-maintainers@lists.alioth.debian.org",
|
||||
"Date": "Wed, 13 Sep 2017 17:51:05 +0000"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"id": 1,
|
||||
"content-type": "text/plain",
|
||||
"content-disposition": "inline",
|
||||
"content": "Processing control commands:\n\n> block 601455 by 857452\nBug #601455 [debian-policy] Standardize how to disable an init script\nBug #522163 [debian-policy] standard for disabling daemons in /etc/default\nBug #661496 [debian-policy] Standardize how to disable an init script\n601455 was not blocked by any bugs.\n601455 was not blocking any bugs.\nAdded blocking bug(s) of 601455: 857452\n522163 was not blocked by any bugs.\n522163 was not blocking any bugs.\nAdded blocking bug(s) of 522163: 857452\n661496 was not blocked by any bugs.\n661496 was not blocking any bugs.\nAdded blocking bug(s) of 661496: 857452\n\n-- \n522163: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=522163\n601455: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=601455\n661496: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=661496\nDebian Bug Tracking System\nContact owner@bugs.debian.org with problems\n\n"
|
||||
}
|
||||
]
|
||||
},
|
||||
[]
|
||||
],
|
||||
[
|
||||
{
|
||||
"id": "20170914190335.flyi6434gedo3vkz@cloud",
|
||||
"match": false,
|
||||
"excluded": false,
|
||||
"filename": [
|
||||
"/home/bremner/Maildir/tethera/new/1505416300.H973951P10371.fethera.tethera.net"
|
||||
],
|
||||
"timestamp": 1505415815,
|
||||
"date_relative": "September 14",
|
||||
"tags": [
|
||||
"unread"
|
||||
],
|
||||
"headers": {
|
||||
"Subject": "Bug#601455: Steps towards a patch to document disabling a daemon upon installation",
|
||||
"From": "Josh Triplett <josh@joshtriplett.org>",
|
||||
"To": "601455@bugs.debian.org",
|
||||
"Reply-To": "Josh Triplett <josh@joshtriplett.org>, 601455@bugs.debian.org",
|
||||
"Date": "Thu, 14 Sep 2017 12:03:35 -0700"
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"id": 1,
|
||||
"content-type": "text/plain",
|
||||
"content-disposition": "inline",
|
||||
"content": "On Mon, 11 Sep 2017 14:41:12 +0100 Ian Jackson <ijackson@chiark.greenend.org.uk> wrote:\n> Sean Whitton writes (\"Steps towards a patch to document disabling a daemon upon installation\"):\n> > [draft policy text]\n> > > +The default behaviour is to enable autostarting your package's daemon.\n> > > +If the daemon should not be autostarted unless the local administrator\n> > > +has explicitly requested this, use instead add to your ``postinst``\n> > > +script\n> > > +\n> > > +::\n> > > +\n> > > + update-rc.d package defaults\n> > > + update-rc.d package disable\n> \n> This has a bug: after the first rune, but before this second, starting\n> the daemon is enabled. (This is a regression compared to the previous\n> approach.)\n> \n> To make this work correctly, I think we need a new update-rc.d\n> mechanism which provides, in one go, the equivalent of\n> update-rc.d DAEMON defaults && update-rc.d DAEMON disable\n> \n> Something like\n> update-rc.d DAEMON add-disabled\n> maybe.\n\nI'd agree with this as a starting point, for setting a daemon-specific\ndefault. However, I also think we need a system-wide policy mechanism to\nallow the sysadmin to say \"start things by default\" or \"don't start\nthings by default\". Similar to systemd's \"preset\" mechanism, and ideally\nusing that under systemd, but providing the same level of control for\nnon-systemd init systems.\n\n> > > +An older practice, which should not be used, was to include a line\n> > > +like ``DISABLED=yes`` in the package's ``/etc/default`` file. The\n> > > +package's init script would not start the service until the local\n> > > +system administrator changed this to ``DISABLED=no``, or similar.\n> ...\n> > 1. Is the 'should not' for the /etc/default practice too strong? I\n> > don't know an efficient way to find out how many packages this would\n> > make buggy. But given that we have very strong reasons against the\n> > old practice, we might want to use a 'should not' regardless.\n> \n> On sysvinit systems, using update-rc.d disable/defaults are rather\n> more awkward:\n> \n> * Enabling and disabling cannot, in practice, be conveniently made\n> without using the update-rc.d tool.\n\nWhy is this an issue? We have update-rc.d to do this. \n\n> * Enabling and disabling generates a tremendous amount of noise in\n> /etc (especially visible when using etckeeper).\n\nThis seems like an artifact of sysvinit's choice of storage format for\nrunlevel configuration. (And I never found that noise particularly\nexcessive in etckeeper; it's a handful of symlink deletions/creations.)\n\n> > 2. Do we need to include any text saying *why* the /etc/default practice\n> > is a bad idea? I couldn't come up with a succinct way to state it.\n> > In general, I think we can err on the side of not including the text,\n> > since we have policy bugs that document the reasons.\n> \n> How about this text:\n> \n> Setting a value in /etc/default/PACKAGE is nowadays troublesome\n> because supporting that pattern is very hard due to inflexibility in\n> systemd, which is usually the default init system.\n> \n> This also makes it clear that this pattern is perfectly fine if for\n> any reason the package does not support systemd.\n\nWhich (among many other reasons) is precisely why we shouldn't use this\ntext, because many people have been very reasonably arguing for the\nelimination of /etc/default and *especially* mechanisms like\n\"DISABLED=true\" in it for longer than systemd has existed.\n\n/etc/default is Debian-specific, and things like DISABLED=true break the\nability to *manually* start services. They also make it difficult to\nprogrammatically configure services, such as by dropping in a\nconfiguration .d file from a configuration package.\n\n"
|
||||
}
|
||||
]
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
186
assignments/A3/example3.json
Normal file
186
assignments/A3/example3.json
Normal file
@ -0,0 +1,186 @@
|
||||
[
|
||||
[
|
||||
[
|
||||
{
|
||||
"id" : "87boejw7ll.fsf@tamas.ihs.ac.at",
|
||||
"body" : [
|
||||
{
|
||||
"id" : 1,
|
||||
"content-type" : "text/plain",
|
||||
"content" : "Hi,\n\nI have a T430s with an ultrabay battery, which is discharged before the\nmain one. I was hoping I could balance the discharge between batteries\n--- I found http://www.thinkwiki.org/wiki/Talk:Code/tp-bat-balance but\nit needs tp_smapi which is not supported on this machine (AFAIK).\n\nIs there a way to balance battery discharging on this model? I would\nalso be happy if I could manually select which battery is discharged.\n\nBest,\n\nTamas\n-- \nThe linux-thinkpad mailing list home page is at:\nhttp://mailman.linux-thinkpad.org/mailman/listinfo/linux-thinkpad\n"
|
||||
}
|
||||
],
|
||||
"timestamp" : 1354019462,
|
||||
"filename" : [
|
||||
"/home/bremner/Maildir/unb/.list.linux-thinkpad/cur/1354019706.H536188P5506.tesseract.cs.unb.ca:2,S"
|
||||
],
|
||||
"date_relative" : "2012-11-27",
|
||||
"tags" : [],
|
||||
"excluded" : false,
|
||||
"match" : true,
|
||||
"headers" : {
|
||||
"Date" : "Tue, 27 Nov 2012 13:31:02 +0100",
|
||||
"Reply-To" : "linux-thinkpad@linux-thinkpad.org",
|
||||
"To" : "\"linux-thinkpad@linux-thinkpad.org\" <linux-thinkpad@linux-thinkpad.org>",
|
||||
"Subject" : "[ltp] battery balancing on T430s?",
|
||||
"From" : "Tamas Papp <tkpapp@gmail.com>"
|
||||
}
|
||||
},
|
||||
[
|
||||
[
|
||||
{
|
||||
"excluded" : false,
|
||||
"match" : false,
|
||||
"headers" : {
|
||||
"Subject" : "Re: [ltp] battery balancing on T430s?",
|
||||
"From" : "Frank Baumeister <baumeisterf@web.de>",
|
||||
"Reply-To" : "linux-thinkpad@linux-thinkpad.org",
|
||||
"Date" : "Tue, 27 Nov 2012 14:31:03 +0100",
|
||||
"To" : "linux-thinkpad@linux-thinkpad.org"
|
||||
},
|
||||
"body" : [
|
||||
{
|
||||
"content" : "Perhaps there is a way with TLP. Linrunner.de/en/tlp/tlp.html\n\n\n\nTamas Papp <tkpapp@gmail.com> schrieb:\n\n>Hi,\n>\n>I have a T430s with an ultrabay battery, which is discharged before the\n>main one. I was hoping I could balance the discharge between batteries\n>--- I found http://www.thinkwiki.org/wiki/Talk:Code/tp-bat-balance but\n>it needs tp_smapi which is not supported on this machine (AFAIK).\n>\n>Is there a way to balance battery discharging on this model? I would\n>also be happy if I could manually select which battery is discharged.\n>\n>Best,\n>\n>Tamas\n\n\n\n\n-- \nDiese Nachricht wurde von meinem Android-Mobiltelefon mit K-9 Mail gesendet.\n-- \nThe linux-thinkpad mailing list home page is at:\nhttp://mailman.linux-thinkpad.org/mailman/listinfo/linux-thinkpad\n",
|
||||
"content-type" : "text/plain",
|
||||
"id" : 1
|
||||
}
|
||||
],
|
||||
"id" : "88b04c58-95b0-4633-aaf3-a611cf8c7176@email.android.com",
|
||||
"tags" : [
|
||||
"unread"
|
||||
],
|
||||
"filename" : [
|
||||
"/home/bremner/Maildir/unb/.list.linux-thinkpad/cur/1354023304.H68786P5655.tesseract.cs.unb.ca:2,"
|
||||
],
|
||||
"date_relative" : "2012-11-27",
|
||||
"timestamp" : 1354023063
|
||||
},
|
||||
[
|
||||
[
|
||||
{
|
||||
"body" : [
|
||||
{
|
||||
"content" : "Thanks -- I am already using TLP, but I don't think that it offers this\nfunctionality.\n\nOn Tue, Nov 27 2012, Frank Baumeister <baumeisterf@web.de> wrote:\n\n> Perhaps there is a way with TLP. Linrunner.de/en/tlp/tlp.html\n>\n>\n>\n> Tamas Papp <tkpapp@gmail.com> schrieb:\n>\n>>Hi,\n>>\n>>I have a T430s with an ultrabay battery, which is discharged before the\n>>main one. I was hoping I could balance the discharge between batteries\n>>--- I found http://www.thinkwiki.org/wiki/Talk:Code/tp-bat-balance but\n>>it needs tp_smapi which is not supported on this machine (AFAIK).\n>>\n>>Is there a way to balance battery discharging on this model? I would\n>>also be happy if I could manually select which battery is discharged.\n>>\n>>Best,\n>>\n>>Tamas\n>\n>\n>\n>\n> -- \n> Diese Nachricht wurde von meinem Android-Mobiltelefon mit K-9 Mail gesendet.\n\n-- \nThe linux-thinkpad mailing list home page is at:\nhttp://mailman.linux-thinkpad.org/mailman/listinfo/linux-thinkpad\n",
|
||||
"content-type" : "text/plain",
|
||||
"id" : 1
|
||||
}
|
||||
],
|
||||
"id" : "878v9nw4cy.fsf@tamas.ihs.ac.at",
|
||||
"tags" : [
|
||||
"unread"
|
||||
],
|
||||
"timestamp" : 1354023661,
|
||||
"date_relative" : "2012-11-27",
|
||||
"filename" : [
|
||||
"/home/bremner/Maildir/unb/.list.linux-thinkpad/cur/1354023901.H934938P5672.tesseract.cs.unb.ca:2,"
|
||||
],
|
||||
"excluded" : false,
|
||||
"match" : false,
|
||||
"headers" : {
|
||||
"Subject" : "Re: [ltp] battery balancing on T430s?",
|
||||
"From" : "Tamas Papp <tkpapp@gmail.com>",
|
||||
"Date" : "Tue, 27 Nov 2012 14:41:01 +0100",
|
||||
"Reply-To" : "linux-thinkpad@linux-thinkpad.org",
|
||||
"To" : "linux-thinkpad@linux-thinkpad.org"
|
||||
}
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
{
|
||||
"timestamp" : 1354522521,
|
||||
"date_relative" : "2012-12-03",
|
||||
"filename" : [
|
||||
"/home/bremner/Maildir/unb/.list.linux-thinkpad/cur/1354522806.H600217P26331.tesseract.cs.unb.ca:2,"
|
||||
],
|
||||
"tags" : [
|
||||
"unread"
|
||||
],
|
||||
"id" : "CAOLOJ0xO1PoxUdRZYJDoZUfFaTu5r1yiDtSXEEXD_8YhzEU+3A@mail.gmail.com",
|
||||
"body" : [
|
||||
{
|
||||
"content" : "you may take a look at this: http://savannah.nongnu.org/projects/battwd.\nIt can works with several batteries (the only bad is that, at the\nmoment, it's alpha code).\n\nOn 27 November 2012 13:31, Tamas Papp <tkpapp@gmail.com> wrote:\n> Hi,\n>\n> I have a T430s with an ultrabay battery, which is discharged before the\n> main one. I was hoping I could balance the discharge between batteries\n> --- I found http://www.thinkwiki.org/wiki/Talk:Code/tp-bat-balance but\n> it needs tp_smapi which is not supported on this machine (AFAIK).\n>\n> Is there a way to balance battery discharging on this model? I would\n> also be happy if I could manually select which battery is discharged.\n>\n> Best,\n>\n> Tamas\n> --\n> The linux-thinkpad mailing list home page is at:\n> http://mailman.linux-thinkpad.org/mailman/listinfo/linux-thinkpad\n-- \nThe linux-thinkpad mailing list home page is at:\nhttp://mailman.linux-thinkpad.org/mailman/listinfo/linux-thinkpad\n",
|
||||
"content-type" : "text/plain",
|
||||
"id" : 1
|
||||
}
|
||||
],
|
||||
"headers" : {
|
||||
"From" : "alfon <alfon.gz@gmail.com>",
|
||||
"Subject" : "Re: [ltp] battery balancing on T430s?",
|
||||
"To" : "linux-thinkpad@linux-thinkpad.org",
|
||||
"Reply-To" : "linux-thinkpad@linux-thinkpad.org",
|
||||
"Date" : "Mon, 03 Dec 2012 09:15:21 +0100"
|
||||
},
|
||||
"match" : false,
|
||||
"excluded" : false
|
||||
},
|
||||
[
|
||||
[
|
||||
{
|
||||
"tags" : [
|
||||
"unread"
|
||||
],
|
||||
"date_relative" : "2012-12-03",
|
||||
"filename" : [
|
||||
"/home/bremner/Maildir/unb/.list.linux-thinkpad/cur/1354539302.H582083P27170.tesseract.cs.unb.ca:2,"
|
||||
],
|
||||
"timestamp" : 1354538957,
|
||||
"body" : [
|
||||
{
|
||||
"content" : "Thanks. Does this support selecting which battery to discharge on the\nTP T430s? How? I can see that it can monitor the batteries, but for me\nthe problem is not monitoring but controlling the battery discharge.\n\nThe problem is that tp_smapi does not support this laptop yet, so there\nis no /sys/devices/platform/smapi/BAT0/force_discharge etc.\n\nOn Mon, Dec 03 2012, alfon <alfon.gz@gmail.com> wrote:\n\n> you may take a look at this: http://savannah.nongnu.org/projects/battwd.\n> It can works with several batteries (the only bad is that, at the\n> moment, it's alpha code).\n>\n> On 27 November 2012 13:31, Tamas Papp <tkpapp@gmail.com> wrote:\n>> Hi,\n>>\n>> I have a T430s with an ultrabay battery, which is discharged before the\n>> main one. I was hoping I could balance the discharge between batteries\n>> --- I found http://www.thinkwiki.org/wiki/Talk:Code/tp-bat-balance but\n>> it needs tp_smapi which is not supported on this machine (AFAIK).\n>>\n>> Is there a way to balance battery discharging on this model? I would\n>> also be happy if I could manually select which battery is discharged.\n>>\n>> Best,\n>>\n>> Tamas\n>> --\n>> The linux-thinkpad mailing list home page is at:\n>> http://mailman.linux-thinkpad.org/mailman/listinfo/linux-thinkpad\n\n-- \nThe linux-thinkpad mailing list home page is at:\nhttp://mailman.linux-thinkpad.org/mailman/listinfo/linux-thinkpad\n",
|
||||
"content-type" : "text/plain",
|
||||
"id" : 1
|
||||
}
|
||||
],
|
||||
"id" : "87lidfwbaq.fsf@tamas.ihs.ac.at",
|
||||
"match" : false,
|
||||
"headers" : {
|
||||
"Date" : "Mon, 03 Dec 2012 13:49:17 +0100",
|
||||
"Reply-To" : "linux-thinkpad@linux-thinkpad.org",
|
||||
"To" : "linux-thinkpad@linux-thinkpad.org",
|
||||
"Subject" : "Re: [ltp] battery balancing on T430s?",
|
||||
"From" : "Tamas Papp <tkpapp@gmail.com>"
|
||||
},
|
||||
"excluded" : false
|
||||
},
|
||||
[
|
||||
[
|
||||
{
|
||||
"id" : "CAOLOJ0yKgyZf6w5+D1n8ogkgAD_chHpo29D122C7wSgTRzVs8w@mail.gmail.com",
|
||||
"body" : [
|
||||
{
|
||||
"id" : 1,
|
||||
"content-type" : "text/plain",
|
||||
"content" : "No, for now, only works if the battery is under /sys/device, /proc or\nanother filesystem... sorry.\n\nOn 3 December 2012 13:49, Tamas Papp <tkpapp@gmail.com> wrote:\n> Thanks. Does this support selecting which battery to discharge on the\n> TP T430s? How? I can see that it can monitor the batteries, but for me\n> the problem is not monitoring but controlling the battery discharge.\n>\n> The problem is that tp_smapi does not support this laptop yet, so there\n> is no /sys/devices/platform/smapi/BAT0/force_discharge etc.\n>\n> On Mon, Dec 03 2012, alfon <alfon.gz@gmail.com> wrote:\n>\n>> you may take a look at this: http://savannah.nongnu.org/projects/battwd.\n>> It can works with several batteries (the only bad is that, at the\n>> moment, it's alpha code).\n>>\n>> On 27 November 2012 13:31, Tamas Papp <tkpapp@gmail.com> wrote:\n>>> Hi,\n>>>\n>>> I have a T430s with an ultrabay battery, which is discharged before the\n>>> main one. I was hoping I could balance the discharge between batteries\n>>> --- I found http://www.thinkwiki.org/wiki/Talk:Code/tp-bat-balance but\n>>> it needs tp_smapi which is not supported on this machine (AFAIK).\n>>>\n>>> Is there a way to balance battery discharging on this model? I would\n>>> also be happy if I could manually select which battery is discharged.\n>>>\n>>> Best,\n>>>\n>>> Tamas\n>>> --\n>>> The linux-thinkpad mailing list home page is at:\n>>> http://mailman.linux-thinkpad.org/mailman/listinfo/linux-thinkpad\n>\n> --\n> The linux-thinkpad mailing list home page is at:\n> http://mailman.linux-thinkpad.org/mailman/listinfo/linux-thinkpad\n-- \nThe linux-thinkpad mailing list home page is at:\nhttp://mailman.linux-thinkpad.org/mailman/listinfo/linux-thinkpad\n"
|
||||
}
|
||||
],
|
||||
"timestamp" : 1354542140,
|
||||
"date_relative" : "2012-12-03",
|
||||
"filename" : [
|
||||
"/home/bremner/Maildir/unb/.list.linux-thinkpad/cur/1354542304.H658190P27485.tesseract.cs.unb.ca:2,"
|
||||
],
|
||||
"tags" : [
|
||||
"unread"
|
||||
],
|
||||
"excluded" : false,
|
||||
"match" : false,
|
||||
"headers" : {
|
||||
"Subject" : "Re: [ltp] battery balancing on T430s?",
|
||||
"From" : "alfon <alfon.gz@gmail.com>",
|
||||
"Date" : "Mon, 03 Dec 2012 14:42:20 +0100",
|
||||
"Reply-To" : "linux-thinkpad@linux-thinkpad.org",
|
||||
"To" : "linux-thinkpad@linux-thinkpad.org"
|
||||
}
|
||||
},
|
||||
[]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
49
assignments/A3/message.js
Normal file
49
assignments/A3/message.js
Normal file
@ -0,0 +1,49 @@
|
||||
function match(message, headers) {
|
||||
for (let header in headers) {
|
||||
if (message.headers[header] !== headers[header]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function body(message) {
|
||||
if (message["body"] !== undefined) {
|
||||
if (message["body"][0]["content-type"] === "text/plain") {
|
||||
return message["body"][0]["content"];
|
||||
}
|
||||
/* istanbul ignore else */
|
||||
if (message["body"][0]["content-type"] === "multipart/signed") {
|
||||
return message["body"][0]["content"][0]["content"];
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function string(message) {
|
||||
let string = "";
|
||||
if (message["headers"]["From"] !== undefined) {
|
||||
string += "From: " + message["headers"]["From"] + "\n";
|
||||
}
|
||||
/* istanbul ignore else */
|
||||
if (message["headers"]["Date"] !== undefined) {
|
||||
string += "Date: " + message["headers"]["Date"] + "\n";
|
||||
}
|
||||
/* istanbul ignore else */
|
||||
if (message["headers"]["Subject"] !== undefined) {
|
||||
string += "Subject: " + message["headers"]["Subject"] + "\n";
|
||||
}
|
||||
if (message["headers"]["To"] !== undefined) {
|
||||
|
||||
string += "To: " + message["headers"]["To"] + "\n";
|
||||
}
|
||||
if (message["body"] !== undefined) {
|
||||
string += "\n";
|
||||
string += body(message);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
exports.match = match;
|
||||
exports.body = body;
|
||||
exports.string = string;
|
8
assignments/A3/read_json_file.js
Normal file
8
assignments/A3/read_json_file.js
Normal file
@ -0,0 +1,8 @@
|
||||
let fs = require('fs');
|
||||
|
||||
function read_json_file(filename) {
|
||||
let contents = fs.readFileSync(filename);
|
||||
|
||||
return JSON.parse(contents);
|
||||
}
|
||||
exports.read_json_file=read_json_file;
|
128
assignments/A3/spec/message.spec.js
Normal file
128
assignments/A3/spec/message.spec.js
Normal file
@ -0,0 +1,128 @@
|
||||
let read_json_file = require("../read_json_file.js").read_json_file;
|
||||
let message = require("../message.js");
|
||||
|
||||
let testMsg = {"headers": {"Subject" : "lunch", "Date" : "now"}};
|
||||
let otherMsg = {"headers": {"Subject" : "dinner", "Date" : "now"}};
|
||||
|
||||
describe("match",
|
||||
function() {
|
||||
it("message matches itself",
|
||||
function () {
|
||||
expect(message.match(testMsg,testMsg.headers)).toEqual(true);
|
||||
});
|
||||
it("message does not match if field changes",
|
||||
function () {
|
||||
expect(message.match(testMsg,otherMsg.headers)).toEqual(false);
|
||||
});
|
||||
it("match subset of fields",
|
||||
function () {
|
||||
expect(message.match(testMsg,{"Subject": "lunch"})).toEqual(true);
|
||||
});
|
||||
});
|
||||
describe("message body",
|
||||
function () {
|
||||
it("unsigned message",
|
||||
function () {
|
||||
let message_objects=read_json_file("example1.json").flat(Infinity);
|
||||
let msg = message_objects.filter((m) => message.match(m,{ "From": "Aron Griffis <agriffis@n01se.net>"}))[0];
|
||||
expect(msg).not.toEqual(null);
|
||||
expect(message.body(msg)).toEqual(`Just subscribed, I'd like to catch up on the previous postings,
|
||||
but the archive link seems to be bogus?
|
||||
|
||||
Thanks,
|
||||
Aron
|
||||
|
||||
`);
|
||||
});
|
||||
it("signed message",
|
||||
function () {
|
||||
let message_objects=read_json_file("example2.json").flat(Infinity);
|
||||
let msg = message_objects.filter((m) => message.match(m,{"From": "md@Linux.IT (Marco d'Itri)"}))[0];
|
||||
|
||||
expect(msg).not.toEqual(null);
|
||||
expect(message.body(msg)).toEqual(`On Sep 09, Sean Whitton <spwhitton@spwhitton.name> wrote:
|
||||
|
||||
> 1. Is the 'should not' for the /etc/default practice too strong? I
|
||||
No, because it cannot be supported in a sane way by systemd units.
|
||||
It should even be "must not".
|
||||
|
||||
--
|
||||
ciao,
|
||||
Marco
|
||||
`);
|
||||
});
|
||||
it("no body",
|
||||
function() {
|
||||
expect(message.body(testMsg)).toEqual(undefined)
|
||||
});
|
||||
|
||||
});
|
||||
let fullHeaderMsg ={"headers": {
|
||||
"Subject": "[notmuch] archive",
|
||||
"From": "Aron Griffis <agriffis@n01se.net>",
|
||||
"To": "notmuch <notmuch@notmuchmail.org>",
|
||||
"Date": "Tue, 17 Nov 2009 18:21:38 -0500"
|
||||
}};
|
||||
|
||||
describe("toString",
|
||||
function () {
|
||||
it("works with no body",
|
||||
function () {
|
||||
expect(message.string(testMsg)).toEqual(`Date: now
|
||||
Subject: lunch
|
||||
`);
|
||||
});
|
||||
|
||||
it("full set of headers",
|
||||
function() {
|
||||
expect(message.string(fullHeaderMsg)).toEqual(`From: Aron Griffis <agriffis@n01se.net>
|
||||
Date: Tue, 17 Nov 2009 18:21:38 -0500
|
||||
Subject: [notmuch] archive
|
||||
To: notmuch <notmuch@notmuchmail.org>
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe("toString real data",
|
||||
function () {
|
||||
it("unsigned message",
|
||||
function () {
|
||||
let message_objects=read_json_file("example1.json").flat(Infinity);
|
||||
let msg = message_objects.filter((m) => message.match(m,{ "From": "Aron Griffis <agriffis@n01se.net>"}))[0];
|
||||
expect(msg).not.toEqual(null);
|
||||
expect(message.string(msg)).toEqual(`From: Aron Griffis <agriffis@n01se.net>
|
||||
Date: Tue, 17 Nov 2009 18:21:38 -0500
|
||||
Subject: [notmuch] archive
|
||||
To: notmuch <notmuch@notmuchmail.org>
|
||||
|
||||
Just subscribed, I'd like to catch up on the previous postings,
|
||||
but the archive link seems to be bogus?
|
||||
|
||||
Thanks,
|
||||
Aron
|
||||
|
||||
`);
|
||||
});
|
||||
|
||||
it("signed message",
|
||||
function () {
|
||||
let message_objects=read_json_file("example2.json").flat(Infinity);
|
||||
let msg = message_objects.filter((m) => message.match(m,{"From": "md@Linux.IT (Marco d'Itri)"}))[0];
|
||||
|
||||
expect(msg).not.toEqual(null);
|
||||
expect(message.string(msg)).toEqual(`From: md@Linux.IT (Marco d'Itri)
|
||||
Date: Sun, 10 Sep 2017 09:48:44 +0200
|
||||
Subject: Bug#601455: Steps towards a patch to document disabling a daemon upon installation
|
||||
To: debian-policy@lists.debian.org
|
||||
|
||||
On Sep 09, Sean Whitton <spwhitton@spwhitton.name> wrote:
|
||||
|
||||
> 1. Is the 'should not' for the /etc/default practice too strong? I
|
||||
No, because it cannot be supported in a sane way by systemd units.
|
||||
It should even be "must not".
|
||||
|
||||
--
|
||||
ciao,
|
||||
Marco
|
||||
`);});
|
||||
});
|
13
assignments/A3/spec/support/jasmine.json
Normal file
13
assignments/A3/spec/support/jasmine.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"spec_dir": "spec",
|
||||
"spec_files": [
|
||||
"**/*[sS]pec.?(m)js"
|
||||
],
|
||||
"helpers": [
|
||||
"helpers/**/*.?(m)js"
|
||||
],
|
||||
"env": {
|
||||
"stopSpecOnExpectationFailure": false,
|
||||
"random": true
|
||||
}
|
||||
}
|
178
assignments/A4/life.js
Normal file
178
assignments/A4/life.js
Normal file
@ -0,0 +1,178 @@
|
||||
// ES2015 classes based on https://eloquentjavascript.net/2nd_edition/07_elife.html
|
||||
class Vector {
|
||||
constructor(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
plus(other) {
|
||||
return new Vector(this.x + other.x, this.y + other.y);
|
||||
};
|
||||
};
|
||||
|
||||
class Grid {
|
||||
constructor (width, height) {
|
||||
this.space = new Array(width * height);
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
};
|
||||
|
||||
isInside(vector) {
|
||||
return vector.x >= 0 && vector.x < this.width &&
|
||||
vector.y >= 0 && vector.y < this.height;
|
||||
};
|
||||
|
||||
get(vector) {
|
||||
return this.space[vector.x + this.width * vector.y];
|
||||
};
|
||||
|
||||
set(vector, value) {
|
||||
this.space[vector.x + this.width * vector.y] = value;
|
||||
};
|
||||
|
||||
forEach(f, context) {
|
||||
for (let y = 0; y < this.height; y++) {
|
||||
for (let x = 0; x < this.width; x++) {
|
||||
let value = this.space[x + y * this.width];
|
||||
if (value != null)
|
||||
f.call(context, value, new Vector(x, y));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let directions = {
|
||||
"n": new Vector( 0, -1),
|
||||
"ne": new Vector( 1, -1),
|
||||
"e": new Vector( 1, 0),
|
||||
"se": new Vector( 1, 1),
|
||||
"s": new Vector( 0, 1),
|
||||
"sw": new Vector(-1, 1),
|
||||
"w": new Vector(-1, 0),
|
||||
"nw": new Vector(-1, -1)
|
||||
};
|
||||
|
||||
function randomElement(array) {
|
||||
return array[Math.floor(Math.random() * array.length)];
|
||||
}
|
||||
|
||||
let directionNames = "n ne e se s sw w nw".split(" ");
|
||||
|
||||
function BouncingCritter() {
|
||||
this.direction = randomElement(directionNames);
|
||||
};
|
||||
|
||||
BouncingCritter.prototype.act = function(view) {
|
||||
if (view.look(this.direction) != " ")
|
||||
this.direction = view.find(" ") || "s";
|
||||
return {type: "move", direction: this.direction};
|
||||
};
|
||||
|
||||
class View {
|
||||
constructor(world, vector) {
|
||||
this.world = world;
|
||||
this.vector = vector;
|
||||
}
|
||||
look(dir) {
|
||||
let target = this.vector.plus(directions[dir]);
|
||||
if (this.world.grid.isInside(target))
|
||||
return charFromElement(this.world.grid.get(target));
|
||||
else
|
||||
return "#";
|
||||
}
|
||||
findAll(ch) {
|
||||
let found = [];
|
||||
for (let dir in directions)
|
||||
if (this.look(dir) == ch)
|
||||
found.push(dir);
|
||||
return found;
|
||||
}
|
||||
|
||||
find(ch) {
|
||||
let found = this.findAll(ch);
|
||||
if (found.length == 0) return null;
|
||||
return randomElement(found);
|
||||
}
|
||||
}
|
||||
|
||||
class World {
|
||||
constructor(map, legend) {
|
||||
let grid = new Grid(map[0].length, map.length);
|
||||
this.grid = grid;
|
||||
this.legend = legend;
|
||||
|
||||
map.forEach(function(line, y) {
|
||||
for (let x = 0; x < line.length; x++)
|
||||
grid.set(new Vector(x, y),
|
||||
World.elementFromChar(legend, line[x]));
|
||||
});
|
||||
}
|
||||
|
||||
static elementFromChar(legend, ch) {
|
||||
if (ch == " ")
|
||||
return null;
|
||||
let element = new legend[ch]();
|
||||
element.originChar = ch;
|
||||
return element;
|
||||
}
|
||||
|
||||
toString() {
|
||||
let output = "";
|
||||
for (let y = 0; y < this.grid.height; y++) {
|
||||
for (let x = 0; x < this.grid.width; x++) {
|
||||
let element = this.grid.get(new Vector(x, y));
|
||||
output += charFromElement(element);
|
||||
}
|
||||
output += "\n";
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
turn () {
|
||||
let acted = [];
|
||||
this.grid.forEach(function(critter, vector) {
|
||||
if (critter.act && acted.indexOf(critter) == -1) {
|
||||
acted.push(critter);
|
||||
this.letAct(critter, vector);
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
letAct(critter, vector) {
|
||||
let action = critter.act(new View(this, vector));
|
||||
if (action && action.type == "move") {
|
||||
let dest = this.checkDestination(action, vector);
|
||||
if (dest && this.grid.get(dest) == null) {
|
||||
this.grid.set(vector, null);
|
||||
this.grid.set(dest, critter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkDestination(action, vector) {
|
||||
if (directions.hasOwnProperty(action.direction)) {
|
||||
let dest = vector.plus(directions[action.direction]);
|
||||
if (this.grid.isInside(dest))
|
||||
return dest;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
function charFromElement(element) {
|
||||
if (element == null)
|
||||
return " ";
|
||||
else
|
||||
return element.originChar;
|
||||
}
|
||||
|
||||
|
||||
function Wall() {};
|
||||
|
||||
exports.BouncingCritter=BouncingCritter;
|
||||
exports.Grid=Grid;
|
||||
exports.Wall=Wall;
|
||||
exports.World=World;
|
||||
exports.Vector=Vector;
|
||||
exports.View=View;
|
122
assignments/A4/moarlife.js
Normal file
122
assignments/A4/moarlife.js
Normal file
@ -0,0 +1,122 @@
|
||||
let life=require("./life.js");
|
||||
|
||||
let View=life.View;
|
||||
|
||||
let actionTypes = Object.create(null);
|
||||
|
||||
actionTypes.grow = function(critter) {
|
||||
critter.energy += 0.5;
|
||||
return true;
|
||||
};
|
||||
|
||||
actionTypes.move = function(critter, vector, action) {
|
||||
let dest = this.checkDestination(action, vector);
|
||||
if (dest == null ||
|
||||
critter.energy <= 1 ||
|
||||
this.grid.get(dest) != null)
|
||||
return false;
|
||||
critter.energy -= 1;
|
||||
this.grid.set(vector, null);
|
||||
this.grid.set(dest, critter);
|
||||
return true;
|
||||
};
|
||||
|
||||
actionTypes.eat = function(critter, vector, action) {
|
||||
let dest = this.checkDestination(action, vector);
|
||||
let atDest = dest != null && this.grid.get(dest);
|
||||
if (!atDest || atDest.energy == null)
|
||||
return false;
|
||||
critter.energy += atDest.energy;
|
||||
this.grid.set(dest, null);
|
||||
return true;
|
||||
};
|
||||
|
||||
actionTypes.reproduce = function(critter, vector, action) {
|
||||
let baby = life.World.elementFromChar(this.legend,
|
||||
critter.originChar);
|
||||
let dest = this.checkDestination(action, vector);
|
||||
if (dest == null ||
|
||||
critter.energy <= 2 * baby.energy ||
|
||||
this.grid.get(dest) != null)
|
||||
return false;
|
||||
critter.energy -= 2 * baby.energy;
|
||||
this.grid.set(dest, baby);
|
||||
return true;
|
||||
};
|
||||
|
||||
actionTypes.die = function(critter, action) {
|
||||
|
||||
}
|
||||
|
||||
class LifelikeWorld extends life.World {
|
||||
constructor(map,legend){
|
||||
super(map,legend);
|
||||
}
|
||||
letAct(critter, vector) {
|
||||
let action = critter.act(new View(this, vector));
|
||||
let handled = action &&
|
||||
action.type in actionTypes &&
|
||||
actionTypes[action.type].call(this, critter,
|
||||
vector, action);
|
||||
if (!handled) {
|
||||
critter.energy -= 0.2;
|
||||
if (critter.energy <= 0)
|
||||
this.grid.set(vector, null);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class Plant {
|
||||
constructor() {
|
||||
this.energy = 3 + Math.random() * 4;
|
||||
}
|
||||
|
||||
act(view) {
|
||||
if (this.energy > 15) {
|
||||
let space = view.find(" ");
|
||||
if (space)
|
||||
return {type: "reproduce", direction: space};
|
||||
}
|
||||
if (this.energy < 20)
|
||||
return {type: "grow"};
|
||||
};
|
||||
}
|
||||
|
||||
class PlantEater{
|
||||
constructor () {
|
||||
this.energy = 20;
|
||||
}
|
||||
|
||||
act(view) {
|
||||
let space = view.find(" ");
|
||||
if (this.energy > 60 && space)
|
||||
return {type: "reproduce", direction: space};
|
||||
let plant = view.find("*");
|
||||
if (plant)
|
||||
return {type: "eat", direction: plant};
|
||||
if (space)
|
||||
return {type: "move", direction: space};
|
||||
};
|
||||
}
|
||||
|
||||
class ExplodingBunnyRabbit extends PlantEater {
|
||||
constructor () {
|
||||
super()
|
||||
}
|
||||
|
||||
act(view) {
|
||||
super.act(view);
|
||||
if(this.energy > 55) {
|
||||
if (Math.random() < 0.25) {
|
||||
return {type: "die"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.LifelikeWorld=LifelikeWorld;
|
||||
exports.BouncingCritter=life.BouncingCritter;
|
||||
exports.Wall=life.Wall;
|
||||
exports.PlantEater = PlantEater;
|
||||
exports.Plant = Plant;
|
||||
exports.actionTypes = actionTypes;
|
136
assignments/A4/spec/life.spec.js
Normal file
136
assignments/A4/spec/life.spec.js
Normal file
@ -0,0 +1,136 @@
|
||||
let life=require ("../life.js");
|
||||
let plan = ["############################",
|
||||
"# # # o ##",
|
||||
"# #",
|
||||
"# ##### #",
|
||||
"## # # ## #",
|
||||
"### ## # #",
|
||||
"# ### # #",
|
||||
"# #### #",
|
||||
"# ## o #",
|
||||
"# o # o ### #",
|
||||
"# # #",
|
||||
"############################"];
|
||||
|
||||
let Vector = life.Vector;
|
||||
|
||||
describe("Grid",
|
||||
function() {
|
||||
it("initially undefined",
|
||||
function() {
|
||||
let grid = new life.Grid(5, 5);
|
||||
expect(grid.get(new life.Vector(1, 1))).toBe(undefined);
|
||||
});
|
||||
it("setting a value",
|
||||
function() {
|
||||
let grid = new life.Grid(5, 5);
|
||||
grid.set(new Vector(1, 1), "X");
|
||||
expect(grid.get(new Vector(1, 1))).toEqual("X");
|
||||
});
|
||||
it("forEach",
|
||||
function() {
|
||||
let grid = new life.Grid(5, 5);
|
||||
let test = {grid: grid, sum: 0,
|
||||
method: function () {
|
||||
this.grid.forEach(function() { this.sum++; }, this);
|
||||
}
|
||||
};
|
||||
|
||||
test.grid.set(new Vector(2,3), "#");
|
||||
test.grid.set(new Vector(3,4), "#");
|
||||
test.method();
|
||||
expect(test.sum).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("BouncingCritter",
|
||||
function() {
|
||||
let bob = null;
|
||||
beforeEach(function () {
|
||||
spyOn(Math, 'random').and.returnValue(0.5);
|
||||
bob=new life.BouncingCritter();
|
||||
});
|
||||
it("constructor",
|
||||
function() {
|
||||
expect('direction' in bob).toBe(true);
|
||||
expect(bob.direction).toBe('s');
|
||||
});
|
||||
it("act, clear path",
|
||||
function () {
|
||||
let clear = {look: function () {return " ";}};
|
||||
expect(bob.act(clear)).toEqual({type: "move", direction: "s"});
|
||||
});
|
||||
it("act, unclear path",
|
||||
function () {
|
||||
let unclear = {look: function () {return "#";}, find: function () { return "n";}};
|
||||
expect(bob.act(unclear)).toEqual({type: "move", direction: "n"});
|
||||
});
|
||||
});
|
||||
|
||||
describe("World",
|
||||
function () {
|
||||
it("roundtrip",
|
||||
function() {
|
||||
let world = new life.World(plan, {"#": life.Wall, "o": life.BouncingCritter});
|
||||
let rows = world.toString().split("\n");
|
||||
// drop blank row
|
||||
rows.pop();
|
||||
expect(rows).toEqual(plan);
|
||||
});
|
||||
it("turn",
|
||||
function () {
|
||||
let world = new life.World(plan, {"#": life.Wall, "o": life.BouncingCritter});
|
||||
let count=0;
|
||||
spyOn(world, 'letAct').and.callFake(function(critter,vector) {count++;});
|
||||
world.turn();
|
||||
expect(count).toBe(4);
|
||||
});
|
||||
it("checkDestination",
|
||||
function () {
|
||||
let world = new life.World(plan, {"#": life.Wall, "o": life.BouncingCritter});
|
||||
expect(world.checkDestination({direction: 's'},
|
||||
new life.Vector(19,1))).toEqual(new life.Vector(19,2));
|
||||
expect(world.checkDestination({direction: 'n'},
|
||||
new life.Vector(0,0))).toEqual(undefined);
|
||||
});
|
||||
it("letAct",
|
||||
function () {
|
||||
let world = new life.World(plan, {"#": life.Wall, "o": life.BouncingCritter});
|
||||
let src=new life.Vector(19,1);
|
||||
let dest=new life.Vector(19,2);
|
||||
let bob=world.grid.get(src);
|
||||
spyOn(bob,'act').and.returnValue({type: 'move', direction: 's'});
|
||||
world.letAct(bob, src);
|
||||
expect(world.grid.get(dest)).toEqual(bob);
|
||||
});
|
||||
});
|
||||
|
||||
describe("View",
|
||||
function () {
|
||||
let world = new life.World(plan, {"#": life.Wall, "o": life.BouncingCritter});
|
||||
let View=life.View;
|
||||
let position=new Vector(15,9);
|
||||
it("constructor",
|
||||
function () {
|
||||
let view=new View(world, position);
|
||||
expect(view.vector).toEqual(position);
|
||||
});
|
||||
it("look",
|
||||
function () {
|
||||
let view=new View(world, position);
|
||||
expect(view.look("s")).toBe(" ");
|
||||
});
|
||||
it("findAll",
|
||||
function () {
|
||||
let view=new View(world, position);
|
||||
let directionNames = [ 'e', 'n', 'ne', 'nw', 's', 'se', 'sw', 'w' ];
|
||||
expect(view.findAll(" ").sort()).toEqual(directionNames);
|
||||
});
|
||||
it("find",
|
||||
function () {
|
||||
let view=new View(world, position);
|
||||
spyOn(Math, 'random').and.returnValue(0.5);
|
||||
expect(view.find(" ")).toBe('s');
|
||||
});
|
||||
|
||||
});
|
103
assignments/A4/spec/moarlife.spec.js
Normal file
103
assignments/A4/spec/moarlife.spec.js
Normal file
@ -0,0 +1,103 @@
|
||||
let life=require ("../moarlife.js");
|
||||
|
||||
let plan= ["############################",
|
||||
"##### ######",
|
||||
"## *** **##",
|
||||
"# *##** ** O *##",
|
||||
"# *** O ##** *#",
|
||||
"# O ##*** #",
|
||||
"# ##** #",
|
||||
"# O #* #",
|
||||
"#* #** O #",
|
||||
"#*** ##** O **#",
|
||||
"##**** ###*** *###",
|
||||
"############################"];
|
||||
|
||||
|
||||
describe("World",
|
||||
function () {
|
||||
let valley = new life.LifelikeWorld(plan,
|
||||
{"#": life.Wall,
|
||||
"O": life.PlantEater,
|
||||
"*": life.Plant});
|
||||
it("roundtrip",
|
||||
function() {
|
||||
let rows = valley.toString().split("\n");
|
||||
// drop blank row
|
||||
rows.pop();
|
||||
expect(rows).toEqual(plan);
|
||||
});
|
||||
});
|
||||
|
||||
describe("actionTypes",
|
||||
function () {
|
||||
it("grow",
|
||||
function () {
|
||||
let critter = new life.Plant();
|
||||
let energy = critter.energy;
|
||||
life.actionTypes.grow(critter);
|
||||
expect(critter.energy).toBeGreaterThan(energy);
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
describe("PlantEater",
|
||||
function () {
|
||||
it("constructor",
|
||||
function () {
|
||||
let pe = new life.PlantEater();
|
||||
expect('energy' in pe).toBe(true);
|
||||
expect(pe.energy).toBe(20);
|
||||
});
|
||||
it("act, reproduce",
|
||||
function () {
|
||||
let pe = new life.PlantEater();
|
||||
pe.energy = 65
|
||||
expect(pe.act({find: function (ch) { if (ch === " ") return "n"; } })).toEqual({ type: "reproduce", direction: "n" });
|
||||
|
||||
});
|
||||
it("act, eat",
|
||||
function () {
|
||||
let pe = new life.PlantEater();
|
||||
pe.energy = 20
|
||||
expect(pe.act({find: function (ch ) { if (ch === "*") return "n"; } })).toEqual({ type: "eat", direction: "n" });
|
||||
});
|
||||
it("act, move",
|
||||
function () {
|
||||
let pe = new life.PlantEater();
|
||||
expect(pe.act({find: function (ch) { if (ch === " ") return "n"; } })).toEqual({ type: "move", direction: "n" });
|
||||
});
|
||||
});
|
||||
|
||||
describe("ExplodingBunnyRabbit",
|
||||
function () {
|
||||
it("constructor",
|
||||
function () {
|
||||
let pe = new life.ExplodingBunnyRabbit();
|
||||
expect('energy' in pe).toBe(true);
|
||||
expect(pe.energy).toBe(20);
|
||||
});
|
||||
it("act, reproduce",
|
||||
function () {
|
||||
let pe = new life.ExplodingBunnyRabbit();
|
||||
pe.energy = 65
|
||||
expect(pe.act({find: function (ch) { if (ch === " ") return "n"; } })).toEqual({ type: "reproduce", direction: "n" });
|
||||
|
||||
});
|
||||
it("act, eat",
|
||||
function () {
|
||||
let pe = new life.ExplodingBunnyRabbit();
|
||||
pe.energy = 20
|
||||
expect(pe.act({find: function (ch ) { if (ch === "*") return "n"; } })).toEqual({ type: "eat", direction: "n" });
|
||||
});
|
||||
it("act, move",
|
||||
function () {
|
||||
let pe = new life.ExplodingBunnyRabbit();
|
||||
expect(pe.act({find: function (ch) { if (ch === " ") return "n"; } })).toEqual({ type: "move", direction: "n" });
|
||||
});
|
||||
it("act, explode",
|
||||
function () {
|
||||
let pe = new life.ExplodingBunnyRabbit();
|
||||
expect(pe.act({find: function (ch) { if (ch === "O") return "n"; } })).toEqual({ type: "explode", direction: "n" });
|
||||
});
|
||||
});
|
13
assignments/A4/spec/support/jasmine.json
Normal file
13
assignments/A4/spec/support/jasmine.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"spec_dir": "spec",
|
||||
"spec_files": [
|
||||
"**/*[sS]pec.?(m)js"
|
||||
],
|
||||
"helpers": [
|
||||
"helpers/**/*.?(m)js"
|
||||
],
|
||||
"env": {
|
||||
"stopSpecOnExpectationFailure": false,
|
||||
"random": true
|
||||
}
|
||||
}
|
28
assignments/A4/valley.js
Normal file
28
assignments/A4/valley.js
Normal file
@ -0,0 +1,28 @@
|
||||
let life=require("./moarlife.js");
|
||||
|
||||
let valley = new life.LifelikeWorld(
|
||||
["############################",
|
||||
"##### ######",
|
||||
"## *** **##",
|
||||
"# *##** ** O *##",
|
||||
"# *** O ##** *#",
|
||||
"# O ##*** #",
|
||||
"# ##** #",
|
||||
"# O #* #",
|
||||
"#* #** O #",
|
||||
"#*** ##** O **#",
|
||||
"##**** ###*** *###",
|
||||
"############################"],
|
||||
{"#": life.Wall,
|
||||
"O": life.PlantEater,
|
||||
"*": life.Plant}
|
||||
);
|
||||
|
||||
function loop () {
|
||||
valley.turn();
|
||||
console.log("\33c");
|
||||
console.log(valley.toString());
|
||||
setTimeout(function() { loop(); },250);
|
||||
}
|
||||
|
||||
loop();
|
8
assignments/A5/.idea/.gitignore
generated
vendored
Normal file
8
assignments/A5/.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
8
assignments/A5/.idea/A5.iml
generated
Normal file
8
assignments/A5/.idea/A5.iml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
6
assignments/A5/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
assignments/A5/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
4
assignments/A5/.idea/misc.xml
generated
Normal file
4
assignments/A5/.idea/misc.xml
generated
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (python-venv)" project-jdk-type="Python SDK" />
|
||||
</project>
|
8
assignments/A5/.idea/modules.xml
generated
Normal file
8
assignments/A5/.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/A5.iml" filepath="$PROJECT_DIR$/.idea/A5.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
assignments/A5/.idea/vcs.xml
generated
Normal file
6
assignments/A5/.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
1000
assignments/A5/2014-1000.csv
Normal file
1000
assignments/A5/2014-1000.csv
Normal file
File diff suppressed because one or more lines are too long
122
assignments/A5/readcsv.py
Normal file
122
assignments/A5/readcsv.py
Normal file
@ -0,0 +1,122 @@
|
||||
def read_csv(filename):
|
||||
"""Read a CSV file, return list of rows"""
|
||||
|
||||
import csv
|
||||
with open(filename, 'rt', newline='') as f:
|
||||
reader = csv.reader(f, skipinitialspace=True)
|
||||
return [row for row in reader]
|
||||
|
||||
|
||||
def header_map(headers):
|
||||
"""
|
||||
Read a list, and convert it to a dictionary where the key is each element of the given list and the value is
|
||||
its position in the list
|
||||
:param headers: List
|
||||
:return: Dict
|
||||
"""
|
||||
|
||||
header_dict = dict()
|
||||
i = 0
|
||||
for header in headers:
|
||||
header_dict[header] = i
|
||||
i = i + 1
|
||||
return header_dict
|
||||
|
||||
|
||||
def select(table, search_items):
|
||||
"""
|
||||
Read the set in the second argument and search through the table in the first argument and return the
|
||||
columns that match the query in the search items
|
||||
:param table: List
|
||||
:param search_items: List
|
||||
:return: List
|
||||
"""
|
||||
|
||||
header_numbers = header_map(table[0])
|
||||
ret_list = list()
|
||||
columns = list()
|
||||
|
||||
for item in search_items:
|
||||
if type(item) is int: # Convert searched elements into strings if it is a number
|
||||
columns.append(header_numbers[str(item)])
|
||||
else:
|
||||
columns.append(header_numbers[item])
|
||||
columns.sort()
|
||||
for item in table:
|
||||
lst = list()
|
||||
for number in columns:
|
||||
lst.append(item[number])
|
||||
ret_list.append(lst)
|
||||
return ret_list
|
||||
|
||||
|
||||
def row2dict(hmap, row):
|
||||
"""
|
||||
Convert a row in the second argument, given the headers in the first argument to a dictionary which uses the
|
||||
headers as keys and the row data as values
|
||||
:param hmap: Dictionary
|
||||
:param row: List
|
||||
:return: Dictionary
|
||||
"""
|
||||
ret_dict = dict()
|
||||
for key in hmap:
|
||||
ret_dict[key] = row[hmap[key]]
|
||||
return ret_dict
|
||||
|
||||
|
||||
def check_row(row, query):
|
||||
"""
|
||||
Check the row in the first argument passes a query in the second argument. The second argument is a formatted
|
||||
tuple where the first element in the tuple is a column name, the second is an operation (==, <=, >=, AND,
|
||||
OR) and the third element is a condition, numeric or string matching. (ex: is age == 34, is color == blue). AND
|
||||
and OR are special in that you can pass in recursive tuples (left and right argument are tuples) that will also
|
||||
be evaluated recursively
|
||||
:param row: List
|
||||
:param query: Tuple
|
||||
:return: Boolean
|
||||
"""
|
||||
|
||||
def perform_operation(op, var, cond):
|
||||
if type(var) is str:
|
||||
if var.isnumeric():
|
||||
var = int(var)
|
||||
if type(cond) is str:
|
||||
if cond.isnumeric():
|
||||
cond = int(cond)
|
||||
|
||||
if op == '==':
|
||||
return var == cond
|
||||
elif op == '>=':
|
||||
return var >= cond
|
||||
elif op == '<=':
|
||||
return var <= cond
|
||||
elif op == 'OR':
|
||||
return perform_operation(var[1], row[var[0]], var[2]) or perform_operation(cond[1], row[cond[0]], cond[2])
|
||||
elif op == 'AND':
|
||||
return perform_operation(var[1], row[var[0]], var[2]) and perform_operation(cond[1], row[cond[0]], cond[2])
|
||||
else:
|
||||
return False
|
||||
|
||||
if type(query[0]) and type(query[2]) is tuple:
|
||||
return perform_operation(query[1], query[0], query[2])
|
||||
else:
|
||||
stringify = str(query[2])
|
||||
return perform_operation(query[1], row[str(query[0])], stringify)
|
||||
|
||||
|
||||
def filter_table(table, query):
|
||||
"""
|
||||
This function takes a table of csv values, and performs the query to filter out the rows that do not match the query
|
||||
:param table: List
|
||||
:param query: Tuple
|
||||
:return: List
|
||||
"""
|
||||
header_row = header_map(table[0])
|
||||
data_rows = table[1:]
|
||||
result = list()
|
||||
result.append(table[0])
|
||||
for row in data_rows:
|
||||
data_dict = row2dict(header_row, row)
|
||||
if check_row(data_dict, query):
|
||||
result.append(row)
|
||||
return result
|
4
assignments/A5/test1.csv
Normal file
4
assignments/A5/test1.csv
Normal file
@ -0,0 +1,4 @@
|
||||
name, age, eye colour
|
||||
Bob, 5, blue
|
||||
Mary, 27, brown
|
||||
Vij, 54, green
|
|
3
assignments/A5/test2.csv
Normal file
3
assignments/A5/test2.csv
Normal file
@ -0,0 +1,3 @@
|
||||
name, 100
|
||||
teddy, 500
|
||||
lovely, 1000
|
|
114
assignments/A5/test_readcsv.py
Normal file
114
assignments/A5/test_readcsv.py
Normal file
@ -0,0 +1,114 @@
|
||||
from readcsv import read_csv
|
||||
from readcsv import header_map
|
||||
from readcsv import select
|
||||
from readcsv import row2dict
|
||||
from readcsv import check_row
|
||||
from readcsv import filter_table
|
||||
|
||||
table = read_csv('test1.csv')
|
||||
sampledata = read_csv('2014-1000.csv')
|
||||
|
||||
|
||||
def test_read_csv():
|
||||
assert read_csv('test1.csv') == [['name', 'age', 'eye colour'],
|
||||
['Bob', '5', 'blue'],
|
||||
['Mary', '27', 'brown'],
|
||||
['Vij', '54', 'green']]
|
||||
|
||||
|
||||
def test_header_map_1():
|
||||
hmap = header_map(table[0])
|
||||
assert hmap == {'name': 0, 'age': 1, 'eye colour': 2}
|
||||
|
||||
|
||||
def test_select_1():
|
||||
assert select(table, {'name', 'eye colour'}) == [['name', 'eye colour'],
|
||||
['Bob', 'blue'],
|
||||
['Mary', 'brown'],
|
||||
['Vij', 'green']]
|
||||
|
||||
|
||||
def test_row2dict():
|
||||
hmap = header_map(table[0])
|
||||
assert row2dict(hmap, table[1]) == {'name': 'Bob', 'age': '5', 'eye colour': 'blue'}
|
||||
|
||||
|
||||
def test_check_row():
|
||||
row = {'name': 'Bob', 'age': '5', 'eye colour': 'blue'}
|
||||
assert check_row(row, ('age', '==', 5))
|
||||
assert not check_row(row, ('eye colour', '==', 5))
|
||||
assert check_row(row, ('eye colour', '==', 'blue'))
|
||||
assert check_row(row, ('age', '>=', 4))
|
||||
assert check_row(row, ('age', '<=', 1000))
|
||||
|
||||
|
||||
def test_check_row_logical():
|
||||
row = {'name': 'Bob', 'age': '5', 'eye colour': 'blue'}
|
||||
assert check_row(row, (('age', '==', 5), 'OR', ('eye colour', '==', 5)))
|
||||
assert not check_row(row, (('age', '==', 5), 'AND', ('eye colour', '==', 5)))
|
||||
|
||||
|
||||
def test_filter_table1():
|
||||
assert filter_table(table, ('age', '>=', 0)) == [['name', 'age', 'eye colour'],
|
||||
['Bob', '5', 'blue'],
|
||||
['Mary', '27', 'brown'],
|
||||
['Vij', '54', 'green']]
|
||||
|
||||
assert filter_table(table, ('age', '<=', 27)) == [['name', 'age', 'eye colour'],
|
||||
['Bob', '5', 'blue'],
|
||||
['Mary', '27', 'brown']]
|
||||
|
||||
assert filter_table(table, ('eye colour', '==', 'brown')) == [['name', 'age', 'eye colour'],
|
||||
['Mary', '27', 'brown']]
|
||||
|
||||
assert filter_table(table, ('name', '==', 'Vij')) == [['name', 'age', 'eye colour'],
|
||||
['Vij', '54', 'green']]
|
||||
|
||||
|
||||
def test_filter_table2():
|
||||
assert filter_table(table, (('age', '>=', 0), 'AND', ('age', '>=', '27'))) == [['name', 'age', 'eye colour'],
|
||||
['Mary', '27', 'brown'],
|
||||
['Vij', '54', 'green']]
|
||||
|
||||
assert filter_table(table, (('age', '<=', 27), 'AND', ('age', '>=', '27'))) == [['name', 'age', 'eye colour'],
|
||||
['Mary', '27', 'brown']]
|
||||
|
||||
assert filter_table(table, (('eye colour', '==', 'brown'),
|
||||
'OR',
|
||||
('name', '==', 'Vij'))) == [['name', 'age', 'eye colour'],
|
||||
['Mary', '27', 'brown'],
|
||||
['Vij', '54', 'green']]
|
||||
|
||||
|
||||
# Student Tests
|
||||
table2 = read_csv('test2.csv')
|
||||
hmap2 = header_map(table2[0])
|
||||
|
||||
|
||||
def test_header_map2():
|
||||
assert header_map(table2[0]) == {"name": 0, "100": 1}
|
||||
|
||||
|
||||
def test_select2():
|
||||
assert select(table2, [100]) == [["100"], ["500"], ["1000"]]
|
||||
assert select(table2, ["name"]) == [["name"], ["teddy"], ["lovely"]]
|
||||
assert select(table2, ["name", 100]) == [["name", "100"], ["teddy", "500"], ["lovely", "1000"]]
|
||||
|
||||
|
||||
def test_row2dict2():
|
||||
assert row2dict(hmap2, table2[1]) == {"name": "teddy", "100": "500"}
|
||||
assert row2dict(hmap2, table2[2]) == {"name": "lovely", "100": "1000"}
|
||||
|
||||
|
||||
def test_check_row_2():
|
||||
row = {'name': 'Bob', 'age': '5', 'eye colour': 'blue'}
|
||||
assert not check_row(row, ('age', '===', 5))
|
||||
|
||||
|
||||
def test_check_row_3():
|
||||
row = row2dict(hmap2, table2[1])
|
||||
assert check_row(row, ("100", "==", 500))
|
||||
|
||||
|
||||
def test_filter_table3():
|
||||
assert filter_table(table2, ("100", ">=", 100)) == [["name", "100"], ["teddy", "500"], ["lovely", "1000"]]
|
1752
assignments/A5/test_readcsv_bigdata.py
Normal file
1752
assignments/A5/test_readcsv_bigdata.py
Normal file
File diff suppressed because it is too large
Load Diff
32
assignments/A6/classify.m
Normal file
32
assignments/A6/classify.m
Normal file
@ -0,0 +1,32 @@
|
||||
iris = csvread("iris.csv");
|
||||
|
||||
[training, testing] = randomsplit(iris, 2/3)
|
||||
|
||||
p = 2
|
||||
cells = p^(columns(iris)-1)+1
|
||||
|
||||
minmax = ranges(iris);
|
||||
classes = minmax(2,1) - minmax(1,1) + 1;
|
||||
|
||||
votes = zeros(cells,classes);
|
||||
|
||||
for i=1:rows(training)
|
||||
label = training(i,1);
|
||||
hashval = hash(training(i,:), minmax, p);
|
||||
votes(hashval,label) += 1;
|
||||
endfor
|
||||
|
||||
classification = tally(votes)
|
||||
|
||||
correct = 0
|
||||
for i=1:rows(testing);
|
||||
hashval = hash(testing(i,:), minmax, p);
|
||||
class=classification(hashval);
|
||||
label = testing(i,1);
|
||||
if label == class
|
||||
correct += 1;
|
||||
endif
|
||||
endfor
|
||||
|
||||
display(correct/rows(testing))
|
||||
|
151
assignments/A6/iris.csv
Normal file
151
assignments/A6/iris.csv
Normal file
@ -0,0 +1,151 @@
|
||||
1,5.1,3.5,1.4,0.2
|
||||
1,4.9,3.0,1.4,0.2
|
||||
1,4.7,3.2,1.3,0.2
|
||||
1,4.6,3.1,1.5,0.2
|
||||
1,5.0,3.6,1.4,0.2
|
||||
1,5.4,3.9,1.7,0.4
|
||||
1,4.6,3.4,1.4,0.3
|
||||
1,5.0,3.4,1.5,0.2
|
||||
1,4.4,2.9,1.4,0.2
|
||||
1,4.9,3.1,1.5,0.1
|
||||
1,5.4,3.7,1.5,0.2
|
||||
1,4.8,3.4,1.6,0.2
|
||||
1,4.8,3.0,1.4,0.1
|
||||
1,4.3,3.0,1.1,0.1
|
||||
1,5.8,4.0,1.2,0.2
|
||||
1,5.7,4.4,1.5,0.4
|
||||
1,5.4,3.9,1.3,0.4
|
||||
1,5.1,3.5,1.4,0.3
|
||||
1,5.7,3.8,1.7,0.3
|
||||
1,5.1,3.8,1.5,0.3
|
||||
1,5.4,3.4,1.7,0.2
|
||||
1,5.1,3.7,1.5,0.4
|
||||
1,4.6,3.6,1.0,0.2
|
||||
1,5.1,3.3,1.7,0.5
|
||||
1,4.8,3.4,1.9,0.2
|
||||
1,5.0,3.0,1.6,0.2
|
||||
1,5.0,3.4,1.6,0.4
|
||||
1,5.2,3.5,1.5,0.2
|
||||
1,5.2,3.4,1.4,0.2
|
||||
1,4.7,3.2,1.6,0.2
|
||||
1,4.8,3.1,1.6,0.2
|
||||
1,5.4,3.4,1.5,0.4
|
||||
1,5.2,4.1,1.5,0.1
|
||||
1,5.5,4.2,1.4,0.2
|
||||
1,4.9,3.1,1.5,0.1
|
||||
1,5.0,3.2,1.2,0.2
|
||||
1,5.5,3.5,1.3,0.2
|
||||
1,4.9,3.1,1.5,0.1
|
||||
1,4.4,3.0,1.3,0.2
|
||||
1,5.1,3.4,1.5,0.2
|
||||
1,5.0,3.5,1.3,0.3
|
||||
1,4.5,2.3,1.3,0.3
|
||||
1,4.4,3.2,1.3,0.2
|
||||
1,5.0,3.5,1.6,0.6
|
||||
1,5.1,3.8,1.9,0.4
|
||||
1,4.8,3.0,1.4,0.3
|
||||
1,5.1,3.8,1.6,0.2
|
||||
1,4.6,3.2,1.4,0.2
|
||||
1,5.3,3.7,1.5,0.2
|
||||
1,5.0,3.3,1.4,0.2
|
||||
2,7.0,3.2,4.7,1.4
|
||||
2,6.4,3.2,4.5,1.5
|
||||
2,6.9,3.1,4.9,1.5
|
||||
2,5.5,2.3,4.0,1.3
|
||||
2,6.5,2.8,4.6,1.5
|
||||
2,5.7,2.8,4.5,1.3
|
||||
2,6.3,3.3,4.7,1.6
|
||||
2,4.9,2.4,3.3,1.0
|
||||
2,6.6,2.9,4.6,1.3
|
||||
2,5.2,2.7,3.9,1.4
|
||||
2,5.0,2.0,3.5,1.0
|
||||
2,5.9,3.0,4.2,1.5
|
||||
2,6.0,2.2,4.0,1.0
|
||||
2,6.1,2.9,4.7,1.4
|
||||
2,5.6,2.9,3.6,1.3
|
||||
2,6.7,3.1,4.4,1.4
|
||||
2,5.6,3.0,4.5,1.5
|
||||
2,5.8,2.7,4.1,1.0
|
||||
2,6.2,2.2,4.5,1.5
|
||||
2,5.6,2.5,3.9,1.1
|
||||
2,5.9,3.2,4.8,1.8
|
||||
2,6.1,2.8,4.0,1.3
|
||||
2,6.3,2.5,4.9,1.5
|
||||
2,6.1,2.8,4.7,1.2
|
||||
2,6.4,2.9,4.3,1.3
|
||||
2,6.6,3.0,4.4,1.4
|
||||
2,6.8,2.8,4.8,1.4
|
||||
2,6.7,3.0,5.0,1.7
|
||||
2,6.0,2.9,4.5,1.5
|
||||
2,5.7,2.6,3.5,1.0
|
||||
2,5.5,2.4,3.8,1.1
|
||||
2,5.5,2.4,3.7,1.0
|
||||
2,5.8,2.7,3.9,1.2
|
||||
2,6.0,2.7,5.1,1.6
|
||||
2,5.4,3.0,4.5,1.5
|
||||
2,6.0,3.4,4.5,1.6
|
||||
2,6.7,3.1,4.7,1.5
|
||||
2,6.3,2.3,4.4,1.3
|
||||
2,5.6,3.0,4.1,1.3
|
||||
2,5.5,2.5,4.0,1.3
|
||||
2,5.5,2.6,4.4,1.2
|
||||
2,6.1,3.0,4.6,1.4
|
||||
2,5.8,2.6,4.0,1.2
|
||||
2,5.0,2.3,3.3,1.0
|
||||
2,5.6,2.7,4.2,1.3
|
||||
2,5.7,3.0,4.2,1.2
|
||||
2,5.7,2.9,4.2,1.3
|
||||
2,6.2,2.9,4.3,1.3
|
||||
2,5.1,2.5,3.0,1.1
|
||||
2,5.7,2.8,4.1,1.3
|
||||
3,6.3,3.3,6.0,2.5
|
||||
3,5.8,2.7,5.1,1.9
|
||||
3,7.1,3.0,5.9,2.1
|
||||
3,6.3,2.9,5.6,1.8
|
||||
3,6.5,3.0,5.8,2.2
|
||||
3,7.6,3.0,6.6,2.1
|
||||
3,4.9,2.5,4.5,1.7
|
||||
3,7.3,2.9,6.3,1.8
|
||||
3,6.7,2.5,5.8,1.8
|
||||
3,7.2,3.6,6.1,2.5
|
||||
3,6.5,3.2,5.1,2.0
|
||||
3,6.4,2.7,5.3,1.9
|
||||
3,6.8,3.0,5.5,2.1
|
||||
3,5.7,2.5,5.0,2.0
|
||||
3,5.8,2.8,5.1,2.4
|
||||
3,6.4,3.2,5.3,2.3
|
||||
3,6.5,3.0,5.5,1.8
|
||||
3,7.7,3.8,6.7,2.2
|
||||
3,7.7,2.6,6.9,2.3
|
||||
3,6.0,2.2,5.0,1.5
|
||||
3,6.9,3.2,5.7,2.3
|
||||
3,5.6,2.8,4.9,2.0
|
||||
3,7.7,2.8,6.7,2.0
|
||||
3,6.3,2.7,4.9,1.8
|
||||
3,6.7,3.3,5.7,2.1
|
||||
3,7.2,3.2,6.0,1.8
|
||||
3,6.2,2.8,4.8,1.8
|
||||
3,6.1,3.0,4.9,1.8
|
||||
3,6.4,2.8,5.6,2.1
|
||||
3,7.2,3.0,5.8,1.6
|
||||
3,7.4,2.8,6.1,1.9
|
||||
3,7.9,3.8,6.4,2.0
|
||||
3,6.4,2.8,5.6,2.2
|
||||
3,6.3,2.8,5.1,1.5
|
||||
3,6.1,2.6,5.6,1.4
|
||||
3,7.7,3.0,6.1,2.3
|
||||
3,6.3,3.4,5.6,2.4
|
||||
3,6.4,3.1,5.5,1.8
|
||||
3,6.0,3.0,4.8,1.8
|
||||
3,6.9,3.1,5.4,2.1
|
||||
3,6.7,3.1,5.6,2.4
|
||||
3,6.9,3.1,5.1,2.3
|
||||
3,5.8,2.7,5.1,1.9
|
||||
3,6.8,3.2,5.9,2.3
|
||||
3,6.7,3.3,5.7,2.5
|
||||
3,6.7,3.0,5.2,2.3
|
||||
3,6.3,2.5,5.0,1.9
|
||||
3,6.5,3.0,5.2,2.0
|
||||
3,6.2,3.4,5.4,2.3
|
||||
3,5.9,3.0,5.1,1.8
|
||||
|
|
1
assignments/A6/workspace.octave-workspace
Normal file
1
assignments/A6/workspace.octave-workspace
Normal file
@ -0,0 +1 @@
|
||||
# Created by Octave 7.3.0, Wed Dec 07 23:43:44 2022 GMT <unknown@Isaac-DesktopPC>
|
17
journal/_src/posts/2022-10-17-lab-10.md
Normal file
17
journal/_src/posts/2022-10-17-lab-10.md
Normal file
@ -0,0 +1,17 @@
|
||||
Title: Lab Ten
|
||||
Date: 2022-10-17T08:30:00
|
||||
Tags: cs2613, lab, javascript, methods, tests, classes, prototypes, arrays, recursion
|
||||
|
||||
In this lab, I learned about classes, prototypes, arrays and how to use recursion in javascript
|
||||
<!-- more -->
|
||||
|
||||
## Prototypes
|
||||
In javascript, there is a notion of a prototype, which is a way of making objects by calling the `Object.create()` function on a "prototype" of an object, which can be viewed as a form of constructor
|
||||
## Classes
|
||||
In reality, classes should be made by the new keyword instead of calling `Object.create()`. In "recent" times there has been an addition to javascript which allows the use of the class keyword and a constructor keyword, which lets you define an object in a very similar way to Java. It should be noted that both the new and the class/constructor syntax is just the same prototype based system that has been made more convenient to read.
|
||||
## Arrays
|
||||
Arrays in javascript are implemented as objects, which is similar to java, but due to the type casting nature of javascript can lead to some unintuitive behavior. We were tasked to create a function that takes a range and creates an array filled with numbers from the start of the range to the end. This can be achieved with a simple for loop.
|
||||
|
||||
We were also tasked with creating function that sums the elements of a javascript array. This can also be done with a for loop, by looping over each element and adding it to a running total and returning the result. We were introduced to some higher order functions like reduce and forEach, which take functions as arguments and are similar to `foldl` in racket. We can use foreach as a way to skip the syntax of a normal for loop and simply operate once on each element of an array.
|
||||
## Recursion
|
||||
We were tasked with using recursion to recreate the `mult` and `add` methods from the first javascript lab, but with recursion. In my opinion it was much more readable than the sample racket solution, but there was an noticeable similarity in the syntax
|
9
journal/_src/posts/2022-10-19-lab-11.md
Normal file
9
journal/_src/posts/2022-10-19-lab-11.md
Normal file
@ -0,0 +1,9 @@
|
||||
Title: Lab Eleven
|
||||
Date: 2022-10-19T08:30:00
|
||||
Tags: cs2613, lab, javascript
|
||||
|
||||
Sample description
|
||||
<!-- more -->
|
||||
|
||||
## Sample Body
|
||||
Sample Body
|
9
journal/_src/posts/2022-10-24-lab-12.md
Normal file
9
journal/_src/posts/2022-10-24-lab-12.md
Normal file
@ -0,0 +1,9 @@
|
||||
Title: Lab Twelve
|
||||
Date: 2022-10-24T08:30:00
|
||||
Tags: cs2613, lab, javascript
|
||||
|
||||
Sample description
|
||||
<!-- more -->
|
||||
|
||||
## Sample Body
|
||||
Sample Body
|
9
journal/_src/posts/2022-10-26-lab-13.md
Normal file
9
journal/_src/posts/2022-10-26-lab-13.md
Normal file
@ -0,0 +1,9 @@
|
||||
Title: Lab Thirteen
|
||||
Date: 2022-10-26T08:30:00
|
||||
Tags: cs2613, lab, javascript
|
||||
|
||||
Sample description
|
||||
<!-- more -->
|
||||
|
||||
## Sample Body
|
||||
Sample Body
|
21
journal/_src/posts/2022-10-31-lab-14.md
Normal file
21
journal/_src/posts/2022-10-31-lab-14.md
Normal file
@ -0,0 +1,21 @@
|
||||
Title: Lab Fourteen
|
||||
Date: 2022-10-31T08:30:00
|
||||
Tags: cs2613, lab, python, pytest, exceptions, modules
|
||||
|
||||
In this lab I learned about python, pytest, python exceptions and modules.
|
||||
<!-- more -->
|
||||
|
||||
## Pytest
|
||||
Pytest is a python testing framework. It can show you code coverage with line counts. This is pretty similar to `nyc` from javascript. You run tests by just running `pytest` or `pytest -cov` for code coverage. Tests are defined by in a file having a function with an assert statement. Pytest will then scan your files for assert statements and run those functions to run tests. Testing in python is pretty simple, like with javascript. Racket testing is a little more abstract and confusing in my opinion.
|
||||
|
||||
## Modules
|
||||
In python functions are exported by default, in contrast to javascript. You must guard your main method with the `if __name__ =='__main__'` text so it does not run when the module is imported. You can make tests to ensure you have documentation for your functions, by checking for the imports `__doc__` variable.
|
||||
|
||||
## Indentation
|
||||
In python, blocks are defined by indentation (also known as whitespace). This sets the scope for a given statement. It can be a little confusing to tell if an if statement is in a for loop or not, but linters help.
|
||||
|
||||
## Exceptions
|
||||
Python can raise errors when things go wrong, for example diving by zero. You can catch these exceptions and handle them if you desire.
|
||||
|
||||
## FizzBuzz missing case
|
||||
You can fix the missing case just by adding another if statement above the other if statement for the fizz case.
|
18
labs/L10/arrays.js
Normal file
18
labs/L10/arrays.js
Normal file
@ -0,0 +1,18 @@
|
||||
function range(start, end, step=1) {
|
||||
let result = [];
|
||||
for (let i = start; i <= end; i += step) {
|
||||
result.push(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function sum(array) {
|
||||
let result = 0;
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
result += array[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
exports.range = range;
|
||||
exports.sum = sum;
|
17
labs/L10/loop-arith.js
Normal file
17
labs/L10/loop-arith.js
Normal file
@ -0,0 +1,17 @@
|
||||
function plus(a,b) {
|
||||
for (let i=0; i < a; i++){
|
||||
b++;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
function mult(a,b) {
|
||||
sum=0;
|
||||
for(let i=0; i < a; i++) {
|
||||
sum = plus(sum, b)
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
exports.plus = plus;
|
||||
exports.mult = mult;
|
16
labs/L10/rec-arith.js
Normal file
16
labs/L10/rec-arith.js
Normal file
@ -0,0 +1,16 @@
|
||||
function plus(a,b) {
|
||||
if (a === 0) {
|
||||
return b;
|
||||
} else {
|
||||
return plus(a-1, b+1);
|
||||
}
|
||||
}
|
||||
function mult(a,b) {
|
||||
if (a === 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return plus(mult(a-1, b), b);
|
||||
}
|
||||
}
|
||||
exports.plus = plus;
|
||||
exports.mult = mult;
|
31
labs/L10/spec/arrays.spec.js
Normal file
31
labs/L10/spec/arrays.spec.js
Normal file
@ -0,0 +1,31 @@
|
||||
let array=require("../arrays.js");
|
||||
|
||||
describe("range", function () {
|
||||
it("empty", function () {
|
||||
expect(array.range(2,1)).toEqual([]);
|
||||
});
|
||||
it("single", function () {
|
||||
expect(array.range(2,2)).toEqual([2]);
|
||||
});
|
||||
it("multiple", function () {
|
||||
expect(array.range(42,50)).toEqual([42,43,44,45,46,47,48,49,50]);
|
||||
});
|
||||
it("step", function() {
|
||||
expect(array.range(2,10,2)).toEqual([2,4,6,8,10]);
|
||||
})
|
||||
});
|
||||
|
||||
describe("sum", function () {
|
||||
it("empty", function () {
|
||||
expect(array.sum([])).toBe(0);
|
||||
});
|
||||
it("single", function () {
|
||||
expect(array.sum([2])).toBe(2);
|
||||
});
|
||||
it("multiple", function () {
|
||||
expect(array.sum(array.range(1,10))).toBe(55);
|
||||
})
|
||||
it("stepped", function() {
|
||||
expect(array.sum(array.range(2,10,2))).toBe(30)
|
||||
});
|
||||
});
|
30
labs/L10/spec/rec_arith.spec.js
Normal file
30
labs/L10/spec/rec_arith.spec.js
Normal file
@ -0,0 +1,30 @@
|
||||
let arith=require ("../rec-arith.js");
|
||||
|
||||
describe("plus",
|
||||
function() {
|
||||
it("1 + 1 = 2",
|
||||
function() {
|
||||
expect(arith.plus(1, 1)).toBe(2);
|
||||
});
|
||||
it("0 + x = x",
|
||||
function() {
|
||||
expect(arith.plus(0, 1)).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("mult",
|
||||
function() {
|
||||
it("0 * 2 = 0",
|
||||
function() {
|
||||
expect(arith.mult(0, 2)).toBe(0);
|
||||
});
|
||||
|
||||
it("1 * 2 = 2",
|
||||
function() {
|
||||
expect(arith.mult(1,2)).toBe(2);
|
||||
});
|
||||
it("2 * 2 = 4",
|
||||
function() {
|
||||
expect(arith.mult(2, 2)).toBe(4);
|
||||
});
|
||||
});
|
31
labs/L10/spec/rec_vs_loop.spec.js
Normal file
31
labs/L10/spec/rec_vs_loop.spec.js
Normal file
@ -0,0 +1,31 @@
|
||||
let loop_arith=require ("../loop-arith.js");
|
||||
let rec_arith=require ("../rec-arith.js");
|
||||
|
||||
describe("plus",
|
||||
function() {
|
||||
it("1 + 1 = 2",
|
||||
function() {
|
||||
expect(loop_arith.plus(1, 1)).toBe(rec_arith.plus(1, 1));
|
||||
});
|
||||
it("0 + x = x",
|
||||
function() {
|
||||
expect(loop_arith.plus(0, 1)).toBe(rec_arith.plus(0, 1));
|
||||
});
|
||||
});
|
||||
|
||||
describe("mult",
|
||||
function() {
|
||||
it("0 * 2 = 0",
|
||||
function() {
|
||||
expect(loop_arith.mult(0, 2)).toBe(rec_arith.mult(0, 2));
|
||||
});
|
||||
|
||||
it("1 * 2 = 2",
|
||||
function() {
|
||||
expect(loop_arith.mult(1, 2)).toBe(rec_arith.mult(1, 2));
|
||||
});
|
||||
it("2 * 2 = 4",
|
||||
function() {
|
||||
expect(loop_arith.mult(2, 2)).toBe(rec_arith.mult(2, 2));
|
||||
});
|
||||
});
|
13
labs/L10/spec/support/jasmine.json
Normal file
13
labs/L10/spec/support/jasmine.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"spec_dir": "spec",
|
||||
"spec_files": [
|
||||
"**/*[sS]pec.?(m)js"
|
||||
],
|
||||
"helpers": [
|
||||
"helpers/**/*.?(m)js"
|
||||
],
|
||||
"env": {
|
||||
"stopSpecOnExpectationFailure": false,
|
||||
"random": true
|
||||
}
|
||||
}
|
72
labs/L10/time.js
Normal file
72
labs/L10/time.js
Normal file
@ -0,0 +1,72 @@
|
||||
function timePlus(time1, time2) {
|
||||
let mins = (time1.mins + time2.mins) % 60;
|
||||
let hours = time1.hours + time2.hours + Math.floor((time1.mins+time2.mins)/60);
|
||||
return {'hours': hours, 'mins': mins};
|
||||
}
|
||||
console.log(timePlus({hours: 10, mins:30}, {hours: 17, mins:47}));
|
||||
function maketime(hours, mins){
|
||||
let plus=function (other) {
|
||||
let raw=timePlus(this,other);
|
||||
return maketime(raw.hours, raw.mins);
|
||||
};
|
||||
|
||||
return { 'hours': hours, 'mins': mins, 'plus': plus};
|
||||
}
|
||||
|
||||
let A=maketime(10, 30);
|
||||
let B=maketime(17, 47);
|
||||
let C=A.plus(B);
|
||||
console.log(C);
|
||||
|
||||
let protoTime = {
|
||||
plus: function(other) {
|
||||
let raw=timePlus(this,other);
|
||||
return timeNew(raw.hours, raw.mins);
|
||||
}
|
||||
};
|
||||
|
||||
function timeNew(hours, mins) {
|
||||
let obj=Object.create(protoTime);
|
||||
obj.hours = hours;
|
||||
obj.mins = mins;
|
||||
return obj;
|
||||
}
|
||||
|
||||
D=timeNew(21,42);
|
||||
E=timeNew(17,37);
|
||||
|
||||
F=D.plus(E);
|
||||
console.log(F);
|
||||
|
||||
function Time(hours, mins){
|
||||
this.hours=hours;
|
||||
this.mins=mins;
|
||||
}
|
||||
|
||||
Time.prototype.plus=function (other) {
|
||||
let raw=timePlus(this,other);
|
||||
return new Time(raw.hours, raw.mins);
|
||||
}
|
||||
|
||||
G = new Time(20,59);
|
||||
H = new Time(11,11);
|
||||
|
||||
I=G.plus(H);
|
||||
console.log(I);
|
||||
|
||||
class Time2 {
|
||||
constructor(hours, mins){
|
||||
this.hours=hours;
|
||||
this.mins=mins;
|
||||
};
|
||||
plus(other) {
|
||||
let raw=timePlus(this,other);
|
||||
return new Time2(raw.hours, raw.mins);
|
||||
}
|
||||
}
|
||||
|
||||
J= new Time2(5,30);
|
||||
K= new Time2(11,55);
|
||||
|
||||
L=J.plus(K);
|
||||
console.log(L)
|
0
labs/L11/deep-equal.js
Normal file
0
labs/L11/deep-equal.js
Normal file
16
labs/L11/spec/deep-equal.spec.js
Normal file
16
labs/L11/spec/deep-equal.spec.js
Normal file
@ -0,0 +1,16 @@
|
||||
describe("equal", function () {
|
||||
let obj = {here: {is: "an"}, object: 2};
|
||||
it("self", function () {
|
||||
expect(deepEqual(obj,obj)).toBe(true);
|
||||
});
|
||||
it("null", function () {
|
||||
expect(deepEqual(null,null)).toBe(true);
|
||||
});
|
||||
|
||||
it("different", function () {
|
||||
expect(deepEqual(obj, {here: 1, object: 2})).toBe(false);
|
||||
});
|
||||
it("equivalent", function () {
|
||||
expect(deepEqual(obj, {here: {is: "an"}, object: 2})).toBe(true);
|
||||
});
|
||||
});
|
13
labs/L11/spec/support/jasmine.json
Normal file
13
labs/L11/spec/support/jasmine.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"spec_dir": "spec",
|
||||
"spec_files": [
|
||||
"**/*[sS]pec.?(m)js"
|
||||
],
|
||||
"helpers": [
|
||||
"helpers/**/*.?(m)js"
|
||||
],
|
||||
"env": {
|
||||
"stopSpecOnExpectationFailure": false,
|
||||
"random": true
|
||||
}
|
||||
}
|
0
labs/L11/spec/village.spec.js
Normal file
0
labs/L11/spec/village.spec.js
Normal file
59
labs/L11/village.js
Normal file
59
labs/L11/village.js
Normal file
@ -0,0 +1,59 @@
|
||||
const roads = [
|
||||
"Alice's House-Bob's House", "Alice's House-Cabin",
|
||||
"Alice's House-Post Office", "Bob's House-Town Hall",
|
||||
"Daria's House-Ernie's House", "Daria's House-Town Hall",
|
||||
"Ernie's House-Grete's House", "Grete's House-Farm",
|
||||
"Grete's House-Shop", "Marketplace-Farm",
|
||||
"Marketplace-Post Office", "Marketplace-Shop",
|
||||
"Marketplace-Town Hall", "Shop-Town Hall"
|
||||
];
|
||||
|
||||
function buildGraph(edges) {
|
||||
let graph = Object.create(null);
|
||||
function addEdge(from, to) {
|
||||
if (graph[from] == null) {
|
||||
graph[from] = [to];
|
||||
} else {
|
||||
graph[from].push(to);
|
||||
}
|
||||
}
|
||||
for (let [from, to] of edges.map(r => r.split("-"))) {
|
||||
addEdge(from, to);
|
||||
addEdge(to, from);
|
||||
}
|
||||
return graph;
|
||||
}
|
||||
|
||||
const roadGraph = buildGraph(roads);
|
||||
|
||||
class VillageState {
|
||||
constructor(place, parcels) {
|
||||
this.place = place;
|
||||
this.parcels = parcels;
|
||||
}
|
||||
|
||||
move(destination) {
|
||||
if (!roadGraph[this.place].includes(destination)) {
|
||||
return this;
|
||||
} else {
|
||||
let parcels = this.parcels.map(p => {
|
||||
if (p.place != this.place) return p;
|
||||
return { place: destination, address: p.address };
|
||||
}).filter(p => p.place != p.address);
|
||||
return new VillageState(destination, parcels);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let first = new VillageState(
|
||||
"Post Office",
|
||||
[{ place: "Post Office", address: "Alice's House" }]
|
||||
);
|
||||
let next = first.move("Alice's House");
|
||||
|
||||
console.log(next.place);
|
||||
// → Alice's House
|
||||
console.log(next.parcels);
|
||||
// → []
|
||||
console.log(first.place);
|
||||
// → Post Office
|
13
labs/L12/spec/support/jasmine.json
Normal file
13
labs/L12/spec/support/jasmine.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"spec_dir": "spec",
|
||||
"spec_files": [
|
||||
"**/*[sS]pec.?(m)js"
|
||||
],
|
||||
"helpers": [
|
||||
"helpers/**/*.?(m)js"
|
||||
],
|
||||
"env": {
|
||||
"stopSpecOnExpectationFailure": false,
|
||||
"random": true
|
||||
}
|
||||
}
|
28
labs/L12/spec/village.spec.js
Normal file
28
labs/L12/spec/village.spec.js
Normal file
@ -0,0 +1,28 @@
|
||||
let village = require("../village.js");
|
||||
let VillageState = village.VillageState;
|
||||
describe("roadGraph",
|
||||
function () {
|
||||
let roadGraph = village.roadGraph;
|
||||
it("Alice's house",
|
||||
() => expect(roadGraph["Alice's House"]).toEqual(["Bob's House", "Cabin", "Post Office"]));
|
||||
it("Bob's house",
|
||||
() => expect(roadGraph["Bob's House"]).toEqual(
|
||||
jasmine.objectContaining(["Alice's House"])));
|
||||
});
|
||||
|
||||
|
||||
describe("VillageState",
|
||||
function () {
|
||||
let first = new VillageState(
|
||||
"Post Office",
|
||||
[{ place: "Post Office", address: "Alice's House" }]
|
||||
);
|
||||
let next = first.move("Alice's House");
|
||||
it("next place",
|
||||
() => expect(next.place).toBe("Alice's House"));
|
||||
it("next parcels",
|
||||
() => expect(next.parcels).toEqual([]));
|
||||
it("first place",
|
||||
() => expect(first.place).toEqual("Post Office"));
|
||||
}
|
||||
);
|
48
labs/L12/village.js
Normal file
48
labs/L12/village.js
Normal file
@ -0,0 +1,48 @@
|
||||
const roads = [
|
||||
"Alice's House-Bob's House", "Alice's House-Cabin",
|
||||
"Alice's House-Post Office", "Bob's House-Town Hall",
|
||||
"Daria's House-Ernie's House", "Daria's House-Town Hall",
|
||||
"Ernie's House-Grete's House", "Grete's House-Farm",
|
||||
"Grete's House-Shop", "Marketplace-Farm",
|
||||
"Marketplace-Post Office", "Marketplace-Shop",
|
||||
"Marketplace-Town Hall", "Shop-Town Hall"
|
||||
];
|
||||
function buildGraph(edges) {
|
||||
let graph = Object.create(null);
|
||||
function addEdge(from, to) {
|
||||
if (graph[from] == null) {
|
||||
graph[from] = [to];
|
||||
} else {
|
||||
graph[from].push(to);
|
||||
}
|
||||
}
|
||||
for (let [from, to] of edges.map(r => r.split("-"))) {
|
||||
addEdge(from, to);
|
||||
addEdge(to, from);
|
||||
}
|
||||
return graph;
|
||||
}
|
||||
|
||||
const roadGraph = buildGraph(roads);
|
||||
|
||||
class VillageState {
|
||||
constructor(place, parcels) {
|
||||
this.place = place;
|
||||
this.parcels = parcels;
|
||||
}
|
||||
|
||||
move(destination) {
|
||||
if (!roadGraph[this.place].includes(destination)) {
|
||||
return this;
|
||||
} else {
|
||||
let parcels = this.parcels.map(p => {
|
||||
if (p.place != this.place) return p;
|
||||
return { place: destination, address: p.address };
|
||||
}).filter(p => p.place != p.address);
|
||||
return new VillageState(destination, parcels);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.roadGraph = roadGraph;
|
||||
exports.VillageState = VillageState;
|
39
labs/L13/animation.js
Normal file
39
labs/L13/animation.js
Normal file
@ -0,0 +1,39 @@
|
||||
// let str="";
|
||||
// for (let i=0; i<60; i++) {
|
||||
// console.log('\033c');
|
||||
// str+= "*";
|
||||
// console.log(str);
|
||||
// }
|
||||
|
||||
//console.log("all done!");
|
||||
|
||||
// function loop(i,str) {
|
||||
// if (i>0) {
|
||||
// console.log("\033c");
|
||||
// console.log(str);
|
||||
// setTimeout(function() { loop(i-1, str+"*"); }, 1000);
|
||||
// }
|
||||
// }
|
||||
|
||||
// loop(20,"*");
|
||||
|
||||
// console.log("all done!");
|
||||
|
||||
function animate(iterations) {
|
||||
let i=0;
|
||||
let str="*";
|
||||
let timer = null;
|
||||
function frame() {
|
||||
|
||||
console.log('\033c');
|
||||
console.log(str);
|
||||
if (i>=iterations) {
|
||||
clearInterval(timer);
|
||||
console.log("all done!");
|
||||
}
|
||||
|
||||
}
|
||||
timer=setInterval(frame,300);
|
||||
}
|
||||
|
||||
animate(20);
|
8
labs/L14/.idea/.gitignore
generated
vendored
Normal file
8
labs/L14/.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
10
labs/L14/.idea/L14.iml
generated
Normal file
10
labs/L14/.idea/L14.iml
generated
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.10 (python-venv)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
12
labs/L14/.idea/dataSources.xml
generated
Normal file
12
labs/L14/.idea/dataSources.xml
generated
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name=".coverage" uuid="af2f1fdd-3241-4470-93b5-53f58bcdd0d2">
|
||||
<driver-ref>sqlite.xerial</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||
<jdbc-url>jdbc:sqlite:C:\Users\Isaac\OneDrive - University of New Brunswick\Year 3 UNB\CS2613\Git\cs2613-ishoebot\labs\L14\.coverage</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
6
labs/L14/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
labs/L14/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
4
labs/L14/.idea/misc.xml
generated
Normal file
4
labs/L14/.idea/misc.xml
generated
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (python-venv)" project-jdk-type="Python SDK" />
|
||||
</project>
|
8
labs/L14/.idea/modules.xml
generated
Normal file
8
labs/L14/.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/L14.iml" filepath="$PROJECT_DIR$/.idea/L14.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
24
labs/L14/.idea/runConfigurations/client.xml
generated
Normal file
24
labs/L14/.idea/runConfigurations/client.xml
generated
Normal file
@ -0,0 +1,24 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="client" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
|
||||
<module name="L14" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/client.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
24
labs/L14/.idea/runConfigurations/fizzbuzz.xml
generated
Normal file
24
labs/L14/.idea/runConfigurations/fizzbuzz.xml
generated
Normal file
@ -0,0 +1,24 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="fizzbuzz" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
|
||||
<module name="L14" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/fizzbuzz.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
24
labs/L14/.idea/runConfigurations/humansize.xml
generated
Normal file
24
labs/L14/.idea/runConfigurations/humansize.xml
generated
Normal file
@ -0,0 +1,24 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="humansize" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
|
||||
<module name="L14" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/humansize.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
17
labs/L14/.idea/runConfigurations/pytest.xml
generated
Normal file
17
labs/L14/.idea/runConfigurations/pytest.xml
generated
Normal file
@ -0,0 +1,17 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="pytest" type="ShConfigurationType">
|
||||
<option name="SCRIPT_TEXT" value="pytest --cov --cov-report=term-missing" />
|
||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||
<option name="SCRIPT_PATH" value="" />
|
||||
<option name="SCRIPT_OPTIONS" value="" />
|
||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||
<option name="INTERPRETER_PATH" value="" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="EXECUTE_IN_TERMINAL" value="true" />
|
||||
<option name="EXECUTE_SCRIPT_FILE" value="false" />
|
||||
<envs />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
6
labs/L14/.idea/vcs.xml
generated
Normal file
6
labs/L14/.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
16
labs/L14/client.py
Normal file
16
labs/L14/client.py
Normal file
@ -0,0 +1,16 @@
|
||||
import humansize
|
||||
|
||||
|
||||
def approximate_size(size):
|
||||
"""Returns the size of a file in a human-readable format where kilobytes are 1000 bytes
|
||||
|
||||
:param size: the size of a file
|
||||
:return: string
|
||||
"""
|
||||
return humansize.approximate_size(size, False)
|
||||
|
||||
|
||||
if __name__ == '__main__': # pragma: no cover
|
||||
print(approximate_size(1_000))
|
||||
print(approximate_size(100_000_000))
|
||||
print(approximate_size(1_000_000_000))
|
8
labs/L14/divisive.py
Normal file
8
labs/L14/divisive.py
Normal file
@ -0,0 +1,8 @@
|
||||
import math
|
||||
|
||||
|
||||
def fraction(a, b):
|
||||
try:
|
||||
return a / b
|
||||
except ZeroDivisionError:
|
||||
return math.nan
|
10
labs/L14/fizzbuzz.py
Normal file
10
labs/L14/fizzbuzz.py
Normal file
@ -0,0 +1,10 @@
|
||||
if __name__ == '__main__':
|
||||
for i in range(1, 101):
|
||||
if i % 3 == 0 and i % 5 == 0:
|
||||
print("FizzBuzz")
|
||||
elif i % 3 == 0:
|
||||
print("Fizz")
|
||||
elif i % 5 == 0:
|
||||
print("Buzz")
|
||||
else:
|
||||
print(i)
|
67
labs/L14/humansize.py
Normal file
67
labs/L14/humansize.py
Normal file
@ -0,0 +1,67 @@
|
||||
"""Convert file sizes to human-readable form.
|
||||
|
||||
Available functions:
|
||||
approximate_size(size, a_kilobyte_is_1024_bytes)
|
||||
takes a file size and returns a human-readable string
|
||||
|
||||
Examples:
|
||||
>>> approximate_size(1024)
|
||||
'1.0 KiB'
|
||||
>>> approximate_size(1000, False)
|
||||
'1.0 KB'
|
||||
|
||||
"""
|
||||
|
||||
SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
|
||||
1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}
|
||||
|
||||
|
||||
def approximate_size(size, a_kilobyte_is_1024_bytes=True):
|
||||
"""Convert a file size to human-readable form.
|
||||
|
||||
Keyword arguments:
|
||||
size -- file size in bytes
|
||||
a_kilobyte_is_1024_bytes -- if True (default), use multiples of 1024
|
||||
if False, use multiples of 1000
|
||||
|
||||
Returns: string
|
||||
|
||||
"""
|
||||
if size < 0:
|
||||
raise ValueError('number must be non-negative')
|
||||
|
||||
multiple = 1024 if a_kilobyte_is_1024_bytes else 1000
|
||||
for suffix in SUFFIXES[multiple]:
|
||||
size /= multiple
|
||||
if size < multiple:
|
||||
return '{0:.1f} {1}'.format(size, suffix)
|
||||
|
||||
raise ValueError('number too large')
|
||||
|
||||
|
||||
if __name__ == '__main__': # pragma: no cover
|
||||
print(approximate_size(1000000000000, False))
|
||||
print(approximate_size(1000000000000))
|
||||
|
||||
# Copyright (c) 2009, Mark Pilgrim, All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
18
labs/L14/test_client.py
Normal file
18
labs/L14/test_client.py
Normal file
@ -0,0 +1,18 @@
|
||||
import pytest
|
||||
from client import approximate_size
|
||||
|
||||
|
||||
def test_1kb():
|
||||
assert approximate_size(1_000) == "1.0 KB"
|
||||
|
||||
|
||||
def test_100mb():
|
||||
assert approximate_size(100_000_000) == "100.0 MB"
|
||||
|
||||
|
||||
def test_1gb():
|
||||
assert approximate_size(1_000_000_000) == "1.0 GB"
|
||||
|
||||
|
||||
def test_docstring():
|
||||
assert approximate_size.__doc__ is not None
|
10
labs/L14/test_divisive.py
Normal file
10
labs/L14/test_divisive.py
Normal file
@ -0,0 +1,10 @@
|
||||
from divisive import fraction
|
||||
import math
|
||||
|
||||
|
||||
def test_fraction_int():
|
||||
assert fraction(4, 2) == 2
|
||||
|
||||
|
||||
def test_fraction_NaN():
|
||||
assert math.isnan(fraction(4, 0))
|
20
labs/L14/test_humansize.py
Normal file
20
labs/L14/test_humansize.py
Normal file
@ -0,0 +1,20 @@
|
||||
import pytest
|
||||
from humansize import approximate_size
|
||||
|
||||
|
||||
def test_1000():
|
||||
assert approximate_size(1000000000000, False) == "1.0 TB"
|
||||
|
||||
|
||||
def test_1024():
|
||||
assert approximate_size(1000000000000) == "931.3 GiB"
|
||||
|
||||
|
||||
def test_negative():
|
||||
with pytest.raises(ValueError):
|
||||
approximate_size(-1)
|
||||
|
||||
|
||||
def test_huge_number():
|
||||
with pytest.raises(ValueError):
|
||||
approximate_size(1_000_000_000_000_000_000_000_000_000_000)
|
8
labs/L15/.idea/.gitignore
generated
vendored
Normal file
8
labs/L15/.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
8
labs/L15/.idea/L15.iml
generated
Normal file
8
labs/L15/.idea/L15.iml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="jdk" jdkName="Python 3.10 (python-venv)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
6
labs/L15/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
labs/L15/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
4
labs/L15/.idea/misc.xml
generated
Normal file
4
labs/L15/.idea/misc.xml
generated
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (python-venv)" project-jdk-type="Python SDK" />
|
||||
</project>
|
8
labs/L15/.idea/modules.xml
generated
Normal file
8
labs/L15/.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/L15.iml" filepath="$PROJECT_DIR$/.idea/L15.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
24
labs/L15/.idea/runConfigurations/globex.xml
generated
Normal file
24
labs/L15/.idea/runConfigurations/globex.xml
generated
Normal file
@ -0,0 +1,24 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="globex" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
|
||||
<module name="L15" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||
<option name="SCRIPT_NAME" value="C:\Users\Isaac\Documents\CS2613-Repo\cs2613-ishoebot\labs\L15\globex.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
17
labs/L15/.idea/runConfigurations/pytest.xml
generated
Normal file
17
labs/L15/.idea/runConfigurations/pytest.xml
generated
Normal file
@ -0,0 +1,17 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="pytest" type="ShConfigurationType">
|
||||
<option name="SCRIPT_TEXT" value="pytest --cov --cov-report=term-missing" />
|
||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||
<option name="SCRIPT_PATH" value="" />
|
||||
<option name="SCRIPT_OPTIONS" value="" />
|
||||
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||
<option name="INTERPRETER_PATH" value="" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="EXECUTE_IN_TERMINAL" value="true" />
|
||||
<option name="EXECUTE_SCRIPT_FILE" value="false" />
|
||||
<envs />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
6
labs/L15/.idea/vcs.xml
generated
Normal file
6
labs/L15/.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
22
labs/L15/globex.py
Normal file
22
labs/L15/globex.py
Normal file
@ -0,0 +1,22 @@
|
||||
import glob
|
||||
import os
|
||||
|
||||
# new_dir = os.path.expanduser("~/fcshome/cs2613/labs/test") # For lab machines
|
||||
new_dir = os.path.abspath("C:\\Users\\Isaac\\Documents\\CS2613-Repo\\cs2613-ishoebot\\labs\\L14") # For local machine
|
||||
|
||||
python_files_for = []
|
||||
|
||||
for file in glob.glob("*.py"):
|
||||
python_files_for.append(os.path.join(new_dir, file))
|
||||
|
||||
python_files_comp = [os.path.join(new_dir, file) for file in glob.glob("*.py")]
|
||||
|
||||
python_files_map = map(lambda file: os.path.join(new_dir, file), glob.glob("*.py"))
|
||||
|
||||
|
||||
if __name__ == '__main__': # pragma: no cover
|
||||
print(python_files_for)
|
||||
print()
|
||||
print(python_files_comp)
|
||||
print()
|
||||
print(list(python_files_map))
|
7
labs/L15/list2dict.py
Normal file
7
labs/L15/list2dict.py
Normal file
@ -0,0 +1,7 @@
|
||||
def list2dict(lst):
|
||||
lst_dict = dict()
|
||||
counter = 1
|
||||
for i in range(lst):
|
||||
lst_dict[counter] = i
|
||||
counter += 1
|
||||
return lst_dict
|
9
labs/L15/test_globex.py
Normal file
9
labs/L15/test_globex.py
Normal file
@ -0,0 +1,9 @@
|
||||
import globex
|
||||
|
||||
|
||||
def test_for():
|
||||
assert sorted(globex.python_files_for) == sorted(globex.python_files_comp)
|
||||
|
||||
|
||||
def test_map():
|
||||
assert sorted(globex.python_files_comp) == sorted(globex.python_files_map)
|
10
labs/L15/test_list2dict.py
Normal file
10
labs/L15/test_list2dict.py
Normal file
@ -0,0 +1,10 @@
|
||||
from list2dict import list2dict
|
||||
|
||||
|
||||
def test_empty():
|
||||
assert list2dict([]) == {}
|
||||
|
||||
|
||||
def test_abc():
|
||||
dictionary = list2dict(["a", "b", "c"])
|
||||
assert dictionary == {1: 'a', 2: 'b', 3: 'c'}
|
8
labs/L16/.idea/.gitignore
generated
vendored
Normal file
8
labs/L16/.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
8
labs/L16/.idea/L16.iml
generated
Normal file
8
labs/L16/.idea/L16.iml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
12
labs/L16/.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
12
labs/L16/.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@ -0,0 +1,12 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PyPep8Inspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="ignoredErrors">
|
||||
<list>
|
||||
<option value="E501" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
6
labs/L16/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
labs/L16/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
4
labs/L16/.idea/misc.xml
generated
Normal file
4
labs/L16/.idea/misc.xml
generated
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="CS2613-venv" project-jdk-type="Python SDK" />
|
||||
</project>
|
8
labs/L16/.idea/modules.xml
generated
Normal file
8
labs/L16/.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/L16.iml" filepath="$PROJECT_DIR$/.idea/L16.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
labs/L16/.idea/vcs.xml
generated
Normal file
6
labs/L16/.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
14
labs/L16/parse_csv.py
Normal file
14
labs/L16/parse_csv.py
Normal file
@ -0,0 +1,14 @@
|
||||
import re
|
||||
|
||||
|
||||
def split_csv(string):
|
||||
return [row.split(",") for row in string.splitlines()]
|
||||
|
||||
|
||||
def strip_quotes(string):
|
||||
strip_regex = re.compile(r'("?)*$("?)')
|
||||
search = strip_regex.search(string)
|
||||
if search:
|
||||
return search.group(1)
|
||||
else:
|
||||
return None
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user