├── libpeerconnection.log ├── src ├── scripts │ ├── libs │ │ ├── version.txt │ │ ├── qa │ │ │ ├── graphs.txt │ │ │ ├── geometry.ls │ │ │ ├── fpolys.ls │ │ │ └── guessExact.ls │ │ ├── console-helper.js │ │ └── html5shiv-printshiv.js │ ├── pubs │ │ ├── frogs │ │ │ ├── services │ │ │ │ └── semver.ls │ │ │ ├── views │ │ │ │ └── nav.html │ │ │ ├── routes.ls │ │ │ ├── styles.less │ │ │ ├── directives │ │ │ │ ├── frogs.ls │ │ │ │ └── frog.ls │ │ │ ├── index.html │ │ │ ├── main.ls │ │ │ └── controllers │ │ │ │ └── frogController.ls │ │ ├── mathmo │ │ │ ├── services │ │ │ │ ├── semver.ls │ │ │ │ ├── seeder.ls │ │ │ │ └── questionStore.ls │ │ │ ├── img │ │ │ │ ├── icon.png │ │ │ │ ├── well.png │ │ │ │ ├── mathmoIcon.png │ │ │ │ └── nrichIcon.png │ │ │ ├── views │ │ │ │ └── nav.html │ │ │ ├── routes.ls │ │ │ ├── styles.less │ │ │ ├── directives │ │ │ │ └── mathmoPlot.ls │ │ │ ├── index.html │ │ │ └── main.ls │ │ ├── todo │ │ │ ├── services │ │ │ │ └── semver.ls │ │ │ ├── views │ │ │ │ └── nav.html │ │ │ ├── routes.ls │ │ │ ├── controllers │ │ │ │ └── todoController.ls │ │ │ ├── index.html │ │ │ └── main.ls │ │ ├── boomerangs │ │ │ ├── services │ │ │ │ └── semver.ls │ │ │ ├── views │ │ │ │ └── nav.html │ │ │ ├── styles.less │ │ │ ├── routes.ls │ │ │ ├── controllers │ │ │ │ └── boomerangController.ls │ │ │ ├── index.html │ │ │ └── main.ls │ │ ├── probability │ │ │ ├── services │ │ │ │ └── semver.ls │ │ │ ├── styles.less │ │ │ ├── views │ │ │ │ └── nav.html │ │ │ ├── routes.ls │ │ │ ├── controllers │ │ │ │ ├── sampleSpinController.ls │ │ │ │ ├── prob9546ResultsController.ls │ │ │ │ └── prob9525ResultsController.ls │ │ │ ├── index.html │ │ │ └── main.ls │ │ └── tilted │ │ │ ├── views │ │ │ └── nav.html │ │ │ ├── routes.ls │ │ │ ├── styles.less │ │ │ ├── index.html │ │ │ └── main.ls │ ├── directives │ │ ├── appVersion.ls │ │ ├── svgCheck.ls │ │ └── d3DotGrid.ls │ ├── views.ls │ ├── bootstrap.ls │ ├── services │ │ ├── semver.ls │ │ ├── d3LineChart.ls │ │ └── d3MultiLineChart.ls │ ├── routes.ls │ ├── controllers │ │ └── appController.ls │ └── app.ls ├── img │ ├── redFrog.png │ ├── blueFrog.png │ ├── glyphicons-halflings.png │ └── glyphicons-halflings-white.png ├── styles │ ├── d3DotGrid.less │ ├── d3Axis.less │ ├── styles.less │ ├── layouts.less │ ├── component-animations.less │ ├── utilities.less │ ├── grid.less │ ├── breadcrumbs.less │ ├── responsive-768px-979px.less │ ├── d3Vis.less │ ├── hero-unit.less │ ├── wells.less │ ├── responsive-1200px-min.less │ ├── close.less │ ├── accordion.less │ ├── pager.less │ ├── media.less │ ├── scaffolding.less │ ├── responsive.less │ ├── thumbnails.less │ ├── code.less │ ├── alerts.less │ ├── bootstrap.less │ ├── responsive-utilities.less │ ├── tooltip.less │ ├── labels-badges.less │ ├── modals.less │ ├── pagination.less │ ├── carousel.less │ ├── progress-bars.less │ ├── popovers.less │ └── responsive-767px-max.less ├── views │ ├── directives │ │ └── svgCheck.html │ ├── todo.html │ ├── tilted.html │ ├── nav.html │ ├── boomerangs.html │ ├── spinners.html │ └── frogs.html └── index.html ├── test ├── scripts │ ├── libs │ │ └── version.txt │ ├── controllers │ │ └── todoSpec.ls │ └── directives │ │ └── d3VisSpec.ls ├── test.sh ├── pubs │ ├── mathmo │ │ ├── TODO.md │ │ └── mathmo-tests.md │ └── frogs │ │ ├── frogDirectiveSpec.ls │ │ └── frogControllerSpec.ls ├── unit │ └── problemsSpec.js ├── mathmoTestsTodo │ ├── lib │ │ └── jasmine-1.0.2 │ │ │ ├── MIT.LICENSE │ │ │ └── jasmine.css │ ├── SpecRunner.html │ └── spec │ │ ├── problems.js │ │ └── fractions.js └── runner.html ├── boilerplate ├── styles.less ├── services │ └── semver.ls ├── controllers │ └── maskController.ls ├── views │ └── nav.html ├── directives │ └── maskDirective.ls ├── routes.ls ├── main.ls └── index.html ├── Procfile ├── assets ├── frogs.ai ├── mathmo │ └── newraph.psd └── boomerangs │ ├── 0-concrete │ ├── ctrlConcrete.coffee │ └── expConcrete.html │ ├── styles.css │ ├── 1-FirstPass │ ├── ctrlFirstPass.coffee │ └── expFirstPass.html │ ├── 2-Abstract │ ├── ctrlAbstract.coffee │ └── expAbstract.html │ └── question.html ├── .gitignore ├── publish ├── mathmo.sh ├── frogs.sh └── probability.sh ├── todo └── gruntCreateApp ├── .editorconfig ├── .jshintrc ├── server.coffee ├── karma-e2e.conf.js ├── routes.coffee ├── LICENSE ├── karma.conf.js ├── package.json └── README.md /libpeerconnection.log: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/scripts/libs/version.txt: -------------------------------------------------------------------------------- 1 | 1.0.7 -------------------------------------------------------------------------------- /test/scripts/libs/version.txt: -------------------------------------------------------------------------------- 1 | 1.0.5 2 | -------------------------------------------------------------------------------- /boilerplate/styles.less: -------------------------------------------------------------------------------- 1 | /* add app specific styles here */ 2 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: "./node_modules/.bin/grunt" prod && "./node_modules/.bin/grunt" server -------------------------------------------------------------------------------- /boilerplate/services/semver.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').factory 'semver', ->"0.1.0" -------------------------------------------------------------------------------- /assets/frogs.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexwlchan/Apps1/master/assets/frogs.ai -------------------------------------------------------------------------------- /src/img/redFrog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexwlchan/Apps1/master/src/img/redFrog.png -------------------------------------------------------------------------------- /src/scripts/pubs/frogs/services/semver.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').factory 'semver', ->"1.0.1" -------------------------------------------------------------------------------- /src/scripts/pubs/mathmo/services/semver.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').factory 'semver', ->"0.9.5" -------------------------------------------------------------------------------- /src/scripts/pubs/todo/services/semver.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').factory 'semver', ->"0.1.6" -------------------------------------------------------------------------------- /src/img/blueFrog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexwlchan/Apps1/master/src/img/blueFrog.png -------------------------------------------------------------------------------- /src/scripts/pubs/boomerangs/services/semver.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').factory 'semver', ->"0.9.0" -------------------------------------------------------------------------------- /src/scripts/pubs/probability/services/semver.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').factory 'semver', ->"0.9.0" -------------------------------------------------------------------------------- /assets/mathmo/newraph.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexwlchan/Apps1/master/assets/mathmo/newraph.psd -------------------------------------------------------------------------------- /src/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexwlchan/Apps1/master/src/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /src/scripts/pubs/mathmo/img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexwlchan/Apps1/master/src/scripts/pubs/mathmo/img/icon.png -------------------------------------------------------------------------------- /src/scripts/pubs/mathmo/img/well.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexwlchan/Apps1/master/src/scripts/pubs/mathmo/img/well.png -------------------------------------------------------------------------------- /src/styles/d3DotGrid.less: -------------------------------------------------------------------------------- 1 | /* d3DotGrid */ 2 | @grid-icon-fill: #22cc88; 3 | 4 | .grid-dot { 5 | fill: @grid-icon-fill; 6 | } -------------------------------------------------------------------------------- /src/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexwlchan/Apps1/master/src/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /src/scripts/pubs/mathmo/img/mathmoIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexwlchan/Apps1/master/src/scripts/pubs/mathmo/img/mathmoIcon.png -------------------------------------------------------------------------------- /src/scripts/pubs/mathmo/img/nrichIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexwlchan/Apps1/master/src/scripts/pubs/mathmo/img/nrichIcon.png -------------------------------------------------------------------------------- /src/scripts/libs/qa/graphs.txt: -------------------------------------------------------------------------------- 1 | makeModulus 2 | var qString="Sketch the graph of \\(|"+a+"-|x||\\) for \\("+l+"\\leq{x}\\leq"+r+"\\)."; 3 | -------------------------------------------------------------------------------- /src/scripts/pubs/mathmo/services/seeder.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').factory 'seeder', -> 2 | 3 | newSeed = (seed) -> 4 | Math.seedrandom -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | dist/ 3 | node_modules/ 4 | .temp/ 5 | dist_test/ 6 | incoming 7 | src/scripts/pubs/styles.less 8 | *~ 9 | .appmask 10 | apps -------------------------------------------------------------------------------- /src/scripts/directives/appVersion.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').directive 'appVersion', [ 2 | 'semver' 3 | (semver) -> (scope, elm, attrs) -> elm.text(semver) 4 | ] -------------------------------------------------------------------------------- /boilerplate/controllers/maskController.ls: -------------------------------------------------------------------------------- 1 | (angular.module 'app') 2 | .controller '<%= mask %>Controller', [ 3 | '$scope' 4 | ($scope) -> 5 | 6 | 7 | ] 8 | 9 | -------------------------------------------------------------------------------- /publish/mathmo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd ~/angular/Apps1 3 | grunt mask:mathmo 4 | grunt prod 5 | rsync -av ~/angular/Apps1/dist/ gmp26@maths.org:/www/nrich/html/mathmoApp -------------------------------------------------------------------------------- /publish/frogs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd ~/angular/Apps1 3 | grunt mask:frogs 4 | grunt prod 5 | rsync -av ~/angular/Frogs/dist/ gmp26@maths.org:/www/nrich/html/content/00/12/game1/frogs -------------------------------------------------------------------------------- /publish/probability.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd ~/angular/Apps1 3 | grunt mask:probability 4 | grunt prod 5 | rsync -av ~/angular/Apps1/dist/ gmp26@maths.org:/www/nrich/html/probabilityApps -------------------------------------------------------------------------------- /src/scripts/pubs/todo/views/nav.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/scripts/views.ls: -------------------------------------------------------------------------------- 1 | # this file kept intentionally blank 2 | # this file needs to be here for the dev build 3 | # it is effectively ignored 4 | # views will be loaded as html files 5 | 0 -------------------------------------------------------------------------------- /src/scripts/pubs/mathmo/views/nav.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/scripts/pubs/tilted/views/nav.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/scripts/pubs/boomerangs/views/nav.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /boilerplate/views/nav.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/scripts/bootstrap.ls: -------------------------------------------------------------------------------- 1 | angular.bootstrap document, [ 2 | # 3 | # angular module dependencies 4 | # 5 | 'app' 6 | 'ui.bootstrap.collapse' 7 | 'ui.bootstrap.pagination' 8 | 'ui.bootstrap.alert' 9 | ] -------------------------------------------------------------------------------- /assets/boomerangs/0-concrete/ctrlConcrete.coffee: -------------------------------------------------------------------------------- 1 | 2 | #concrete 3 | 4 | angular.module('app') 5 | .controller 'boomerangController', ($scope) -> 6 | 7 | $scope.small = 2 8 | $scope.large = 2 9 | 10 | -------------------------------------------------------------------------------- /boilerplate/directives/maskDirective.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').directive '<%= mask %>Directive', [ 2 | '$timeout' 3 | ($timeout) -> 4 | restrict: 'EA' 5 | link: (scope, element, attrs) -> 6 | console.log '<%= mask %>Directive' 7 | ] 8 | -------------------------------------------------------------------------------- /src/scripts/services/semver.ls: -------------------------------------------------------------------------------- 1 | # 2 | # Define the app version number. 3 | # Override in pubs 4 | # 5 | # If a pubs app needs uses prelude you can import it there like so: 6 | # 7 | # import prelude 8 | # 9 | angular.module('app').factory 'semver', ->"0.1.6" -------------------------------------------------------------------------------- /src/scripts/pubs/probability/styles.less: -------------------------------------------------------------------------------- 1 | #spinset1 input[type=number] { 2 | width:100px; 3 | } 4 | div[d3-vis] { 5 | display: inline-block; 6 | } 7 | .twoway-strong { 8 | vertical-align: top; 9 | text-align:right !important; 10 | font-weight:bold; 11 | } -------------------------------------------------------------------------------- /test/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BASE_DIR=`dirname $0` 4 | 5 | echo "" 6 | echo "Starting Karma Server (http://karma-runner.github.io)" 7 | echo "-------------------------------------------------------------------" 8 | 9 | karma start $BASE_DIR/../karma.conf.js $* 10 | -------------------------------------------------------------------------------- /src/scripts/pubs/probability/views/nav.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /boilerplate/routes.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').config [ 2 | '$routeProvider' 3 | '$locationProvider' 4 | ($routeProvider, $locationProvider) -> 5 | 6 | $routeProvider 7 | .when '/<%= mask %>', templateUrl: '/views/<%= mask %>.html' 8 | .otherwise redirectTo: '/<%= mask %>' 9 | 10 | ] -------------------------------------------------------------------------------- /src/scripts/pubs/boomerangs/styles.less: -------------------------------------------------------------------------------- 1 | input[type="number"] { 2 | width:50px; 3 | height: 30px; 4 | font-size: 18px; 5 | } 6 | 7 | em { 8 | font-style: normal; 9 | font-weight:bold; 10 | font-size:1.4em; 11 | } 12 | 13 | .bad { 14 | color:blue; 15 | } 16 | 17 | .good { 18 | color:red; 19 | } -------------------------------------------------------------------------------- /src/scripts/pubs/frogs/views/nav.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /todo/gruntCreateApp: -------------------------------------------------------------------------------- 1 | Make a grunt task to create a new App. 2 | 3 | grunt init mathmo 4 | 5 | it should: 6 | create pubs/mathmo 7 | create pubs/mathmo/controllers, services, directives,views 8 | from generic code, copy 9 | main.ls, routes.ls 10 | create a main view in generics 11 | mathmo.html -------------------------------------------------------------------------------- /src/views/directives/svgCheck.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | This collection will only run in a browser which supports SVG. 4 |
5 |
6 |
7 | -------------------------------------------------------------------------------- /assets/boomerangs/styles.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/styles/d3Axis.less: -------------------------------------------------------------------------------- 1 | /* d3Axis styles */ 2 | 3 | @axis-stroke: #666; 4 | @axis-fill: none; 5 | @axis-width: 1.5px; 6 | 7 | .axis line, 8 | .axis tick, 9 | .axis path { 10 | fill: @axis-fill; 11 | stroke: @axis-stroke; 12 | shape-rendering: crispEdges; 13 | } 14 | 15 | .arrow { 16 | stroke: @axis-stroke; 17 | stroke-width: @axis-width; 18 | } 19 | -------------------------------------------------------------------------------- /src/scripts/pubs/todo/routes.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').config [ 2 | '$routeProvider' 3 | '$locationProvider' 4 | ($routeProvider, $locationProvider) -> 5 | 6 | # use /tiltedApp rather than #/tiltedApp 7 | #$locationProvider.html5Mode true 8 | 9 | $routeProvider 10 | .when '/todo', templateUrl: '/views/todo.html' 11 | .otherwise redirectTo: '/todo' 12 | 13 | ] -------------------------------------------------------------------------------- /src/styles/styles.less: -------------------------------------------------------------------------------- 1 | @import "bootstrap.less"; 2 | @import "responsive.less"; 3 | 4 | @import "d3Vis.less"; 5 | @import "d3DotGrid.less"; 6 | @import "d3Axis.less"; 7 | 8 | @import "../scripts/pubs/styles.less"; 9 | 10 | 11 | .ng-cloak { 12 | display: none; 13 | } 14 | 15 | .view { 16 | display: inline-block; 17 | } 18 | 19 | .header { 20 | padding-left:20px 21 | } 22 | -------------------------------------------------------------------------------- /src/scripts/pubs/tilted/routes.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').config [ 2 | '$routeProvider' 3 | '$locationProvider' 4 | ($routeProvider, $locationProvider) -> 5 | 6 | # use /tiltedApp rather than #/tiltedApp 7 | #$locationProvider.html5Mode true 8 | 9 | $routeProvider 10 | .when '/tilted', templateUrl: '/views/tilted.html' 11 | .otherwise redirectTo: '/tilted' 12 | 13 | ] -------------------------------------------------------------------------------- /src/scripts/pubs/boomerangs/routes.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').config [ 2 | '$routeProvider' 3 | '$locationProvider' 4 | ($routeProvider, $locationProvider) -> 5 | 6 | # use /tiltedApp rather than #/tiltedApp 7 | #$locationProvider.html5Mode true 8 | 9 | $routeProvider 10 | .when '/boomerangs', templateUrl: '/views/boomerangs.html' 11 | .otherwise redirectTo: '/boomerangs' 12 | 13 | ] -------------------------------------------------------------------------------- /src/styles/layouts.less: -------------------------------------------------------------------------------- 1 | // 2 | // Layouts 3 | // -------------------------------------------------- 4 | 5 | 6 | // Container (centered, fixed-width layouts) 7 | .container { 8 | .container-fixed(); 9 | } 10 | 11 | // Fluid layouts (left aligned, with sidebar, min- & max-width content) 12 | .container-fluid { 13 | padding-right: @gridGutterWidth; 14 | padding-left: @gridGutterWidth; 15 | .clearfix(); 16 | } -------------------------------------------------------------------------------- /src/scripts/pubs/frogs/routes.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').config [ 2 | '$routeProvider' 3 | '$locationProvider' 4 | ($routeProvider, $locationProvider) -> 5 | 6 | # use /tiltedApp rather than #/tiltedApp 7 | #$locationProvider.html5Mode true 8 | 9 | $routeProvider 10 | .when '/frogs/:users/:id/:reds/:blues' templateUrl: '/views/frogs.html' 11 | .otherwise redirectTo: '/frogs/single/1246/2/2' 12 | 13 | ] -------------------------------------------------------------------------------- /src/scripts/pubs/mathmo/routes.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').config [ 2 | '$routeProvider' 3 | '$locationProvider' 4 | ($routeProvider, $locationProvider) -> 5 | 6 | $routeProvider 7 | .when '/mathmo/:help' templateUrl: '/views/mathmo.html' 8 | .when '/mathmo/:cmd/:x/:t/:q' templateUrl: '/views/mathmo.html' 9 | .when '/mathmo', templateUrl: '/views/mathmo.html' 10 | .otherwise redirectTo: '/mathmo' 11 | 12 | ] -------------------------------------------------------------------------------- /src/scripts/pubs/tilted/styles.less: -------------------------------------------------------------------------------- 1 | /* TiltedSquares App */ 2 | 3 | .tilted { 4 | fill: #a04; 5 | opacity: 0.5; 6 | } 7 | 8 | .tilted-control0 { 9 | fill: #048; 10 | opacity: 0.5; 11 | &:hover, &:active { 12 | opacity:0.7; 13 | cursor:pointer; 14 | } 15 | } 16 | 17 | .tilted-control1 { 18 | fill: #f00; 19 | opacity: 0.5; 20 | &:hover, &:active { 21 | opacity:0.7; 22 | cursor:pointer; 23 | } 24 | } -------------------------------------------------------------------------------- /src/styles/component-animations.less: -------------------------------------------------------------------------------- 1 | // 2 | // Component animations 3 | // -------------------------------------------------- 4 | 5 | 6 | .fade { 7 | opacity: 0; 8 | .transition(opacity .15s linear); 9 | &.in { 10 | opacity: 1; 11 | } 12 | } 13 | 14 | .collapse { 15 | position: relative; 16 | height: 0; 17 | overflow: hidden; 18 | .transition(height .35s ease); 19 | &.in { 20 | height: auto; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/scripts/libs/console-helper.js: -------------------------------------------------------------------------------- 1 | // Make it safe to do console.log() always. 2 | (function (con) { 3 | var method; 4 | var dummy = function() {}; 5 | var methods = ('assert,count,debug,dir,dirxml,error,exception,group,' + 6 | 'groupCollapsed,groupEnd,info,log,markTimeline,profile,profileEnd,' + 7 | 'time,timeEnd,trace,warn').split(','); 8 | while (method = methods.pop()) { 9 | con[method] = con[method] || dummy; 10 | } 11 | })(window.console = window.console || {}); 12 | -------------------------------------------------------------------------------- /src/styles/utilities.less: -------------------------------------------------------------------------------- 1 | // 2 | // Utility classes 3 | // -------------------------------------------------- 4 | 5 | 6 | // Quick floats 7 | .pull-right { 8 | float: right; 9 | } 10 | .pull-left { 11 | float: left; 12 | } 13 | 14 | // Toggling content 15 | .hide { 16 | display: none; 17 | } 18 | .show { 19 | display: block; 20 | } 21 | 22 | // Visibility 23 | .invisible { 24 | visibility: hidden; 25 | } 26 | 27 | // For Affix plugin 28 | .affix { 29 | position: fixed; 30 | } 31 | -------------------------------------------------------------------------------- /test/pubs/mathmo/TODO.md: -------------------------------------------------------------------------------- 1 | Mathmo Tests 2 | ============ 3 | 4 | Exercise names less than 4 chars long should cause +Add button to be disabled and show red input border 5 | Add exercise should place the exercise name in a tab 6 | 7 | A successful add Question Topic should remove the topic from the accordion 8 | Question topics restored from local store should not appear in the add Question accordion 9 | Add Question should pop up the Add Question dialog 10 | Close button should close AddQuestion Dialog -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | # Change these settings to your own preference 9 | indent_style = space 10 | indent_size = 2 11 | 12 | # We recommend you to keep these unchanged 13 | end_of_line = lf 14 | charset = utf-8 15 | trim_trailing_whitespace = true 16 | insert_final_newline = true 17 | 18 | [*.md] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /src/scripts/pubs/probability/routes.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').config [ 2 | '$routeProvider' 3 | '$locationProvider' 4 | ($routeProvider, $locationProvider) -> 5 | 6 | # use /tiltedApp rather than #/tiltedApp 7 | #$locationProvider.html5Mode true 8 | 9 | $routeProvider 10 | #.when '/spinners', templateUrl: '/views/spinners.html' 11 | .when '/prob9546', templateUrl: '/views/prob9546.html' 12 | .when '/prob9525', templateUrl: '/views/prob9525.html' 13 | .otherwise redirectTo: '/prob9546' 14 | 15 | ] -------------------------------------------------------------------------------- /src/styles/grid.less: -------------------------------------------------------------------------------- 1 | // 2 | // Grid system 3 | // -------------------------------------------------- 4 | 5 | 6 | // Fixed (940px) 7 | #grid > .core(@gridColumnWidth, @gridGutterWidth); 8 | 9 | // Fluid (940px) 10 | #grid > .fluid(@fluidGridColumnWidth, @fluidGridGutterWidth); 11 | 12 | // Reset utility classes due to specificity 13 | [class*="span"].hide, 14 | .row-fluid [class*="span"].hide { 15 | display: none; 16 | } 17 | 18 | [class*="span"].pull-right, 19 | .row-fluid [class*="span"].pull-right { 20 | float: right; 21 | } 22 | -------------------------------------------------------------------------------- /assets/boomerangs/1-FirstPass/ctrlFirstPass.coffee: -------------------------------------------------------------------------------- 1 | # First Pass 2 | 3 | angular.module('app') 4 | .controller 'boomerangController', ($scope) -> 5 | 6 | $scope.small = 2 7 | $scope.large = 2 8 | 9 | $scope.decTime = () -> @small + @large 10 | 11 | $scope.carveTime = () -> 2*@small + 3*@large 12 | 13 | 14 | $scope.decTimeOK = () -> if 0 <= @decTime() <= 10 then "good" else "bad" 15 | 16 | $scope.carveTimeOK = () -> if 0 <= @carveTime() <= 24 then "good" else "bad" 17 | 18 | 19 | $scope.totalIncome = () -> @small * 8 + @large * 10 20 | 21 | -------------------------------------------------------------------------------- /src/scripts/directives/svgCheck.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').directive 'svgCheck', 2 | [ 3 | '$timeout', '$window' 4 | ($timeout, $window) -> 5 | 6 | restrict: 'A' 7 | templateUrl: '/views/directives/svgCheck.html' 8 | replace: false 9 | transclude: true 10 | 11 | link: (scope, element, attrs) -> 12 | 13 | # check that browser is SVG capable. 14 | scope.svgOK = $window.document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature" + \#BasicStructure, "1.1") 15 | console.log("svgCheck scope = ", scope.$id) 16 | ] -------------------------------------------------------------------------------- /src/styles/breadcrumbs.less: -------------------------------------------------------------------------------- 1 | // 2 | // Breadcrumbs 3 | // -------------------------------------------------- 4 | 5 | 6 | .breadcrumb { 7 | padding: 8px 15px; 8 | margin: 0 0 @baseLineHeight; 9 | list-style: none; 10 | background-color: #f5f5f5; 11 | .border-radius(@baseBorderRadius); 12 | > li { 13 | display: inline-block; 14 | .ie7-inline-block(); 15 | text-shadow: 0 1px 0 @white; 16 | > .divider { 17 | padding: 0 5px; 18 | color: #ccc; 19 | } 20 | } 21 | > .active { 22 | color: @grayLight; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/styles/responsive-768px-979px.less: -------------------------------------------------------------------------------- 1 | // 2 | // Responsive: Tablet to desktop 3 | // -------------------------------------------------- 4 | 5 | 6 | @media (min-width: 768px) and (max-width: 979px) { 7 | 8 | // Fixed grid 9 | #grid > .core(@gridColumnWidth768, @gridGutterWidth768); 10 | 11 | // Fluid grid 12 | #grid > .fluid(@fluidGridColumnWidth768, @fluidGridGutterWidth768); 13 | 14 | // Input grid 15 | #grid > .input(@gridColumnWidth768, @gridGutterWidth768); 16 | 17 | // No need to reset .thumbnails here since it's the same @gridGutterWidth 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/scripts/pubs/boomerangs/controllers/boomerangController.ls: -------------------------------------------------------------------------------- 1 | # First Pass 2 | 3 | angular.module('app') 4 | .controller 'boomerangController', 5 | [ 6 | '$scope' 7 | ($scope) -> 8 | 9 | $scope.small = 1 10 | $scope.large = 1 11 | 12 | $scope.decTime = -> @small + @large 13 | 14 | $scope.carveTime = -> 2 * @small + 3 * @large 15 | 16 | $scope.decTimeOK = -> if 0 <= @decTime() <= 10 then "good" else "bad" 17 | 18 | $scope.carveTimeOK = -> if 0 <= @carveTime() <= 24 then "good" else "bad" 19 | 20 | 21 | $scope.totalIncome = -> @small * 8 + @large * 10 22 | ] 23 | -------------------------------------------------------------------------------- /src/styles/d3Vis.less: -------------------------------------------------------------------------------- 1 | /* d3Vis styles */ 2 | @base-font-size: 14px; 3 | @base-font-family: sans-serif; 4 | @outer-fill: none; 5 | @outer-stroke: #DDD; 6 | @inner-fill: none; 7 | @inner-stroke: #888; 8 | 9 | svg { 10 | font: @base-font-size; 11 | font-family: @base-font-family; 12 | } 13 | 14 | .hide { 15 | display:none; 16 | } 17 | 18 | .outer, 19 | .inner { 20 | shape-rendering: crispEdges; 21 | } 22 | 23 | .outer { 24 | fill: none; 25 | stroke: @outer-stroke; 26 | } 27 | 28 | .inner { 29 | fill: @inner-fill; 30 | stroke: @inner-stroke; 31 | stroke-dasharray: 3, 4; 32 | } 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/styles/hero-unit.less: -------------------------------------------------------------------------------- 1 | // 2 | // Hero unit 3 | // -------------------------------------------------- 4 | 5 | 6 | .hero-unit { 7 | padding: 60px; 8 | margin-bottom: 30px; 9 | font-size: 18px; 10 | font-weight: 200; 11 | line-height: @baseLineHeight * 1.5; 12 | color: @heroUnitLeadColor; 13 | background-color: @heroUnitBackground; 14 | .border-radius(6px); 15 | h1 { 16 | margin-bottom: 0; 17 | font-size: 60px; 18 | line-height: 1; 19 | color: @heroUnitHeadingColor; 20 | letter-spacing: -1px; 21 | } 22 | li { 23 | line-height: @baseLineHeight * 1.5; // Reset since we specify in type.less 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/styles/wells.less: -------------------------------------------------------------------------------- 1 | // 2 | // Wells 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base class 7 | .well { 8 | min-height: 20px; 9 | padding: 19px; 10 | margin-bottom: 20px; 11 | background-color: @wellBackground; 12 | border: 1px solid darken(@wellBackground, 7%); 13 | .border-radius(@baseBorderRadius); 14 | .box-shadow(inset 0 1px 1px rgba(0,0,0,.05)); 15 | blockquote { 16 | border-color: #ddd; 17 | border-color: rgba(0,0,0,.15); 18 | } 19 | } 20 | 21 | // Sizes 22 | .well-large { 23 | padding: 24px; 24 | .border-radius(@borderRadiusLarge); 25 | } 26 | .well-small { 27 | padding: 9px; 28 | .border-radius(@borderRadiusSmall); 29 | } 30 | -------------------------------------------------------------------------------- /src/views/todo.html: -------------------------------------------------------------------------------- 1 |

