diff --git a/.gitignore b/.gitignore
index 243eb9ab..71239be2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,4 @@
Gemfile.lock
.bundle/
-vendor/
benchmark/
lib/linguist/samples.json
diff --git a/Gemfile b/Gemfile
index eccdb902..b92cab78 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,4 +1,3 @@
source 'https://rubygems.org'
gemspec
-gem 'rugged', '0.21.1b2'
gem 'test-unit', require: false if RUBY_VERSION >= '2.2'
diff --git a/README.md b/README.md
index 3fba928a..94430f4d 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,7 @@ The repository stats API, accessed through `#languages`, can be used on a direct
***API UPDATE***
-Since [Version 3.0.0](https://github.com/github/linguist/releases/tag/v3.0.0) Linguist requires a git repository (in the form of a [Rugged::Repository](https://github.com/libgit2/rugged#repositories)) to be passed when initializing `Linguist::Repository`.
+Since [Version 3.0.0](https://github.com/github/linguist/releases/tag/v3.0.0) Linguist expects a git repository (in the form of a [Rugged::Repository](https://github.com/libgit2/rugged#repositories)) to be passed when initializing `Linguist::Repository`.
```ruby
@@ -104,9 +104,34 @@ Linguist::FileBlob.new("underscore.min.js").generated? # => true
See [Linguist::Generated#generated?](https://github.com/github/linguist/blob/master/lib/linguist/generated.rb).
+## Overrides
+
+Linguist supports custom overrides for language definitions and vendored paths. Add a `.gitattributes` file to your project using the keys `linguist-language` and `linguist-vendored` with the standard git-style path matchers for the files you want to override.
+
+Please note that the overrides currently only affect the language statistics for a repository and not the syntax-highlighting of files.
+
+```
+$ cat .gitattributes
+*.rb linguist-language=Java
+
+$ linguist --breakdown
+100.00% Java
+
+Java:
+ruby_file.rb
+```
+
+By default, Linguist treats all of the paths defined in [lib/linguist/vendor.yml](https://github.com/github/linguist/blob/master/lib/linguist/vendor.yml) as vendored and therefore doesn't include them in the language statistics for a repository. Use the `linguist-vendored` attribute to vendor or un-vendor paths.
+
+```
+$ cat .gitattributes
+special-vendored-path/* linguist-vendored
+jquery.js linguist-vendored=false
+```
+
## Installation
-github.com is usually running the latest version of the `github-linguist` gem that is released on [RubyGems.org](http://rubygems.org/gems/github-linguist).
+Github.com is usually running the latest version of the `github-linguist` gem that is released on [RubyGems.org](http://rubygems.org/gems/github-linguist).
But for development you are going to want to checkout out the source. To get it, clone the repo and run [Bundler](http://gembundler.com/) to install its dependencies.
diff --git a/Rakefile b/Rakefile
index 08186e27..8a044135 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,3 +1,4 @@
+require 'bundler/setup'
require 'json'
require 'rake/clean'
require 'rake/testtask'
diff --git a/github-linguist.gemspec b/github-linguist.gemspec
index ff086b04..6a06a6f2 100644
--- a/github-linguist.gemspec
+++ b/github-linguist.gemspec
@@ -17,6 +17,7 @@ Gem::Specification.new do |s|
s.add_dependency 'escape_utils', '~> 1.0.1'
s.add_dependency 'mime-types', '~> 1.19'
s.add_dependency 'pygments.rb', '~> 0.6.0'
+ s.add_dependency 'rugged', '~> 0.21.1b2'
s.add_development_dependency 'json'
s.add_development_dependency 'mocha'
diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml
index de1f5229..24bb9bb4 100644
--- a/lib/linguist/languages.yml
+++ b/lib/linguist/languages.yml
@@ -37,6 +37,7 @@ AGS Script:
extensions:
- .asc
- .ash
+ tm_scope: source.c++
ANTLR:
type: programming
@@ -50,6 +51,7 @@ APL:
color: "#8a0707"
extensions:
- .apl
+ - .dyalog
ASP:
type: programming
@@ -79,6 +81,7 @@ ATS:
- .atxt
- .hats
- .sats
+ tm_scope: source.ocaml
ActionScript:
type: programming
@@ -117,12 +120,14 @@ ApacheConf:
- apache
extensions:
- .apacheconf
+ tm_scope: source.apache-config
Apex:
type: programming
lexer: Java
extensions:
- .cls
+ tm_scope: source.java
AppleScript:
type: programming
@@ -147,6 +152,7 @@ Arduino:
lexer: C++
extensions:
- .ino
+ tm_scope: source.c++
AsciiDoc:
type: prose
@@ -174,6 +180,8 @@ Assembly:
- nasm
extensions:
- .asm
+ - .a51
+ tm_scope: source.asm.x86
Augeas:
type: programming
@@ -198,6 +206,7 @@ AutoIt:
- AutoItScript
extensions:
- .au3
+ tm_scope: source.autoit.3
Awk:
type: programming
@@ -223,6 +232,7 @@ Batchfile:
extensions:
- .bat
- .cmd
+ tm_scope: source.dosbatch
Befunge:
extensions:
@@ -236,6 +246,7 @@ BlitzBasic:
extensions:
- .bb
- .decls
+ tm_scope: source.blitzmax
BlitzMax:
type: programming
@@ -248,6 +259,7 @@ Bluespec:
lexer: verilog
extensions:
- .bsv
+ tm_scope: source.verilog
Boo:
type: programming
@@ -259,6 +271,7 @@ Brainfuck:
extensions:
- .b
- .bf
+ tm_scope: source.bf
Brightscript:
type: programming
@@ -322,6 +335,7 @@ C-ObjDump:
lexer: c-objdump
extensions:
- .c-objdump
+ tm_scope: objdump.x86asm
C2hs Haskell:
type: programming
@@ -331,6 +345,7 @@ C2hs Haskell:
- c2hs
extensions:
- .chs
+ tm_scope: source.haskell
CLIPS:
type: programming
@@ -378,6 +393,7 @@ ChucK:
lexer: Java
extensions:
- .ck
+ tm_scope: source.java
Cirru:
type: programming
@@ -441,6 +457,7 @@ ColdFusion:
- cfml
extensions:
- .cfm
+ tm_scope: text.html.cfm
ColdFusion CFC:
type: programming
@@ -453,6 +470,7 @@ ColdFusion CFC:
- cfc
extensions:
- .cfc
+ tm_scope: source.cfscript
Common Lisp:
type: programming
@@ -481,6 +499,7 @@ Component Pascal:
extensions:
- .cp
- .cps
+ tm_scope: source.pascal
Coq:
type: programming
@@ -495,6 +514,7 @@ Cpp-ObjDump:
- .cppobjdump
- .c++objdump
- .cxx-objdump
+ tm_scope: objdump.x86asm
Creole:
type: prose
@@ -509,11 +529,13 @@ Crystal:
extensions:
- .cr
ace_mode: ruby
+ tm_scope: source.ruby
Cucumber:
lexer: Gherkin
extensions:
- .feature
+ tm_scope: text.gherkin.feature
Cuda:
type: programming
@@ -521,12 +543,14 @@ Cuda:
extensions:
- .cu
- .cuh
+ tm_scope: source.cuda-c++
Cycript:
type: programming
lexer: JavaScript
extensions:
- .cy
+ tm_scope: source.js
Cython:
type: programming
@@ -548,6 +572,7 @@ D-ObjDump:
lexer: d-objdump
extensions:
- .d-objdump
+ tm_scope: objdump.x86asm
DM:
type: programming
@@ -557,6 +582,7 @@ DM:
- .dm
aliases:
- byond
+ tm_scope: source.c++
DOT:
type: data
@@ -612,6 +638,7 @@ Ecere Projects:
lexer: JSON
extensions:
- .epj
+ tm_scope: source.json
ECL:
type: programming
@@ -628,6 +655,7 @@ Eagle:
extensions:
- .sch
- .brd
+ tm_scope: text.xml
Eiffel:
type: programming
@@ -648,6 +676,7 @@ Elm:
lexer: Haskell
extensions:
- .elm
+ tm_scope: source.haskell
Emacs Lisp:
type: programming
@@ -670,6 +699,7 @@ EmberScript:
extensions:
- .em
- .emberscript
+ tm_scope: source.coffee
Erlang:
type: programming
@@ -690,6 +720,7 @@ F#:
- .fs
- .fsi
- .fsx
+ tm_scope: source.fsharp
FLUX:
type: programming
@@ -744,6 +775,7 @@ Fantom:
color: "#dbded5"
extensions:
- .fan
+ tm_scope: source.fan
Forth:
type: programming
@@ -761,6 +793,7 @@ Frege:
lexer: Haskell
extensions:
- .fr
+ tm_scope: source.haskell
G-code:
type: data
@@ -776,6 +809,7 @@ Game Maker Language:
lexer: JavaScript
extensions:
- .gml
+ tm_scope: source.js
GAMS:
type: programming
@@ -825,18 +859,21 @@ GLSL:
Genshi:
extensions:
- .kid
+ tm_scope: text.xml.genshi
Gentoo Ebuild:
group: Shell
lexer: Bash
extensions:
- .ebuild
+ tm_scope: source.shell
Gentoo Eclass:
group: Shell
lexer: Bash
extensions:
- .eclass
+ tm_scope: source.shell
Gettext Catalog:
search_term: pot
@@ -846,6 +883,7 @@ Gettext Catalog:
extensions:
- .po
- .pot
+ tm_scope: source.po
Glyph:
type: programming
@@ -853,6 +891,7 @@ Glyph:
lexer: Tcl
extensions:
- .glf
+ tm_scope: source.tcl
Gnuplot:
type: programming
@@ -879,6 +918,7 @@ Gosu:
- .gst
- .gsx
- .vark
+ tm_scope: source.gosu.2
Grace:
type: programming
@@ -896,6 +936,7 @@ Grammatical Framework:
- .gf
searchable: true
color: "#ff0000"
+ tm_scope: source.haskell
Graph Modeling Language:
type: data
@@ -913,6 +954,7 @@ Groff:
- '.5'
- '.6'
- '.7'
+ tm_scope: text.groff
Groovy:
type: programming
@@ -920,7 +962,6 @@ Groovy:
color: "#e69f56"
extensions:
- .groovy
- - .gradle
- .grt
- .gtpl
- .gvy
@@ -934,6 +975,7 @@ Groovy Server Pages:
- gsp
extensions:
- .gsp
+ tm_scope: text.html.jsp
HTML:
type: markup
@@ -989,9 +1031,12 @@ Haml:
Handlebars:
type: markup
lexer: Handlebars
+ aliases:
+ - hbs
extensions:
- .handlebars
- .hbs
+ tm_scope: text.html.handlebars
Harbour:
type: programming
@@ -1014,6 +1059,7 @@ Haxe:
extensions:
- .hx
- .hxsl
+ tm_scope: source.haxe.2
Hy:
type: programming
@@ -1043,6 +1089,7 @@ INI:
- .ini
- .prefs
- .properties
+ tm_scope: source.ini
Inno Setup:
extensions:
@@ -1063,6 +1110,7 @@ Inform 7:
extensions:
- .ni
- .i7x
+ tm_scope: source.inform
Inno Setup:
extensions:
@@ -1128,6 +1176,7 @@ JSON5:
lexer: JavaScript
extensions:
- .json5
+ tm_scope: source.js
JSONLD:
type: data
@@ -1136,6 +1185,7 @@ JSONLD:
lexer: JavaScript
extensions:
- .jsonld
+ tm_scope: source.js
JSONiq:
type: programming
@@ -1143,12 +1193,14 @@ JSONiq:
lexer: XQuery
extensions:
- .jq
+ tm_scope: source.xquery
Jade:
group: HTML
type: markup
extensions:
- .jade
+ tm_scope: source.jade
Java:
type: programming
@@ -1165,6 +1217,7 @@ Java Server Pages:
- jsp
extensions:
- .jsp
+ tm_scope: text.html.jsp
JavaScript:
type: programming
@@ -1216,6 +1269,7 @@ Kit:
ace_mode: html
extensions:
- .kit
+ tm_scope: text.html.basic
Kotlin:
type: programming
@@ -1223,6 +1277,7 @@ Kotlin:
- .kt
- .ktm
- .kts
+ tm_scope: source.Kotlin
LFE:
type: programming
@@ -1231,11 +1286,19 @@ LFE:
color: "#004200"
lexer: Common Lisp
group: Erlang
+ tm_scope: source.lisp
LLVM:
extensions:
- .ll
+LOLCODE:
+ type: programming
+ lexer: Text only
+ extensions:
+ - .lol
+ color: "#cc9900"
+
LSL:
type: programming
lexer: LSL
@@ -1261,6 +1324,7 @@ Lasso:
- .las
- .lasso9
- .ldml
+ tm_scope: file.lasso
Latte:
type: markup
@@ -1269,6 +1333,7 @@ Latte:
lexer: Smarty
extensions:
- .latte
+ tm_scope: source.smarty
Less:
type: markup
@@ -1276,6 +1341,7 @@ Less:
lexer: CSS
extensions:
- .less
+ tm_scope: source.css
LilyPond:
lexer: Text only
@@ -1316,6 +1382,7 @@ Literate Haskell:
- lhs
extensions:
- .lhs
+ tm_scope: text.tex.latex.haskell
LiveScript:
type: programming
@@ -1347,6 +1414,7 @@ LookML:
color: "#652B81"
extensions:
- .lookml
+ tm_scope: source.yaml
Lua:
type: programming
@@ -1354,6 +1422,7 @@ Lua:
color: "#fa1fa1"
extensions:
- .lua
+ - .fcgi
- .nse
- .pd_lua
- .rbxs
@@ -1368,6 +1437,7 @@ M:
extensions:
- .mumps
- .m
+ tm_scope: source.lisp
MTML:
type: markup
@@ -1375,6 +1445,7 @@ MTML:
color: "#0095d9"
extensions:
- .mtml
+ tm_scope: text.html.basic
Makefile:
aliases:
@@ -1393,6 +1464,7 @@ Mako:
extensions:
- .mako
- .mao
+ tm_scope: text.html.mako
Markdown:
type: prose
@@ -1406,6 +1478,7 @@ Markdown:
- .mkdn
- .mkdown
- .ron
+ tm_scope: text.html.markdown
Mask:
type: markup
@@ -1414,6 +1487,7 @@ Mask:
ace_mode: scss
extensions:
- .mask
+ tm_scope: source.scss
Mathematica:
type: programming
@@ -1444,6 +1518,7 @@ Max:
- .maxproj
- .mxt
- .pat
+ tm_scope: source.json
MediaWiki:
type: prose
@@ -1460,6 +1535,7 @@ Mercury:
extensions:
- .m
- .moo
+ tm_scope: source.prolog
MiniD: # Legacy
searchable: false
@@ -1476,6 +1552,7 @@ Mirah:
- .duby
- .mir
- .mirah
+ tm_scope: source.ruby
Monkey:
type: programming
@@ -1493,6 +1570,8 @@ MoonScript:
type: programming
extensions:
- .moon
+ interpreters:
+ - moon
Myghty:
extensions:
@@ -1515,12 +1594,14 @@ NetLogo:
color: "#ff2b2b"
extensions:
- .nlogo
+ tm_scope: source.lisp
Nginx:
type: markup
lexer: Nginx configuration file
extensions:
- .nginxconf
+ tm_scope: source.nginx
Nimrod:
type: programming
@@ -1552,6 +1633,7 @@ Nu:
- .nu
filenames:
- Nukefile
+ tm_scope: source.scheme
NumPy:
group: Python
@@ -1578,6 +1660,7 @@ ObjDump:
lexer: objdump
extensions:
- .objdump
+ tm_scope: objdump.x86asm
Objective-C:
type: programming
@@ -1608,6 +1691,7 @@ Objective-J:
extensions:
- .j
- .sj
+ tm_scope: source.js.objj
Omgrofl:
type: programming
@@ -1635,6 +1719,7 @@ OpenCL:
extensions:
- .cl
- .opencl
+ tm_scope: source.c
OpenEdge ABL:
type: programming
@@ -1645,6 +1730,7 @@ OpenEdge ABL:
extensions:
- .p
- .cls
+ tm_scope: source.abl
OpenSCAD:
type: programming
@@ -1680,6 +1766,7 @@ PAWN:
color: "#dbb284"
extensions:
- .pwn
+ tm_scope: source.c++
PHP:
type: programming
@@ -1690,6 +1777,7 @@ PHP:
- .php
- .aw
- .ctp
+ - .fcgi
- .module
- .php3
- .php4
@@ -1707,6 +1795,13 @@ Pan:
extensions:
- .pan
+Papyrus:
+ type: programming
+ color: "#6600cc"
+ lexer: Text only
+ extensions:
+ - .psc
+
Parrot:
type: programming
color: "#f3ca0a"
@@ -1810,6 +1905,7 @@ PostScript:
extensions:
- .ps
- .eps
+ tm_scope: source.postscript
PowerShell:
type: programming
@@ -1852,6 +1948,7 @@ Protocol Buffer:
- Protocol Buffers
extensions:
- .proto
+ tm_scope: source.protobuf
Puppet:
type: programming
@@ -1874,6 +1971,7 @@ PureScript:
lexer: Haskell
extensions:
- .purs
+ tm_scope: source.haskell
Python:
type: programming
@@ -1882,6 +1980,7 @@ Python:
extensions:
- .py
- .cgi
+ - .fcgi
- .gyp
- .lmi
- .pyde
@@ -1910,6 +2009,7 @@ QML:
color: "#44a51c"
extensions:
- .qml
+ tm_scope: source.qml
QMake:
lexer: Text only
@@ -1942,6 +2042,7 @@ RDoc:
wrap: true
extensions:
- .rdoc
+ tm_scope: text.rdoc
REALbasic:
type: programming
@@ -1953,12 +2054,14 @@ REALbasic:
- .rbres
- .rbtbar
- .rbuistate
+ tm_scope: source.vbnet
RHTML:
type: markup
group: HTML
extensions:
- .rhtml
+ tm_scope: text.html.ruby
RMarkdown:
type: prose
@@ -1978,6 +2081,7 @@ Racket:
- .rktd
- .rktl
- .scrbl
+ tm_scope: source.scheme
Ragel in Ruby Host:
type: programming
@@ -2021,6 +2125,7 @@ RobotFramework:
extensions:
- .robot
# - .txt
+ tm_scope: text.robot
Rouge:
type: programming
@@ -2029,6 +2134,7 @@ Rouge:
color: "#cc0088"
extensions:
- .rg
+ tm_scope: source.clojure
Ruby:
type: programming
@@ -2043,6 +2149,7 @@ Ruby:
extensions:
- .rb
- .builder
+ - .fcgi
- .gemspec
- .god
- .irbrc
@@ -2103,6 +2210,7 @@ SQF:
extensions:
- .sqf
- .hqf
+ tm_scope: source.c++
SQL:
type: data
@@ -2121,6 +2229,7 @@ STON:
lexer: JSON
extensions:
- .ston
+ tm_scope: source.json
Sage:
type: programming
@@ -2128,6 +2237,7 @@ Sage:
group: Python
extensions:
- .sage
+ tm_scope: source.python
Sass:
type: markup
@@ -2151,6 +2261,7 @@ Scaml:
type: markup
extensions:
- .scaml
+ tm_scope: source.scaml
Scheme:
type: programming
@@ -2185,7 +2296,7 @@ Shell:
type: programming
lexer: Bash
search_term: bash
- color: "#5861ce"
+ color: "#89e051"
aliases:
- sh
- bash
@@ -2195,6 +2306,8 @@ Shell:
- .bash
- .bats
- .cgi
+ - .command
+ - .fcgi
- .tmux
- .zsh
interpreters:
@@ -2222,6 +2335,7 @@ Slash:
color: "#007eff"
extensions:
- .sl
+ tm_scope: text.html.slash
Slim:
group: HTML
@@ -2248,12 +2362,14 @@ SourcePawn:
- sourcemod
extensions:
- .sp
+ tm_scope: source.sp
Squirrel:
type: programming
lexer: C++
extensions:
- .nut
+ tm_scope: source.c++
Standard ML:
type: programming
@@ -2265,6 +2381,7 @@ Standard ML:
- .fun
- .sig
- .sml
+ tm_scope: source.ml
Stata:
type: programming
@@ -2312,6 +2429,7 @@ TOML:
type: data
extensions:
- .toml
+ tm_scope: source.toml
TXL:
type: programming
@@ -2326,6 +2444,9 @@ Tcl:
- .tcl
- .adp
- .tm
+ interpreters:
+ - tclsh
+ - wish
Tcsh:
type: programming
@@ -2333,6 +2454,7 @@ Tcsh:
extensions:
- .tcsh
- .csh
+ tm_scope: source.shell
TeX:
type: markup
@@ -2362,6 +2484,7 @@ Tea:
type: markup
extensions:
- .tea
+ tm_scope: source.tea
Textile:
type: prose
@@ -2385,6 +2508,7 @@ Twig:
lexer: HTML+Django/Jinja
extensions:
- .twig
+ tm_scope: text.html.twig
TypeScript:
type: programming
@@ -2393,6 +2517,7 @@ TypeScript:
- ts
extensions:
- .ts
+ tm_scope: source.ts
Unified Parallel C:
type: programming
@@ -2402,6 +2527,7 @@ Unified Parallel C:
color: "#755223"
extensions:
- .upc
+ tm_scope: source.c
UnrealScript:
type: programming
@@ -2409,6 +2535,7 @@ UnrealScript:
lexer: Java
extensions:
- .uc
+ tm_scope: source.java
VCL:
type: programming
@@ -2417,6 +2544,7 @@ VCL:
color: "#0298c3"
extensions:
- .vcl
+ tm_scope: source.perl
VHDL:
type: programming
@@ -2457,6 +2585,7 @@ VimL:
- .vim
filenames:
- .vimrc
+ - _vimrc
- vimrc
- gvimrc
@@ -2473,6 +2602,7 @@ Visual Basic:
- .vba
- .vbhtml
- .vbs
+ tm_scope: source.vbnet
Volt:
type: programming
@@ -2480,12 +2610,14 @@ Volt:
color: "#0098db"
extensions:
- .volt
+ tm_scope: source.d
XC:
type: programming
lexer: C
extensions:
- .xc
+ tm_scope: source.c
XML:
type: markup
@@ -2564,6 +2696,7 @@ XProc:
extensions:
- .xpl
- .xproc
+ tm_scope: text.xml
XQuery:
type: programming
@@ -2579,6 +2712,7 @@ XS:
lexer: C
extensions:
- .xs
+ tm_scope: source.c
XSLT:
type: programming
@@ -2587,6 +2721,7 @@ XSLT:
extensions:
- .xslt
- .xsl
+ tm_scope: text.xml.xsl
Xojo:
type: programming
@@ -2598,6 +2733,7 @@ Xojo:
- .xojo_script
- .xojo_toolbar
- .xojo_window
+ tm_scope: source.vbnet
Xtend:
type: programming
@@ -2621,6 +2757,7 @@ Zephir:
color: "#118f9e"
extensions:
- .zep
+ tm_scope: text.html.php
Zimpl:
type: programming
@@ -2644,6 +2781,7 @@ edn:
color: "#db5855"
extensions:
- .edn
+ tm_scope: source.clojure
fish:
type: programming
@@ -2688,6 +2826,7 @@ wisp:
color: "#7582D1"
extensions:
- .wisp
+ tm_scope: source.clojure
xBase:
type: programming
diff --git a/lib/linguist/repository.rb b/lib/linguist/repository.rb
index 1f9e09c4..41e829c5 100644
--- a/lib/linguist/repository.rb
+++ b/lib/linguist/repository.rb
@@ -128,13 +128,20 @@ module Linguist
protected
def compute_stats(old_commit_oid, cache = nil)
- file_map = cache ? cache.dup : {}
old_tree = old_commit_oid && Rugged::Commit.lookup(repository, old_commit_oid).tree
read_index
diff = Rugged::Tree.diff(repository, old_tree, current_tree)
+ # Clear file map and fetch full diff if any .gitattributes files are changed
+ if cache && diff.each_delta.any? { |delta| File.basename(delta.new_file[:path]) == ".gitattributes" }
+ diff = Rugged::Tree.diff(repository, old_tree = nil, current_tree)
+ file_map = {}
+ else
+ file_map = cache ? cache.dup : {}
+ end
+
diff.each_delta do |delta|
old = delta.old_file[:path]
new = delta.new_file[:path]
diff --git a/lib/linguist/vendor.yml b/lib/linguist/vendor.yml
index e141eff8..490a910f 100644
--- a/lib/linguist/vendor.yml
+++ b/lib/linguist/vendor.yml
@@ -242,3 +242,7 @@
# Typesafe Activator
- (^|/)activator$
- (^|/)activator\.bat$
+
+# ProGuard
+- proguard.pro
+- proguard-rules.pro
diff --git a/lib/linguist/version.rb b/lib/linguist/version.rb
index 2edc3c5a..f02c0c45 100644
--- a/lib/linguist/version.rb
+++ b/lib/linguist/version.rb
@@ -1,3 +1,3 @@
module Linguist
- VERSION = "3.3.1"
+ VERSION = "3.4.1"
end
diff --git a/samples/APL/UT.dyalog b/samples/APL/UT.dyalog
new file mode 100644
index 00000000..6c5f28fa
--- /dev/null
+++ b/samples/APL/UT.dyalog
@@ -0,0 +1,367 @@
+:NameSpace UT
+
+ sac ← 0
+ expect_orig ← expect ← ⎕NS⍬
+ exception ← ⍬
+ nexpect_orig ← nexpect ← ⎕NS⍬
+
+ ∇ {Z}←{Conf}run Argument;PRE_test;POST_test;TEST_step;COVER_step;FromSpace
+
+ load_display_if_not_already_loaded
+ load_salt_scripts_into_current_namespace_if_configured
+
+ FromSpace←1⊃⎕RSI
+
+ PRE_test←{}
+ POST_test←{}
+ COVER_step←{}
+ :If 0≠⎕NC'Conf'
+ :If Conf has'cover_target'
+ PRE_test←{{}⎕PROFILE'start'}
+ POST_test←{{}⎕PROFILE'stop'}
+ :EndIf
+ :EndIf
+
+ :If is_function Argument
+ TEST_step←single_function_test_function
+ COVER_file←Argument,'_coverage.html'
+
+ :ElseIf is_list_of_functions Argument
+ TEST_step←list_of_functions_test_function
+ COVER_file←'list_coverage.html'
+
+ :ElseIf is_file Argument
+ TEST_step←file_test_function
+ COVER_file←(get_file_name Argument),'_coverage.html'
+
+ :ElseIf is_dir Argument
+ test_files←test_files_in_dir Argument
+ TEST_step←test_dir_function
+ Argument←test_files
+ :EndIf
+
+ :If 0≠⎕NC'Conf'
+ :If Conf has'cover_target'
+ COVER_step←{Conf,←⊂('cover_file'COVER_file)
+ generate_coverage_page Conf}
+ :EndIf
+ :EndIf
+
+ PRE_test ⍬
+ Z←FromSpace TEST_step Argument
+ POST_test ⍬
+ COVER_step ⍬
+ ∇
+
+ ∇ load_display_if_not_already_loaded
+ :If 0=⎕NC'#.DISPLAY'
+ 'DISPLAY'#.⎕CY'display'
+ :EndIf
+ ∇
+
+ ∇ load_salt_scripts_into_current_namespace_if_configured
+ :If 0≠⎕NC'#.UT.appdir'
+ :If ⍬≢#.UT.appdir
+ ⎕SE.SALT.Load #.UT.appdir,'src/*.dyalog -target=#'
+ ⎕SE.SALT.Load #.UT.appdir,'test/*.dyalog -target=#'
+ :EndIf
+ :EndIf
+ ∇
+
+ ∇ Z←FromSpace single_function_test_function TestName
+ Z←run_ut FromSpace TestName
+ ∇
+
+ ∇ Z←FromSpace list_of_functions_test_function ListOfNames;t
+ t←⎕TS
+ Z←run_ut¨{FromSpace ⍵}¨ListOfNames
+ t←⎕TS-t
+ ('Test execution report')print_passed_crashed_failed Z t
+ ∇
+
+ ∇ Z←FromSpace file_test_function FilePath;FileNS;Functions;TestFunctions;t
+ FileNS←⎕SE.SALT.Load FilePath,' -target=#'
+ Functions←↓FileNS.⎕NL 3
+ TestFunctions←(is_test¨Functions)/Functions
+ :If (0/⍬,⊂0/'')≡TestFunctions
+ ⎕←'No test functions found'
+ Z←⍬
+ :Else
+ t←⎕TS
+ Z←run_ut¨{FileNS ⍵}¨TestFunctions
+ t←⎕TS-t
+ (FilePath,' tests')print_passed_crashed_failed Z t
+ :EndIf
+ ∇
+
+ ∇ Z←FromSpace test_dir_function Test_files
+ :If Test_files≡⍬/⍬,⊂''
+ ⎕←'No test files found'
+ Z←⍬
+ :Else
+ Z←#.UT.run¨Test_files
+ :EndIf
+ ∇
+
+ ∇ Z←get_file_name Argument;separator
+ separator←⊃⌽(Argument∊'/\')/⍳⍴Argument
+ Z←¯7↓separator↓Argument
+ ∇
+
+ ∇ generate_coverage_page Conf;ProfileData;CoverResults;HTML
+ ProfileData←⎕PROFILE'data'
+ ToCover←retrieve_coverables¨(⊃'cover_target'in Conf)
+ :If (⍴ToCover)≡(⍴⊂1)
+ ToCover←⊃ToCover
+ :EndIf
+ Representations←get_representation¨ToCover
+ CoverResults←ProfileData∘generate_cover_result¨↓ToCover,[1.5]Representations
+ HTML←generate_html CoverResults
+ Conf write_html_to_page HTML
+ ⎕PROFILE'clear'
+ ∇
+
+ ∇ Z←retrieve_coverables Something;nc;functions
+ nc←⎕NC Something
+ :If nc=3
+ Z←Something
+ :ElseIf nc=9
+ functions←strip¨↓⍎Something,'.⎕NL 3'
+ Z←{(Something,'.',⍵)}¨functions
+ :EndIf
+ ∇
+
+ ∇ Z←strip input
+ Z←(input≠' ')/input
+ ∇
+
+ ∇ Z←get_representation Function;nc;rep
+ nc←⎕NC⊂Function
+ :If nc=3.1
+ rep←↓⎕CR Function
+ rep[1]←⊂'∇',⊃rep[1]
+ rep,←⊂'∇'
+ rep←↑rep
+ :Else
+ rep←⎕CR Function
+ :EndIf
+ Z←rep
+ ∇
+
+ ∇ Z←ProfileData generate_cover_result(name representation);Indices;lines;functionlines;covered_lines
+ Indices←({name≡⍵}¨ProfileData[;1])/⍳⍴ProfileData[;1]
+ lines←ProfileData[Indices;2]
+ nc←⎕NC⊂name
+ :If 3.1=nc
+ functionlines←¯2+⍴↓representation
+ :Else
+ functionlines←⊃⍴↓representation
+ :EndIf
+ covered_lines←(⍬∘≢¨lines)/lines
+ Z←(nc lines functionlines covered_lines representation)
+ ∇
+
+ ∇ Z←generate_html CoverResults;Covered;Total;Percentage;CoverageText;ColorizedCode;Timestamp;Page
+ Covered←⊃⊃+/{⍴4⊃⍵}¨CoverResults
+ Total←⊃⊃+/{3⊃⍵}¨CoverResults
+ Percentage←100×Covered÷Total
+ CoverageText←'Coverage: ',Percentage,'% (',Covered,'/',Total,')'
+ ColorizedCode←⊃,/{colorize_code_by_coverage ⍵}¨CoverResults
+ Timestamp←generate_timestamp_text
+ Page←⍬
+ Page,←⊂⍬,''
+ Page,←⊂⍬,''
+ Page,←⊂⍬,''
+ Page,←⊂⍬,CoverageText
+ Page,←⊂⍬,'
'
+ Page,←ColorizedCode
+ Page,←⊂⍬,'
'
+ Page,←Timestamp
+ Page,←⊂⍬,''
+ Z←Page
+ ∇
+
+ ∇ Z←colorize_code_by_coverage CoverResult;Colors;Ends;Code
+ :If 3.1=⊃CoverResult
+ Colors←(2+3⊃CoverResult)⍴⊂''
+ Colors[1]←⊂''
+ Colors[⍴Colors]←⊂''
+ Ends←(2+3⊃CoverResult)⍴⊂''
+ Ends[1]←⊂''
+ Ends[⍴Ends]←⊂''
+ :Else
+ Colors←(3⊃CoverResult)⍴⊂''
+ Ends←(3⊃CoverResult)⍴⊂''
+ :EndIf
+ Colors[1+4⊃CoverResult]←⊂''
+ Ends[1+4⊃CoverResult]←⊂''
+ Code←↓5⊃CoverResult
+ Z←Colors,[1.5]Code
+ Z←{⍺,(⎕UCS 13),⍵}/Z,Ends
+ ∇
+
+ ∇ Z←generate_timestamp_text;TS;YYMMDD;HHMMSS
+ TS←⎕TS
+ YYMMDD←⊃{⍺,'-',⍵}/3↑TS
+ HHMMSS←⊃{⍺,':',⍵}/3↑3↓TS
+ Z←'Page generated: ',YYMMDD,'|',HHMMSS
+ ∇
+
+ ∇ Conf write_html_to_page Page;tie;filename
+ filename←(⊃'cover_out'in Conf),(⊃'cover_file'in Conf)
+ :Trap 22
+ tie←filename ⎕NTIE 0
+ filename ⎕NERASE tie
+ filename ⎕NCREATE tie
+ :Else
+ tie←filename ⎕NCREATE 0
+ :EndTrap
+ Simple_array←⍕⊃,/Page
+ (⎕UCS'UTF-8'⎕UCS Simple_array)⎕NAPPEND tie
+ ∇
+
+ ∇ Z←is_function Argument
+ Z←'_TEST'≡¯5↑Argument
+ ∇
+
+ ∇ Z←is_list_of_functions Argument
+ Z←2=≡Argument
+ ∇
+
+ ∇ Z←is_file Argument
+ Z←'.dyalog'≡¯7↑Argument
+ ∇
+
+ ∇ Z←is_dir Argument;attr
+ :If 'Linux'≡5↑⊃'.'⎕WG'APLVersion'
+ Z←'yes'≡⊃⎕CMD'test -d ',Argument,' && echo yes || echo no'
+ :Else
+ 'gfa'⎕NA'I kernel32|GetFileAttributes* <0t'
+ :If Z←¯1≠attr←gfa⊂Argument ⍝ If file exists
+ Z←⊃2 16⊤attr ⍝ Return bit 4
+ :EndIf
+ :EndIf
+ ∇
+
+
+ ∇ Z←test_files_in_dir Argument
+ :If 'Linux'≡5↑⊃'.'⎕WG'APLVersion'
+ Z←⎕SH'find ',Argument,' -name \*_tests.dyalog'
+ :Else
+ #.⎕CY'files'
+ Z←#.Files.Dir Argument,'\*_tests.dyalog'
+ Z←(Argument,'\')∘,¨Z
+ :EndIf
+ ∇
+
+ ∇ Z←run_ut ut_data;returned;crashed;pass;crash;fail;message
+ (returned crashed time)←execute_function ut_data
+ (pass crash fail)←determine_pass_crash_or_fail returned crashed
+ message←determine_message pass fail crashed(2⊃ut_data)returned time
+ print_message_to_screen message
+ Z←(pass crash fail)
+ ∇
+
+ ∇ Z←execute_function ut_data;function;t
+ reset_UT_globals
+ function←(⍕(⊃ut_data[1])),'.',⊃ut_data[2]
+ :Trap sac
+ :If 3.2≡⎕NC⊂function
+ t←⎕TS
+ Z←(⍎function,' ⍬')0
+ t←⎕TS-t
+ :Else
+ t←⎕TS
+ Z←(⍎function)0
+ t←⎕TS-t
+ :EndIf
+
+ :Else
+ Z←(↑⎕DM)1
+ :If exception≢⍬
+ expect←exception
+ Z[2]←0
+ t←⎕TS-t
+ :EndIf
+ :EndTrap
+ Z,←⊂t
+ ∇
+
+ ∇ reset_UT_globals
+ expect_orig ← expect← ⎕NS⍬
+ exception←⍬
+ nexpect_orig ← nexpect← ⎕NS⍬
+ ∇
+
+ ∇ Z←is_test FunctionName;wsIndex
+ wsIndex←FunctionName⍳' '
+ FunctionName←(wsIndex-1)↑FunctionName
+ Z←'_TEST'≡¯5↑FunctionName
+ ∇
+
+ ∇ Heading print_passed_crashed_failed(ArrayRes time)
+ ⎕←'-----------------------------------------'
+ ⎕←Heading
+ ⎕←' ⍋ Passed: ',+/{1⊃⍵}¨ArrayRes
+ ⎕←' ⍟ Crashed: ',+/{2⊃⍵}¨ArrayRes
+ ⎕←' ⍒ Failed: ',+/{3⊃⍵}¨ArrayRes
+ ⎕←' ○ Runtime: ',time[5],'m',time[6],'s',time[7],'ms'
+ ∇
+
+ determine_pass_crash_or_fail←{
+ r c←⍵ ⋄ 0≠c:0 1 0 ⋄ z←(0 0 1)(1 0 0)
+ expect_orig≢expect:(⎕IO+expect≡r)⊃z ⋄ (⎕IO+nexpect≢r)⊃z
+ }
+
+ ∇ Z←determine_message(pass fail crashed name returned time)
+ :If crashed
+ Z←'CRASHED: 'failure_message name returned
+ :ElseIf pass
+ Z←'Passed ',time[5],'m',time[6],'s',time[7],'ms'
+ :Else
+ Z←'FAILED: 'failure_message name returned
+ :EndIf
+ ∇
+
+ ∇ print_message_to_screen message
+ ⎕←message
+ ∇
+
+ ∇ Z←term_to_text Term;Text;Rows
+ Text←#.DISPLAY Term
+ Rows←1⊃⍴Text
+ Z←(Rows 4⍴''),Text
+ ∇
+
+ ∇ Z←Cause failure_message(name returned);hdr;exp;expterm;got;gotterm
+ hdr←Cause,name
+ exp←'Expected'
+ expterm←term_to_text #.UT.expect
+ got←'Got'
+ gotterm←term_to_text returned
+ Z←align_and_join_message_parts hdr exp expterm got gotterm
+ ∇
+
+ ∇ Z←align_and_join_message_parts Parts;hdr;exp;expterm;got;gotterm;R1;C1;R2;C2;W
+ (hdr exp expterm got gotterm)←Parts
+ (R1 C1)←⍴expterm
+ (R2 C2)←⍴gotterm
+ W←⊃⊃⌈/C1 C2(⍴hdr)(⍴exp)(⍴got)
+ Z←(W↑hdr),[0.5](W↑exp)
+ Z←Z⍪(R1 W↑expterm)
+ Z←Z⍪(W↑got)
+ Z←Z⍪(R2 W↑gotterm)
+ ∇
+
+ ∇ Z←confparam in config
+ Z←1↓⊃({confparam≡⊃⍵}¨config)/config
+ ∇
+
+ ∇ Z←config has confparam
+ Z←∨/{confparam≡⊃⍵}¨config
+ ∇
+
+:EndNameSpace
diff --git a/samples/Assembly/External Interrupt.a51 b/samples/Assembly/External Interrupt.a51
new file mode 100644
index 00000000..33feadc2
--- /dev/null
+++ b/samples/Assembly/External Interrupt.a51
@@ -0,0 +1,66 @@
+ ORG 0000h
+ SJMP START
+ ORG 0003h
+ LCALL INT0_ISR
+ RETI
+ ORG 000Bh
+ LCALL T0_ISR
+ RETI
+ ORG 0013h
+ LCALL INT1_ISR
+ RETI
+ ORG 001Bh
+ LCALL T1_ISR
+ RETI
+ ORG 0023h
+ LCALL UART_ISR
+ RETI
+ ORG 0030h
+START:
+ MOV A,#11111110b
+ SETB IT0 ; Set External Interrupt 0 to be falling edge triggered
+ SETB EX0 ; Enable External Interrut 0
+ SETB EA ; Enable Interrupt
+LEFT:
+ CJNE A,#01111111b,LOOP1
+ JMP RIGHT
+LOOP1:
+ MOV P1,A
+ RL A
+ LCALL DELAY
+ SJMP LEFT
+RIGHT:
+ CJNE A,#11111110b,LOOP2
+ JMP LEFT
+LOOP2:
+ MOV P1,A
+ RR A
+ LCALL DELAY
+ SJMP RIGHT
+
+INT0_ISR:
+ MOV R1,#3
+FLASH:
+ MOV P1,#00h
+ LCALL DELAY
+ MOV P1,#0FFh
+ LCALL DELAY
+ DJNZ R1,FLASH
+ RET
+T0_ISR:
+ RET
+INT1_ISR:
+ RET
+T1_ISR:
+ RET
+UART_ISR:
+ RET
+
+DELAY: MOV R5,#20 ;R5*20 mS
+D1: MOV R6,#40
+D2: MOV R7,#249
+ DJNZ R7,$
+ DJNZ R6,D2
+ DJNZ R5,D1
+ RET
+ END
diff --git a/samples/LOLCODE/LOLTracer.lol b/samples/LOLCODE/LOLTracer.lol
new file mode 100644
index 00000000..9d8a6d20
--- /dev/null
+++ b/samples/LOLCODE/LOLTracer.lol
@@ -0,0 +1,795 @@
+HAI 1.3
+ OBTW
+ Author: Logan Kelly (logan.kelly@gmail.com)
+ Github: https://github.com/LoganKelly/LOLTracer
+ TLDR
+
+ OBTW prev is the number used in the randin function.
+ I had to declare it in global scope so that it
+ would retain its value between calls to randin.
+ TLDR
+ I HAS A prev ITZ 0
+ I HAS A rand_max ITZ 104729
+
+
+ OBTW Equivalent to C's rand() function, except returns
+ a number in the range of 0 to rand_max.
+ TLDR
+ HOW IZ I randin
+ I HAS A a ITZ 33083
+ I HAS A c ITZ 67607
+ prev R MOD OF SUM OF PRODUKT OF prev AN a AN c AN rand_max
+ FOUND YR prev
+ IF U SAY SO
+
+
+ BTW Returns a random number within the range of 0-1.
+ HOW IZ I rand_onein
+ I HAS A rand_num ITZ I IZ randin MKAY
+ rand_num IS NOW A NUMBAR
+ I HAS A rand_max_float ITZ MAEK rand_max A NUMBAR
+ FOUND YR QUOSHUNT OF rand_num AN rand_max_float
+ IF U SAY SO
+
+
+ OBTW Equivalent to C ceil() function. Returns the next
+ largest integer for the given number.
+ TLDR
+ HOW IZ I ceilin YR num
+ I HAS A int_num ITZ num
+ int_num IS NOW A NUMBR
+ BOTH SAEM int_num AN num, O RLY?
+ YA RLY, FOUND YR num
+ OIC
+ DIFFRINT num AN SMALLR OF num AN 0, O RLY?
+ YA RLY
+ int_num R SUM OF int_num AN 1
+ FOUND YR MAEK int_num A NUMBAR
+ OIC
+ DIFFRINT num AN BIGGR OF num AN 0, O RLY?
+ YA RLY
+ FOUND YR MAEK int_num A NUMBAR
+ OIC
+ IF U SAY SO
+
+
+ OBTW Convert a number to hexadecimal. This
+ is returned as a string.
+ TLDR
+ HOW IZ I decimal_to_hex YR num
+ I HAS A i ITZ 0
+ I HAS A rem
+ I HAS A hex_num ITZ A BUKKIT
+ I HAS A decimal_num ITZ num
+ IM IN YR num_loop
+ rem R MOD OF decimal_num AN 16
+ I HAS A hex_digit
+ rem, WTF?
+ OMG 10, hex_digit R "A", GTFO
+ OMG 11, hex_digit R "B", GTFO
+ OMG 12, hex_digit R "C", GTFO
+ OMG 13, hex_digit R "D", GTFO
+ OMG 14, hex_digit R "E", GTFO
+ OMG 15, hex_digit R "F", GTFO
+ OMGWTF, hex_digit R rem
+ OIC
+ hex_num HAS A SRS i ITZ hex_digit
+ decimal_num R QUOSHUNT OF decimal_num AN 16
+ BOTH SAEM decimal_num AN 0, O RLY?
+ YA RLY, GTFO
+ NO WAI, i R SUM OF i AN 1
+ OIC
+ IM OUTTA YR num_loop
+ I HAS A hex_string ITZ A YARN
+ IM IN YR string_reverse
+ DIFFRINT i AN BIGGR OF i AN 0, O RLY?
+ YA RLY, GTFO
+ OIC
+ hex_string R SMOOSH hex_string AN hex_num'Z SRS i MKAY
+ i R DIFF OF i AN 1
+ IM OUTTA YR string_reverse
+ FOUND YR hex_string
+ IF U SAY SO
+
+
+ OBTW Convert a number to binary. This is returned
+ as a bukkit which has slots number 0-N where
+ n is equal to the number of binary digits - 1.
+ It also has a length slot which is equal to
+ the number of binary digits.
+ TLDR
+ HOW IZ I decimal_to_binary YR num
+ I HAS A i ITZ 0
+ I HAS A decimal_num ITZ num
+ I HAS A binary_num ITZ A BUKKIT
+ IM IN YR num_loop
+ binary_num HAS A SRS i ITZ MOD OF decimal_num AN 2
+ decimal_num R QUOSHUNT OF decimal_num AN 2
+ BOTH SAEM decimal_num AN 0, O RLY?
+ YA RLY
+ I HAS A length ITZ SUM OF i AN 1
+ binary_num HAS A length ITZ length
+ GTFO
+ NO WAI, i R SUM OF i AN 1
+ OIC
+ IM OUTTA YR num_loop
+ FOUND YR binary_num
+ IF U SAY SO
+
+
+ OBTW Bitwise and two binary numbers. The numbers
+ must be provided in the format returned by
+ decimal_to_binary.
+ TLDR
+ HOW IZ I bitwise_andin YR first_num AN YR second_num
+ I HAS A binary_first_num ITZ I IZ decimal_to_binary YR first_num MKAY
+ I HAS A binary_second_num ITZ I IZ decimal_to_binary YR second_num MKAY
+ I HAS A first_length ITZ binary_first_num'Z length
+ I HAS A second_length ITZ binary_second_num'Z length
+ I HAS A max_length ITZ BIGGR OF first_length AN second_length
+ I HAS A final_binary ITZ A BUKKIT
+ I HAS A final_length ITZ 0
+ I HAS A i ITZ 0
+ IM IN YR num_loop
+ BOTH SAEM i AN max_length, O RLY?
+ YA RLY, GTFO
+ OIC
+ I HAS A first_binary ITZ 0
+ I HAS A second_binary ITZ 0
+ DIFFRINT i AN BIGGR OF i AN first_length, O RLY?
+ YA RLY, first_binary R binary_first_num'Z SRS i
+ OIC
+ DIFFRINT i AN BIGGR OF i AN second_length, O RLY?
+ YA RLY, second_binary R binary_second_num'Z SRS i
+ OIC
+ EITHER OF BOTH SAEM first_binary AN 0 AN ...
+ BOTH SAEM second_binary AN 0, O RLY?
+ YA RLY, final_binary HAS A SRS i ITZ 0
+ NO WAI
+ final_binary HAS A SRS i ITZ 1
+ final_length R SUM OF i AN 1
+ OIC
+ i R SUM OF i AN 1
+ IM OUTTA YR num_loop
+ final_binary HAS A length ITZ final_length
+ FOUND YR final_binary
+ IF U SAY SO
+
+
+ OBTW Bitshift left a binary number by num_bits.
+ The binary number must be provided in the format
+ returned by decimal_to_binary.
+ TLDR
+ HOW IZ I bit_shift_leftin YR num AN YR num_bits
+ I HAS A binary_num ITZ num
+ I HAS A length ITZ binary_num'Z length
+ I HAS A i ITZ SUM OF DIFF OF length AN 1 AN num_bits
+ I HAS A shifted_binary_num ITZ A BUKKIT
+ IM IN YR num_loop
+ BOTH SAEM i AN -1, O RLY?
+ YA RLY, GTFO
+ OIC
+ I HAS A unshifted_index ITZ DIFF OF i AN num_bits
+ BOTH SAEM unshifted_index AN BIGGR OF unshifted_index AN 0, O RLY?
+ YA RLY
+ shifted_binary_num HAS A SRS i ITZ binary_num'Z SRS unshifted_index
+ NO WAI
+ shifted_binary_num HAS A SRS i ITZ 0
+ OIC
+ i R DIFF OF i AN 1
+ IM OUTTA YR num_loop
+ shifted_binary_num HAS A length ITZ SUM OF binary_num'Z length AN num_bits
+ FOUND YR shifted_binary_num
+ IF U SAY SO
+
+
+ OBTW Convert a binary number into a decimal number.
+ The binary number must be provided in the format
+ return by decimal_to_binary.
+ TLDR
+ HOW IZ I binary_to_decimal YR binary_num
+ I HAS A length ITZ binary_num'Z length
+ I HAS A decimal_num ITZ 0
+ I HAS A i ITZ 0
+ IM IN YR num_loop
+ BOTH SAEM i AN length, O RLY?
+ YA RLY, GTFO
+ OIC
+ I HAS A binary_value ITZ binary_num'Z SRS i
+ I HAS A decimal_value ITZ 0
+ BOTH SAEM binary_value AN 1, O RLY?
+ YA RLY, decimal_value R I IZ power_of YR 2 AN YR i MKAY
+ OIC
+ decimal_num R SUM OF decimal_num AN decimal_value
+ i R SUM OF i AN 1
+ IM OUTTA YR num_loop
+ FOUND YR decimal_num
+ IF U SAY SO
+
+
+ OBTW Equivalent to C's pow() function. Raises
+ base to the power of exponent.
+ TLDR
+ HOW IZ I power_of YR base AN YR exponent
+ I HAS A i ITZ 0
+ I HAS A num ITZ 1
+ IM IN YR num_loop
+ BOTH SAEM i AN exponent, O RLY?
+ YA RLY, GTFO
+ OIC
+ num R PRODUKT OF num AN base
+ i R SUM OF i AN 1
+ IM OUTTA YR num_loop
+ FOUND YR num
+ IF U SAY SO
+
+
+ OBTW Return a binary number as a YARN.
+ The binary number must be provided in the format
+ return by decimal_to_binary.
+ TLDR
+ HOW IZ I binary_to_string YR binary_num
+ I HAS A binary_string ITZ A YARN
+ I HAS A i ITZ DIFF OF binary_num'Z length AN 1
+ IM IN YR string_reverse
+ DIFFRINT i AN BIGGR OF i AN 0, O RLY?
+ YA RLY, GTFO
+ OIC
+ binary_string R SMOOSH binary_string AN binary_num'Z SRS i MKAY
+ i R DIFF OF i AN 1
+ IM OUTTA YR string_reverse
+ FOUND YR binary_string
+ IF U SAY SO
+
+ OBTW Converts a hexadecimal number to the character
+ equivalent in UNICODE. This was originally used
+ in an attempt to write out to the P6 format of PPM,
+ but the string produced by VISIBLE didn't seem to be
+ properly formatted for some reason. Instead I fell back
+ to P3 of PPM and wrote out to regular ascii format.
+ TLDR
+ HOW IZ I hex_to_char YR hex_string
+ OBTW This is a hack I found for converting hexadecimal strings
+ into their unicode character equivalents. Instead of using
+ the ":" character directly, we escape it and get it using its
+ unicode hex value (3A). This allows us to assemble the string
+ with our inserted hex value without errors.
+ TLDR
+ FOUND YR SMOOSH ":(3A)" AN "(" AN hex_string AN ")" MKAY
+ IF U SAY SO
+
+
+ OBTW Equivalent to C's square() function. However it will only
+ produce accurate results if the number is no larger than
+ 1048576. See the note below. This is based upon Newton's
+ Approximation Method as adapted in C at this website (#11):
+
+ http://www.codeproject.com/Articles/69941/Best-Square-Root-Method-Algorithm-Function-Precisi
+ TLDR
+ HOW IZ I square_rootin YR number
+ OBTW Forcing a comparison between the accuracy and a number
+ which is so big that its precision is larger than the
+ accuracy causes an infinite loop to occur. For this
+ reason we have to set any number larger than 2^20 to
+ a value below it.
+ TLDR
+ BOTH SAEM number AN BIGGR OF number AN 1048576.00, O RLY?
+ YA RLY, number R 1048575.00
+ OIC
+ I HAS A accuracy ITZ 0.0001
+ I HAS A lower ITZ A NUMBAR
+ I HAS A upper ITZ A NUMBAR
+ I HAS A guess ITZ A NUMBAR
+ DIFFRINT number AN BIGGR OF number AN 1.0, O RLY?
+ YA RLY
+ lower R number
+ upper R 1.0
+ NO WAI
+ lower R 1.0
+ upper R number
+ OIC
+ IM IN YR LOOP
+ I HAS A delta ITZ DIFF OF upper AN lower
+ BOTH SAEM delta AN SMALLR OF delta AN accuracy, O RLY?
+ YA RLY, GTFO
+ OIC
+ I HAS A guess ITZ QUOSHUNT OF SUM OF lower AN upper AN 2.0
+ I HAS A guess_squared ITZ PRODUKT OF guess AN guess
+ DIFFRINT guess_squared AN SMALLR OF guess_squared AN number, O RLY?
+ YA RLY
+ upper R guess
+ NO WAI
+ lower R guess
+ OIC
+ IM OUTTA YR LOOP
+ FOUND YR QUOSHUNT OF SUM OF lower AN upper AN 2.0
+ IF U SAY SO
+
+
+ OBTW
+ The intersection test for line [o, d]
+ Return 2 if a hit was found (and also return distance t and bouncing ray n).
+ Return 0 if no hit was found but ray goes upward
+ Return 1 if no hit was found but ray goes downward
+ TLDR
+ HOW IZ I tracin YR o AN YR d
+ I HAS A t ITZ 1000000000
+ I HAS A m ITZ 0
+ BOTH SAEM d'Z z AN 0, O RLY?
+ YA RLY, d'Z z R 0.00001
+ OIC
+ I HAS A p ITZ QUOSHUNT OF DIFF OF 0 AN o'Z z AN d'Z z
+ I HAS A n ITZ LIEK A Vector
+ DIFFRINT p AN SMALLR OF p AN 0.01, O RLY?
+ YA RLY
+ t R p
+ n R Vector IZ constructin YR 0.0 AN YR 0.0 AN YR 1.0 MKAY
+ m R 1
+ OIC
+
+ BTW The world is encoded in sphere_positions, with 9 lines and 19 columns
+ I HAS A k ITZ 18
+ IM IN YR column_loop BTW For each column of objects
+ BOTH SAEM k AN -1, O RLY?
+ YA RLY, GTFO
+ OIC
+
+ I HAS A j ITZ 8
+ IM IN YR line_loop BTW For each line on that column
+ BOTH SAEM j AN -1, O RLY?
+ YA RLY, GTFO
+ OIC
+
+ I HAS A sphere_positions_line ITZ sphere_positions'Z SRS j
+ sphere_positions_line'Z SRS k, O RLY?
+ YA RLY
+ BTW There is a sphere, but does the ray hit it?
+ p R Vector IZ addin YR o AN YR ...
+ Vector IZ constructin YR DIFF OF 0 AN k AN ...
+ YR 0 AN ...
+ YR DIFF OF DIFF OF 0 AN j AN 4 MKAY ...
+ MKAY
+ I HAS A b ITZ Vector IZ dot_productin YR p AN YR d MKAY
+ I HAS A q_c ITZ DIFF OF Vector IZ dot_productin YR p AN YR p MKAY AN 1
+ I HAS A q ITZ DIFF OF PRODUKT OF b AN b AN q_c
+
+
+ DIFFRINT q AN SMALLR OF q AN 0, O RLY?
+ YA RLY
+ BTW It does, compute the distance camera-sphere
+ I HAS A s ITZ DIFF OF DIFF OF 0 AN b AN I IZ square_rootin YR q MKAY
+
+
+ BOTH OF DIFFRINT s AN BIGGR OF s AN t AN ...
+ DIFFRINT s AN SMALLR OF s AN 0.01, O RLY?
+ YA RLY
+ BTW So far this is the minimum distance, save it. And
+ BTW also compute the bouncing ray vector into 'n'
+ t R s
+ I HAS A bouncing_ray ITZ Vector IZ scalin YR direction AN YR t MKAY
+ bouncing_ray R Vector IZ addin YR p AN YR bouncing_ray MKAY
+ n R Vector IZ normalizin YR bouncing_ray MKAY
+ m R 2
+ OIC
+ OIC
+ OIC
+ j R DIFF OF j AN 1
+ IM OUTTA YR line_loop
+ k R DIFF OF k AN 1
+ IM OUTTA YR column_loop
+ I HAS A result ITZ A BUKKIT
+ result HAS A m ITZ m
+ result HAS A t ITZ t
+ result HAS A n ITZ n
+ FOUND YR result
+ IF U SAY SO
+
+
+ OBTW
+ Sample the world and return the pixel color for
+ a ray [o, d]
+ TLDR
+ HOW IZ I samplin YR o AN YR d
+
+ BTW Search for an intersection ray Vs. world
+ I HAS A result ITZ I IZ tracin YR o AN YR d MKAY
+ I HAS A m ITZ result'Z m
+ I HAS A t ITZ result'Z t
+ I HAS A n ITZ result'Z n
+
+ BOTH SAEM m AN 0, O RLY?
+ YA RLY
+ BTW No sphere found and the ray goes upward: Generate a sky color
+ I HAS A vec_result ITZ Vector IZ constructin YR 0.7 AN YR 0.6 AN YR 1.0 MKAY
+
+ I HAS A z_component ITZ d'Z z
+ DIFFRINT z_component AN BIGGR OF z_component AN 0, O RLY?
+ YA RLY, z_component R 0
+ OIC
+ I HAS A vec_num ITZ DIFF OF 1 AN z_component
+ vec_num R I IZ power_of YR vec_num AN YR 4 MKAY
+ FOUND YR Vector IZ scalin YR vec_result AN YR vec_num MKAY
+ OIC
+
+ BTW h = intersection coordinate
+ I HAS A h ITZ Vector IZ scalin YR d AN YR t MKAY
+ h R Vector IZ addin YR o AN YR h MKAY
+ BTW l = direction to light (with random delta for soft shadows)
+ I HAS A l ITZ LIEK A Vector
+ l HAS A x ITZ SUM OF 9 AN I IZ rand_onein MKAY
+ l HAS A y ITZ SUM OF 9 AN I IZ rand_onein MKAY
+ l HAS A z ITZ 16
+ I HAS A l_two ITZ Vector IZ scalin YR h AN YR -1.0 MKAY
+ l R Vector IZ addin YR l AN YR l_two MKAY
+ l R Vector IZ normalizin YR l MKAY
+ BTW r = The half-vector
+ I HAS A r ITZ Vector IZ dot_productin YR n AN YR d MKAY
+ r R PRODUKT OF r AN -2
+ r R Vector IZ scalin YR n AN YR r MKAY
+ r R Vector IZ addin YR d AN YR r MKAY
+
+ BTW Calculate the lambertian factor
+ I HAS A b ITZ Vector IZ dot_productin YR l AN YR n MKAY
+
+ BTW Calculate illumination factor (lambertian coefficient > 0 or in shadow)?
+ I HAS A illumination_result ITZ I IZ tracin YR h AN YR l MKAY
+ I HAS A i_m ITZ illumination_result'Z m
+ EITHER OF DIFFRINT b AN BIGGR OF b AN 0 AN BOTH SAEM i_m AN 2, O RLY?
+ YA RLY, b R 0
+ OIC
+
+ BTW Calculate the color 'p' with diffuse and specular component
+ I HAS A base
+ DIFFRINT b AN SMALLR OF b AN 0, O RLY?
+ YA RLY, base R 1
+ NO WAI, base R 0
+ OIC
+ base R Vector IZ scalin YR r AN YR base MKAY
+ base R Vector IZ dot_productin YR l AN YR r MKAY
+ I HAS A p ITZ I IZ power_of YR base AN YR 99 MKAY
+
+ BOTH SAEM m AN 1, O RLY?
+ YA RLY
+ BTW No sphere was hit and the ray was going downward: Generate a floor color
+ h R Vector IZ scalin YR h AN YR 0.2 MKAY
+ I HAS A ceil_h_x ITZ I IZ ceilin YR h'Z x MKAY
+ I HAS A ceil_h_y ITZ I IZ ceilin YR h'Z y MKAY
+ I HAS A ceil_h ITZ SUM OF ceil_h_x AN ceil_h_y
+ ceil_h IS NOW A NUMBR
+ I HAS A color_choice ITZ MOD OF ceil_h AN 2
+ I HAS A color ITZ LIEK A Vector
+ color_choice, O RLY?
+ YA RLY
+ color HAS A x ITZ 3
+ color HAS A y ITZ 1
+ color HAS A z ITZ 1
+ NO WAI
+ color HAS A x ITZ 3
+ color HAS A y ITZ 3
+ color HAS A z ITZ 3
+ OIC
+ FOUND YR Vector IZ scalin YR color AN YR SUM OF PRODUKT OF b AN 0.2 AN 0.1 MKAY
+ OIC
+
+ BTW m == 2 A sphere was hit. Cast a ray bouncing from the sphere surface.
+ I HAS A sphere_color ITZ LIEK A Vector
+ sphere_color HAS A x ITZ p
+ sphere_color HAS A y ITZ p
+ sphere_color HAS A z ITZ p
+ I HAS A recursive_color ITZ I IZ samplin YR h AN YR r MKAY
+ BTW Attenuate color by 50% since it is bouncing (* .5)
+ recursive_color R Vector IZ scalin YR recursive_color AN YR 0.5 MKAY
+ FOUND YR Vector IZ addin YR sphere_color AN YR recursive_color MKAY
+ IF U SAY SO
+
+
+ OBTW The vector class provides functionality for all the common
+ linear algebra operations performed on vectors.
+ TLDR
+ O HAI IM Vector
+ I HAS A x ITZ 0
+ I HAS A y ITZ 0
+ I HAS A z ITZ 0
+
+ BTW Add vector_one and vector_two
+ HOW IZ I addin YR vector_one AN YR vector_two
+ I HAS A result ITZ LIEK A Vector
+ result HAS A x ITZ 0
+ result HAS A y ITZ 0
+ result HAS A z ITZ 0
+ result'Z x R SUM OF vector_one'Z x AN vector_two'Z x
+ result'Z y R SUM OF vector_one'Z y AN vector_two'Z y
+ result'Z z R SUM OF vector_one'Z z AN vector_two'Z z
+ FOUND YR result
+ IF U SAY SO
+
+ BTW Scale vector_one by value
+ HOW IZ I scalin YR vector_one AN YR value
+ I HAS A result ITZ LIEK A Vector
+ result HAS A x ITZ 0
+ result HAS A y ITZ 0
+ result HAS A z ITZ 0
+ result'Z x R PRODUKT OF vector_one'Z x AN value
+ result'Z y R PRODUKT OF vector_one'Z y AN value
+ result'Z z R PRODUKT OF vector_one'Z z AN value
+ FOUND YR result
+ IF U SAY SO
+
+ BTW Dot product of vector_one and vector_two
+ HOW IZ I dot_productin YR vector_one AN YR vector_two
+ FOUND YR SUM OF SUM OF PRODUKT OF vector_one'Z x AN vector_two'Z x AN ...
+ PRODUKT OF vector_one'Z y AN vector_two'Z y AN ...
+ PRODUKT OF vector_one'Z z AN vector_two'Z z
+ IF U SAY SO
+
+ BTW Cross product of vector_one and vector_two
+ HOW IZ I cross_productin YR vector_one AN YR vector_two
+ I HAS A result ITZ LIEK A Vector
+ result HAS A x ITZ 0
+ result HAS A y ITZ 0
+ result HAS A z ITZ 0
+ result'Z x R DIFF OF PRODUKT OF vector_one'Z y AN vector_two'Z z AN ...
+ PRODUKT OF vector_one'Z z AN vector_two'Z y
+ result'Z y R DIFF OF PRODUKT OF vector_one'Z z AN vector_two'Z x AN ...
+ PRODUKT OF vector_one'Z x AN vector_two'Z z
+ result'Z z R DIFF OF PRODUKT OF vector_one'Z x AN vector_two'Z y AN ...
+ PRODUKT OF vector_one'Z y AN vector_two'Z x
+ FOUND YR result
+ IF U SAY SO
+
+ BTW Length of vector_one
+ HOW IZ I lengthin YR vector_one
+ FOUND YR I IZ square_rootin YR ...
+ SUM OF SUM OF PRODUKT OF vector_one'Z x AN vector_one'Z x AN ...
+ PRODUKT OF vector_one'Z y AN vector_one'Z y AN ...
+ PRODUKT OF vector_one'Z z AN vector_one'Z z MKAY
+ IF U SAY SO
+
+ BTW Normalize vector_one
+ HOW IZ I normalizin YR vector_one
+ I HAS A result ITZ LIEK A Vector
+ result HAS A x ITZ 0
+ result HAS A y ITZ 0
+ result HAS A z ITZ 0
+ I HAS A length ITZ Vector IZ lengthin YR vector_one MKAY
+ BOTH SAEM length AN 0, O RLY?
+ YA RLY
+ length R 1
+ OIC
+ result'Z x R QUOSHUNT OF vector_one'Z x AN length
+ result'Z y R QUOSHUNT OF vector_one'Z y AN length
+ result'Z z R QUOSHUNT OF vector_one'Z z AN length
+ FOUND YR result
+ IF U SAY SO
+
+ BTW Printable YARN version of vector
+ HOW IZ I to_stringin YR vector
+ FOUND YR SMOOSH "[" AN vector'Z x AN ", " ...
+ AN vector'Z y AN ", " ...
+ AN vector'Z z AN "]" MKAY
+ IF U SAY SO
+
+ BTW Create and return a vector with components x, y, and z
+ HOW IZ I constructin YR x AN YR y AN YR z
+ I HAS A result ITZ LIEK A Vector
+ result HAS A x ITZ x
+ result HAS A y ITZ y
+ result HAS A z ITZ z
+ FOUND YR result
+ IF U SAY SO
+ KTHX
+
+ OBTW The positions of the spheres are essentially
+ stored in a 2-D array. This differs from Kensler's
+ version where he used bit flags to store the
+ positions in a compressed and quickly accessed
+ manner. Unfortunately for us, bit operations
+ in LOLCODE were too slow for this to be a tenable
+ solution.
+ TLDR
+ I HAS A sphere_positions ITZ A BUKKIT
+ I HAS A sphere_positions_0 ITZ A BUKKIT
+ IM IN YR LOOP UPPIN YR pos_index TIL BOTH SAEM pos_index AN 19
+ sphere_positions_0 HAS A SRS pos_index ITZ FAIL
+ IM OUTTA YR LOOP
+ sphere_positions HAS A SRS 0 ITZ sphere_positions_0
+ I HAS A sphere_positions_1 ITZ A BUKKIT
+ sphere_positions_1 HAS A SRS 0 ITZ WIN
+ BTW sphere_positions_1 HAS A SRS 0 ITZ FAIL
+ sphere_positions_1 HAS A SRS 1 ITZ FAIL
+ sphere_positions_1 HAS A SRS 2 ITZ WIN
+ BTW sphere_positions_1 HAS A SRS 2 ITZ FAIL
+ sphere_positions_1 HAS A SRS 3 ITZ FAIL
+ sphere_positions_1 HAS A SRS 4 ITZ WIN
+ BTW sphere_positions_1 HAS A SRS 4 ITZ FAIL
+ sphere_positions_1 HAS A SRS 5 ITZ FAIL
+ sphere_positions_1 HAS A SRS 6 ITZ FAIL
+ sphere_positions_1 HAS A SRS 7 ITZ WIN
+ BTW sphere_positions_1 HAS A SRS 7 ITZ FAIL
+ sphere_positions_1 HAS A SRS 8 ITZ FAIL
+ sphere_positions_1 HAS A SRS 9 ITZ WIN
+ BTW sphere_positions_1 HAS A SRS 9 ITZ FAIL
+ sphere_positions_1 HAS A SRS 10 ITZ FAIL
+ sphere_positions_1 HAS A SRS 11 ITZ WIN
+ BTW sphere_positions_1 HAS A SRS 11 ITZ FAIL
+ sphere_positions_1 HAS A SRS 12 ITZ FAIL
+ sphere_positions_1 HAS A SRS 13 ITZ FAIL
+ sphere_positions_1 HAS A SRS 14 ITZ WIN
+ BTWsphere_positions_1 HAS A SRS 14 ITZ FAIL
+ sphere_positions_1 HAS A SRS 15 ITZ FAIL
+ sphere_positions_1 HAS A SRS 16 ITZ WIN
+ BTW sphere_positions_1 HAS A SRS 16 ITZ FAIL
+ sphere_positions_1 HAS A SRS 17 ITZ FAIL
+ sphere_positions_1 HAS A SRS 18 ITZ WIN
+ BTW sphere_positions_1 HAS A SRS 18 ITZ FAIL
+ sphere_positions HAS A SRS 1 ITZ sphere_positions_1
+ I HAS A sphere_positions_2 ITZ A BUKKIT
+ IM IN YR LOOP UPPIN YR pos_index TIL BOTH SAEM pos_index AN 19
+ sphere_positions_2 HAS A SRS pos_index ITZ FAIL
+ IM OUTTA YR LOOP
+ sphere_positions HAS A SRS 2 ITZ sphere_positions_2
+ I HAS A sphere_positions_3 ITZ A BUKKIT
+ sphere_positions_3 HAS A SRS 0 ITZ FAIL
+ sphere_positions_3 HAS A SRS 1 ITZ FAIL
+ sphere_positions_3 HAS A SRS 2 ITZ FAIL
+ sphere_positions_3 HAS A SRS 3 ITZ FAIL
+ sphere_positions_3 HAS A SRS 4 ITZ WIN
+ BTW sphere_positions_3 HAS A SRS 4 ITZ FAIL
+ sphere_positions_3 HAS A SRS 5 ITZ FAIL
+ sphere_positions_3 HAS A SRS 6 ITZ FAIL
+ sphere_positions_3 HAS A SRS 7 ITZ WIN
+ BTW sphere_positions_3 HAS A SRS 7 ITZ FAIL
+ sphere_positions_3 HAS A SRS 8 ITZ FAIL
+ sphere_positions_3 HAS A SRS 9 ITZ FAIL
+ sphere_positions_3 HAS A SRS 10 ITZ FAIL
+ sphere_positions_3 HAS A SRS 11 ITZ WIN
+ sphere_positions_3 HAS A SRS 12 ITZ FAIL
+ sphere_positions_3 HAS A SRS 13 ITZ FAIL
+ sphere_positions_3 HAS A SRS 14 ITZ FAIL
+ sphere_positions_3 HAS A SRS 15 ITZ FAIL
+ sphere_positions_3 HAS A SRS 16 ITZ FAIL
+ sphere_positions_3 HAS A SRS 17 ITZ FAIL
+ sphere_positions_3 HAS A SRS 18 ITZ WIN
+ BTW sphere_positions_3 HAS A SRS 18 ITZ FAIL
+ sphere_positions HAS A SRS 3 ITZ sphere_positions_3
+ I HAS A sphere_positions_4 ITZ A BUKKIT
+ IM IN YR LOOP UPPIN YR pos_index TIL BOTH SAEM pos_index AN 19
+ sphere_positions_4 HAS A SRS pos_index ITZ FAIL
+ IM OUTTA YR LOOP
+ sphere_positions HAS A SRS 4 ITZ sphere_positions_4
+ I HAS A sphere_positions_5 ITZ A BUKKIT
+ sphere_positions_5 HAS A SRS 0 ITZ FAIL
+ sphere_positions_5 HAS A SRS 1 ITZ FAIL
+ sphere_positions_5 HAS A SRS 2 ITZ FAIL
+ sphere_positions_5 HAS A SRS 3 ITZ FAIL
+ sphere_positions_5 HAS A SRS 4 ITZ WIN
+ BTW sphere_positions_5 HAS A SRS 4 ITZ FAIL
+ sphere_positions_5 HAS A SRS 5 ITZ FAIL
+ sphere_positions_5 HAS A SRS 6 ITZ FAIL
+ sphere_positions_5 HAS A SRS 7 ITZ WIN
+ BTW sphere_positions_5 HAS A SRS 7 ITZ FAIL
+ sphere_positions_5 HAS A SRS 8 ITZ FAIL
+ sphere_positions_5 HAS A SRS 9 ITZ WIN
+ BTW sphere_positions_5 HAS A SRS 9 ITZ FAIL
+ sphere_positions_5 HAS A SRS 10 ITZ FAIL
+ sphere_positions_5 HAS A SRS 11 ITZ WIN
+ BTW sphere_positions_5 HAS A SRS 11 ITZ FAIL
+ sphere_positions_5 HAS A SRS 12 ITZ FAIL
+ sphere_positions_5 HAS A SRS 13 ITZ FAIL
+ sphere_positions_5 HAS A SRS 14 ITZ FAIL
+ sphere_positions_5 HAS A SRS 15 ITZ FAIL
+ sphere_positions_5 HAS A SRS 16 ITZ FAIL
+ sphere_positions_5 HAS A SRS 17 ITZ FAIL
+ sphere_positions_5 HAS A SRS 18 ITZ WIN
+ BTW sphere_positions_5 HAS A SRS 18 ITZ FAIL
+ sphere_positions HAS A SRS 5 ITZ sphere_positions_5
+ I HAS A sphere_positions_6 ITZ A BUKKIT
+ IM IN YR LOOP UPPIN YR pos_index TIL BOTH SAEM pos_index AN 19
+ sphere_positions_6 HAS A SRS pos_index ITZ FAIL
+ IM OUTTA YR LOOP
+ sphere_positions HAS A SRS 6 ITZ sphere_positions_6
+ I HAS A sphere_positions_7 ITZ A BUKKIT
+ IM IN YR LOOP UPPIN YR pos_index TIL BOTH SAEM pos_index AN 19
+ sphere_positions_7 HAS A SRS pos_index ITZ FAIL
+ IM OUTTA YR LOOP
+ sphere_positions HAS A SRS 7 ITZ sphere_positions_7
+ I HAS A sphere_positions_8 ITZ A BUKKIT
+ IM IN YR LOOP UPPIN YR pos_index TIL BOTH SAEM pos_index AN 19
+ sphere_positions_8 HAS A SRS pos_index ITZ FAIL
+ IM OUTTA YR LOOP
+ sphere_positions HAS A SRS 8 ITZ sphere_positions_8
+
+ BTW Camera direction
+ I HAS A g ITZ Vector IZ constructin YR -6.0 AN YR -16.0 AN YR 0.0 MKAY
+ g R Vector IZ normalizin YR g MKAY
+
+ BTW Camera up vector
+ I HAS A a ITZ Vector IZ constructin YR 0.0 AN YR 0.0 AN YR 1.0 MKAY
+ a R Vector IZ cross_productin YR a AN YR g MKAY
+ a R Vector IZ normalizin YR a MKAY
+ a R Vector IZ scalin YR a AN YR 0.002 MKAY
+ BTW Camera right vector
+ I HAS A b ITZ Vector IZ cross_productin YR g AN YR a MKAY
+ b R Vector IZ normalizin YR b MKAY
+ b R Vector IZ scalin YR b AN YR 0.002 MKAY
+ BTW Camera eye offset
+ I HAS A c ITZ Vector IZ addin YR a AN YR b MKAY
+ c R Vector IZ scalin YR c AN YR -256.0 MKAY
+ c R Vector IZ addin YR c AN YR g MKAY
+
+ I HAS A max_x ITZ 511
+ I HAS A max_y ITZ max_x
+ BTW Issue the PPM Header info
+ VISIBLE "P3 " SUM OF max_x AN 1 " " SUM OF max_y AN 1 " 255"!
+
+ I HAS A viewpoint ITZ Vector IZ constructin YR 17 AN YR 16 AN YR 8 MKAY
+
+ I HAS A y ITZ max_y
+ IM IN YR y_loop
+ BOTH SAEM y AN -1, O RLY?
+ YA RLY, GTFO
+ OIC
+ I HAS A x ITZ max_x
+ IM IN YR x_loop
+ BOTH SAEM x AN -1, O RLY?
+ YA RLY, GTFO
+ OIC
+ I HAS A pixel_color ITZ Vector IZ constructin YR 13 AN YR 13 AN YR 13 MKAY
+
+ I HAS A rays ITZ 64
+ IM IN YR ray_loop
+ BOTH SAEM rays AN 0, O RLY?
+ YA RLY, GTFO
+ OIC
+
+ BTW The delta to apply to the origin of the view (For Depth of View blur).
+ I HAS A a_rand ITZ DIFF OF I IZ rand_onein MKAY AN 0.5
+ I HAS A t_a ITZ Vector IZ scalin YR a AN YR a_rand MKAY
+ t_a R Vector IZ scalin YR t_a AN YR 99.0 MKAY
+ I HAS A b_rand ITZ DIFF OF I IZ rand_onein MKAY AN 0.5
+ I HAS A t_b ITZ Vector IZ scalin YR b AN YR b_rand MKAY
+ t_b R Vector IZ scalin YR t_b AN YR 99.0 MKAY
+ I HAS A t ITZ Vector IZ addin YR t_a AN YR t_b MKAY
+
+ I HAS A origin ITZ Vector IZ addin YR viewpoint AN YR t MKAY
+
+ BTW Ray direction with random deltas for stochastic sampling
+ I HAS A direction_up ITZ SUM OF I IZ rand_onein MKAY AN x
+ direction_up R Vector IZ scalin YR a AN YR direction_up MKAY
+ I HAS A direction_right ITZ SUM OF I IZ rand_onein MKAY AN y
+ direction_right R Vector IZ scalin YR b AN YR direction_right MKAY
+ I HAS A direction_t ITZ Vector IZ scalin YR t AN YR -1 MKAY
+ I HAS A direction ITZ Vector IZ addin YR direction_right AN YR direction_up MKAY
+ direction R Vector IZ addin YR direction AN YR c MKAY
+ direction R Vector IZ scalin YR direction AN YR 16 MKAY
+ direction R Vector IZ addin YR direction AN YR direction_t MKAY
+ direction R Vector IZ normalizin YR direction MKAY
+
+ I HAS A sample_color ITZ I IZ samplin YR origin AN YR direction MKAY
+ sample_color R Vector IZ scalin YR sample_color AN YR 3.5 MKAY
+ BTW + pixel_color for color accumulation
+ pixel_color R Vector IZ addin YR sample_color AN YR pixel_color MKAY
+ rays R DIFF OF rays AN 1
+ IM OUTTA YR ray_loop
+ I HAS A write_color ITZ pixel_color
+ write_color'Z x IS NOW A NUMBR
+ write_color'Z y IS NOW A NUMBR
+ write_color'Z z IS NOW A NUMBR
+ DIFFRINT write_color'Z x AN BIGGR OF write_color'Z x AN 0, O RLY?
+ YA RLY, write_color'Z x R 0
+ OIC
+ DIFFRINT write_color'Z y AN BIGGR OF write_color'Z y AN 0, O RLY?
+ YA RLY, write_color'Z y R 0
+ OIC
+ DIFFRINT write_color'Z z AN BIGGR OF write_color'Z z AN 0, O RLY?
+ YA RLY, write_color'Z z R 0
+ OIC
+ VISIBLE " " write_color'Z x " " ...
+ " " write_color'Z y " " ...
+ " " write_color'Z z " "!
+ x R DIFF OF x AN 1
+ IM OUTTA YR x_loop
+ y R DIFF OF y AN 1
+ IM OUTTA YR y_loop
+
+KTHXBYE
diff --git a/samples/Lua/wsapi.fcgi b/samples/Lua/wsapi.fcgi
new file mode 100755
index 00000000..6eeef23c
--- /dev/null
+++ b/samples/Lua/wsapi.fcgi
@@ -0,0 +1,28 @@
+#!/usr/bin/lua
+
+-- Generic WSAPI FastCGI launcher, extracts application to launch
+-- from SCRIPT_FILENAME/PATH_TRANSLATED, each application (defined
+-- by its script entry point) gets an isolated Lua VM; sequential
+-- requests to the same application go to the same VM
+
+pcall(require,"luarocks.require")
+
+local common = require "wsapi.common"
+local fastcgi = require "wsapi.fastcgi"
+
+local ONE_HOUR = 60 * 60
+local ONE_DAY = 24 * ONE_HOUR
+
+local wsapi_loader = common.make_loader{
+ isolated = true, -- isolate each script in its own Lua state
+ filename = nil, -- if you want to force the launch of a single script
+ launcher = "wsapi.fcgi", -- the name of this script
+ reload = false, -- if you want to reload the application on every request
+ period = ONE_HOUR, -- frequency of Lua state staleness checks
+ ttl = ONE_DAY, -- time-to-live for Lua states
+ vars = -- order of checking for the path of the script
+ { "SCRIPT_FILENAME",
+ "PATH_TRANSLATED" }
+}
+
+fastcgi.run(wsapi_loader)
diff --git a/samples/PHP/prefix.fcgi b/samples/PHP/prefix.fcgi
new file mode 100755
index 00000000..e3883520
--- /dev/null
+++ b/samples/PHP/prefix.fcgi
@@ -0,0 +1,3 @@
+
diff --git a/samples/Papyrus/CAMTEST_OverShoulderME.psc b/samples/Papyrus/CAMTEST_OverShoulderME.psc
new file mode 100644
index 00000000..716a9a1b
--- /dev/null
+++ b/samples/Papyrus/CAMTEST_OverShoulderME.psc
@@ -0,0 +1,68 @@
+Scriptname CAMTEST_OverShoulderME extends activemagiceffect
+{Play with camera effects}
+
+;--=== Imports ===--
+
+Import Utility
+Import Game
+
+;--=== Properties ===--
+
+Actor Property PlayerRef Auto
+ActorBase Property CAMTEST_CameraActor Auto
+
+;--=== Variables ===--
+
+Actor Player
+
+Actor Camera
+
+Actor Target
+
+Float PosX
+Float PosY
+Float PosZ
+Float SpeedMult
+
+ObjectReference Mist
+ObjectReference Fog
+
+;--=== Events ===--
+
+Event OnInit()
+ Player = PlayerRef
+EndEvent
+
+Event onEffectStart(Actor akTarget, Actor akCaster)
+ Camera = Player.PlaceActorAtMe(CAMTEST_CameraActor)
+ Camera.EnableAI(False)
+ Camera.SetScale(0.1)
+ Camera.TranslateTo(Player.X + 40,Player.Y,Player.Z,0,0,0,800,30)
+ DisablePlayerControls(abMovement = true, abFighting = true, abCamSwitch = true, abLooking = true, abSneaking = true, abMenu = true, abActivate = true, abJournalTabs = false)
+ SetPlayerAIDriven(True)
+ ForceThirdPerson()
+ SetHUDCartMode()
+ SetInChargen(True, True, False)
+ SetCameraTarget(Camera)
+ ForceFirstPerson()
+ Wait(1)
+ Camera.SplineTranslateTo(Player.X + 4000,Player.Y,Player.Z + 1000,15,0,Camera.GetHeadingAngle(Player) + Camera.GetAngleZ(),1800,800,100)
+; Camera.SetLookAt(Player)
+ Wait(10)
+ Camera.SplineTranslateTo(Player.X + 1000,Player.Y - 500,Player.Z + 500,25,0,Camera.GetHeadingAngle(Player) + Camera.GetAngleZ(),1800,800,100)
+ Wait(10)
+ SetHUDCartMode(False)
+ SetCameraTarget(Player)
+ SetInChargen(False, False, False)
+ EnablePlayerControls()
+ SetPlayerAIDriven(False)
+EndEvent
+
+Event onUpdate()
+EndEvent
+
+Event onEffectFinish(Actor akTarget, Actor akCaster)
+EndEvent
+
+;--=== Functions ===--
+
diff --git a/samples/Papyrus/vMFX_FXPlugin.psc b/samples/Papyrus/vMFX_FXPlugin.psc
new file mode 100644
index 00000000..a806a048
--- /dev/null
+++ b/samples/Papyrus/vMFX_FXPlugin.psc
@@ -0,0 +1 @@
+Scriptname vMFX_FXPlugin extends Quest
diff --git a/samples/Papyrus/vSCM_MetaQuestScript.psc b/samples/Papyrus/vSCM_MetaQuestScript.psc
new file mode 100644
index 00000000..d073a508
--- /dev/null
+++ b/samples/Papyrus/vSCM_MetaQuestScript.psc
@@ -0,0 +1,120 @@
+Scriptname vSCM_MetaQuestScript extends Quest
+{Do initialization and track variables for scripts}
+
+;--=== Imports ===--
+
+Import Utility
+Import Game
+
+;--=== Properties ===--
+
+Actor Property PlayerRef Auto
+
+Float Property ModVersion Auto Hidden
+
+String Property ModName = "Smarter Combat Music" Auto Hidden
+
+Message Property vSCM_ModLoadedMSG Auto
+Message Property vSCM_ModUpdatedMSG Auto
+
+;--=== Variables ===--
+
+Float _CurrentVersion
+String _sCurrentVersion
+
+Bool _Running
+
+Float _ScriptLatency
+Float _StartTime
+Float _EndTime
+
+;--=== Events ===--
+
+Event OnInit()
+ If ModVersion == 0
+ DoUpkeep(True)
+ EndIf
+EndEvent
+
+Event OnReset()
+ Debug.Trace("SCM: Metaquest event: OnReset")
+EndEvent
+
+Event OnGameReloaded()
+ Debug.Trace("SCM: Metaquest event: OnGameReloaded")
+EndEvent
+
+;--=== Functions ===--
+
+Function DoUpkeep(Bool DelayedStart = True)
+ ;FIXME: CHANGE THIS WHEN UPDATING!
+ _CurrentVersion = 0.01
+ _sCurrentVersion = GetVersionString(_CurrentVersion)
+ String sErrorMessage
+ If DelayedStart
+ Wait(RandomFloat(2,4))
+ EndIf
+ Debug.Trace("SCM: " + ModName)
+ Debug.Trace("SCM: Performing upkeep...")
+ Debug.Trace("SCM: Loaded version is " + GetVersionString(ModVersion) + ", Current version is " + _sCurrentVersion)
+ If ModVersion == 0
+ Debug.Trace("SCM: Newly installed, doing initialization...")
+ DoInit()
+ If ModVersion == _CurrentVersion
+ Debug.Trace("SCM: Initialization succeeded.")
+ Else
+ Debug.Trace("SCM: WARNING! Initialization had a problem!")
+ EndIf
+ ElseIf ModVersion < _CurrentVersion
+ Debug.Trace("SCM: Installed version is older. Starting the upgrade...")
+ DoUpgrade()
+ If ModVersion != _CurrentVersion
+ Debug.Trace("SCM: WARNING! Upgrade failed!")
+ Debug.MessageBox("WARNING! " + ModName + " upgrade failed for some reason. You should report this to the mod author.")
+ EndIf
+ Debug.Trace("SCM: Upgraded to " + _CurrentVersion)
+ vSCM_ModUpdatedMSG.Show(_CurrentVersion)
+ Else
+ Debug.Trace("SCM: Loaded, no updates.")
+ ;CheckForOrphans()
+ EndIf
+ CheckForExtras()
+ UpdateConfig()
+ Debug.Trace("SCM: Upkeep complete!")
+EndFunction
+
+Function DoInit()
+ Debug.Trace("SCM: Initializing...")
+ _Running = True
+ ModVersion = _CurrentVersion
+ vSCM_ModLoadedMSG.Show(_CurrentVersion)
+EndFunction
+
+Function DoUpgrade()
+ _Running = False
+ If ModVersion < 0.01
+ Debug.Trace("SCM: Upgrading to 0.01...")
+ ModVersion = 0.01
+ EndIf
+ _Running = True
+ Debug.Trace("SCM: Upgrade complete!")
+EndFunction
+
+Function UpdateConfig()
+ Debug.Trace("SCM: Updating configuration...")
+
+ Debug.Trace("SCM: Updated configuration values, some scripts may update in the background!")
+EndFunction
+
+String Function GetVersionString(Float fVersion)
+ Int Major = Math.Floor(fVersion) as Int
+ Int Minor = ((fVersion - (Major as Float)) * 100.0) as Int
+ If Minor < 10
+ Return Major + ".0" + Minor
+ Else
+ Return Major + "." + Minor
+ EndIf
+EndFunction
+
+Function CheckForExtras()
+EndFunction
diff --git a/samples/Python/backstage.fcgi b/samples/Python/backstage.fcgi
new file mode 100755
index 00000000..393ee58b
--- /dev/null
+++ b/samples/Python/backstage.fcgi
@@ -0,0 +1,120 @@
+#!/usr/bin/env python
+
+import sqlite
+import urllib2
+import csv
+import cgi
+import simplejson
+import jsontemplate
+import time
+
+log = open('log.txt', 'a')
+
+def urldecode(query):
+ d = {}
+ a = query.split('&')
+ for s in a:
+ if s.find('='):
+ k,v = map(urllib2.unquote, s.split('='))
+ try:
+ d[k].append(v)
+ except KeyError:
+ d[k] = [v]
+
+ return d
+
+def load_table(uri, cur):
+ table = uri.split('/')[-1]
+ table = table.split('.')[0]
+
+ contents = urllib2.urlopen(uri)
+ fields = ""
+ for field in contents.readline().strip().split(','):
+ fields += field
+ fields += ","
+ fields = fields.rstrip(',')
+
+ cur.execute("SELECT name FROM sqlite_master WHERE type='table' \
+ AND name='%s';" % (table))
+ if cur.fetchone() == None:
+# cur.execute("DROP TABLE %s;" % (table))
+ cur.execute("CREATE TABLE %s (%s);" % (table, fields))
+ for line in contents:
+ values = line.strip()
+ values = "','".join([val.strip() for val in values.split(",")])
+ values = "'" + values + "'"
+ sql = "INSERT INTO %s (%s) VALUES (%s);" % (table, fields, values)
+ cur.execute(sql)
+ return table
+
+def build_structure(headings, allresults):
+ results = []
+ for result in allresults:
+ results.append(dict(zip(headings, result)))
+ results = { "query" : results }
+ return results
+
+def build_json(headings, allresults, callback):
+ results = build_structure(headings, allresults)
+ return_str = simplejson.dumps(results)
+ if callback != None:
+ return_str = callback + "(" + return_str + ");";
+ return return_str
+
+def load_template(templatefile):
+ return "".join(urllib2.urlopen(templatefile).readlines())
+
+def build_template(headings, allresults, template_str):
+ results = build_structure(headings, allresults)
+ return jsontemplate.expand(template_str, results)
+ return ""
+
+def myapp(environ, start_response):
+ args = cgi.parse_qs(environ['QUERY_STRING'])
+
+ query = args['query'][0]
+ uri = args['uri'][0]
+ callback = None
+ if 'callback' in args:
+ callback = args['callback'][0]
+ label = "no label"
+ if 'label' in args:
+ label = args['label'][0]
+ templatefile = None
+ if 'templatefile' in args:
+ templatefile = args['templatefile'][0]
+
+ con = sqlite.connect('mydatabase.db')
+ cur = con.cursor()
+ table_uris = uri.split(',')
+ tables = [load_table(uri, cur) for uri in table_uris]
+ con.commit()
+ before = time.time()
+ cur.execute(query)
+ allresults = cur.fetchall()
+ after = time.time()
+ log.write("%s: query time %f\n" % (label, after - before))
+
+ headings = [name[0] for name in cur.description]
+ return_str = ""
+ if templatefile != None:
+ start_response('200 OK', [('Content-Type', 'text/html')])
+ before = time.time()
+ template_str = load_template(templatefile)
+ after = time.time()
+ log.write("%s: template loading time %f\n" % (label, after - before))
+ before = time.time()
+ return_str = build_template(headings, allresults, template_str)
+ after = time.time()
+ log.write("%s: template rendering time %f\n" % (label, after - before))
+ else:
+ start_response('200 OK', [('Content-Type', 'text/plain')])
+ before = time.time()
+ return_str = build_json(headings, allresults, callback)
+ after = time.time()
+ log.write("%s: json-making time %f\n" % (label, after - before))
+ return return_str
+
+if __name__ == '__main__':
+ from fcgi import WSGIServer
+ WSGIServer(myapp).run()
diff --git a/samples/Ruby/mdata_server.fcgi b/samples/Ruby/mdata_server.fcgi
new file mode 100755
index 00000000..c09d5047
--- /dev/null
+++ b/samples/Ruby/mdata_server.fcgi
@@ -0,0 +1,68 @@
+#!/usr/bin/env ruby
+require "xmlrpc/server"
+
+# NOTE: force the usage of the pure-ruby version of fcgi.
+# - this is required by the workaround to get fcgi+xmlrpc working together
+FCGI_PURE_RUBY=true
+require 'fcgi'
+
+require File.join(File.dirname(__FILE__), '../bt_cast/mdata_echo_server/bt_cast_mdata_server_t.rb')
+
+################################################################################
+################################################################################
+# CGI handling for xmlrpc
+################################################################################
+################################################################################
+# - for basic xmlrpc via CGI example
+# - see http://www.ntecs.de/projects/xmlrpc4r/server.html#label-19
+
+# create the directory needed for Neoip::Cast_mdata_server_t
+Neoip::Cast_mdata_server_t.create_dir_ifneeded();
+
+# init the cgi_server
+cgi_server = XMLRPC::CGIServer.new
+# register all the xmlrpc function
+cgi_server.add_handler("set_cast_mdata_pull") do |web2srv_str, cast_name, cast_privtext, cast_id,
+ port_lview, port_pview, uri_pathquery|
+ Neoip::Cast_mdata_server_t.set_cast_mdata_pull(web2srv_str, cast_name, cast_privtext, cast_id,
+ port_lview, port_pview, uri_pathquery, ENV['REMOTE_ADDR']);
+end
+cgi_server.add_handler("set_cast_mdata_push") do |web2srv_str, cast_name, cast_privtext, cast_mdata|
+ Neoip::Cast_mdata_server_t.set_cast_mdata_push(web2srv_str, cast_name, cast_privtext, cast_mdata);
+end
+cgi_server.add_handler("get_cast_mdata") do |cast_name, cast_privhash|
+ Neoip::Cast_mdata_server_t.get_cast_mdata(cast_name, cast_privhash);
+end
+cgi_server.add_handler("del_cast_mdata") do |cast_name, cast_privtext|
+ Neoip::Cast_mdata_server_t.del_cast_mdata(cast_name, cast_privtext);
+end
+
+# handle the unknown/bad formered calls
+cgi_server.set_default_handler do |name, *args|
+ raise XMLRPC::FaultException.new(-99, "Method #{name} missing" +
+ " or wrong number of parameters!")
+end
+
+# server the cgi_server
+#cgi_server.serve
+#exit
+
+# experiment at using fast-cgi
+FCGI.each_request do |request|
+ # XMLRPC::CGIServer expect some value in ENV[] but FCGI doesnt provides them
+ # - so working around by copying them by hand... dirty
+ ENV['REMOTE_ADDR'] = request.env['REMOTE_ADDR'];
+ ENV['REQUEST_METHOD'] = request.env['REQUEST_METHOD'];
+ ENV['CONTENT_TYPE'] = "text/xml";
+ ENV['CONTENT_LENGTH'] = "#{request.in.length}";
+
+ # copy the request in/out into the stdin/stdout to act as a CGI
+ $stdin = request.in
+ $stdout = request.out
+
+ # process the cgi itself
+ cgi_server.serve
+
+ # mark the request as finished
+ request.finish
+end
diff --git a/samples/Shell/build.command b/samples/Shell/build.command
new file mode 100644
index 00000000..8e793c3a
--- /dev/null
+++ b/samples/Shell/build.command
@@ -0,0 +1,30 @@
+set -e
+
+echo "/************/"
+echo "/* BUILDING */"
+echo "/************/"
+echo ""
+
+cd `dirname $0`
+
+cd build
+
+cmake ..
+
+make
+
+echo ""
+echo "/***********/"
+echo "/* TESTING */"
+echo "/***********/"
+echo ""
+
+# ctest ..
+
+make Experimental
+
+echo ""
+echo "/***********/"
+echo "/* SUCCESS */"
+echo "/***********/"
+echo ""
diff --git a/samples/Shell/php.fcgi b/samples/Shell/php.fcgi
new file mode 100755
index 00000000..cd573a30
--- /dev/null
+++ b/samples/Shell/php.fcgi
@@ -0,0 +1,16 @@
+#!/bin/sh
+# you can change the PHP version here.
+version="RB_PHP_VERSION_X_Y_Z"
+
+# php.ini file location
+PHPRC=/usr/local/php/phpfarm/inst/php-${version}/lib/php.ini
+export PHPRC
+
+PHP_FCGI_CHILDREN=3
+export PHP_FCGI_CHILDREN
+
+PHP_FCGI_MAX_REQUESTS=5000
+export PHP_FCGI_MAX_REQUESTS
+
+# which php-cgi binary to execute
+exec /usr/local/php/inst/php-${version}/bin/php-cgi
diff --git a/samples/Tcl/filenames/owh b/samples/Tcl/filenames/owh
new file mode 100755
index 00000000..9354c704
--- /dev/null
+++ b/samples/Tcl/filenames/owh
@@ -0,0 +1,63 @@
+#!/usr/bin/env tclsh
+# http://wiki.tcl.tk/906
+
+if {[llength $argv] < 1} {
+ puts "usage: owh ?init? body ?exit?
+ performs body (in Tcl) for each line (\$0) from stdin
+ owh: Ousterhout - Welch - Hobbs, to name a few"
+ exit -1
+}
+
+proc awksplit {text {split default}} {
+ set no 0
+ if {$split eq "default"} {
+ set t {}
+ foreach string [split $text] {
+ if {$string ne {}} {
+ lappend t $string
+ }
+ }
+ } else {
+ set t [list $text $split]
+ }
+ uplevel 1 [list set NF [llength $t]]
+ foreach i $t {uplevel 1 [list set [incr no] $i]}
+ uplevel 1 {set 0 {};trace variable 0 ru 0}
+}
+proc 0 {_name index op} {
+ switch $op {
+ r {
+ uplevel {
+ set 0 {}
+ for {set i 1} {$i <= $NF} {incr i} {lappend 0 [set $i]}
+ set 0 [join $0 $OFS]
+ }
+ }
+ u {rename 0 {} ;# leave no traces of the trace..}
+ }
+}
+
+proc print s {if {[catch {puts $s}]} exit} ;# good for broken pipe
+
+set FS default
+set OFS { }
+
+if {[llength $argv] > 1} {
+ eval [lindex $argv 0]
+ set _body [lindex $argv 1] ;# strip outer braces
+ set _exit [lindex $argv 2]
+} else {
+ set _body [lindex $argv 0] ;# strip outer braces
+ set _exit {}
+}
+
+set NR 1
+while 1 {
+ gets stdin line
+ if {[eof stdin]} break
+ awksplit $line $FS
+ eval $_body
+ incr NR
+}
+set res [eval $_exit]
+if {[string length $res]} {puts $res}
diff --git a/samples/Tcl/filenames/starfield b/samples/Tcl/filenames/starfield
new file mode 100755
index 00000000..674ba779
--- /dev/null
+++ b/samples/Tcl/filenames/starfield
@@ -0,0 +1,28 @@
+#!/usr/bin/env wish
+# http://wiki.tcl.tk/14140
+
+proc stars'go {c factor} {
+ set w [winfo width $c]
+ set h [winfo height $c]
+ $c scale all [expr {$w/2}] [expr {$h/2}] $factor $factor
+ foreach item [$c find all] {
+ if {[llength [$c bbox $item]] == 0} {$c delete $item; continue} ;# (1)
+ foreach {x0 y0 x1 y1} [$c bbox $item] break
+ if {$x1<0 || $x0>$w || $y1<0 || $y0>$h} {$c delete $item}
+ }
+ time {
+ set x [expr {rand()*$w}]
+ set y [expr {rand()*$h}]
+ set col [lpick {white yellow beige bisque cyan}]
+ $c create oval $x $y [expr {$x+1}] [expr {$y+1}] -fill $col \
+ -outline $col
+ } 10
+ after $::ms [info level 0]
+}
+proc lpick list {lindex $list [expr {int(rand()*[llength $list])}]}
+#-- Let's go!
+pack [canvas .c -bg black] -fill both -expand 1
+set ms 40
+bind . {incr ms -5}
+bind . {incr ms 5}
+stars'go .c 1.05
diff --git a/samples/VimL/filenames/_vimrc b/samples/VimL/filenames/_vimrc
new file mode 100644
index 00000000..2e9f626c
--- /dev/null
+++ b/samples/VimL/filenames/_vimrc
@@ -0,0 +1,8 @@
+set nocompatible
+set ignorecase
+set incsearch
+set smartcase
+set showmatch
+set showcmd
+
+syntax on
diff --git a/script/cibuild b/script/cibuild
new file mode 100755
index 00000000..f2596ea3
--- /dev/null
+++ b/script/cibuild
@@ -0,0 +1,18 @@
+#!/bin/sh
+if [ -d /usr/share/rbenv/shims ]; then
+ export PATH=/usr/share/rbenv/shims:$PATH
+ export RBENV_VERSION=2.1.2-github
+ export RUBY_VERSION=2.1.2-github
+fi
+
+set -x
+git log -n 1 HEAD | cat
+ruby -v
+bundle -v
+set +x
+
+mkdir -p ./vendor/gems
+
+bundle install --local --path ./vendor/gems
+bundle exec rake samples
+bundle exec rake
diff --git a/test/test_repository.rb b/test/test_repository.rb
index 8e10e9b6..1fba9b57 100644
--- a/test/test_repository.rb
+++ b/test/test_repository.rb
@@ -68,6 +68,19 @@ class TestRepository < Test::Unit::TestCase
assert !repo.breakdown_by_file["Ruby"].empty?
end
+ def test_commit_with_git_attributes_data
+ # Before we had any .gitattributes data
+ old_commit = '4a017d9033f91b2776eb85275463f9613cc371ef'
+ old_repo = linguist_repo(old_commit)
+
+ # With some .gitattributes data
+ attr_commit = '7ee006cbcb2d7261f9e648510a684ee9ac64126b'
+ # It's incremental but should bust the cache
+ new_repo = Linguist::Repository.incremental(rugged_repository, attr_commit, old_commit, old_repo.cache)
+
+ assert new_repo.breakdown_by_file["Java"].include?("lib/linguist.rb")
+ end
+
def test_linguist_override_vendored?
attr_commit = '351c1cc8fd57340839bdb400d7812332af80e9bd'
repo = linguist_repo(attr_commit).read_index
diff --git a/vendor/cache/charlock_holmes-0.7.3.gem b/vendor/cache/charlock_holmes-0.7.3.gem
new file mode 100644
index 00000000..f07f5cba
Binary files /dev/null and b/vendor/cache/charlock_holmes-0.7.3.gem differ
diff --git a/vendor/cache/coderay-1.1.0.gem b/vendor/cache/coderay-1.1.0.gem
new file mode 100644
index 00000000..20f29116
Binary files /dev/null and b/vendor/cache/coderay-1.1.0.gem differ
diff --git a/vendor/cache/escape_utils-1.0.1.gem b/vendor/cache/escape_utils-1.0.1.gem
new file mode 100644
index 00000000..08021101
Binary files /dev/null and b/vendor/cache/escape_utils-1.0.1.gem differ
diff --git a/vendor/cache/json-1.8.1.gem b/vendor/cache/json-1.8.1.gem
new file mode 100644
index 00000000..d903086b
Binary files /dev/null and b/vendor/cache/json-1.8.1.gem differ
diff --git a/vendor/cache/metaclass-0.0.4.gem b/vendor/cache/metaclass-0.0.4.gem
new file mode 100644
index 00000000..b32424b0
Binary files /dev/null and b/vendor/cache/metaclass-0.0.4.gem differ
diff --git a/vendor/cache/method_source-0.8.2.gem b/vendor/cache/method_source-0.8.2.gem
new file mode 100644
index 00000000..842453a3
Binary files /dev/null and b/vendor/cache/method_source-0.8.2.gem differ
diff --git a/vendor/cache/mime-types-1.25.1.gem b/vendor/cache/mime-types-1.25.1.gem
new file mode 100644
index 00000000..877d8a97
Binary files /dev/null and b/vendor/cache/mime-types-1.25.1.gem differ
diff --git a/vendor/cache/mocha-1.1.0.gem b/vendor/cache/mocha-1.1.0.gem
new file mode 100644
index 00000000..39128ca4
Binary files /dev/null and b/vendor/cache/mocha-1.1.0.gem differ
diff --git a/vendor/cache/posix-spawn-0.3.9.gem b/vendor/cache/posix-spawn-0.3.9.gem
new file mode 100644
index 00000000..ba4f19e9
Binary files /dev/null and b/vendor/cache/posix-spawn-0.3.9.gem differ
diff --git a/vendor/cache/pry-0.10.1.gem b/vendor/cache/pry-0.10.1.gem
new file mode 100644
index 00000000..25868753
Binary files /dev/null and b/vendor/cache/pry-0.10.1.gem differ
diff --git a/vendor/cache/pygments.rb-0.6.0.gem b/vendor/cache/pygments.rb-0.6.0.gem
new file mode 100644
index 00000000..7146f3d8
Binary files /dev/null and b/vendor/cache/pygments.rb-0.6.0.gem differ
diff --git a/vendor/cache/rake-10.3.2.gem b/vendor/cache/rake-10.3.2.gem
new file mode 100644
index 00000000..59f5fb63
Binary files /dev/null and b/vendor/cache/rake-10.3.2.gem differ
diff --git a/vendor/cache/rugged-0.21.1b2.gem b/vendor/cache/rugged-0.21.1b2.gem
new file mode 100644
index 00000000..1d5a7dc8
Binary files /dev/null and b/vendor/cache/rugged-0.21.1b2.gem differ
diff --git a/vendor/cache/slop-3.6.0.gem b/vendor/cache/slop-3.6.0.gem
new file mode 100644
index 00000000..153a673d
Binary files /dev/null and b/vendor/cache/slop-3.6.0.gem differ
diff --git a/vendor/cache/yajl-ruby-1.1.0.gem b/vendor/cache/yajl-ruby-1.1.0.gem
new file mode 100644
index 00000000..3fcb580e
Binary files /dev/null and b/vendor/cache/yajl-ruby-1.1.0.gem differ