Todo

2 |
{{remaining()}} of {{todos.length}} remaining [archive] 3 | 10 |
11 |

12 | 13 | 14 |

15 |
16 |
-------------------------------------------------------------------------------- /src/styles/responsive-1200px-min.less: -------------------------------------------------------------------------------- 1 | // 2 | // Responsive: Large desktop and up 3 | // -------------------------------------------------- 4 | 5 | 6 | @media (min-width: 1200px) { 7 | 8 | // Fixed grid 9 | #grid > .core(@gridColumnWidth1200, @gridGutterWidth1200); 10 | 11 | // Fluid grid 12 | #grid > .fluid(@fluidGridColumnWidth1200, @fluidGridGutterWidth1200); 13 | 14 | // Input grid 15 | #grid > .input(@gridColumnWidth1200, @gridGutterWidth1200); 16 | 17 | // Thumbnails 18 | .thumbnails { 19 | margin-left: -@gridGutterWidth1200; 20 | } 21 | .thumbnails > li { 22 | margin-left: @gridGutterWidth1200; 23 | } 24 | .row-fluid .thumbnails { 25 | margin-left: 0; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /assets/boomerangs/0-concrete/expConcrete.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

Let's experiment

5 | 6 |
7 | 8 |

Suppose Phil makes 1 small and 1 large boomerangs.

9 | 10 |

Carving 1 small boomerangs will take 2 hours.

11 |

Carving 1 large boomerangs will take 3 hours.

12 |
13 |

Phil will need 5 hours to carve them all.

14 |

Cath has to decorate 2 boomerangs.

15 |
16 |

1 small boomerangs will make $8.

17 |

1 large boomerangs will make $10.

18 |
19 |

Total amount made will be $18

20 | 21 |
-------------------------------------------------------------------------------- /assets/boomerangs/2-Abstract/ctrlAbstract.coffee: -------------------------------------------------------------------------------- 1 | #abstract 2 | 3 | angular.module('app') 4 | .controller 'boomerangController', ($scope) -> 5 | 6 | $scope.x = 2 7 | $scope.y = 2 8 | 9 | $scope.smallTime = (x) -> 2*x 10 | 11 | $scope.largeTime = (x) -> 3*x 12 | 13 | $scope.smallIncome = (x) -> 8*x 14 | 15 | $scope.largeIncome = (x) -> 10*x 16 | 17 | $scope.decTime = (x,y) -> x + y 18 | 19 | $scope.carveTime = (x,y) -> @smallTime(x) + @largeTime(y) 20 | 21 | $scope.totalIncome = (x,y) -> @smallIncome(x) + @largeIncome(y) 22 | 23 | 24 | $scope.decTimeOK = (x,y) -> if 0 <= @decTime(x,y) <= 10 then "good" else "bad" 25 | 26 | $scope.carveTimeOK = (x,y) -> if 0 <= @carveTime(x,y) <= 24 then "good" else "bad" 27 | -------------------------------------------------------------------------------- /src/styles/close.less: -------------------------------------------------------------------------------- 1 | // 2 | // Close icons 3 | // -------------------------------------------------- 4 | 5 | 6 | .close { 7 | float: right; 8 | font-size: 20px; 9 | font-weight: bold; 10 | line-height: @baseLineHeight; 11 | color: @black; 12 | text-shadow: 0 1px 0 rgba(255,255,255,1); 13 | .opacity(20); 14 | &:hover, 15 | &:focus { 16 | color: @black; 17 | text-decoration: none; 18 | cursor: pointer; 19 | .opacity(40); 20 | } 21 | } 22 | 23 | // Additional properties for button version 24 | // iOS requires the button element instead of an anchor tag. 25 | // If you want the anchor version, it requires `href="#"`. 26 | button.close { 27 | padding: 0; 28 | cursor: pointer; 29 | background: transparent; 30 | border: 0; 31 | -webkit-appearance: none; 32 | } -------------------------------------------------------------------------------- /src/views/tilted.html: -------------------------------------------------------------------------------- 1 |
2 |

Tilted Squares NRICH 2293

3 |

Find a quick way to work out the area of the square even if it is tilted.

4 |

This version uses SVG rather than canvas

5 |
6 | 7 |
11 | 12 |
16 | 17 |
18 | 19 | 22 | 23 |
24 | 25 |
26 | 27 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "globals": { 3 | "angular": true 4 | }, 5 | 6 | "node": true, 7 | "es5": false, 8 | "browser": true, 9 | "boss": false, 10 | "curly": false, 11 | "debug": false, 12 | "devel": false, 13 | "eqeqeq": true, 14 | "eqnull": true, 15 | "evil": true, 16 | "expr": true, 17 | "forin": false, 18 | "immed": true, 19 | "laxbreak": true, 20 | "loopfunc": true, 21 | "multistr": true, 22 | "newcap": true, 23 | "noarg": true, 24 | "noempty": false, 25 | "nonew": false, 26 | "nomen": false, 27 | "onevar": false, 28 | "plusplus": false, 29 | "regexp": false, 30 | "undef": true, 31 | "sub": true, 32 | "strict": false, 33 | "white": false, 34 | "unused": true 35 | } -------------------------------------------------------------------------------- /src/styles/accordion.less: -------------------------------------------------------------------------------- 1 | // 2 | // Accordion 3 | // -------------------------------------------------- 4 | 5 | 6 | // Parent container 7 | .accordion { 8 | margin-bottom: @baseLineHeight; 9 | } 10 | 11 | // Group == heading + body 12 | .accordion-group { 13 | margin-bottom: 2px; 14 | border: 1px solid #e5e5e5; 15 | .border-radius(@baseBorderRadius); 16 | } 17 | .accordion-heading { 18 | border-bottom: 0; 19 | } 20 | .accordion-heading .accordion-toggle { 21 | display: block; 22 | padding: 8px 15px; 23 | } 24 | 25 | // General toggle styles 26 | .accordion-toggle { 27 | cursor: pointer; 28 | } 29 | 30 | // Inner needs the styles because you can't animate properly with any styles on the element 31 | .accordion-inner { 32 | padding: 9px 15px; 33 | border-top: 1px solid #e5e5e5; 34 | } 35 | -------------------------------------------------------------------------------- /src/scripts/pubs/frogs/styles.less: -------------------------------------------------------------------------------- 1 | .frog-space { 2 | position:relative; 3 | height: 100px; 4 | padding:10px 0px 10px 10px; 5 | .border-radius(20px); 6 | 7 | .blue { 8 | background-image: url("../img/blueFrog.png"); 9 | } 10 | 11 | .red { 12 | background-image: url("../img/redFrog.png"); 13 | } 14 | 15 | .frog { 16 | width: 100px; 17 | height: 100px; 18 | display: inline-block; 19 | opacity: 0.7; 20 | 21 | position: absolute; 22 | .transition(.2s ease-in-out left); 23 | 24 | &:hover { 25 | cursor: pointer; 26 | opacity:1; 27 | } 28 | } 29 | } 30 | 31 | .froginput { 32 | width: 40px; 33 | height: 30px; 34 | font-size: 18px; 35 | } 36 | 37 | /* 38 | [ng-controller = frogController] .pagination { 39 | margin-bottom:0px 40 | } 41 | */ 42 | -------------------------------------------------------------------------------- /src/scripts/pubs/todo/controllers/todoController.ls: -------------------------------------------------------------------------------- 1 | (angular.module 'app') 2 | .controller('todoController', [ 3 | '$scope' 4 | 5 | ($scope) -> 6 | 7 | $scope.todos = [ 8 | text: "learn angular" 9 | done: true 10 | , 11 | text: "build an angular app" 12 | done: false 13 | ] 14 | 15 | $scope.addTodo = -> 16 | $scope.todos.push { 17 | text: $scope.todoText 18 | done: false 19 | } 20 | 21 | $scope.todoText = "" 22 | 23 | $scope.remaining = -> 24 | count = 0 25 | angular.forEach $scope.todos, (todo) -> 26 | count += (if todo.done then 0 else 1) 27 | 28 | count 29 | 30 | $scope.archive = -> 31 | oldTodos = $scope.todos 32 | $scope.todos = [] 33 | angular.forEach oldTodos, (todo) -> 34 | $scope.todos.push todo unless todo.done 35 | 36 | ]) 37 | 38 | -------------------------------------------------------------------------------- /assets/boomerangs/question.html: -------------------------------------------------------------------------------- 1 | 2 |

Boomerangs

3 | 4 |

Phil and Cath make and sell boomerangs for a school event. 5 | The money they raise will go to charity.

6 | 7 |

They plan to make them in two sizes: small and large.

8 | 9 |

Phil will carve them from wood. 10 | The small boomerang takes 2 hours to carve and the large one takes 3 11 | hours to carve. 12 | Phil has a total of 24 hours available for carving.

13 | 14 |

Cath will decorate them. 15 | She only has time to decorate 10 boomerangs of either size.

16 | 17 |

The small boomerang will make $8 for charity. 18 | The large boomerang will make $10 for charity. 19 | They want to make as much money for charity as they can.

20 | 21 |

How many small and large boomerangs should they make?

22 | 23 |

How much money will they then make?

24 | -------------------------------------------------------------------------------- /server.coffee: -------------------------------------------------------------------------------- 1 | express = require 'express' 2 | routes = require './routes' 3 | dir = "#{__dirname}/dist" 4 | port = process.env.PORT ? process.argv.splice(2)[0] ? 3005 5 | 6 | # Create express facility. 7 | app = express() 8 | # Create a HTTP server object. 9 | server = require('http').createServer(app) 10 | # Create SocketIO binding. 11 | io = require('socket.io').listen(server) 12 | 13 | app.configure -> 14 | # use livereload middleware 15 | app.use require('grunt-contrib-livereload/lib/utils').livereloadSnippet 16 | app.use express.logger 'dev' 17 | app.use express.bodyParser() 18 | app.use express.methodOverride() 19 | app.use express.errorHandler() 20 | app.use express.static dir 21 | app.use app.router 22 | routes app, dir 23 | 24 | module.exports = server 25 | 26 | # Override: Provide an "use" used by grunt-express. 27 | module.exports.use = -> app.use.apply app, arguments -------------------------------------------------------------------------------- /test/unit/problemsSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jasmine specs for controllers go here */ 4 | describe("mathmoController", function() { 5 | 6 | beforeEach(module('app')); 7 | 8 | var scope; 9 | beforeEach(inject(function($rootScope, $controller) { 10 | scope = $rootScope.$new(); 11 | $controller("mathmoController", { 12 | $scope: scope 13 | }); 14 | 15 | var pane = scope.addQSet('unit-test') 16 | })); 17 | 18 | describe("makePartial", function() { 19 | 20 | var mypane = {"name": "unit-test"}; 21 | 22 | it("should produce lists", function() { 23 | expect(scope.testQ("C11", mypane)[0]).toBe("By completing the square, find (for real \\(x\\)) the minimum value of$$x^2 + 4x + 9.$$"); 24 | expect(scope.testQ("C11", mypane)[1]).toBe("The minimum value is \\(5\\) which occurs at \\(x=-2\\)"); 25 | }); 26 | 27 | }); 28 | 29 | }); 30 | 31 | -------------------------------------------------------------------------------- /src/scripts/pubs/mathmo/styles.less: -------------------------------------------------------------------------------- 1 | /* add mathmo specific styles here */ 2 | 3 | input[type="text"]:focus.ng-invalid { 4 | border-color: #e9322d; 5 | -webkit-box-shadow: 0 0 6px #f8b9b7; 6 | -moz-box-shadow: 0 0 6px #f8b9b7; 7 | box-shadow: 0 0 6px #f8b9b7; 8 | } 9 | 10 | .line { 11 | stroke-width: 1; 12 | stroke-opacity: 1.0; 13 | fill: none; 14 | } 15 | 16 | .tick text { 17 | font-size:10px; 18 | } 19 | 20 | .mathmo .nav { 21 | margin-bottom:10px; 22 | } 23 | 24 | .modal-body.share textarea { 25 | width: 80%; 26 | } 27 | 28 | .exercise { 29 | list-style-type: lower-roman; 30 | } 31 | 32 | .subexercise { 33 | list-style-type: lower-alpha; 34 | } 35 | 36 | /* 37 | .container { 38 | margin-left:15px; 39 | min-width:50%; 40 | -moz-transition:width 100ms; 41 | -webkit-transition:width 100ms; 42 | -o-transition:width 100ms; 43 | -transition:width 100ms; 44 | } 45 | */ 46 | -------------------------------------------------------------------------------- /src/views/nav.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/scripts/routes.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').config [ 2 | '$routeProvider' 3 | '$locationProvider' 4 | ($routeProvider, $locationProvider) -> 5 | 6 | # use /tiltedApp rather than #/tiltedApp 7 | #$locationProvider.html5Mode true 8 | 9 | $routeProvider 10 | .when '/tilted', templateUrl: '/views/tilted.html' 11 | .when '/todo', templateUrl: '/views/todo.html' 12 | .when '/spinners', templateUrl: '/views/spinners.html' 13 | .when '/prob9546', templateUrl: '/views/prob9546.html' 14 | .when '/prob9525', templateUrl: '/views/prob9525.html' 15 | .when '/boomerangs', templateUrl: '/views/boomerangs.html' 16 | .when '/frogs/:users/:id/:reds/:blues' templateUrl: '/views/frogs.html' 17 | .when '/mathmo', templateUrl: '/views/mathmo.html' 18 | .when '/mathmo/:cmd/:x/:t/:q' templateUrl: '/views/mathmo.html' 19 | .when '/mathmo', templateUrl: '/views/mathmo.html' 20 | .otherwise redirectTo: '/tilted' 21 | 22 | ] -------------------------------------------------------------------------------- /assets/boomerangs/1-FirstPass/expFirstPass.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Let's experiment

4 | 5 |
6 |

Suppose Phil makes small and large boomerangs.

7 |

Carving {{small}} small boomerangs will take {{2*small}} hours.

8 |

Carving {{large}} large boomerangs will take {{3*large}} hours.

9 |
10 |

Phil will need {{ 2*small + 3*large }} hours to carve them all.

11 |

Cath has to decorate {{ small + large }} boomerangs.

12 |
13 |

{{small}} small boomerangs will make ${{8*small}}.

14 |

{{large}} large boomerangs will make ${{10*large}}.

15 |
16 |

Total amount made will be ${{ 8*small + 10*large }}

17 |
18 | -------------------------------------------------------------------------------- /src/styles/pager.less: -------------------------------------------------------------------------------- 1 | // 2 | // Pager pagination 3 | // -------------------------------------------------- 4 | 5 | 6 | .pager { 7 | margin: @baseLineHeight 0; 8 | list-style: none; 9 | text-align: center; 10 | .clearfix(); 11 | } 12 | .pager li { 13 | display: inline; 14 | } 15 | .pager li > a, 16 | .pager li > span { 17 | display: inline-block; 18 | padding: 5px 14px; 19 | background-color: #fff; 20 | border: 1px solid #ddd; 21 | .border-radius(15px); 22 | } 23 | .pager li > a:hover, 24 | .pager li > a:focus { 25 | text-decoration: none; 26 | background-color: #f5f5f5; 27 | } 28 | .pager .next > a, 29 | .pager .next > span { 30 | float: right; 31 | } 32 | .pager .previous > a, 33 | .pager .previous > span { 34 | float: left; 35 | } 36 | .pager .disabled > a, 37 | .pager .disabled > a:hover, 38 | .pager .disabled > a:focus, 39 | .pager .disabled > span { 40 | color: @grayLight; 41 | background-color: #fff; 42 | cursor: default; 43 | } -------------------------------------------------------------------------------- /assets/boomerangs/2-Abstract/expAbstract.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Let's experiment

4 | 5 |
6 |

Suppose Phil makes small and large boomerangs.

7 |

Carving {{x}} small boomerangs will take {{smallTime(x)}} hours.

8 |

Carving {{y}} large boomerangs will take {{largeTime(x)}} hours.

9 |
10 |

Phil will need {{ carveTime(x,y) }} hours to carve them all.

11 |

Cath has to decorate {{ decTime(x,y) }} boomerangs.

12 |
13 |

{{x}} small boomerangs will make ${{smallIncome(x)}}.

14 |

{{y}} large boomerangs will make ${{largeIncome(y)}}.

15 |
16 |

Total amount made will be ${{ totalIncome(x,y) }}

17 |
18 | 19 | -------------------------------------------------------------------------------- /karma-e2e.conf.js: -------------------------------------------------------------------------------- 1 | basePath = './'; 2 | 3 | files = [ 4 | ANGULAR_SCENARIO, 5 | ANGULAR_SCENARIO_ADAPTER, 6 | './dist/scripts/libs/jquery.js', 7 | './dist/scripts/libs/d3.v3.js', 8 | './dist/scripts/libs/angular.js', 9 | './dist/scripts/libs/angular-resource.js', 10 | './test/scripts/libs/angular-mocks.js', 11 | './dist/scripts/app.js', 12 | './dist/scripts/templates.js', 13 | './dist/scripts/controllers/*.js', 14 | './dist/scripts/directives/*.js', 15 | // './dist/scripts/filters/*.js', 16 | './dist/scripts/services/*.js', 17 | 18 | './test/scripts/e2e/**/*.js' 19 | /*, 20 | './test/scripts/directives/*.js', 21 | './test/scripts/filters/*.js', 22 | './test/scripts/services/*.js', 23 | */ 24 | ]; 25 | 26 | autoWatch = false; 27 | 28 | browsers = ['Chrome']; 29 | 30 | singleRun = true; 31 | 32 | proxies = { 33 | '/': 'http://localhost:3005/' 34 | }; 35 | 36 | junitReporter = { 37 | outputFile: 'test_out/e2e.xml', 38 | suite: 'e2e' 39 | }; -------------------------------------------------------------------------------- /src/scripts/pubs/frogs/directives/frogs.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').directive 'frogs', [ 2 | '$window' 3 | ($window) -> 4 | template: '
' 5 | replace: false 6 | link: (scope,element,attrs) -> 7 | 8 | #console.log "woff=", ~~attrs.woff 9 | 10 | rescale = (winSize, padCount) -> 11 | zoom = (winSize)/(130*padCount) 12 | #console.log "zoom=", zoom 13 | element.css("zoom", zoom) 14 | 15 | resizeHandler = (event) -> 16 | #console.log "innerWidth =", $window.innerWidth 17 | rescale($window.innerWidth, scope.frogs.length) 18 | 19 | scope.$watch 'frogs', (val) -> 20 | #console.log("pads =", val.length) 21 | rescale($window.innerWidth, val.length) 22 | 23 | #console.log("scope=",scope.$id) 24 | #console.log("window=", $window) 25 | 26 | win = angular.element($window) 27 | win.bind "resize", resizeHandler 28 | 29 | ] 30 | 31 | -------------------------------------------------------------------------------- /src/styles/media.less: -------------------------------------------------------------------------------- 1 | // Media objects 2 | // Source: http://stubbornella.org/content/?p=497 3 | // -------------------------------------------------- 4 | 5 | 6 | // Common styles 7 | // ------------------------- 8 | 9 | // Clear the floats 10 | .media, 11 | .media-body { 12 | overflow: hidden; 13 | *overflow: visible; 14 | zoom: 1; 15 | } 16 | 17 | // Proper spacing between instances of .media 18 | .media, 19 | .media .media { 20 | margin-top: 15px; 21 | } 22 | .media:first-child { 23 | margin-top: 0; 24 | } 25 | 26 | // For images and videos, set to block 27 | .media-object { 28 | display: block; 29 | } 30 | 31 | // Reset margins on headings for tighter default spacing 32 | .media-heading { 33 | margin: 0 0 5px; 34 | } 35 | 36 | 37 | // Media image alignment 38 | // ------------------------- 39 | 40 | .media > .pull-left { 41 | margin-right: 10px; 42 | } 43 | .media > .pull-right { 44 | margin-left: 10px; 45 | } 46 | 47 | 48 | // Media list variation 49 | // ------------------------- 50 | 51 | // Undo default ul/ol styles 52 | .media-list { 53 | margin-left: 0; 54 | list-style: none; 55 | } 56 | -------------------------------------------------------------------------------- /src/styles/scaffolding.less: -------------------------------------------------------------------------------- 1 | // 2 | // Scaffolding 3 | // -------------------------------------------------- 4 | 5 | 6 | // Body reset 7 | // ------------------------- 8 | 9 | body { 10 | margin: 0; 11 | font-family: @baseFontFamily; 12 | font-size: @baseFontSize; 13 | line-height: @baseLineHeight; 14 | color: @textColor; 15 | background-color: @bodyBackground; 16 | } 17 | 18 | 19 | // Links 20 | // ------------------------- 21 | 22 | a { 23 | color: @linkColor; 24 | text-decoration: none; 25 | } 26 | a:hover, 27 | a:focus { 28 | color: @linkColorHover; 29 | text-decoration: underline; 30 | } 31 | 32 | 33 | // Images 34 | // ------------------------- 35 | 36 | // Rounded corners 37 | .img-rounded { 38 | .border-radius(6px); 39 | } 40 | 41 | // Add polaroid-esque trim 42 | .img-polaroid { 43 | padding: 4px; 44 | background-color: #fff; 45 | border: 1px solid #ccc; 46 | border: 1px solid rgba(0,0,0,.2); 47 | .box-shadow(0 1px 3px rgba(0,0,0,.1)); 48 | } 49 | 50 | // Perfect circle 51 | .img-circle { 52 | .border-radius(500px); // crank the border-radius so it works with most reasonably sized images 53 | } 54 | -------------------------------------------------------------------------------- /routes.coffee: -------------------------------------------------------------------------------- 1 | module.exports = (app, dir) -> 2 | app.get '/', (req, res) -> 3 | res.render "#{dir}/index.html" 4 | 5 | ### 6 | # 7 | # Original AngularFun app server - useful reference 8 | # 9 | 10 | nextId = 0 11 | 12 | people = [ 13 | {"id": "#{nextId++}", "name": "Saasha", "age": "5"} 14 | {"id": "#{nextId++}", "name": "Planet", "age": "7"} 15 | ] 16 | 17 | isUniqueName = (name) -> 18 | (name for person in people when person.name is name).length is 0 19 | 20 | app.get '/people', (req, res) -> 21 | res.json people 22 | 23 | app.post '/people', (req, res) -> 24 | name = req.body.name 25 | age = req.body.age 26 | 27 | message = 28 | "title": "Duplicate!" 29 | "message": "#{name} is a duplicate. Please enter a new name." 30 | 31 | return res.send(message, 403) if not isUniqueName name 32 | 33 | person = 34 | "id": "#{nextId++}" 35 | "name": "#{name}" 36 | "age": "#{age}" 37 | 38 | people.push person 39 | res.json person 40 | 41 | app.get '/people/:id', (req, res) -> 42 | id = req.params.id 43 | current = person for person in people when parseInt(person.id, 10) is parseInt(id, 10) 44 | 45 | res.json current 46 | ### -------------------------------------------------------------------------------- /src/scripts/controllers/appController.ls: -------------------------------------------------------------------------------- 1 | # 2 | # do this once only! 3 | # 4 | # TODO: duplicate in pubs and remove prelude from any that don't need it. 5 | # 6 | # import prelude 7 | 8 | angular.module('app').controller('appController', [ 9 | '$scope' 10 | '$location' 11 | '$resource' 12 | '$rootScope' 13 | 14 | ($scope, $location, $resource, $rootScope) -> 15 | 16 | # Uses the url to determine if the selected 17 | # menu item should have the class active. 18 | $scope.$location = $location 19 | 20 | $scope.$watch '$location.path()', (path) -> 21 | 22 | #console.log 'path=', path 23 | $scope.activeNavId = path || '/' 24 | 25 | 26 | # getClass compares the current url with the id. 27 | # If the current url starts with the id it returns 'active' 28 | # otherwise it will return '' an empty string. E.g. 29 | # 30 | # # current url = '/products/1' 31 | # getClass('/products') # returns 'active' 32 | # getClass('/orders') # returns '' 33 | # 34 | $scope.getClass = (id) -> 35 | 36 | if $scope.activeNavId && $scope.activeNavId.indexOf(id) == 0 37 | return 'active' 38 | else 39 | return '' 40 | ]) 41 | 42 | -------------------------------------------------------------------------------- /test/mathmoTestsTodo/lib/jasmine-1.0.2/MIT.LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-2010 Pivotal Labs 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2013 University of Cambridge 4 | Copyright (c) 2013 Cary Landholt 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. -------------------------------------------------------------------------------- /src/scripts/app.ls: -------------------------------------------------------------------------------- 1 | (angular.module 'app', ['ngResource', 'ui.bootstrap']) 2 | .run ['$rootScope', '$log', ($rootScope, $log) -> 3 | 4 | # fire an event related to the current route 5 | $rootScope.$on '$routeChangeSuccess', (event, currentRoute, priorRoute) -> 6 | $rootScope.$broadcast "#{currentRoute.controller}$routeChangeSuccess", currentRoute, priorRoute 7 | 8 | ] 9 | 10 | /* 11 | See https://github.com/angular/angular.js/issues/1050 12 | and https://github.com/angular/angular.js/issues/1925 13 | 14 | The code below is based on suggestions in 1050, but these 15 | still fail when the svg attributes contain interpolate values. 16 | 17 | So instead use gmp26 angular patch to Angular v1.0.4 documented 18 | in 1925. Hopefully the Chrome/Angular teams will sort this out. 19 | 20 | .config () -> 21 | for name in ['width', 'height', 'x1', 'x2', 'y1', 'y2'] 22 | svgName = 'svg' + name[0].toUpperCase() + name.slice(1) 23 | angular.module('app').directive svgName, () -> 24 | link: (scope, element, attrs) -> 25 | attrs.$observe ngName, (value) -> 26 | # NB watch can fail initially if attribute value is interpolated 27 | if(value) 28 | attrs.$set(name, value) 29 | */ -------------------------------------------------------------------------------- /src/styles/responsive.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.3.1 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */ 10 | 11 | 12 | // Responsive.less 13 | // For phone and tablet devices 14 | // ------------------------------------------------------------- 15 | 16 | 17 | // REPEAT VARIABLES & MIXINS 18 | // ------------------------- 19 | // Required since we compile the responsive stuff separately 20 | 21 | @import "variables.less"; // Modify this for custom colors, font-sizes, etc 22 | @import "mixins.less"; 23 | 24 | 25 | // RESPONSIVE CLASSES 26 | // ------------------ 27 | 28 | @import "responsive-utilities.less"; 29 | 30 | 31 | // MEDIA QUERIES 32 | // ------------------ 33 | 34 | // Large desktops 35 | @import "responsive-1200px-min.less"; 36 | 37 | // Tablets to regular desktops 38 | @import "responsive-768px-979px.less"; 39 | 40 | // Phones to portrait tablets and narrow desktops 41 | @import "responsive-767px-max.less"; 42 | 43 | 44 | // RESPONSIVE NAVBAR 45 | // ------------------ 46 | 47 | // From 979px and below, show a button to toggle navbar contents 48 | @import "responsive-navbar.less"; 49 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // list of files / patterns to load in the browser 2 | files = [ 3 | JASMINE, 4 | JASMINE_ADAPTER, 5 | './dist/scripts/libs/angular.js', 6 | './dist/scripts/libs/angular-resource.js', 7 | './dist/scripts/libs/ui-bootstrap-tpls.js', 8 | './dist/scripts/libs/d3.v3.js', 9 | './test/scripts/libs/angular-mocks.js', 10 | './test/scripts/libs/prelude-browser-min.js', 11 | 12 | /* things under test */ 13 | './dist/scripts/app.js', 14 | './dist/scripts/**/controllers/*.js', 15 | './dist/scripts/**/directives/*.js', 16 | './dist/scripts/**/filters/*.js', 17 | './dist/scripts/**/responseInterceptors/*.js', 18 | './dist/scripts/**/services/*.js', 19 | 20 | /* test scripts */ 21 | // './dist_test/scripts/controllers/*.js', 22 | // './dist_test/scripts/directives/*.js', 23 | // './dist_test/scripts/filters/*.js', 24 | // './dist_test/scripts/services/*.js', 25 | 26 | /* This line needs to be specific or bootstrap.js throws an error :( */ 27 | /* See http://stackoverflow.com/questions/9227406/ */ 28 | './dist/scripts/libs/qa/*.js', 29 | 30 | /* Unit tests for mathmo */ 31 | './dist/scripts/pubs/mathmo/services/*.js', 32 | './dist/scripts/libs/seedrandom.js', 33 | './dist_test/pubs/**/*.js' 34 | // './test/unit/**/*.js' 35 | ]; 36 | 37 | // level of logging 38 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG 39 | logLevel = LOG_INFO; 40 | -------------------------------------------------------------------------------- /test/scripts/controllers/todoSpec.ls: -------------------------------------------------------------------------------- 1 | beforeEach module 'app' 2 | 3 | describe 'App', (_) -> 4 | 5 | # we want to make the scope available generally 6 | scope = {} 7 | 8 | beforeEach inject ($controller, $rootScope) -> 9 | 10 | scope := $rootScope.$new() 11 | $controller 'todoController', 12 | $scope: scope 13 | 14 | describe 'add', (_) -> 15 | 16 | it 'should add new todo', -> 17 | scope.todos = [] 18 | scope.todoText = 'FAKE TODO' 19 | 20 | scope.addTodo() 21 | 22 | expect(scope.todos.length).toBe 1 23 | expect(scope.todos[0].text).toBe 'FAKE TODO' 24 | 25 | 26 | it 'should reset newText', -> 27 | scope.todos = [] 28 | scope.todoText = 'SOME TEXT' 29 | scope.addTodo() 30 | 31 | expect(scope.todoText).toBe '' 32 | 33 | 34 | describe 'remaining', (_) -> 35 | 36 | it 'should return number of todos that are not done', -> 37 | scope.todos = [ 38 | {done: false} 39 | {done: false} 40 | {done: false} 41 | {done: false} 42 | ] 43 | expect(scope.remaining()).toBe 4 44 | 45 | scope.todos[0].done = true 46 | expect(scope.remaining()).toBe 3 47 | 48 | describe 'archive', (_) -> 49 | 50 | it 'should remove todos that are done', -> 51 | scope.todos = [ 52 | {done: false} 53 | {done: true} 54 | {done: false} 55 | ] 56 | 57 | expect(scope.todos.length).toBe 3 58 | 59 | scope.archive() 60 | expect(scope.todos.length).toBe 2 61 | -------------------------------------------------------------------------------- /test/mathmoTestsTodo/SpecRunner.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Jasmine Test Runner 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/styles/thumbnails.less: -------------------------------------------------------------------------------- 1 | // 2 | // Thumbnails 3 | // -------------------------------------------------- 4 | 5 | 6 | // Note: `.thumbnails` and `.thumbnails > li` are overriden in responsive files 7 | 8 | // Make wrapper ul behave like the grid 9 | .thumbnails { 10 | margin-left: -@gridGutterWidth; 11 | list-style: none; 12 | .clearfix(); 13 | } 14 | // Fluid rows have no left margin 15 | .row-fluid .thumbnails { 16 | margin-left: 0; 17 | } 18 | 19 | // Float li to make thumbnails appear in a row 20 | .thumbnails > li { 21 | float: left; // Explicity set the float since we don't require .span* classes 22 | margin-bottom: @baseLineHeight; 23 | margin-left: @gridGutterWidth; 24 | } 25 | 26 | // The actual thumbnail (can be `a` or `div`) 27 | .thumbnail { 28 | display: block; 29 | padding: 4px; 30 | line-height: @baseLineHeight; 31 | border: 1px solid #ddd; 32 | .border-radius(@baseBorderRadius); 33 | .box-shadow(0 1px 3px rgba(0,0,0,.055)); 34 | .transition(all .2s ease-in-out); 35 | } 36 | // Add a hover/focus state for linked versions only 37 | a.thumbnail:hover, 38 | a.thumbnail:focus { 39 | border-color: @linkColor; 40 | .box-shadow(0 1px 4px rgba(0,105,214,.25)); 41 | } 42 | 43 | // Images and captions 44 | .thumbnail > img { 45 | display: block; 46 | max-width: 100%; 47 | margin-left: auto; 48 | margin-right: auto; 49 | } 50 | .thumbnail .caption { 51 | padding: 9px; 52 | color: @gray; 53 | } 54 | -------------------------------------------------------------------------------- /src/styles/code.less: -------------------------------------------------------------------------------- 1 | // 2 | // Code (inline and blocK) 3 | // -------------------------------------------------- 4 | 5 | 6 | // Inline and block code styles 7 | code, 8 | pre { 9 | padding: 0 3px 2px; 10 | #font > #family > .monospace; 11 | font-size: @baseFontSize - 2; 12 | color: @grayDark; 13 | .border-radius(3px); 14 | } 15 | 16 | // Inline code 17 | code { 18 | padding: 2px 4px; 19 | color: #d14; 20 | background-color: #f7f7f9; 21 | border: 1px solid #e1e1e8; 22 | white-space: nowrap; 23 | } 24 | 25 | // Blocks of code 26 | pre { 27 | display: block; 28 | padding: (@baseLineHeight - 1) / 2; 29 | margin: 0 0 @baseLineHeight / 2; 30 | font-size: @baseFontSize - 1; // 14px to 13px 31 | line-height: @baseLineHeight; 32 | word-break: break-all; 33 | word-wrap: break-word; 34 | white-space: pre; 35 | white-space: pre-wrap; 36 | background-color: #f5f5f5; 37 | border: 1px solid #ccc; // fallback for IE7-8 38 | border: 1px solid rgba(0,0,0,.15); 39 | .border-radius(@baseBorderRadius); 40 | 41 | // Make prettyprint styles more spaced out for readability 42 | &.prettyprint { 43 | margin-bottom: @baseLineHeight; 44 | } 45 | 46 | // Account for some code outputs that place code tags in pre tags 47 | code { 48 | padding: 0; 49 | color: inherit; 50 | white-space: pre; 51 | white-space: pre-wrap; 52 | background-color: transparent; 53 | border: 0; 54 | } 55 | } 56 | 57 | // Enable scrollable blocks of code 58 | .pre-scrollable { 59 | max-height: 340px; 60 | overflow-y: scroll; 61 | } -------------------------------------------------------------------------------- /test/pubs/frogs/frogDirectiveSpec.ls: -------------------------------------------------------------------------------- 1 | beforeEach module 'app' 2 | 3 | describe 'App', -> 4 | 5 | # we want to make the scope available generally 6 | scope = {} 7 | 8 | beforeEach inject ($controller, $rootScope) -> 9 | 10 | scope := $rootScope.$new() 11 | 12 | $controller 'frogController', 13 | $scope: scope 14 | 15 | 16 | /* 17 | describe 'frog colours', -> 18 | it 'should return a red frog on pad 0', -> 19 | expect(scope.getFrog(0)).toBe "pad redfrog" 20 | describe 'add', -> 21 | 22 | it 'should add new todo', -> 23 | scope.todos = [] 24 | scope.todoText = 'FAKE TODO' 25 | 26 | scope.addTodo() 27 | 28 | expect(scope.todos.length).toBe 1 29 | expect(scope.todos[0].text).toBe 'FAKE TODO' 30 | 31 | 32 | it 'should reset newText', -> 33 | scope.todos = [] 34 | scope.todoText = 'SOME TEXT' 35 | scope.addTodo() 36 | 37 | expect(scope.todoText).toBe '' 38 | 39 | 40 | describe 'remaining', -> 41 | 42 | it 'should return number of todos that are not done', -> 43 | scope.todos = [ 44 | {done: false} 45 | {done: false} 46 | {done: false} 47 | {done: false} 48 | ] 49 | expect(scope.remaining()).toBe 4 50 | 51 | scope.todos[0].done = true 52 | expect(scope.remaining()).toBe 3 53 | 54 | describe 'archive', -> 55 | 56 | it 'should remove todos that are done', -> 57 | scope.todos = [ 58 | {done: false} 59 | {done: true} 60 | {done: false} 61 | ] 62 | 63 | expect(scope.todos.length).toBe 3 64 | 65 | scope.archive() 66 | expect(scope.todos.length).toBe 2 67 | */ -------------------------------------------------------------------------------- /src/scripts/pubs/probability/controllers/sampleSpinController.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').controller 'sampleSpinController', [ 2 | '$scope' 3 | ($scope) -> 4 | console.log "results controller scope = #{$scope.$id}" 5 | 6 | $scope.spinnerConfigs = 7 | spin1: # an array of spinner configurations 8 | * "label": \r 9 | "weight": 10 10 | "fill" : \red 11 | * "label": \b 12 | "weight": 10 13 | "fill" : \blue 14 | * "label": \y 15 | "weight": 10 16 | "fill" : \yellow 17 | * "label": \g 18 | "weight": 10 19 | "fill" : \green 20 | * "label": \p 21 | "weight": 10 22 | "fill" : \pink 23 | * "label": \g 24 | "weight": 10 25 | "fill" : \grey 26 | 27 | spin2: 28 | * "label": \Y 29 | "weight": 10 30 | "fill" : \#fe2 31 | * "label": \Y 32 | "weight": 10 33 | "fill" : \#fe2 34 | * "label": \Y 35 | "weight": 10 36 | "fill" : \#fe2 37 | * "label": \Y 38 | "weight": 10 39 | "fill" : \#fe2 40 | * "label": \B 41 | "weight": 10 42 | "fill" : \#6af 43 | * "label": \B 44 | "weight": 10 45 | "fill" : \#4af 46 | 47 | $scope.model = 48 | spin1: 0 49 | spin2: 0 50 | 51 | $scope.reset = !-> 52 | 53 | # called by spinner when spin stops to log the result 54 | $scope.spinLog = (name, sectorIndex, label) -> 55 | console.log "name [#sectorIndex] -> #label" 56 | 57 | ] -------------------------------------------------------------------------------- /src/styles/alerts.less: -------------------------------------------------------------------------------- 1 | // 2 | // Alerts 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base styles 7 | // ------------------------- 8 | 9 | .alert { 10 | padding: 8px 35px 8px 14px; 11 | margin-bottom: @baseLineHeight; 12 | text-shadow: 0 1px 0 rgba(255,255,255,.5); 13 | background-color: @warningBackground; 14 | border: 1px solid @warningBorder; 15 | .border-radius(@baseBorderRadius); 16 | } 17 | .alert, 18 | .alert h4 { 19 | // Specified for the h4 to prevent conflicts of changing @headingsColor 20 | color: @warningText; 21 | } 22 | .alert h4 { 23 | margin: 0; 24 | } 25 | 26 | // Adjust close link position 27 | .alert .close { 28 | position: relative; 29 | top: -2px; 30 | right: -21px; 31 | line-height: @baseLineHeight; 32 | } 33 | 34 | 35 | // Alternate styles 36 | // ------------------------- 37 | 38 | .alert-success { 39 | background-color: @successBackground; 40 | border-color: @successBorder; 41 | color: @successText; 42 | } 43 | .alert-success h4 { 44 | color: @successText; 45 | } 46 | .alert-danger, 47 | .alert-error { 48 | background-color: @errorBackground; 49 | border-color: @errorBorder; 50 | color: @errorText; 51 | } 52 | .alert-danger h4, 53 | .alert-error h4 { 54 | color: @errorText; 55 | } 56 | .alert-info { 57 | background-color: @infoBackground; 58 | border-color: @infoBorder; 59 | color: @infoText; 60 | } 61 | .alert-info h4 { 62 | color: @infoText; 63 | } 64 | 65 | 66 | // Block alerts 67 | // ------------------------- 68 | 69 | .alert-block { 70 | padding-top: 14px; 71 | padding-bottom: 14px; 72 | } 73 | .alert-block > p, 74 | .alert-block > ul { 75 | margin-bottom: 0; 76 | } 77 | .alert-block p + p { 78 | margin-top: 5px; 79 | } 80 | -------------------------------------------------------------------------------- /boilerplate/main.ls: -------------------------------------------------------------------------------- 1 | require { 2 | shim: 3 | 'controllers/appController': 4 | deps: 5 | * 'app' 6 | ... 7 | 'controllers/<%= mask %>Controller': 8 | deps: 9 | * 'app' 10 | ... 11 | 'controllers/<%= mask %>Directive': 12 | deps: 13 | * 'app' 14 | ... 15 | 'directives/d3Vis': 16 | deps: 17 | * 'app' 18 | 'libs/d3.v3' 19 | 'directives/svgCheck' 20 | 'directives/d3DotGrid': 21 | deps: 22 | * 'app' 23 | 'directives/d3Vis' 24 | 'directives/svgCheck': 25 | deps: 26 | * 'app' 27 | 'libs/d3.v3' 28 | 'directives/appVersion': 29 | deps: 30 | * 'app' 31 | 'services/semver' 32 | 'services/semver': 33 | deps: 34 | * 'app' 35 | ... 36 | 'bootstrap': 37 | deps: 38 | * 'app' 39 | ... 40 | 'libs/bootstrap': 41 | deps: 42 | * 'libs/jquery' 43 | ... 44 | 'libs/angular-resource': 45 | deps: 46 | * 'libs/angular' 47 | ... 48 | 'libs/ui-bootstrap-tpls': 49 | deps: 50 | * 'libs/angular' 51 | ... 52 | 'app': 53 | deps: 54 | * 'libs/angular' 55 | 'libs/angular-resource' 56 | 'libs/ui-bootstrap-tpls' 57 | 'routes': 58 | deps: 59 | * 'app' 60 | ... 61 | 'views': 62 | deps: 63 | * 'app' 64 | ... 65 | }, 66 | * 'require' 67 | 'controllers/appController' 68 | 'pubs/<%= mask %>/controllers/<%= mask %>Controller' 69 | 'pubs/<%= mask %>/directives/<%= mask %>Directive' 70 | 'directives/appVersion' 71 | 'routes' 72 | 'views' 73 | , (require) -> require ['bootstrap'] -------------------------------------------------------------------------------- /src/styles/bootstrap.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v2.3.1 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */ 10 | 11 | // Core variables and mixins 12 | @import "variables.less"; // Modify this for custom colors, font-sizes, etc 13 | @import "mixins.less"; 14 | 15 | // CSS Reset 16 | @import "reset.less"; 17 | 18 | // Grid system and page structure 19 | @import "scaffolding.less"; 20 | @import "grid.less"; 21 | @import "layouts.less"; 22 | 23 | // Base CSS 24 | @import "type.less"; 25 | @import "code.less"; 26 | @import "forms.less"; 27 | @import "tables.less"; 28 | 29 | // Components: common 30 | @import "sprites.less"; 31 | @import "dropdowns.less"; 32 | @import "wells.less"; 33 | @import "component-animations.less"; 34 | @import "close.less"; 35 | 36 | // Components: Buttons & Alerts 37 | @import "buttons.less"; 38 | @import "button-groups.less"; 39 | @import "alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less 40 | 41 | // Components: Nav 42 | @import "navs.less"; 43 | @import "navbar.less"; 44 | @import "breadcrumbs.less"; 45 | @import "pagination.less"; 46 | @import "pager.less"; 47 | 48 | // Components: Popovers 49 | @import "modals.less"; 50 | @import "tooltip.less"; 51 | @import "popovers.less"; 52 | 53 | // Components: Misc 54 | @import "thumbnails.less"; 55 | @import "media.less"; 56 | @import "labels-badges.less"; 57 | @import "progress-bars.less"; 58 | @import "accordion.less"; 59 | @import "carousel.less"; 60 | @import "hero-unit.less"; 61 | 62 | // Utility classes 63 | @import "utilities.less"; // Has to be last to override when necessary 64 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Apps1", 3 | "version": "0.1.6", 4 | "author": { 5 | "name": "Mike Pearson", 6 | "email": "gmp26@cam.ac.uk", 7 | "url": "https://github.com/gmp26" 8 | }, 9 | "description": "NRICH App Collection Architecture", 10 | "contributors": [ 11 | { 12 | "name": "Alison Kiddle", 13 | "email": "ajk44@cam.ac.uk", 14 | "url": "https://github.com/ajk44" 15 | }, 16 | { 17 | "name": "Cary Landholt", 18 | "email": "cary@landholt.com", 19 | "url": "https://github.com/CaryLandholt" 20 | }, 21 | { 22 | "name": "David Bochenski", 23 | "email": "david@bochenski.co.uk", 24 | "url": "https://github.com/Bochenski" 25 | } 26 | ], 27 | "main": "./server.coffee", 28 | "repository": { 29 | "type": "git", 30 | "url": "https://github.com/gmp26/Apps1.git" 31 | }, 32 | "dependencies": { 33 | "express": ">=3.0.3", 34 | "grunt-hustler": ">=0.7.4" 35 | }, 36 | "devDependencies": { 37 | "coffee-script": ">=1.6.1", 38 | "express": ">=3.1.0", 39 | "grunt": ">=0.4.0", 40 | "grunt-contrib-clean": ">=0.4.0", 41 | "grunt-contrib-coffee": ">=0.6.0", 42 | "grunt-contrib-copy": ">=0.4.0", 43 | "grunt-contrib-imagemin": ">=0.1.2", 44 | "grunt-contrib-less": ">=0.5.0", 45 | "grunt-contrib-livereload": ">=0.1.2", 46 | "grunt-contrib-requirejs": ">=0.4.0", 47 | "grunt-contrib-watch": ">=0.3.1", 48 | "grunt-express": ">=0.2.1", 49 | "grunt-hustler": ">=0.11.2", 50 | "grunt-regarde": ">=0.1.1", 51 | "grunt-karma": ">=0.4", 52 | "socket.io": ">=0.9.13", 53 | "grunt-livescript": ">=0.5.0", 54 | "prelude-ls": ">=0.6.0" 55 | }, 56 | "engines": { 57 | "node": ">=0.8.x", 58 | "npm": ">=1.1.x" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/views/boomerangs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

Boomerangs

5 | 6 |

Phil and Cath make and sell boomerangs for a school event. 7 | The money they raise will go to charity.

8 | 9 |

They plan to make them in two sizes: small and large.

10 | 11 |

Phil will carve them from wood. 12 | The small boomerang takes 2 hours to carve and the large one takes 3 13 | hours to carve. 14 | Phil has a total of 24 hours available for carving.

15 | 16 |

Cath will decorate them. 17 | She only has time to decorate 10 boomerangs of either size.

18 | 19 |

The small boomerang will make $8 for charity. 20 | The large boomerang will make $10 for charity. 21 | They want to make as much money for charity as they can.

22 | 23 |

How many small and large boomerangs should they make?

24 | 25 |

How much money will they then make?

26 | 27 | 28 | 29 |

Let's experiment

30 | 31 |
32 |

Suppose Phil makes small and large boomerangs.

33 |

Carving {{small}} small boomerangs will take {{3*small}} hours.

34 |

Carving {{large}} large boomerangs will take {{3*large}} hours.

35 |
36 |

Phil will need {{ 2*small + 3*large }} hours to carve them all.

37 |

Cath has to decorate {{ small + large }} boomerangs.

38 |
39 |

{{small}} small boomerangs will make ${{8*small}}.

40 |

{{large}} large boomerangs will make ${{10*large}}.

41 |
42 |

Total amount made will be ${{ 8*small + 10*large }}

43 |
44 | -------------------------------------------------------------------------------- /src/styles/responsive-utilities.less: -------------------------------------------------------------------------------- 1 | // 2 | // Responsive: Utility classes 3 | // -------------------------------------------------- 4 | 5 | 6 | // IE10 Metro responsive 7 | // Required for Windows 8 Metro split-screen snapping with IE10 8 | // Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/ 9 | @-ms-viewport{ 10 | width: device-width; 11 | } 12 | 13 | // Hide from screenreaders and browsers 14 | // Credit: HTML5 Boilerplate 15 | .hidden { 16 | display: none; 17 | visibility: hidden; 18 | } 19 | 20 | // Visibility utilities 21 | 22 | // For desktops 23 | .visible-phone { display: none !important; } 24 | .visible-tablet { display: none !important; } 25 | .hidden-phone { } 26 | .hidden-tablet { } 27 | .hidden-desktop { display: none !important; } 28 | .visible-desktop { display: inherit !important; } 29 | 30 | // Tablets & small desktops only 31 | @media (min-width: 768px) and (max-width: 979px) { 32 | // Hide everything else 33 | .hidden-desktop { display: inherit !important; } 34 | .visible-desktop { display: none !important ; } 35 | // Show 36 | .visible-tablet { display: inherit !important; } 37 | // Hide 38 | .hidden-tablet { display: none !important; } 39 | } 40 | 41 | // Phones only 42 | @media (max-width: 767px) { 43 | // Hide everything else 44 | .hidden-desktop { display: inherit !important; } 45 | .visible-desktop { display: none !important; } 46 | // Show 47 | .visible-phone { display: inherit !important; } // Use inherit to restore previous behavior 48 | // Hide 49 | .hidden-phone { display: none !important; } 50 | } 51 | 52 | // Print utilities 53 | .visible-print { display: none !important; } 54 | .hidden-print { } 55 | 56 | @media print { 57 | .visible-print { display: inherit !important; } 58 | .hidden-print { display: none !important; } 59 | } 60 | -------------------------------------------------------------------------------- /src/scripts/pubs/frogs/directives/frog.ls: -------------------------------------------------------------------------------- 1 | angular.module('app').directive 'frog', [ 2 | '$timeout' 3 | ($timeout) -> 4 | restrict: 'EA' 5 | link: (scope, element, attrs) -> 6 | 7 | # console.log "froggy element ", element 8 | 9 | # we forgot the "px"; and browsers simply ignore unitless properties!!! 10 | X = (x) -> 100*x + "px" 11 | 12 | scope.$watch 'frog.x', (newX, oldX) -> 13 | # console.log "moving #oldX to #newX" 14 | element.css("left", X(newX)) 15 | element.css("z-index", 1) 16 | 17 | # respond to a click on a frog 18 | jump = (me) -> 19 | # currently in browser event context 20 | 21 | # apply this function in angular context 22 | # remove this line and moveCount fails to update 23 | scope.$apply -> 24 | 25 | # ground all the frogs while filtering for the empty pad 26 | emptyPad = (scope.frogs.filter (d) -> 27 | d.element.css("z-index", 0) 28 | d.colour == 1 29 | )[0] 30 | 31 | # can we hop? 32 | diff = Math.abs(me.x - emptyPad.x) 33 | if diff == 1 or diff == 2 34 | 35 | # yes! update the model 36 | scope.hop(me, emptyPad) 37 | 38 | # & update the screen 39 | #me.move(emptyPad) 40 | 41 | 42 | # map colour to css class 43 | classBy = (colour) -> 44 | switch colour 45 | | 0 => "frog red" 46 | | 1 => "frog" 47 | | 2 => "frog blue" 48 | default throw new Error("invalid frog colour") 49 | 50 | element.addClass(classBy(scope.frog.colour)) 51 | 52 | # added to put frogs in right place on startup 53 | element.css("left", X(scope.frog.x)) 54 | 55 | # set up a click handler on the frog 56 | element.bind "click", (event) -> jump(scope.frog) 57 | 58 | scope.frog.element = element 59 | 60 | ] 61 | -------------------------------------------------------------------------------- /test/pubs/mathmo/mathmo-tests.md: -------------------------------------------------------------------------------- 1 | # Mathmo tests 2 | 3 | ## Notes 4 | 5 | When you're populating `testlist` with questions and answers, remember to escape backslashes (`\\`) and quote marks (`\"`) correctly. I'm using a [TextExpander][te] snippet to escape these automatically. I have the following AppleScript: 6 | 7 | on findAndReplace(tofind, toreplace, TheString) 8 | set ditd to text item delimiters 9 | set text item delimiters to tofind 10 | set textItems to text items of TheString 11 | set text item delimiters to toreplace 12 | if (class of TheString is string) then 13 | set res to textItems as string 14 | else -- if (class of TheString is Unicode text) then 15 | set res to textItems as Unicode text 16 | end if 17 | set text item delimiters to ditd 18 | return res 19 | end findAndReplace 20 | 21 | set s to findAndReplace("\\", "\\\\", the clipboard) 22 | set t to findAndReplace("\"", "\\\"", s) 23 | 24 | return t 25 | 26 | bound to `;ls` (for LiveScript, even though the test file is CoffeeScript) to do this automatically. Yes, even if AppleScript is awful for text manipulation. At the core of this project is JavaScript, so we're in no position to judge. 27 | 28 | Notes on `problems.js`: 29 | 30 | * Use `\DeclareMathOperator*` (or even a global stylesheet) rather then `{\rm artanh}` where appropriate. 31 | * Fix `\,\mathrm{d}x` for integrals 32 | * Use an `align*` environment for Newton-Raphson (and possibly a `\phantom{-}` if we can manage it) 33 | * Give the `