mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	Merge branch 'master' into pro
This commit is contained in:
		
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +1,5 @@ | ||||
| Gemfile.lock | ||||
| .bundle/ | ||||
| vendor/ | ||||
| benchmark/ | ||||
| lib/linguist/samples.json | ||||
|   | ||||
| @@ -1,11 +1,10 @@ | ||||
| before_install: | ||||
|   - git fetch origin master:master | ||||
|   - git fetch origin v2.0.0:v2.0.0 | ||||
|   - sudo apt-get install libicu-dev -y | ||||
|   - gem update --system 2.1.11 | ||||
| rvm: | ||||
|   - 1.8.7 | ||||
|   - 1.9.2 | ||||
|   - 1.9.3 | ||||
|   - 2.0.0 | ||||
|   - ree | ||||
|   - 2.1.1 | ||||
| notifications: | ||||
|   disabled: true | ||||
|   | ||||
							
								
								
									
										5
									
								
								Gemfile
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								Gemfile
									
									
									
									
									
								
							| @@ -1,7 +1,2 @@ | ||||
| source 'https://rubygems.org' | ||||
| gemspec | ||||
|  | ||||
| if RUBY_VERSION < "1.9.3" | ||||
|   # escape_utils 1.0.0 requires 1.9.3 and above | ||||
|   gem "escape_utils", "0.3.2" | ||||
| end | ||||
|   | ||||
							
								
								
									
										42
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								README.md
									
									
									
									
									
								
							| @@ -102,12 +102,50 @@ We try to only add languages once they have some usage on GitHub, so please note | ||||
|  | ||||
| Almost all bug fixes or new language additions should come with some additional code samples. Just drop them under [`samples/`](https://github.com/github/linguist/tree/master/samples) in the correct subdirectory and our test suite will automatically test them. In most cases you shouldn't need to add any new assertions. | ||||
|  | ||||
| To update the `samples.json` after adding new files to [`samples/`](https://github.com/github/linguist/tree/master/samples): | ||||
| ### A note on language extensions | ||||
|  | ||||
|     bundle exec rake samples | ||||
| Linguist has a number of methods available to it for identifying the language of a particular file. The initial lookup is based upon the extension of the file, possible file extensions are defined in an array called `extensions`. Take a look at this example for example for `Perl`: | ||||
|  | ||||
| ``` | ||||
| Perl: | ||||
|   type: programming | ||||
|   ace_mode: perl | ||||
|   color: "#0298c3" | ||||
|   extensions: | ||||
|   - .pl | ||||
|   - .PL | ||||
|   - .perl | ||||
|   - .ph | ||||
|   - .plx | ||||
|   - .pm | ||||
|   - .pod | ||||
|   - .psgi | ||||
|   interpreters: | ||||
|   - perl | ||||
| ``` | ||||
| Any of the extensions defined are valid but the first in this array should be the most popular. | ||||
|  | ||||
| ### Testing | ||||
|  | ||||
| Sometimes getting the tests running can be too much work, especially if you don't have much Ruby experience. It's okay: be lazy and let our build bot [Travis](http://travis-ci.org/#!/github/linguist) run the tests for you. Just open a pull request and the bot will start cranking away. | ||||
|  | ||||
| Here's our current build status, which is hopefully green: [](http://travis-ci.org/github/linguist) | ||||
|  | ||||
| ### Releasing | ||||
|  | ||||
| If you are the current maintainer of this gem: | ||||
|  | ||||
|  0. Create a branch for the release: `git checkout -b cut-release-vxx.xx.xx` | ||||
|  0. Make sure your local dependencies are up to date: `bundle install` | ||||
|  0. Ensure that samples are updated: `bundle exec rake samples` | ||||
|  0. Ensure that tests are green: `bundle exec rake test` | ||||
|  0. Bump gem version in `lib/linguist/version.rb`.  For example, [like this](https://github.com/github/linguist/commit/8d2ea90a5ba3b2fe6e1508b7155aa4632eea2985). | ||||
|  0. Make a PR to github/linguist.  For example, [#1238](https://github.com/github/linguist/pull/1238). | ||||
|  0. Build a local gem: `gem build github-linguist.gemspec` | ||||
|  0. Testing: | ||||
|    0. Bump the Gemfile and Gemfile.lock versions for an app which relies on this gem | ||||
|    0. Install the new gem locally | ||||
|    0. Test behavior locally, branch deploy, whatever needs to happen | ||||
|  0. Merge github/linguist PR | ||||
|  0. Tag and push: `git tag vx.xx.xx; git push --tags` | ||||
|  0. Push to rubygems.org -- `gem push github-linguist-3.0.0.gem` | ||||
|   | ||||
							
								
								
									
										83
									
								
								Rakefile
									
									
									
									
									
								
							
							
						
						
									
										83
									
								
								Rakefile
									
									
									
									
									
								
							| @@ -2,11 +2,22 @@ require 'json' | ||||
| require 'rake/clean' | ||||
| require 'rake/testtask' | ||||
| require 'yaml' | ||||
| require 'pry' | ||||
|  | ||||
| task :default => :test | ||||
|  | ||||
| Rake::TestTask.new | ||||
|  | ||||
| # Extend test task to check for samples | ||||
| task :test => :check_samples | ||||
|  | ||||
| desc "Check that we have samples.json generated" | ||||
| task :check_samples do | ||||
|   unless File.exist?('lib/linguist/samples.json') | ||||
|     Rake::Task[:samples].invoke | ||||
|   end | ||||
| end | ||||
|  | ||||
| task :samples do | ||||
|   require 'linguist/samples' | ||||
|   require 'yajl' | ||||
| @@ -15,13 +26,74 @@ task :samples do | ||||
|   File.open('lib/linguist/samples.json', 'w') { |io| io.write json } | ||||
| end | ||||
|  | ||||
| task :build_gem do | ||||
| task :build_gem => :samples do | ||||
|   languages = YAML.load_file("lib/linguist/languages.yml") | ||||
|   File.write("lib/linguist/languages.json", JSON.dump(languages)) | ||||
|   `gem build github-linguist.gemspec` | ||||
|   File.delete("lib/linguist/languages.json") | ||||
| end | ||||
|  | ||||
| namespace :benchmark do | ||||
|   benchmark_path = "benchmark/results" | ||||
|  | ||||
|   # $ bundle exec rake benchmark:generate CORPUS=path/to/samples | ||||
|   desc "Generate results for" | ||||
|   task :generate do | ||||
|     ref = `git rev-parse HEAD`.strip[0,8] | ||||
|  | ||||
|     corpus = File.expand_path(ENV["CORPUS"] || "samples") | ||||
|  | ||||
|     require 'linguist/language' | ||||
|  | ||||
|     results = Hash.new | ||||
|     Dir.glob("#{corpus}/**/*").each do |file| | ||||
|       next unless File.file?(file) | ||||
|       filename = file.gsub("#{corpus}/", "") | ||||
|       results[filename] = Linguist::FileBlob.new(file).language | ||||
|     end | ||||
|  | ||||
|     # Ensure results directory exists | ||||
|     FileUtils.mkdir_p("benchmark/results") | ||||
|  | ||||
|     # Write results | ||||
|     if `git status`.include?('working directory clean') | ||||
|       result_filename = "benchmark/results/#{File.basename(corpus)}-#{ref}.json" | ||||
|     else | ||||
|       result_filename = "benchmark/results/#{File.basename(corpus)}-#{ref}-unstaged.json" | ||||
|     end | ||||
|  | ||||
|     File.write(result_filename, results.to_json) | ||||
|     puts "wrote #{result_filename}" | ||||
|   end | ||||
|  | ||||
|   # $ bundle exec rake benchmark:compare REFERENCE=path/to/reference.json CANDIDATE=path/to/candidate.json | ||||
|   desc "Compare results" | ||||
|   task :compare do | ||||
|     reference_file = ENV["REFERENCE"] | ||||
|     candidate_file = ENV["CANDIDATE"] | ||||
|  | ||||
|     reference = JSON.parse(File.read(reference_file)) | ||||
|     reference_counts = Hash.new(0) | ||||
|     reference.each { |filename, language| reference_counts[language] += 1 } | ||||
|  | ||||
|     candidate = JSON.parse(File.read(candidate_file)) | ||||
|     candidate_counts = Hash.new(0) | ||||
|     candidate.each { |filename, language| candidate_counts[language] += 1 } | ||||
|  | ||||
|     changes = diff(reference_counts, candidate_counts) | ||||
|  | ||||
|     if changes.any? | ||||
|       changes.each do |language, (before, after)| | ||||
|         before_percent = 100 * before / reference.size.to_f | ||||
|         after_percent = 100 * after / candidate.size.to_f | ||||
|         puts "%s changed from %.1f%% to %.1f%%" % [language || 'unknown', before_percent, after_percent] | ||||
|       end | ||||
|     else | ||||
|       puts "No changes" | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| namespace :classifier do | ||||
|   LIMIT = 1_000 | ||||
|  | ||||
| @@ -37,7 +109,7 @@ namespace :classifier do | ||||
|       next if file_language.nil? || file_language == 'Text' | ||||
|       begin | ||||
|         data = open(file_url).read | ||||
|         guessed_language, score = Linguist::Classifier.classify(Linguist::Samples::DATA, data).first | ||||
|         guessed_language, score = Linguist::Classifier.classify(Linguist::Samples.cache, data).first | ||||
|  | ||||
|         total += 1 | ||||
|         guessed_language == file_language ? correct += 1 : incorrect += 1 | ||||
| @@ -71,3 +143,10 @@ namespace :classifier do | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
|  | ||||
| def diff(a, b) | ||||
|   (a.keys | b.keys).each_with_object({}) do |key, diff| | ||||
|     diff[key] = [a[key], b[key]] unless a[key] == b[key] | ||||
|   end | ||||
| end | ||||
|   | ||||
| @@ -4,7 +4,9 @@ | ||||
| #     usage: linguist <path> [<--breakdown>] | ||||
|  | ||||
| require 'linguist/file_blob' | ||||
| require 'linguist/language' | ||||
| require 'linguist/repository' | ||||
| require 'rugged' | ||||
|  | ||||
| path = ARGV[0] || Dir.pwd | ||||
|  | ||||
| @@ -18,7 +20,8 @@ ARGV.shift | ||||
| breakdown = true if ARGV[0] == "--breakdown" | ||||
|  | ||||
| if File.directory?(path) | ||||
|   repo = Linguist::Repository.from_directory(path) | ||||
|   rugged = Rugged::Repository.new(path) | ||||
|   repo = Linguist::Repository.new(rugged, rugged.head.target_id) | ||||
|   repo.languages.sort_by { |_, size| size }.reverse.each do |language, size| | ||||
|     percentage = ((size / repo.size.to_f) * 100) | ||||
|     percentage = sprintf '%.2f' % percentage | ||||
|   | ||||
| @@ -1,6 +1,8 @@ | ||||
| require File.expand_path('../lib/linguist/version', __FILE__) | ||||
|  | ||||
| Gem::Specification.new do |s| | ||||
|   s.name    = 'github-linguist' | ||||
|   s.version = '2.10.11' | ||||
|   s.version = Linguist::VERSION | ||||
|   s.summary = "GitHub Language detection" | ||||
|   s.description = 'We use this library at GitHub to detect blob languages, highlight code, ignore binary files, suppress generated files in diffs, and generate language breakdown graphs.' | ||||
|  | ||||
| @@ -11,13 +13,15 @@ Gem::Specification.new do |s| | ||||
|   s.files = Dir['lib/**/*'] | ||||
|   s.executables << 'linguist' | ||||
|  | ||||
|   s.add_dependency 'charlock_holmes', '~> 0.6.6' | ||||
|   s.add_dependency 'escape_utils',    '>= 0.3.1' | ||||
|   s.add_dependency 'charlock_holmes', '~> 0.7.3' | ||||
|   s.add_dependency 'escape_utils',    '~> 1.0.1' | ||||
|   s.add_dependency 'mime-types',      '~> 1.19' | ||||
|   s.add_dependency 'pygments.rb',     '~> 0.5.4' | ||||
|   s.add_dependency 'pygments.rb',     '~> 0.6.0' | ||||
|   s.add_dependency 'rugged',          '~> 0.21.0' | ||||
|  | ||||
|   s.add_development_dependency 'json' | ||||
|   s.add_development_dependency 'mocha' | ||||
|   s.add_development_dependency 'pry' | ||||
|   s.add_development_dependency 'rake' | ||||
|   s.add_development_dependency 'yajl-ruby' | ||||
| end | ||||
|   | ||||
| @@ -4,3 +4,4 @@ require 'linguist/heuristics' | ||||
| require 'linguist/language' | ||||
| require 'linguist/repository' | ||||
| require 'linguist/samples' | ||||
| require 'linguist/version' | ||||
|   | ||||
| @@ -1,6 +1,4 @@ | ||||
| require 'linguist/generated' | ||||
| require 'linguist/language' | ||||
|  | ||||
| require 'charlock_holmes' | ||||
| require 'escape_utils' | ||||
| require 'mime/types' | ||||
| @@ -112,6 +110,12 @@ module Linguist | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     def ruby_encoding | ||||
|       if hash = detect_encoding | ||||
|         hash[:ruby_encoding] | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     # Try to guess the encoding | ||||
|     # | ||||
|     # Returns: a Hash, with :encoding, :confidence, :type | ||||
| @@ -241,7 +245,31 @@ module Linguist | ||||
|     def lines | ||||
|       @lines ||= | ||||
|         if viewable? && data | ||||
|           data.split(/\r\n|\r|\n/, -1) | ||||
|           # `data` is usually encoded as ASCII-8BIT even when the content has | ||||
|           # been detected as a different encoding. However, we are not allowed | ||||
|           # to change the encoding of `data` because we've made the implicit | ||||
|           # guarantee that each entry in `lines` is encoded the same way as | ||||
|           # `data`. | ||||
|           # | ||||
|           # Instead, we re-encode each possible newline sequence as the | ||||
|           # detected encoding, then force them back to the encoding of `data` | ||||
|           # (usually a binary encoding like ASCII-8BIT). This means that the | ||||
|           # byte sequence will match how newlines are likely encoded in the | ||||
|           # file, but we don't have to change the encoding of `data` as far as | ||||
|           # Ruby is concerned. This allows us to correctly parse out each line | ||||
|           # without changing the encoding of `data`, and | ||||
|           # also--importantly--without having to duplicate many (potentially | ||||
|           # large) strings. | ||||
|           begin | ||||
|             encoded_newlines = ["\r\n", "\r", "\n"]. | ||||
|               map { |nl| nl.encode(ruby_encoding, "ASCII-8BIT").force_encoding(data.encoding) } | ||||
|  | ||||
|             data.split(Regexp.union(encoded_newlines), -1) | ||||
|           rescue Encoding::ConverterNotFoundError | ||||
|             # The data is not splittable in the detected encoding.  Assume it's | ||||
|             # one big line. | ||||
|             [data] | ||||
|           end | ||||
|         else | ||||
|           [] | ||||
|         end | ||||
| @@ -283,15 +311,7 @@ module Linguist | ||||
|     # | ||||
|     # Returns a Language or nil if none is detected | ||||
|     def language | ||||
|       return @language if defined? @language | ||||
|  | ||||
|       if defined?(@data) && @data.is_a?(String) | ||||
|         data = @data | ||||
|       else | ||||
|         data = lambda { (binary_mime_type? || binary?) ? "" : self.data } | ||||
|       end | ||||
|  | ||||
|       @language = Language.detect(name.to_s, data, mode) | ||||
|       @language ||= Language.detect(self) | ||||
|     end | ||||
|  | ||||
|     # Internal: Get the lexer of the blob. | ||||
|   | ||||
| @@ -52,5 +52,20 @@ module Linguist | ||||
|     def size | ||||
|       File.size(@path) | ||||
|     end | ||||
|  | ||||
|     # Public: Get file extension. | ||||
|     # | ||||
|     # Returns a String. | ||||
|     def extension | ||||
|       # File.extname returns nil if the filename is an extension. | ||||
|       extension = File.extname(name) | ||||
|       basename = File.basename(name) | ||||
|       # Checks if the filename is an extension. | ||||
|       if extension.empty? && basename[0] == "." | ||||
|         basename | ||||
|       else | ||||
|         extension | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|   | ||||
| @@ -54,7 +54,7 @@ module Linguist | ||||
|       name == 'Gemfile.lock' || | ||||
|         minified_files? || | ||||
|         compiled_coffeescript? || | ||||
|         xcode_project_file? || | ||||
|         xcode_file? || | ||||
|         generated_parser? || | ||||
|         generated_net_docfile? || | ||||
|         generated_net_designer_file? || | ||||
| @@ -62,17 +62,20 @@ module Linguist | ||||
|         generated_protocol_buffer? || | ||||
|         generated_jni_header? || | ||||
|         composer_lock? || | ||||
|         node_modules? | ||||
|         node_modules? || | ||||
|         godeps? || | ||||
|         vcr_cassette? || | ||||
|         generated_by_zephir? | ||||
|     end | ||||
|  | ||||
|     # Internal: Is the blob an XCode project file? | ||||
|     # Internal: Is the blob an Xcode file? | ||||
|     # | ||||
|     # Generated if the file extension is an XCode project | ||||
|     # Generated if the file extension is an Xcode  | ||||
|     # file extension. | ||||
|     # | ||||
|     # Returns true of false. | ||||
|     def xcode_project_file? | ||||
|       ['.xib', '.nib', '.storyboard', '.pbxproj', '.xcworkspacedata', '.xcuserstate'].include?(extname) | ||||
|     def xcode_file? | ||||
|       ['.nib', '.xcworkspacedata', '.xcuserstate'].include?(extname) | ||||
|     end | ||||
|  | ||||
|     # Internal: Is the blob minified files? | ||||
| @@ -229,11 +232,37 @@ module Linguist | ||||
|       !!name.match(/node_modules\//) | ||||
|     end | ||||
|  | ||||
|     # Internal: Is the blob part of Godeps/, | ||||
|     # which are not meant for humans in pull requests. | ||||
|     # | ||||
|     # Returns true or false. | ||||
|     def godeps? | ||||
|       !!name.match(/Godeps\//) | ||||
|     end | ||||
|  | ||||
|     # Internal: Is the blob a generated php composer lock file? | ||||
|     # | ||||
|     # Returns true or false. | ||||
|     def composer_lock? | ||||
|       !!name.match(/composer.lock/) | ||||
|       !!name.match(/composer\.lock/) | ||||
|     end | ||||
|  | ||||
|     # Internal: Is the blob a generated by Zephir | ||||
|     # | ||||
|     # Returns true or false. | ||||
|     def generated_by_zephir? | ||||
|       !!name.match(/.\.zep\.(?:c|h|php)$/) | ||||
|     end | ||||
|  | ||||
|     # Is the blob a VCR Cassette file? | ||||
|     # | ||||
|     # Returns true or false | ||||
|     def vcr_cassette? | ||||
|       return false unless extname == '.yml' | ||||
|       return false unless lines.count > 2 | ||||
|       # VCR Cassettes have "recorded_with: VCR" in the second last line. | ||||
|       return lines[-2].include?("recorded_with: VCR") | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| module Linguist | ||||
|   # A collection of simple heuristics that can be used to better analyze languages. | ||||
|   class Heuristics | ||||
|     ACTIVE = false | ||||
|     ACTIVE = true | ||||
|  | ||||
|     # Public: Given an array of String language names, | ||||
|     # apply heuristics against the given data and return an array | ||||
| @@ -13,28 +13,23 @@ module Linguist | ||||
|     # Returns an array of Languages or [] | ||||
|     def self.find_by_heuristics(data, languages) | ||||
|       if active? | ||||
|         if languages.all? { |l| ["Objective-C", "C++"].include?(l) } | ||||
|           disambiguate_c(data, languages) | ||||
|         end | ||||
|         if languages.all? { |l| ["Perl", "Prolog"].include?(l) } | ||||
|           disambiguate_pl(data, languages) | ||||
|           result = disambiguate_pl(data, languages) | ||||
|         end | ||||
|         if languages.all? { |l| ["ECL", "Prolog"].include?(l) } | ||||
|           disambiguate_ecl(data, languages) | ||||
|           result = disambiguate_ecl(data, languages) | ||||
|         end | ||||
|         if languages.all? { |l| ["IDL", "Prolog"].include?(l) } | ||||
|           disambiguate_pro(data, languages) | ||||
|         end | ||||
|         if languages.all? { |l| ["TypeScript", "XML"].include?(l) } | ||||
|           disambiguate_ts(data, languages) | ||||
|           result = disambiguate_pro(data, languages) | ||||
|         end | ||||
|         if languages.all? { |l| ["Common Lisp", "OpenCL"].include?(l) } | ||||
|           disambiguate_cl(data, languages) | ||||
|           result = disambiguate_cl(data, languages) | ||||
|         end | ||||
|         return result | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     # .h extensions are ambigious between C, C++, and Objective-C. | ||||
|     # .h extensions are ambiguous between C, C++, and Objective-C. | ||||
|     # We want to shortcut look for Objective-C _and_ now C++ too! | ||||
|     # | ||||
|     # Returns an array of Languages or [] | ||||
| @@ -86,6 +81,13 @@ module Linguist | ||||
|       matches | ||||
|     end | ||||
|  | ||||
|     def self.disambiguate_r(data, languages) | ||||
|       matches = [] | ||||
|       matches << Language["Rebol"] if /\bRebol\b/i.match(data) | ||||
|       matches << Language["R"] if data.include?("<-") | ||||
|       matches | ||||
|     end | ||||
|  | ||||
|     def self.active? | ||||
|       !!ACTIVE | ||||
|     end | ||||
|   | ||||
| @@ -9,6 +9,8 @@ end | ||||
| require 'linguist/classifier' | ||||
| require 'linguist/heuristics' | ||||
| require 'linguist/samples' | ||||
| require 'linguist/file_blob' | ||||
| require 'linguist/blob_helper' | ||||
|  | ||||
| module Linguist | ||||
|   # Language names that are recognizable by GitHub. Defined languages | ||||
| @@ -24,7 +26,6 @@ module Linguist | ||||
|     @extension_index          = Hash.new { |h,k| h[k] = [] } | ||||
|     @interpreter_index        = Hash.new { |h,k| h[k] = [] } | ||||
|     @filename_index           = Hash.new { |h,k| h[k] = [] } | ||||
|     @primary_extension_index  = {} | ||||
|  | ||||
|     # Valid Languages types | ||||
|     TYPES = [:data, :markup, :programming, :prose] | ||||
| @@ -80,12 +81,6 @@ module Linguist | ||||
|         @extension_index[extension] << language | ||||
|       end | ||||
|  | ||||
|       if @primary_extension_index.key?(language.primary_extension) | ||||
|         raise ArgumentError, "Duplicate primary extension: #{language.primary_extension}" | ||||
|       end | ||||
|  | ||||
|       @primary_extension_index[language.primary_extension] = language | ||||
|  | ||||
|       language.interpreters.each do |interpreter| | ||||
|         @interpreter_index[interpreter] << language | ||||
|       end | ||||
| @@ -99,18 +94,25 @@ module Linguist | ||||
|  | ||||
|     # Public: Detects the Language of the blob. | ||||
|     # | ||||
|     # name - String filename | ||||
|     # data - String blob data. A block also maybe passed in for lazy | ||||
|     #        loading. This behavior is deprecated and you should always | ||||
|     #        pass in a String. | ||||
|     # mode - Optional String mode (defaults to nil) | ||||
|     # blob - an object that includes the Linguist `BlobHelper` interface; | ||||
|     #       see Linguist::LazyBlob and Linguist::FileBlob for examples | ||||
|     # | ||||
|     # Returns Language or nil. | ||||
|     def self.detect(name, data, mode = nil) | ||||
|     def self.detect(blob) | ||||
|       name = blob.name.to_s | ||||
|  | ||||
|       # Check if the blob is possibly binary and bail early; this is a cheap | ||||
|       # test that uses the extension name to guess a binary binary mime type. | ||||
|       # | ||||
|       # We'll perform a more comprehensive test later which actually involves | ||||
|       # looking for binary characters in the blob | ||||
|       return nil if blob.likely_binary? || blob.binary? | ||||
|  | ||||
|       # A bit of an elegant hack. If the file is executable but extensionless, | ||||
|       # append a "magic" extension so it can be classified with other | ||||
|       # languages that have shebang scripts. | ||||
|       if File.extname(name).empty? && mode && (mode.to_i(8) & 05) == 05 | ||||
|       extension = FileBlob.new(name).extension | ||||
|       if extension.empty? && blob.mode && (blob.mode.to_i(8) & 05) == 05 | ||||
|         name += ".script!" | ||||
|       end | ||||
|  | ||||
| @@ -121,10 +123,10 @@ module Linguist | ||||
|       # extension at all, in the case of extensionless scripts), we need to continue | ||||
|       # our detection work | ||||
|       if possible_languages.length > 1 | ||||
|         data = data.call() if data.respond_to?(:call) | ||||
|         data = blob.data | ||||
|         possible_language_names = possible_languages.map(&:name) | ||||
|  | ||||
|         # Don't bother with emptiness | ||||
|         # Don't bother with binary contents or an empty file | ||||
|         if data.nil? || data == "" | ||||
|           nil | ||||
|         # Check if there's a shebang line and use that as authoritative | ||||
| @@ -133,8 +135,8 @@ module Linguist | ||||
|         # No shebang. Still more work to do. Try to find it with our heuristics. | ||||
|         elsif (determined = Heuristics.find_by_heuristics(data, possible_language_names)) && !determined.empty? | ||||
|           determined.first | ||||
|         # Lastly, fall back to the probablistic classifier. | ||||
|         elsif classified = Classifier.classify(Samples::DATA, data, possible_language_names ).first | ||||
|         # Lastly, fall back to the probabilistic classifier. | ||||
|         elsif classified = Classifier.classify(Samples.cache, data, possible_language_names).first | ||||
|           # Return the actual Language object based of the string language name (i.e., first element of `#classify`) | ||||
|           Language[classified[0]] | ||||
|         end | ||||
| @@ -190,9 +192,9 @@ module Linguist | ||||
|     # | ||||
|     # Returns all matching Languages or [] if none were found. | ||||
|     def self.find_by_filename(filename) | ||||
|       basename, extname = File.basename(filename), File.extname(filename) | ||||
|       langs = [@primary_extension_index[extname]] + | ||||
|               @filename_index[basename] + | ||||
|       basename = File.basename(filename) | ||||
|       extname = FileBlob.new(filename).extension | ||||
|       langs = @filename_index[basename] + | ||||
|               @extension_index[extname] | ||||
|       langs.compact.uniq | ||||
|     end | ||||
| @@ -299,15 +301,6 @@ module Linguist | ||||
|       @interpreters = attributes[:interpreters]   || [] | ||||
|       @filenames  = attributes[:filenames]  || [] | ||||
|  | ||||
|       unless @primary_extension = attributes[:primary_extension] | ||||
|         raise ArgumentError, "#{@name} is missing primary extension" | ||||
|       end | ||||
|  | ||||
|       # Prepend primary extension unless its already included | ||||
|       if primary_extension && !extensions.include?(primary_extension) | ||||
|         @extensions = [primary_extension] + extensions | ||||
|       end | ||||
|  | ||||
|       # Set popular, and searchable flags | ||||
|       @popular    = attributes.key?(:popular)    ? attributes[:popular]    : false | ||||
|       @searchable = attributes.key?(:searchable) ? attributes[:searchable] : true | ||||
| @@ -395,20 +388,6 @@ module Linguist | ||||
|     # Returns the extensions Array | ||||
|     attr_reader :extensions | ||||
|  | ||||
|     # Deprecated: Get primary extension | ||||
|     # | ||||
|     # Defaults to the first extension but can be overridden | ||||
|     # in the languages.yml. | ||||
|     # | ||||
|     # The primary extension can not be nil. Tests should verify this. | ||||
|     # | ||||
|     # This attribute is only used by app/helpers/gists_helper.rb for | ||||
|     # creating the language dropdown. It really should be using `name` | ||||
|     # instead. Would like to drop primary extension. | ||||
|     # | ||||
|     # Returns the extension String. | ||||
|     attr_reader :primary_extension | ||||
|  | ||||
|     # Public: Get interpreters | ||||
|     # | ||||
|     # Examples | ||||
| @@ -427,6 +406,27 @@ module Linguist | ||||
|     # Returns the extensions Array | ||||
|     attr_reader :filenames | ||||
|  | ||||
|     # Public: Return all possible extensions for language | ||||
|     def all_extensions | ||||
|       (extensions + [primary_extension]).uniq | ||||
|     end | ||||
|  | ||||
|     # Deprecated: Get primary extension | ||||
|     # | ||||
|     # Defaults to the first extension but can be overridden | ||||
|     # in the languages.yml. | ||||
|     # | ||||
|     # The primary extension can not be nil. Tests should verify this. | ||||
|     # | ||||
|     # This method is only used by app/helpers/gists_helper.rb for creating | ||||
|     # the language dropdown. It really should be using `name` instead. | ||||
|     # Would like to drop primary extension. | ||||
|     # | ||||
|     # Returns the extension String. | ||||
|     def primary_extension | ||||
|       extensions.first | ||||
|     end | ||||
|  | ||||
|     # Public: Get URL escaped name. | ||||
|     # | ||||
|     # Examples | ||||
| @@ -485,7 +485,7 @@ module Linguist | ||||
|     # | ||||
|     # Returns html String | ||||
|     def colorize(text, options = {}) | ||||
|       lexer.highlight(text, options = {}) | ||||
|       lexer.highlight(text, options) | ||||
|     end | ||||
|  | ||||
|     # Public: Return name as String representation | ||||
| @@ -510,9 +510,9 @@ module Linguist | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   extensions = Samples::DATA['extnames'] | ||||
|   interpreters = Samples::DATA['interpreters'] | ||||
|   filenames = Samples::DATA['filenames'] | ||||
|   extensions = Samples.cache['extnames'] | ||||
|   interpreters = Samples.cache['interpreters'] | ||||
|   filenames = Samples.cache['filenames'] | ||||
|   popular = YAML.load_file(File.expand_path("../popular.yml", __FILE__)) | ||||
|  | ||||
|   languages_yml = File.expand_path("../languages.yml", __FILE__) | ||||
| @@ -532,6 +532,7 @@ module Linguist | ||||
|     if extnames = extensions[name] | ||||
|       extnames.each do |extname| | ||||
|         if !options['extensions'].include?(extname) | ||||
|           warn "#{name} has a sample with extension (#{extname}) that isn't explicitly defined in languages.yml" unless extname == '.script!' | ||||
|           options['extensions'] << extname | ||||
|         end | ||||
|       end | ||||
| @@ -568,9 +569,8 @@ module Linguist | ||||
|       :group_name        => options['group'], | ||||
|       :searchable        => options.key?('searchable') ? options['searchable'] : true, | ||||
|       :search_term       => options['search_term'], | ||||
|       :extensions        => options['extensions'].sort, | ||||
|       :extensions        => [options['extensions'].first] + options['extensions'][1..-1].sort, | ||||
|       :interpreters      => options['interpreters'].sort, | ||||
|       :primary_extension => options['primary_extension'], | ||||
|       :filenames         => options['filenames'], | ||||
|       :popular           => popular.include?(name) | ||||
|     ) | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										37
									
								
								lib/linguist/lazy_blob.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								lib/linguist/lazy_blob.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| require 'linguist/blob_helper' | ||||
| require 'rugged' | ||||
|  | ||||
| module Linguist | ||||
|   class LazyBlob | ||||
|     include BlobHelper | ||||
|  | ||||
|     MAX_SIZE = 128 * 1024 | ||||
|  | ||||
|     attr_reader :repository | ||||
|     attr_reader :oid | ||||
|     attr_reader :name | ||||
|     attr_reader :mode | ||||
|  | ||||
|     def initialize(repo, oid, name, mode = nil) | ||||
|       @repository = repo | ||||
|       @oid = oid | ||||
|       @name = name | ||||
|       @mode = mode | ||||
|     end | ||||
|  | ||||
|     def data | ||||
|       load_blob! | ||||
|       @data | ||||
|     end | ||||
|  | ||||
|     def size | ||||
|       load_blob! | ||||
|       @size | ||||
|     end | ||||
|  | ||||
|     protected | ||||
|     def load_blob! | ||||
|       @data, @size = Rugged::Blob.to_buffer(repository, oid, MAX_SIZE) if @data.nil? | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -1,4 +1,5 @@ | ||||
| require 'linguist/file_blob' | ||||
| require 'linguist/lazy_blob' | ||||
| require 'rugged' | ||||
|  | ||||
| module Linguist | ||||
|   # A Repository is an abstraction of a Grit::Repo or a basic file | ||||
| @@ -7,100 +8,146 @@ module Linguist | ||||
|   # Its primary purpose is for gathering language statistics across | ||||
|   # the entire project. | ||||
|   class Repository | ||||
|     # Public: Initialize a new Repository from a File directory | ||||
|     # | ||||
|     # base_path - A path String | ||||
|     # | ||||
|     # Returns a Repository | ||||
|     def self.from_directory(base_path) | ||||
|       new Dir["#{base_path}/**/*"]. | ||||
|         select { |f| File.file?(f) }. | ||||
|         map { |path| FileBlob.new(path, base_path) } | ||||
|     attr_reader :repository | ||||
|  | ||||
|     # Public: Create a new Repository based on the stats of | ||||
|     # an existing one | ||||
|     def self.incremental(repo, commit_oid, old_commit_oid, old_stats) | ||||
|       repo = self.new(repo, commit_oid) | ||||
|       repo.load_existing_stats(old_commit_oid, old_stats) | ||||
|       repo | ||||
|     end | ||||
|  | ||||
|     # Public: Initialize a new Repository | ||||
|     # Public: Initialize a new Repository to be analyzed for language | ||||
|     # data | ||||
|     # | ||||
|     # enum - Enumerator that responds to `each` and | ||||
|     #        yields Blob objects | ||||
|     # repo - a Rugged::Repository object | ||||
|     # commit_oid - the sha1 of the commit that will be analyzed; | ||||
|     #              this is usually the master branch | ||||
|     # | ||||
|     # Returns a Repository | ||||
|     def initialize(enum) | ||||
|       @enum = enum | ||||
|       @computed_stats = false | ||||
|       @language = @size = nil | ||||
|       @sizes = Hash.new { 0 } | ||||
|       @file_breakdown = Hash.new { |h,k| h[k] = Array.new } | ||||
|     def initialize(repo, commit_oid) | ||||
|       @repository = repo | ||||
|       @commit_oid = commit_oid | ||||
|  | ||||
|       raise TypeError, 'commit_oid must be a commit SHA1' unless commit_oid.is_a?(String) | ||||
|     end | ||||
|  | ||||
|     # Public: Load the results of a previous analysis on this repository | ||||
|     # to speed up the new scan. | ||||
|     # | ||||
|     # The new analysis will be performed incrementally as to only take | ||||
|     # into account the file changes since the last time the repository | ||||
|     # was scanned | ||||
|     # | ||||
|     # old_commit_oid - the sha1 of the commit that was previously analyzed | ||||
|     # old_stats - the result of the previous analysis, obtained by calling | ||||
|     #             Repository#cache on the old repository | ||||
|     # | ||||
|     # Returns nothing | ||||
|     def load_existing_stats(old_commit_oid, old_stats) | ||||
|       @old_commit_oid = old_commit_oid | ||||
|       @old_stats = old_stats | ||||
|       nil | ||||
|     end | ||||
|  | ||||
|     # Public: Returns a breakdown of language stats. | ||||
|     # | ||||
|     # Examples | ||||
|     # | ||||
|     #   # => { Language['Ruby'] => 46319, | ||||
|     #          Language['JavaScript'] => 258 } | ||||
|     #   # => { 'Ruby' => 46319, | ||||
|     #          'JavaScript' => 258 } | ||||
|     # | ||||
|     # Returns a Hash of Language keys and Integer size values. | ||||
|     # Returns a Hash of language names and Integer size values. | ||||
|     def languages | ||||
|       compute_stats | ||||
|       @sizes | ||||
|       @sizes ||= begin | ||||
|         sizes = Hash.new { 0 } | ||||
|         cache.each do |_, (language, size)| | ||||
|           sizes[language] += size | ||||
|         end | ||||
|         sizes | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     # Public: Get primary Language of repository. | ||||
|     # | ||||
|     # Returns a Language | ||||
|     # Returns a language name | ||||
|     def language | ||||
|       compute_stats | ||||
|       @language | ||||
|       @language ||= begin | ||||
|         primary = languages.max_by { |(_, size)| size } | ||||
|         primary && primary[0] | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     # Public: Get the total size of the repository. | ||||
|     # | ||||
|     # Returns a byte size Integer | ||||
|     def size | ||||
|       compute_stats | ||||
|       @size | ||||
|       @size ||= languages.inject(0) { |s,(_,v)| s + v } | ||||
|     end | ||||
|  | ||||
|     # Public: Return the language breakdown of this repository by file | ||||
|     # | ||||
|     # Returns a map of language names => [filenames...] | ||||
|     def breakdown_by_file | ||||
|       compute_stats | ||||
|       @file_breakdown | ||||
|       @file_breakdown ||= begin | ||||
|         breakdown = Hash.new { |h,k| h[k] = Array.new } | ||||
|         cache.each do |filename, (language, _)| | ||||
|           breakdown[language] << filename | ||||
|         end | ||||
|         breakdown | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     # Internal: Compute language breakdown for each blob in the Repository. | ||||
|     # Public: Return the cached results of the analysis | ||||
|     # | ||||
|     # Returns nothing | ||||
|     def compute_stats | ||||
|       return if @computed_stats | ||||
|     # This is a per-file breakdown that can be passed to other instances | ||||
|     # of Linguist::Repository to perform incremental scans | ||||
|     # | ||||
|     # Returns a map of filename => [language, size] | ||||
|     def cache | ||||
|       @cache ||= begin | ||||
|         if @old_commit_oid == @commit_oid | ||||
|           @old_stats | ||||
|         else | ||||
|           compute_stats(@old_commit_oid, @commit_oid, @old_stats) | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|  | ||||
|       @enum.each do |blob| | ||||
|         # Skip files that are likely binary | ||||
|         next if blob.likely_binary? | ||||
|     protected | ||||
|     def compute_stats(old_commit_oid, commit_oid, cache = nil) | ||||
|       file_map = cache ? cache.dup : {} | ||||
|       old_tree = old_commit_oid && Rugged::Commit.lookup(repository, old_commit_oid).tree | ||||
|       new_tree = Rugged::Commit.lookup(repository, commit_oid).tree | ||||
|  | ||||
|       diff = Rugged::Tree.diff(repository, old_tree, new_tree) | ||||
|  | ||||
|       diff.each_delta do |delta| | ||||
|         old = delta.old_file[:path] | ||||
|         new = delta.new_file[:path] | ||||
|  | ||||
|         file_map.delete(old) | ||||
|         next if delta.binary | ||||
|  | ||||
|         if [:added, :modified].include? delta.status | ||||
|           # Skip submodules | ||||
|           mode = delta.new_file[:mode] | ||||
|           next if (mode & 040000) != 0 | ||||
|  | ||||
|           blob = Linguist::LazyBlob.new(repository, delta.new_file[:oid], new, mode.to_s(8)) | ||||
|  | ||||
|           # Skip vendored or generated blobs | ||||
|           next if blob.vendored? || blob.generated? || blob.language.nil? | ||||
|  | ||||
|           # Only include programming languages and acceptable markup languages | ||||
|           if blob.language.type == :programming || Language.detectable_markup.include?(blob.language.name) | ||||
|  | ||||
|           # Build up the per-file breakdown stats | ||||
|           @file_breakdown[blob.language.group.name] << blob.name | ||||
|  | ||||
|           @sizes[blob.language.group] += blob.size | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       # Compute total size | ||||
|       @size = @sizes.inject(0) { |s,(_,v)| s + v } | ||||
|  | ||||
|       # Get primary language | ||||
|       if primary = @sizes.max_by { |(_, size)| size } | ||||
|         @language = primary[0] | ||||
|       end | ||||
|  | ||||
|       @computed_stats = true | ||||
|  | ||||
|       nil | ||||
|             file_map[new] = [blob.language.group.name, blob.size] | ||||
|           end | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       file_map | ||||
|     end | ||||
|   end | ||||
| end | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -17,9 +17,11 @@ module Linguist | ||||
|     PATH = File.expand_path('../samples.json', __FILE__) | ||||
|  | ||||
|     # Hash of serialized samples object | ||||
|     if File.exist?(PATH) | ||||
|     def self.cache | ||||
|       @cache ||= begin | ||||
|         serializer = defined?(JSON) ? JSON : YAML | ||||
|       DATA = serializer.load(File.read(PATH)) | ||||
|         serializer.load(File.read(PATH)) | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     # Public: Iterate over each sample. | ||||
| @@ -28,7 +30,7 @@ module Linguist | ||||
|     # | ||||
|     # Returns nothing. | ||||
|     def self.each(&block) | ||||
|       Dir.entries(ROOT).each do |category| | ||||
|       Dir.entries(ROOT).sort!.each do |category| | ||||
|         next if category == '.' || category == '..' | ||||
|  | ||||
|         # Skip text and binary for now | ||||
|   | ||||
| @@ -10,7 +10,7 @@ | ||||
| ## Vendor Conventions ## | ||||
|  | ||||
| # Caches | ||||
| - cache/ | ||||
| - (^|/)cache/ | ||||
|  | ||||
| # Dependencies | ||||
| - ^[Dd]ependencies/ | ||||
| @@ -33,16 +33,36 @@ | ||||
| # Erlang bundles | ||||
| - ^rebar$ | ||||
|  | ||||
| # Go dependencies | ||||
| - Godeps/_workspace/ | ||||
|  | ||||
| # Bootstrap minified css and js | ||||
| - (^|/)bootstrap([^.]*)(\.min)?\.(js|css)$ | ||||
|  | ||||
| # Font Awesome | ||||
| - font-awesome.min.css | ||||
| - font-awesome.css | ||||
|  | ||||
| # Foundation css | ||||
| - foundation.min.css | ||||
| - foundation.css | ||||
|  | ||||
| # Normalize.css | ||||
| - normalize.css | ||||
|  | ||||
| # Bourbon SCSS | ||||
| - (^|/)[Bb]ourbon/.*\.css$ | ||||
| - (^|/)[Bb]ourbon/.*\.scss$ | ||||
|  | ||||
| # Animate.css | ||||
| - animate.css | ||||
| - animate.min.css | ||||
|  | ||||
| # Vendored dependencies | ||||
| - thirdparty/ | ||||
| - third[-_]?party/ | ||||
| - 3rd[-_]?party/ | ||||
| - vendors?/ | ||||
| - extern(al)?/ | ||||
|  | ||||
| # Debian packaging | ||||
| - ^debian/ | ||||
| @@ -98,6 +118,20 @@ | ||||
| # AngularJS | ||||
| - (^|/)angular([^.]*)(\.min)?\.js$ | ||||
|  | ||||
| # D3.js | ||||
| - (^|\/)d3(\.v\d+)?([^.]*)(\.min)?\.js$ | ||||
|  | ||||
| # React | ||||
| - (^|/)react(-[^.]*)?(\.min)?\.js$ | ||||
|  | ||||
| # Modernizr | ||||
| - (^|/)modernizr\-\d\.\d+(\.\d+)?(\.min)?\.js$ | ||||
| - (^|/)modernizr\.custom\.\d+\.js$ | ||||
|  | ||||
| # Knockout | ||||
| - (^|/)knockout-(\d+\.){3}(debug\.)?js$ | ||||
| - knockout-min.js | ||||
|  | ||||
| ## Python ## | ||||
|  | ||||
| # django | ||||
| @@ -114,13 +148,24 @@ | ||||
|  | ||||
| ## Obj-C ## | ||||
|  | ||||
| # Cocoapods | ||||
| - ^Pods/ | ||||
|  | ||||
| # Sparkle | ||||
| - (^|/)Sparkle/ | ||||
|  | ||||
| ## Groovy ## | ||||
|  | ||||
| # Gradle | ||||
| - (^|/)gradlew$ | ||||
| - (^|/)gradlew\.bat$ | ||||
| - (^|/)gradle/wrapper/ | ||||
|  | ||||
| ## .NET ## | ||||
|  | ||||
| # Visual Studio IntelliSense | ||||
| - -vsdoc\.js$ | ||||
| - \.intellisense\.js$ | ||||
|  | ||||
| # jQuery validation plugin (MS bundles this with asp.net mvc) | ||||
| - (^|/)jquery([^.]*)\.validate(\.unobtrusive)?(\.min)?\.js$ | ||||
| @@ -130,7 +175,7 @@ | ||||
| - (^|/)[Mm]icrosoft([Mm]vc)?([Aa]jax|[Vv]alidation)(\.debug)?\.js$ | ||||
|  | ||||
| # NuGet | ||||
| - ^[Pp]ackages/ | ||||
| - ^[Pp]ackages\/.+\.\d+\/ | ||||
|  | ||||
| # ExtJS | ||||
| - (^|/)extjs/.*?\.js$ | ||||
| @@ -150,6 +195,9 @@ | ||||
| - (^|/)extjs/src/ | ||||
| - (^|/)extjs/welcome/ | ||||
|  | ||||
| # Html5shiv | ||||
| - (^|/)html5shiv(\.min)?\.js$ | ||||
|  | ||||
| # Samples folders | ||||
| - ^[Ss]amples/ | ||||
|  | ||||
| @@ -170,8 +218,27 @@ | ||||
| - (^|/)cordova([^.]*)(\.min)?\.js$ | ||||
| - (^|/)cordova\-\d\.\d(\.\d)?(\.min)?\.js$ | ||||
|  | ||||
| # Foundation js | ||||
| - foundation(\..*)?\.js$ | ||||
|  | ||||
| # Vagrant | ||||
| - ^Vagrantfile$ | ||||
|  | ||||
| # .DS_Store's | ||||
| - .[Dd][Ss]_[Ss]tore$ | ||||
|  | ||||
| # Mercury --use-subdirs | ||||
| - Mercury/ | ||||
|  | ||||
| # R packages | ||||
| - ^vignettes/ | ||||
| - ^inst/extdata/ | ||||
|  | ||||
| # Octicons | ||||
| - octicons.css | ||||
| - octicons.min.css | ||||
| - sprockets-octicons.scss | ||||
|  | ||||
| # Typesafe Activator | ||||
| - (^|/)activator$ | ||||
| - (^|/)activator\.bat$ | ||||
|   | ||||
							
								
								
									
										3
									
								
								lib/linguist/version.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								lib/linguist/version.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| module Linguist | ||||
|   VERSION = "3.1.5" | ||||
| end | ||||
							
								
								
									
										521
									
								
								samples/AGS Script/GlobalScript.asc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										521
									
								
								samples/AGS Script/GlobalScript.asc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,521 @@ | ||||
| // main global script file | ||||
|  | ||||
| // A function that initializes a bunch of stuff. | ||||
| function initialize_control_panel() {  | ||||
|   // Centre the control panel | ||||
|   gPanel.Centre();  | ||||
|   // Centre the Restart dialog as well | ||||
|   gRestartYN.Centre();  | ||||
|   if (!IsSpeechVoxAvailable()) {  | ||||
|     // If there is no speech-vox file, and therefore no speech, | ||||
|     // disable all the controls related with speech. | ||||
|     lblVoice.Visible = false;   | ||||
|     btnVoice.Visible = false;   | ||||
|     sldVoice.Visible = false; | ||||
|   } | ||||
|   else { | ||||
|     // If there *is*, then set it to voice and text. It's best to use | ||||
|     // both whenever possible, for the player's sake. | ||||
|     SetVoiceMode(eSpeechVoiceAndText);  | ||||
|     // And reflect this in the control panel. | ||||
|     btnVoice.Text = "Voice and Text";  | ||||
|   } | ||||
|   if (!System.SupportsGammaControl) { | ||||
|     // If we can't change the gamma settings, disable the relevant options. | ||||
|     sldGamma.Visible = false;  | ||||
|     lblGamma.Visible = false; | ||||
|   }  | ||||
|    | ||||
|   //And now, set all the defaults | ||||
|   System.Volume = 100; | ||||
|   sldAudio.Value = System.Volume; | ||||
|   SetGameSpeed(40); | ||||
|   sldSpeed.Value = 40; | ||||
|   if (IsSpeechVoxAvailable()) { | ||||
|      SetVoiceMode(eSpeechVoiceAndText); | ||||
|      btnVoice.Text = "Voice and Text"; | ||||
|      sldVoice.Value = 255; | ||||
|      SetSpeechVolume(255); | ||||
|   } | ||||
|   if (System.SupportsGammaControl) { | ||||
|     System.Gamma = 100; | ||||
|     sldGamma.Value = 100; | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Called when the game starts, before the first room is loaded | ||||
| function game_start() {    | ||||
|   // Put the code all in a function and then just call the function.  | ||||
|   // It saves cluttering up places like game_start. | ||||
|   initialize_control_panel();  | ||||
|   // Use the KeyboardMovement module to, per default, replicate the standard | ||||
|   // keyboard movement of most Sierra games. See KeyboardMovement.txt for more info | ||||
|   KeyboardMovement.SetMode(eKeyboardMovement_Tapping);  | ||||
| } | ||||
|  | ||||
| function repeatedly_execute() { | ||||
|    | ||||
|   // Put here anything you want to happen every game cycle, even when | ||||
|   // the game is paused. This will not run when the game is blocked | ||||
|   // inside a command like a blocking Walk() | ||||
|    | ||||
|   if (IsGamePaused() == 1) return; | ||||
|  | ||||
|   // Put here anything you want to happen every game cycle, but not | ||||
|   // when the game is paused. | ||||
| } | ||||
|  | ||||
| function repeatedly_execute_always() { | ||||
|    | ||||
|   // Put anything you want to happen every game cycle, even | ||||
|   // when the game is blocked inside a command like a | ||||
|   // blocking Walk(). | ||||
|   // You cannot run blocking commands from this function. | ||||
|    | ||||
| } | ||||
|  | ||||
| function show_inventory_window ()  | ||||
| { | ||||
|   gInventory.Visible = true; | ||||
|   // switch to the Use cursor (to select items with) | ||||
|   mouse.Mode = eModeInteract; | ||||
|   // But, override the appearance to look like the arrow | ||||
|   mouse.UseModeGraphic(eModePointer); | ||||
| } | ||||
|  | ||||
| function show_save_game_dialog() | ||||
| { | ||||
|   gSaveGame.Visible = true; | ||||
|   // Get the list of save games | ||||
|   lstSaveGamesList.FillSaveGameList(); | ||||
|   if (lstSaveGamesList.ItemCount > 0) | ||||
|   { | ||||
|     // If there is at least one, set the default text | ||||
|     // to be the first game's name | ||||
|     txtNewSaveName.Text = lstSaveGamesList.Items[0]; | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     // No save games yet, default empty text. | ||||
|     txtNewSaveName.Text = ""; | ||||
|   } | ||||
|   mouse.UseModeGraphic(eModePointer); | ||||
|   gIconbar.Visible = false; | ||||
| } | ||||
|  | ||||
| function show_restore_game_dialog() | ||||
| { | ||||
|   gRestoreGame.Visible = true; | ||||
|   lstRestoreGamesList.FillSaveGameList(); | ||||
|   mouse.UseModeGraphic(eModePointer); | ||||
|   gIconbar.Visible = false; | ||||
| } | ||||
|  | ||||
| function close_save_game_dialog() | ||||
| { | ||||
|   gSaveGame.Visible = false; | ||||
|   mouse.UseDefaultGraphic(); | ||||
|   gIconbar.Visible = true; | ||||
| } | ||||
|  | ||||
| function close_restore_game_dialog() | ||||
| { | ||||
|   gRestoreGame.Visible = false; | ||||
|   mouse.UseDefaultGraphic(); | ||||
|   gIconbar.Visible = true; | ||||
| } | ||||
|  | ||||
| // Called when a key is pressed. keycode holds the key's ASCII code | ||||
| function on_key_press(eKeyCode keycode) { | ||||
|   // The following is called before "if game is paused keycode=0", so | ||||
|   // it'll happen even when the game is paused. | ||||
|    | ||||
|   if ((keycode == eKeyEscape) && gRestartYN.Visible) { | ||||
|     //Use ESC to cancel restart. | ||||
|     gRestartYN.Visible = false;  | ||||
|     gIconbar.Visible = true; | ||||
|     // If the panel's not ON, then the player must have gotten here by tapping F9, | ||||
|     // therefore his cursor needs restoring. If the panel IS on, then it doesn't, | ||||
|     // because it's already a pointer. Get used to thinking like this!! | ||||
|     if (!gPanel.Visible) mouse.UseDefaultGraphic();  | ||||
|     return; | ||||
|   } | ||||
|   if ((keycode == eKeyEscape) && gPanel.Visible) { | ||||
|     // Use ESC to turn the panel off. | ||||
|     gPanel.Visible = false;  | ||||
|     mouse.UseDefaultGraphic(); | ||||
|     gIconbar.Visible = true; | ||||
|     return; | ||||
|   } | ||||
|   if ((keycode == eKeyEscape) && (gSaveGame.Visible)) | ||||
|   { | ||||
|     // Use ESC to close the save game dialog | ||||
|     close_save_game_dialog(); | ||||
|     return; | ||||
|   } | ||||
|   if ((keycode == eKeyEscape) && (gRestoreGame.Visible)) | ||||
|   { | ||||
|     // Use ESC to close the restore game dialog | ||||
|     close_restore_game_dialog(); | ||||
|     return; | ||||
|   } | ||||
|    | ||||
|   if (keycode == eKeyReturn) {  | ||||
|     // ENTER, in this case merely confirms restart | ||||
|     if (gRestartYN.Visible) RestartGame(); | ||||
|   } | ||||
|  | ||||
|   if (IsGamePaused() || (IsInterfaceEnabled() == 0)) | ||||
|   { | ||||
|     // If the game is paused with a modal GUI on the | ||||
|     // screen, or the player interface is disabled in | ||||
|     // a cut scene, ignore any keypresses. | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   // FUNCTION KEYS AND SYSTEM SHORTCUTS | ||||
|   if (keycode == eKeyEscape) { | ||||
|     // ESC | ||||
|     gPanel.Visible = true;  | ||||
|     gIconbar.Visible = false; | ||||
|     mouse.UseModeGraphic(eModePointer); | ||||
|   } | ||||
|   if (keycode == eKeyCtrlQ)  QuitGame(1);   // Ctrl-Q | ||||
|   if (keycode == eKeyF5) show_save_game_dialog();   // F5 | ||||
|   if (keycode == eKeyF7) show_restore_game_dialog();  // F7 | ||||
|   if (keycode == eKeyF9) { | ||||
|     // F9, asks the player to confirm restarting (so much better to always confirm first) | ||||
|     gRestartYN.Visible = true;   | ||||
|     gIconbar.Visible = false; | ||||
|     mouse.UseModeGraphic(eModePointer); | ||||
|   } | ||||
|   if (keycode == eKeyF12) SaveScreenShot("scrnshot.bmp");  // F12 | ||||
|   if (keycode == eKeyTab)   show_inventory_window();  // Tab, show inventory | ||||
|  | ||||
|   // GAME COMMAND SHORTCUTS | ||||
|   if (keycode == 'W') mouse.Mode=eModeWalkto; //Notice this alternate way to indicate keycodes. | ||||
|   if (keycode == 'L') mouse.Mode=eModeLookat; //Note that all we do here is set modes. | ||||
|   if (keycode == 'U') mouse.Mode=eModeInteract; //If you want something else to happen, such as GUI buttons highlighting, | ||||
|   if (keycode == 'T') mouse.Mode=eModeTalkto; //you'll need some more scripting done. | ||||
|   if (keycode == 'I') mouse.Mode=eModeUseinv; //But this will, as-is, give you some standard keyboard shortcuts your players will very much appreciate. | ||||
|  | ||||
|   // For extra cursor modes, such as pick up, feel free to add as you will. | ||||
|   // Uncomment the line below if you use the "Pick Up" mode. | ||||
|   //if (keycode == 'P' || keycode == 'G') mouse.Mode=eModePickup;  | ||||
|  | ||||
|   // DEBUG FUNCTIONS | ||||
|   if (keycode == eKeyCtrlS)  Debug(0,0);  // Ctrl-S, give all inventory | ||||
|   if (keycode == eKeyCtrlV)  Debug(1,0);  // Ctrl-V, version | ||||
|   if (keycode == eKeyCtrlA)  Debug(2,0);  // Ctrl-A, show walkable areas | ||||
|   if (keycode == eKeyCtrlX)  Debug(3,0);  // Ctrl-X, teleport to room | ||||
|   if (keycode == eKeyCtrlW && game.debug_mode)  | ||||
|     player.PlaceOnWalkableArea(); //Ctrl-W, move to walkable area  | ||||
| } | ||||
|  | ||||
|  | ||||
| function on_mouse_click(MouseButton button) { | ||||
|   // called when a mouse button is clicked. button is either LEFT or RIGHT | ||||
|   if (IsGamePaused() == 1) { | ||||
|     // Game is paused, so do nothing (ie. don't allow mouse click) | ||||
|   } | ||||
|   else if (button == eMouseLeft) { | ||||
|     ProcessClick(mouse.x, mouse.y, mouse.Mode ); | ||||
|   } | ||||
|   else if (button == eMouseRight || button == eMouseWheelSouth){ | ||||
|     // right-click our mouse-wheel down, so cycle cursor | ||||
|     mouse.SelectNextMode(); | ||||
|   } | ||||
|   else if (button == eMouseMiddle) {  | ||||
|     // Middle-button-click, default make character walk to clicked area (a little shortcut) | ||||
|     // Could have been just "player.Walk(mouse.x,mouse.y)", but it's best to | ||||
|     // leave our options open - what if you have a special script triggered | ||||
|     // on "walking" mode? | ||||
|     ProcessClick(mouse.x, mouse.y, eModeWalkto);  | ||||
|   } | ||||
|   else if (button == eMouseWheelNorth) {  | ||||
|     // Mouse-wheel up, cycle cursors  | ||||
|     // If mode isn't WALK, set the previous mode (notice usage of numbers instead | ||||
|     // of eNums, when it suits us)... | ||||
|     if (mouse.Mode>0) mouse.Mode=mouse.Mode-1;  | ||||
|     else  | ||||
|     {  | ||||
|       // ...but if it is WALK mode... | ||||
|       if (player.ActiveInventory!=null)  | ||||
|       { | ||||
|         //...and the player has a selected inventory item, set mouse mode to UseInv.  | ||||
|         mouse.Mode=eModeUseinv;  | ||||
|       } | ||||
|       else  | ||||
|       { | ||||
|         // If they don't, however, just set it to mode TALK (change this line if you add more cursor modes) | ||||
|         mouse.Mode=eModeTalkto;  | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| function interface_click(int interface, int button) { | ||||
|   // This function is obsolete, from 2.62 and earlier versions. | ||||
| } | ||||
|  | ||||
| function btnInvUp_Click(GUIControl *control, MouseButton button) { | ||||
|   invCustomInv.ScrollUp(); | ||||
| } | ||||
|  | ||||
| function btnInvDown_Click(GUIControl *control, MouseButton button) { | ||||
|   invCustomInv.ScrollDown(); | ||||
| } | ||||
|  | ||||
| function btnInvOK_Click(GUIControl *control, MouseButton button) { | ||||
| 	// They pressed the OK button, close the GUI | ||||
| 	gInventory.Visible = false; | ||||
| 	mouse.UseDefaultGraphic(); | ||||
| } | ||||
|  | ||||
| function btnInvSelect_Click(GUIControl *control, MouseButton button) { | ||||
|    | ||||
| 	// They pressed SELECT, so switch to the Get cursor | ||||
| 	mouse.Mode = eModeInteract; | ||||
| 	// But, override the appearance to look like the arrow | ||||
| 	mouse.UseModeGraphic(eModePointer); | ||||
| } | ||||
|  | ||||
| function btnIconInv_Click(GUIControl *control, MouseButton button) { | ||||
|    | ||||
|   show_inventory_window(); | ||||
| } | ||||
|  | ||||
| function btnIconCurInv_Click(GUIControl *control, MouseButton button) { | ||||
|    | ||||
|   if (player.ActiveInventory != null) | ||||
|     mouse.Mode = eModeUseinv; | ||||
| } | ||||
|  | ||||
| function btnIconSave_Click(GUIControl *control, MouseButton button)  | ||||
| { | ||||
|   show_save_game_dialog(); | ||||
| } | ||||
|  | ||||
| function btnIconLoad_Click(GUIControl *control, MouseButton button)  | ||||
| { | ||||
|   show_restore_game_dialog(); | ||||
| } | ||||
|  | ||||
| function btnIconExit_Click(GUIControl *control, MouseButton button) { | ||||
|    | ||||
|   QuitGame(1); | ||||
| } | ||||
|  | ||||
| function btnIconAbout_Click(GUIControl *control, MouseButton button) { | ||||
|    | ||||
|   gPanel.Visible=true; | ||||
|   gIconbar.Visible=false; | ||||
|   mouse.UseModeGraphic(eModePointer); | ||||
| } | ||||
|  | ||||
| function cEgo_Look() | ||||
| { | ||||
|   Display("Damn, I'm looking good!"); | ||||
| } | ||||
|  | ||||
| function cEgo_Interact() | ||||
| { | ||||
|   Display("You rub your hands up and down your clothes."); | ||||
| } | ||||
|  | ||||
| function cEgo_Talk() | ||||
| { | ||||
|   Display("Talking to yourself is a sign of madness!"); | ||||
| } | ||||
|  | ||||
| //START OF CONTROL PANEL FUNCTIONS | ||||
| function btnSave_OnClick(GUIControl *control, MouseButton button) | ||||
| { | ||||
|   gPanel.Visible = false; | ||||
|   mouse.UseDefaultGraphic(); | ||||
|   gIconbar.Visible = true; | ||||
|   Wait(1); | ||||
|   btnIconSave_Click(btnIconSave, eMouseLeft); | ||||
| } | ||||
|  | ||||
| function gControl_OnClick(GUI *theGui, MouseButton button) | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| function btnAbout_OnClick(GUIControl *control, MouseButton button) | ||||
| { | ||||
| Display("Adventure Game Studio run-time engine default game."); | ||||
| } | ||||
|  | ||||
| function btnQuit_OnClick(GUIControl *control, MouseButton button) | ||||
| { | ||||
|   gPanel.Visible = false; | ||||
|   Wait(1); | ||||
|   QuitGame(1); | ||||
|   gPanel.Visible = true; | ||||
|   gIconbar.Visible = false; | ||||
|   mouse.UseModeGraphic(eModePointer); | ||||
| } | ||||
|  | ||||
| function btnLoad_OnClick(GUIControl *control, MouseButton button) | ||||
| { | ||||
|   gPanel.Visible = false; | ||||
|   mouse.UseDefaultGraphic(); | ||||
|   gIconbar.Visible = true; | ||||
|   Wait(1); | ||||
|   btnIconLoad_Click(btnIconLoad, eMouseLeft); | ||||
| } | ||||
|  | ||||
| function btnResume_OnClick(GUIControl *control, MouseButton button) | ||||
| { | ||||
|   gPanel.Visible = false; | ||||
|   mouse.UseDefaultGraphic(); | ||||
|   gIconbar.Visible = true; | ||||
| } | ||||
|  | ||||
| function sldAudio_OnChange(GUIControl *control) | ||||
| { | ||||
|   System.Volume = sldAudio.Value; | ||||
| } | ||||
|  | ||||
| function sldVoice_OnChange(GUIControl *control) | ||||
| { | ||||
|   // Sets voice volume. Note that we don't check for the existence of speech.vox -  | ||||
|   // we did that in game_start, so if it's not there the slider won't even be available. | ||||
|   SetSpeechVolume(sldVoice.Value);  | ||||
| } | ||||
|  | ||||
| function btnVoice_OnClick(GUIControl *control, MouseButton button) | ||||
| { | ||||
|   // Note that we don't check for the existence of speech.vox - we did that in game_start, | ||||
|   // so if it's not there the button won't even be available. | ||||
|   if (btnVoice.Text == "Voice and Text") {  | ||||
|     SetVoiceMode(eSpeechVoiceOnly);  | ||||
|     btnVoice.Text = "Voice only"; | ||||
|   } | ||||
|   else if (btnVoice.Text == "Voice only") { | ||||
|     SetVoiceMode(eSpeechTextOnly); | ||||
|     btnVoice.Text = "Text only"; | ||||
|   } | ||||
|   else if (btnVoice.Text == "Text only") { | ||||
|     SetVoiceMode(eSpeechVoiceAndText); | ||||
|     btnVoice.Text = "Voice and Text"; | ||||
|   } | ||||
| } | ||||
|  | ||||
| function sldGamma_OnChange(GUIControl *control) | ||||
| { | ||||
|   // Set the gamma. Note there's no need to check for anything else, as we ensured, | ||||
|   // in game_start, that the slider won't even appear if it's not possible to do this. | ||||
|   System.Gamma = sldGamma.Value;  | ||||
| } | ||||
|  | ||||
| function btnDefault_OnClick(GUIControl *control, MouseButton button) | ||||
| { | ||||
|   // Reset everything to default. You'll have to edit these as well as the sliders | ||||
|   // if you'd rather have different default parameters. | ||||
|   System.Volume = 100; | ||||
|   sldAudio.Value = System.Volume; | ||||
|   sldSpeed.Value = 40; | ||||
|   SetGameSpeed(40); | ||||
|   if (IsSpeechVoxAvailable()) { | ||||
|      SetVoiceMode(eSpeechVoiceAndText); | ||||
|      btnVoice.Text = "Voice and Text"; | ||||
|      sldVoice.Value = 255; | ||||
|      SetSpeechVolume(255); | ||||
|   } | ||||
|   if (System.SupportsGammaControl) { | ||||
|     System.Gamma = 100; | ||||
|     sldGamma.Value = 100; | ||||
|   } | ||||
| } | ||||
| //END OF CONTROL PANEL FUNCTIONS | ||||
|  | ||||
| function dialog_request(int param)  | ||||
| { | ||||
|   // This is used by the dialog text parser if you need to process | ||||
|   // text that the player types in to the parser. | ||||
|   // It is not used by default. | ||||
| } | ||||
|  | ||||
| function sldSpeed_OnChange(GUIControl *control) | ||||
| { | ||||
|   SetGameSpeed(sldSpeed.Value); | ||||
| } | ||||
|  | ||||
| function btnRestart_OnClick(GUIControl *control, MouseButton button) | ||||
| { | ||||
|   gRestartYN.Visible=true; | ||||
|   gIconbar.Visible=false; | ||||
| } | ||||
|  | ||||
| function btnRestartYes_OnClick(GUIControl *control, MouseButton button) | ||||
| { | ||||
|   RestartGame(); | ||||
| } | ||||
|  | ||||
| function btnRestartNo_OnClick(GUIControl *control, MouseButton button) | ||||
| { | ||||
|   gRestartYN.Visible = false; | ||||
|   gIconbar.Visible = true; | ||||
|   // If the panel's not ON, then the player must have gotten here by tapping F9, | ||||
|   // therefore his cursor needs restoring. If the panel IS on, then it doesn't, | ||||
|   // because it's already a pointer. Get used to thinking like this!! | ||||
|   if (!gPanel.Visible) mouse.UseDefaultGraphic();  | ||||
| } | ||||
|  | ||||
| function btnCancelSave_OnClick(GUIControl *control, MouseButton button) | ||||
| { | ||||
|   close_save_game_dialog(); | ||||
| } | ||||
|  | ||||
| function btnSaveGame_OnClick(GUIControl *control, MouseButton button) | ||||
| { | ||||
|   int gameSlotToSaveInto = lstSaveGamesList.ItemCount + 1; | ||||
|   int i = 0; | ||||
|   while (i < lstSaveGamesList.ItemCount) | ||||
|   { | ||||
|     if (lstSaveGamesList.Items[i] == txtNewSaveName.Text) | ||||
|     { | ||||
|       gameSlotToSaveInto = lstSaveGamesList.SaveGameSlots[i]; | ||||
|     } | ||||
|     i++; | ||||
|   } | ||||
|   SaveGameSlot(gameSlotToSaveInto, txtNewSaveName.Text); | ||||
|   close_save_game_dialog(); | ||||
| } | ||||
|  | ||||
| function btnCancelRestore_OnClick(GUIControl *control, MouseButton button) | ||||
| { | ||||
|   close_restore_game_dialog(); | ||||
| } | ||||
|  | ||||
| function btnRestoreGame_OnClick(GUIControl *control, MouseButton button) | ||||
| { | ||||
|   if (lstRestoreGamesList.SelectedIndex >= 0) | ||||
|   { | ||||
|     RestoreGameSlot(lstRestoreGamesList.SaveGameSlots[lstRestoreGamesList.SelectedIndex]); | ||||
|   } | ||||
|   close_restore_game_dialog(); | ||||
| } | ||||
|  | ||||
| function lstSaveGamesList_OnSelectionCh(GUIControl *control) | ||||
| { | ||||
|   txtNewSaveName.Text = lstSaveGamesList.Items[lstSaveGamesList.SelectedIndex]; | ||||
| } | ||||
|  | ||||
| function txtNewSaveName_OnActivate(GUIControl *control) | ||||
| { | ||||
|   // Pressing return in the text box simulates clicking the Save button | ||||
|   btnSaveGame_OnClick(control, eMouseLeft); | ||||
| } | ||||
|  | ||||
| function btnDeleteSave_OnClick(GUIControl *control, MouseButton button) | ||||
| { | ||||
|   if (lstSaveGamesList.SelectedIndex >= 0) | ||||
|   { | ||||
|     DeleteSaveSlot(lstSaveGamesList.SaveGameSlots[lstSaveGamesList.SelectedIndex]); | ||||
|     lstSaveGamesList.FillSaveGameList(); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										4
									
								
								samples/AGS Script/GlobalScript.ash
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								samples/AGS Script/GlobalScript.ash
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| // Main header script - this will be included into every script in | ||||
| // the game (local and global). Do not place functions here; rather, | ||||
| // place import definitions and #define names here to be used by all | ||||
| // scripts. | ||||
							
								
								
									
										216
									
								
								samples/AGS Script/KeyboardMovement_102.asc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								samples/AGS Script/KeyboardMovement_102.asc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,216 @@ | ||||
| // Main script for module 'KeyboardMovement' | ||||
|  | ||||
| //**************************************************************************************************** | ||||
| // DEFINITIONS | ||||
| //**************************************************************************************************** | ||||
|  | ||||
| #define DISTANCE 10000// distance player walks in Tapping mode before he stops | ||||
|  | ||||
| enum KeyboardMovement_Directions { | ||||
| 	eKeyboardMovement_Stop,  | ||||
| 	eKeyboardMovement_DownLeft,  | ||||
| 	eKeyboardMovement_Down,  | ||||
| 	eKeyboardMovement_DownRight,  | ||||
| 	eKeyboardMovement_Left,  | ||||
| 	eKeyboardMovement_Right,  | ||||
| 	eKeyboardMovement_UpLeft,  | ||||
| 	eKeyboardMovement_Up,  | ||||
| 	eKeyboardMovement_UpRight | ||||
| }; | ||||
|  | ||||
| //**************************************************************************************************** | ||||
| // VARIABLES | ||||
| //**************************************************************************************************** | ||||
|  | ||||
| // keycodes as variables for future key customization functions (static variables?): | ||||
| int KeyboardMovement_KeyDown = 380; // down arrow | ||||
| int KeyboardMovement_KeyLeft = 375; // left arrow | ||||
| int KeyboardMovement_KeyRight = 377; // right arrow | ||||
| int KeyboardMovement_KeyUp = 372; // up arrow | ||||
| int KeyboardMovement_KeyDownRight = 381; // PgDn (numpad) | ||||
| int KeyboardMovement_KeyUpRight = 373; // PgUp (numpad) | ||||
| int KeyboardMovement_KeyDownLeft = 379; // End (numpad) | ||||
| int KeyboardMovement_KeyUpLeft = 371; // Home (numpad) | ||||
| int KeyboardMovement_KeyStop = 376; // 5 (numpad) | ||||
|  | ||||
| KeyboardMovement_Modes KeyboardMovement_Mode = eKeyboardMovement_None; // stores current keyboard control mode (disabled by default) | ||||
|  | ||||
| KeyboardMovement_Directions KeyboardMovement_CurrentDirection = eKeyboardMovement_Stop; // stores current walking direction of player character | ||||
|  | ||||
| //**************************************************************************************************** | ||||
| // USER FUNCTIONS | ||||
| //**************************************************************************************************** | ||||
|  | ||||
| //==================================================================================================== | ||||
|  | ||||
| static function KeyboardMovement::SetMode(KeyboardMovement_Modes mode) { | ||||
| 	KeyboardMovement_Mode = mode; | ||||
| } | ||||
|  | ||||
| //==================================================================================================== | ||||
|  | ||||
| // key customization functions here | ||||
|  | ||||
| //==================================================================================================== | ||||
|  | ||||
| //**************************************************************************************************** | ||||
| // EVENT HANDLER FUNCTIONS | ||||
| //**************************************************************************************************** | ||||
|  | ||||
| //==================================================================================================== | ||||
|  | ||||
| function repeatedly_execute() { | ||||
|  | ||||
| 	//-------------------------------------------------- | ||||
| 	// Pressing mode | ||||
| 	//-------------------------------------------------- | ||||
|  | ||||
| 	if ((IsGamePaused() == true) || (KeyboardMovement_Mode != eKeyboardMovement_Pressing) || (IsInterfaceEnabled() == false) || (player.on == false)) return 0; | ||||
| 	  // if game is paused, module or mode disabled, interface disabled or player character hidden, quit function | ||||
|  | ||||
| 	KeyboardMovement_Directions newdirection; // declare variable storing new direction | ||||
|  | ||||
| 	// get new direction: | ||||
| 	if ( ((IsKeyPressed(KeyboardMovement_KeyDown)) && (IsKeyPressed(KeyboardMovement_KeyRight))) || (IsKeyPressed(KeyboardMovement_KeyDownRight)) ) newdirection = eKeyboardMovement_DownRight; // if down&right arrows or PgDn (numeric pad) held down, set new direction to Down-Right | ||||
| 	else if ( ((IsKeyPressed(KeyboardMovement_KeyUp)) && (IsKeyPressed(KeyboardMovement_KeyRight))) || (IsKeyPressed(KeyboardMovement_KeyUpRight)) ) newdirection = eKeyboardMovement_UpRight; // up&right arrows or PgUp (numpad) | ||||
| 	else if ( ((IsKeyPressed(KeyboardMovement_KeyDown)) && (IsKeyPressed(KeyboardMovement_KeyLeft))) || (IsKeyPressed(KeyboardMovement_KeyDownLeft)) ) newdirection = eKeyboardMovement_DownLeft; // down&left arrows or End (numpad) | ||||
| 	else if ( ((IsKeyPressed(KeyboardMovement_KeyUp)) && (IsKeyPressed(KeyboardMovement_KeyLeft))) || (IsKeyPressed(KeyboardMovement_KeyUpLeft)) ) newdirection = eKeyboardMovement_UpLeft; // up&left arrows or Home (numpad) | ||||
| 	else if (IsKeyPressed(KeyboardMovement_KeyDown)) newdirection = eKeyboardMovement_Down; // down arrow | ||||
| 	else if (IsKeyPressed(KeyboardMovement_KeyLeft)) newdirection = eKeyboardMovement_Left; // left arrow | ||||
| 	else if (IsKeyPressed(KeyboardMovement_KeyRight)) newdirection = eKeyboardMovement_Right; // right arrow | ||||
| 	else if (IsKeyPressed(KeyboardMovement_KeyUp)) newdirection = eKeyboardMovement_Up; // up arrow | ||||
| 	else newdirection = eKeyboardMovement_Stop; // if none of the above held down, set it to stop player character | ||||
|  | ||||
| 	if (IsKeyPressed(KeyboardMovement_KeyStop)) newdirection = eKeyboardMovement_Stop; // if 5 (numeric pad) held down, stop player character, regardless of whether some of the above are held down | ||||
|  | ||||
| 	if (newdirection != KeyboardMovement_CurrentDirection) { // if new direction is different from current direction | ||||
|  | ||||
| 		if (newdirection == eKeyboardMovement_Stop) player.StopMoving(); // if new direction is the Stop command, stop movement of player character | ||||
| 		else { // if new direction is NOT the Stop command | ||||
|  | ||||
| 			int dx, dy; // declare variables storing new walk coordinates | ||||
| 			if (newdirection == eKeyboardMovement_DownRight) { | ||||
| 				dx = DISTANCE; | ||||
| 				dy = DISTANCE; | ||||
| 			} | ||||
| 			else if (newdirection == eKeyboardMovement_UpRight) { | ||||
| 				dx = DISTANCE; | ||||
| 				dy = -DISTANCE; | ||||
| 			} | ||||
| 			else if (newdirection == eKeyboardMovement_DownLeft) { | ||||
| 				dx = -DISTANCE; | ||||
| 				dy = DISTANCE; | ||||
| 			} | ||||
| 			else if (newdirection == eKeyboardMovement_UpLeft) { | ||||
| 				dx = -DISTANCE; | ||||
| 				dy = -DISTANCE; | ||||
| 			} | ||||
| 			else if (newdirection == eKeyboardMovement_Down) { | ||||
| 				dx = 0; | ||||
| 				dy = DISTANCE; | ||||
| 			} | ||||
| 			else if (newdirection == eKeyboardMovement_Left) { | ||||
| 				dx = -DISTANCE; | ||||
| 				dy = 0; | ||||
| 			} | ||||
| 			else if (newdirection == eKeyboardMovement_Right) { | ||||
| 				dx = DISTANCE; | ||||
| 				dy = 0; | ||||
| 			} | ||||
| 			else if (newdirection == eKeyboardMovement_Up) { | ||||
| 				dx = 0; | ||||
| 				dy = -DISTANCE; | ||||
| 			} | ||||
|  | ||||
| 			player.WalkStraight(player.x + dx, player.y + dy, eNoBlock); // walk player character to the new coordinates | ||||
| 		} | ||||
| 		KeyboardMovement_CurrentDirection = newdirection; // update current direction to new direction | ||||
|  | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| //==================================================================================================== | ||||
|  | ||||
| function on_key_press(int keycode) { | ||||
|  | ||||
| 	//-------------------------------------------------- | ||||
| 	// Tapping mode | ||||
| 	//-------------------------------------------------- | ||||
|  | ||||
| 	if ((IsGamePaused() == true) || (KeyboardMovement_Mode != eKeyboardMovement_Tapping) || (IsInterfaceEnabled() == false) || (player.on == false)) return 0; | ||||
| 	  // if game is paused, module or mode disabled, interface disabled or player character hidden, quit function | ||||
|  | ||||
| 	KeyboardMovement_Directions newdirection; // declare variable storing new direction | ||||
|  | ||||
| 	// get new direction: | ||||
| 	if (keycode == KeyboardMovement_KeyDownRight) newdirection = eKeyboardMovement_DownRight; // if down-right key pressed, set new direction to Down-Right | ||||
| 	else if (keycode == KeyboardMovement_KeyUpRight) newdirection = eKeyboardMovement_UpRight; | ||||
| 	else if (keycode == KeyboardMovement_KeyDownLeft) newdirection = eKeyboardMovement_DownLeft; | ||||
| 	else if (keycode == KeyboardMovement_KeyUpLeft) newdirection = eKeyboardMovement_UpLeft; | ||||
| 	else if (keycode == KeyboardMovement_KeyDown) newdirection = eKeyboardMovement_Down; | ||||
| 	else if (keycode == KeyboardMovement_KeyLeft) newdirection = eKeyboardMovement_Left; | ||||
| 	else if (keycode == KeyboardMovement_KeyRight) newdirection = eKeyboardMovement_Right; | ||||
| 	else if (keycode == KeyboardMovement_KeyUp) newdirection = eKeyboardMovement_Up; | ||||
| 	else if (keycode == KeyboardMovement_KeyStop) newdirection = eKeyboardMovement_Stop; // if stop key pressed, set to stop player character | ||||
|  | ||||
| 	if (newdirection != KeyboardMovement_CurrentDirection) { // if new direction is different from current direction | ||||
|  | ||||
| 		if (newdirection == eKeyboardMovement_Stop) player.StopMoving(); // if new direction is the Stop command, stop movement of player character | ||||
| 		else { // if new direction is NOT the Stop command | ||||
|  | ||||
| 			int dx, dy; // declare variables storing new walk coordinates | ||||
| 			if (newdirection == eKeyboardMovement_DownRight) { | ||||
| 				dx = DISTANCE; | ||||
| 				dy = DISTANCE; | ||||
| 			} | ||||
| 			else if (newdirection == eKeyboardMovement_UpRight) { | ||||
| 				dx = DISTANCE; | ||||
| 				dy = -DISTANCE; | ||||
| 			} | ||||
| 			else if (newdirection == eKeyboardMovement_DownLeft) { | ||||
| 				dx = -DISTANCE; | ||||
| 				dy = DISTANCE; | ||||
| 			} | ||||
| 			else if (newdirection == eKeyboardMovement_UpLeft) { | ||||
| 				dx = -DISTANCE; | ||||
| 				dy = -DISTANCE; | ||||
| 			} | ||||
| 			else if (newdirection == eKeyboardMovement_Down) { | ||||
| 				dx = 0; | ||||
| 				dy = DISTANCE; | ||||
| 			} | ||||
| 			else if (newdirection == eKeyboardMovement_Left) { | ||||
| 				dx = -DISTANCE; | ||||
| 				dy = 0; | ||||
| 			} | ||||
| 			else if (newdirection == eKeyboardMovement_Right) { | ||||
| 				dx = DISTANCE; | ||||
| 				dy = 0; | ||||
| 			} | ||||
| 			else if (newdirection == eKeyboardMovement_Up) { | ||||
| 				dx = 0; | ||||
| 				dy = -DISTANCE; | ||||
| 			} | ||||
|  | ||||
| 			player.WalkStraight(player.x + dx, player.y + dy, eNoBlock); // walk player character to the new coordinates | ||||
| 		} | ||||
| 		KeyboardMovement_CurrentDirection = newdirection; // update current direction to new direction | ||||
|  | ||||
| 	} | ||||
| 	else { // if new direction is same as current direction | ||||
| 		player.StopMoving(); // stop player character | ||||
| 		KeyboardMovement_CurrentDirection = eKeyboardMovement_Stop; // update current direction | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| //==================================================================================================== | ||||
|  | ||||
| function on_event(EventType event, int data) { | ||||
|  | ||||
| 	if (event == eEventLeaveRoom) KeyboardMovement_CurrentDirection = eKeyboardMovement_Stop; | ||||
|  | ||||
| } | ||||
|  | ||||
| //==================================================================================================== | ||||
							
								
								
									
										13
									
								
								samples/AGS Script/KeyboardMovement_102.ash
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								samples/AGS Script/KeyboardMovement_102.ash
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| // Script header for module 'KeyboardMovement' | ||||
|  | ||||
| #define KeyboardMovement_VERSION 101 | ||||
|  | ||||
| enum KeyboardMovement_Modes { | ||||
| 	eKeyboardMovement_None,  | ||||
| 	eKeyboardMovement_Tapping,  | ||||
| 	eKeyboardMovement_Pressing | ||||
| }; | ||||
|  | ||||
| struct KeyboardMovement { | ||||
| 	import static function SetMode(KeyboardMovement_Modes mode); | ||||
| }; | ||||
							
								
								
									
										18
									
								
								samples/APL/DeepakChopra.apl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								samples/APL/DeepakChopra.apl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| ⍝   You can try this at http://tryapl.org/ | ||||
| ⍝   I can not explain how much I suddenly love this crypto-language | ||||
|  | ||||
|  | ||||
|  | ||||
| Starts     ← 'Experiential truth ' 'The physical world ' 'Non-judgment '       'Quantum physics ' | ||||
| Middles    ← 'nurtures an '        'projects onto '      'imparts reality to ' 'constructs with ' | ||||
| Qualifiers ← 'abundance of '       'the barrier of '     'self-righteous '     'potential ' | ||||
| Finishes   ← 'marvel.'             'choices.'            'creativity.'         'actions.' | ||||
|  | ||||
| rf     ← {(?⍴⍵)⊃⍵} | ||||
| erf    ← {rf ¨ ⍵} | ||||
|  | ||||
| deepak ← {erf Starts Middles Qualifiers Finishes} | ||||
|  | ||||
|  | ||||
|  | ||||
| deepak ⍬ | ||||
							
								
								
									
										59
									
								
								samples/Alloy/file_system.als
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								samples/Alloy/file_system.als
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| module examples/systems/file_system | ||||
|  | ||||
| /* | ||||
|  * Model of a generic file system. | ||||
|  */ | ||||
|  | ||||
| abstract sig Object {} | ||||
|  | ||||
| sig Name {} | ||||
|  | ||||
| sig File extends Object {} { some d: Dir | this in d.entries.contents } | ||||
|  | ||||
| sig Dir extends Object { | ||||
|   entries: set DirEntry, | ||||
|   parent: lone Dir | ||||
| } { | ||||
|   parent = this.~@contents.~@entries | ||||
|   all e1, e2 : entries | e1.name = e2.name => e1 = e2 | ||||
|   this !in this.^@parent | ||||
|   this != Root => Root in this.^@parent | ||||
| } | ||||
|  | ||||
| one sig Root extends Dir {} { no parent } | ||||
|  | ||||
| lone sig Cur extends Dir {} | ||||
|  | ||||
| sig DirEntry { | ||||
|   name: Name, | ||||
|   contents: Object | ||||
| } { | ||||
|   one this.~entries | ||||
| } | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * all directories besides root have one parent | ||||
|  */ | ||||
| pred OneParent_buggyVersion { | ||||
|     all d: Dir - Root | one d.parent | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * all directories besides root have one parent | ||||
|  */ | ||||
| pred OneParent_correctVersion { | ||||
|     all d: Dir - Root | (one d.parent && one contents.d) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Only files may be linked (that is, have more than one entry) | ||||
|  * That is, all directories are the contents of at most one directory entry | ||||
|  */ | ||||
| pred NoDirAliases { | ||||
|     all o: Dir | lone o.~contents | ||||
| } | ||||
|  | ||||
| check { OneParent_buggyVersion => NoDirAliases } for 5 expect 1 | ||||
|  | ||||
| check { OneParent_correctVersion => NoDirAliases } for 5 expect 0 | ||||
							
								
								
									
										83
									
								
								samples/Alloy/marksweepgc.als
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								samples/Alloy/marksweepgc.als
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| module examples/systems/marksweepgc | ||||
|  | ||||
| /* | ||||
|  * Model of mark and sweep garbage collection. | ||||
|  */ | ||||
|  | ||||
| // a node in the heap | ||||
| sig Node {} | ||||
|  | ||||
| sig HeapState { | ||||
|   left, right : Node -> lone Node, | ||||
|   marked : set Node, | ||||
|   freeList : lone Node | ||||
| } | ||||
|  | ||||
| pred clearMarks[hs, hs' : HeapState] { | ||||
|   // clear marked set | ||||
|   no hs'.marked | ||||
|   // left and right fields are unchanged | ||||
|   hs'.left = hs.left | ||||
|   hs'.right = hs.right | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * simulate the recursion of the mark() function using transitive closure | ||||
|  */ | ||||
| fun reachable[hs: HeapState, n: Node] : set Node { | ||||
|   n + n.^(hs.left + hs.right) | ||||
| } | ||||
|  | ||||
| pred mark[hs: HeapState, from : Node, hs': HeapState] { | ||||
|   hs'.marked = hs.reachable[from] | ||||
|   hs'.left = hs.left | ||||
|   hs'.right = hs.right | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * complete hack to simulate behavior of code to set freeList | ||||
|  */ | ||||
| pred setFreeList[hs, hs': HeapState] { | ||||
|   // especially hackish | ||||
|   hs'.freeList.*(hs'.left) in (Node - hs.marked) | ||||
|   all n: Node | | ||||
|     (n !in hs.marked) => { | ||||
|       no hs'.right[n] | ||||
|       hs'.left[n] in (hs'.freeList.*(hs'.left)) | ||||
|       n in hs'.freeList.*(hs'.left) | ||||
|     } else { | ||||
|       hs'.left[n] = hs.left[n] | ||||
|       hs'.right[n] = hs.right[n] | ||||
|     } | ||||
|   hs'.marked = hs.marked | ||||
| } | ||||
|  | ||||
| pred GC[hs: HeapState, root : Node, hs': HeapState] { | ||||
|   some hs1, hs2: HeapState | | ||||
|     hs.clearMarks[hs1] && hs1.mark[root, hs2] && hs2.setFreeList[hs'] | ||||
| } | ||||
|  | ||||
| assert Soundness1 { | ||||
|   all h, h' : HeapState, root : Node | | ||||
|     h.GC[root, h'] => | ||||
|       (all live : h.reachable[root] | { | ||||
|         h'.left[live] = h.left[live] | ||||
|         h'.right[live] = h.right[live] | ||||
|       }) | ||||
| } | ||||
|  | ||||
| assert Soundness2 { | ||||
|   all h, h' : HeapState, root : Node | | ||||
|     h.GC[root, h'] => | ||||
|       no h'.reachable[root] & h'.reachable[h'.freeList] | ||||
| } | ||||
|  | ||||
| assert Completeness { | ||||
|   all h, h' : HeapState, root : Node | | ||||
|     h.GC[root, h'] => | ||||
|       (Node - h'.reachable[root]) in h'.reachable[h'.freeList] | ||||
| } | ||||
|  | ||||
| check Soundness1 for 3 expect 0 | ||||
| check Soundness2 for 3 expect 0 | ||||
| check Completeness for 3 expect 0 | ||||
							
								
								
									
										217
									
								
								samples/Alloy/views.als
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								samples/Alloy/views.als
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,217 @@ | ||||
| module examples/systems/views | ||||
|  | ||||
| /* | ||||
|  * Model of views in object-oriented programming. | ||||
|  * | ||||
|  * Two object references, called the view and the backing, | ||||
|  * are related by a view mechanism when changes to the | ||||
|  * backing are automatically propagated to the view. Note | ||||
|  * that the state of a view need not be a projection of the | ||||
|  * state of the backing; the keySet method of Map, for | ||||
|  * example, produces two view relationships, and for the | ||||
|  * one in which the map is modified by changes to the key | ||||
|  * set, the value of the new map cannot be determined from | ||||
|  * the key set. Note that in the iterator view mechanism, | ||||
|  * the iterator is by this definition the backing object, | ||||
|  * since changes are propagated from iterator to collection | ||||
|  * and not vice versa. Oddly, a reference may be a view of | ||||
|  * more than one backing: there can be two iterators on the | ||||
|  * same collection, eg. A reference cannot be a view under | ||||
|  * more than one view type. | ||||
|  * | ||||
|  * A reference is made dirty when it is a backing for a view | ||||
|  * with which it is no longer related by the view invariant. | ||||
|  * This usually happens when a view is modified, either | ||||
|  * directly or via another backing. For example, changing a | ||||
|  * collection directly when it has an iterator invalidates | ||||
|  * it, as does changing the collection through one iterator | ||||
|  * when there are others. | ||||
|  * | ||||
|  * More work is needed if we want to model more closely the | ||||
|  * failure of an iterator when its collection is invalidated. | ||||
|  * | ||||
|  * As a terminological convention, when there are two | ||||
|  * complementary view relationships, we will give them types | ||||
|  * t and t'. For example, KeySetView propagates from map to | ||||
|  * set, and KeySetView' propagates from set to map. | ||||
|  * | ||||
|  * author: Daniel Jackson | ||||
|  */ | ||||
|  | ||||
| open util/ordering[State] as so | ||||
| open util/relation as rel | ||||
|  | ||||
| sig Ref {} | ||||
| sig Object {} | ||||
|  | ||||
| -- t->b->v in views when v is view of type t of backing b | ||||
| -- dirty contains refs that have been invalidated | ||||
| sig State { | ||||
|   refs: set Ref, | ||||
|   obj: refs -> one Object, | ||||
|   views: ViewType -> refs -> refs, | ||||
|   dirty: set refs | ||||
| --  , anyviews: Ref -> Ref -- for visualization | ||||
|   } | ||||
| -- {anyviews = ViewType.views} | ||||
|  | ||||
| sig Map extends Object { | ||||
|   keys: set Ref, | ||||
|   map: keys -> one Ref | ||||
|   }{all s: State |  keys + Ref.map in s.refs} | ||||
| sig MapRef extends Ref {} | ||||
| fact {State.obj[MapRef] in Map} | ||||
|  | ||||
| sig Iterator extends Object { | ||||
|   left, done: set Ref, | ||||
|   lastRef: lone done | ||||
|   }{all s: State | done + left + lastRef in s.refs} | ||||
| sig IteratorRef extends Ref {} | ||||
| fact {State.obj[IteratorRef] in Iterator} | ||||
|  | ||||
| sig Set extends Object { | ||||
|   elts: set Ref | ||||
|   }{all s: State | elts in s.refs} | ||||
| sig SetRef extends Ref {} | ||||
| fact {State.obj[SetRef] in Set} | ||||
|  | ||||
| abstract sig ViewType {} | ||||
| one sig KeySetView, KeySetView', IteratorView extends ViewType {} | ||||
| fact ViewTypes { | ||||
|   State.views[KeySetView] in MapRef -> SetRef | ||||
|   State.views[KeySetView'] in SetRef -> MapRef | ||||
|   State.views[IteratorView] in IteratorRef -> SetRef | ||||
|   all s: State | s.views[KeySetView] = ~(s.views[KeySetView']) | ||||
|   } | ||||
|  | ||||
| /** | ||||
|  * mods is refs modified directly or by view mechanism | ||||
|  * doesn't handle possibility of modifying an object and its view at once? | ||||
|  * should we limit frame conds to non-dirty refs? | ||||
|  */ | ||||
| pred modifies [pre, post: State, rs: set Ref] { | ||||
|   let vr = pre.views[ViewType], mods = rs.*vr { | ||||
|     all r: pre.refs - mods | pre.obj[r] = post.obj[r] | ||||
|     all b: mods, v: pre.refs, t: ViewType | | ||||
|       b->v in pre.views[t] => viewFrame [t, pre.obj[v], post.obj[v], post.obj[b]] | ||||
|     post.dirty = pre.dirty + | ||||
|       {b: pre.refs | some v: Ref, t: ViewType | | ||||
|           b->v in pre.views[t] && !viewFrame [t, pre.obj[v], post.obj[v], post.obj[b]] | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
| pred allocates [pre, post: State, rs: set Ref] { | ||||
|   no rs & pre.refs | ||||
|   post.refs = pre.refs + rs | ||||
|   } | ||||
|  | ||||
| /**  | ||||
|  * models frame condition that limits change to view object from v to v' when backing object changes to b' | ||||
|  */ | ||||
| pred viewFrame [t: ViewType, v, v', b': Object] { | ||||
|   t in KeySetView => v'.elts = dom [b'.map] | ||||
|   t in KeySetView' => b'.elts = dom [v'.map] | ||||
|   t in KeySetView' => (b'.elts) <: (v.map) = (b'.elts) <: (v'.map) | ||||
|   t in IteratorView => v'.elts = b'.left + b'.done | ||||
|   } | ||||
|  | ||||
| pred MapRef.keySet [pre, post: State, setRefs: SetRef] { | ||||
|   post.obj[setRefs].elts = dom [pre.obj[this].map] | ||||
|   modifies [pre, post, none] | ||||
|   allocates [pre, post, setRefs] | ||||
|   post.views = pre.views + KeySetView->this->setRefs + KeySetView'->setRefs->this | ||||
|   } | ||||
|  | ||||
| pred MapRef.put [pre, post: State, k, v: Ref] { | ||||
|   post.obj[this].map = pre.obj[this].map ++ k->v | ||||
|   modifies [pre, post, this] | ||||
|   allocates [pre, post, none] | ||||
|   post.views = pre.views | ||||
|   } | ||||
|  | ||||
| pred SetRef.iterator [pre, post: State, iterRef: IteratorRef] { | ||||
|   let i = post.obj[iterRef] { | ||||
|     i.left = pre.obj[this].elts | ||||
|     no i.done + i.lastRef | ||||
|     } | ||||
|   modifies [pre,post,none] | ||||
|   allocates [pre, post, iterRef] | ||||
|   post.views = pre.views + IteratorView->iterRef->this | ||||
|   } | ||||
|  | ||||
| pred IteratorRef.remove [pre, post: State] { | ||||
|   let i = pre.obj[this], i' = post.obj[this] { | ||||
|     i'.left = i.left | ||||
|     i'.done = i.done - i.lastRef | ||||
|     no i'.lastRef | ||||
|     } | ||||
|   modifies [pre,post,this] | ||||
|   allocates [pre, post, none] | ||||
|   pre.views = post.views | ||||
|   } | ||||
|  | ||||
| pred IteratorRef.next [pre, post: State, ref: Ref] { | ||||
|   let i = pre.obj[this], i' = post.obj[this] { | ||||
|     ref in i.left | ||||
|     i'.left = i.left - ref | ||||
|     i'.done = i.done + ref | ||||
|     i'.lastRef = ref | ||||
|     } | ||||
|   modifies [pre, post, this] | ||||
|   allocates [pre, post, none] | ||||
|   pre.views = post.views | ||||
|   } | ||||
|  | ||||
| pred IteratorRef.hasNext [s: State] { | ||||
|   some s.obj[this].left | ||||
|   } | ||||
|  | ||||
| assert zippishOK { | ||||
|   all | ||||
|     ks, vs: SetRef, | ||||
|     m: MapRef, | ||||
|     ki, vi: IteratorRef, | ||||
|     k, v: Ref | | ||||
|     let s0=so/first, | ||||
|     s1=so/next[s0], | ||||
|     s2=so/next[s1], | ||||
|     s3=so/next[s2], | ||||
|     s4=so/next[s3], | ||||
|     s5=so/next[s4], | ||||
|     s6=so/next[s5], | ||||
|     s7=so/next[s6] | | ||||
|   ({ | ||||
|     precondition [s0, ks, vs, m] | ||||
|     no s0.dirty | ||||
|     ks.iterator [s0, s1, ki] | ||||
|     vs.iterator [s1, s2, vi] | ||||
|     ki.hasNext [s2] | ||||
|     vi.hasNext [s2] | ||||
|     ki.this/next [s2, s3, k] | ||||
|     vi.this/next [s3, s4, v] | ||||
|     m.put [s4, s5, k, v] | ||||
|     ki.remove [s5, s6] | ||||
|     vi.remove [s6, s7] | ||||
|   } => no State.dirty) | ||||
|   } | ||||
|  | ||||
| pred precondition [pre: State, ks, vs, m: Ref] { | ||||
|   // all these conditions and other errors discovered in scope of 6 but 8,3 | ||||
|   // in initial state, must have view invariants hold | ||||
|   (all t: ViewType, b, v: pre.refs | | ||||
|     b->v in pre.views[t] => viewFrame [t, pre.obj[v], pre.obj[v], pre.obj[b]]) | ||||
|   // sets are not aliases | ||||
| --  ks != vs | ||||
|   // sets are not views of map | ||||
| --  no (ks+vs)->m & ViewType.pre.views | ||||
|   // no iterator currently on either set | ||||
| --  no Ref->(ks+vs) & ViewType.pre.views | ||||
|   } | ||||
|  | ||||
| check zippishOK for 6 but 8 State, 3 ViewType expect 1 | ||||
|  | ||||
| /**  | ||||
|  * experiment with controlling heap size | ||||
|  */ | ||||
| fact {all s: State | #s.obj < 5} | ||||
							
								
								
									
										41
									
								
								samples/AspectJ/CacheAspect.aj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								samples/AspectJ/CacheAspect.aj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| package com.blogspot.miguelinlas3.aspectj.cache; | ||||
|  | ||||
| import java.util.Map; | ||||
| import java.util.WeakHashMap; | ||||
|  | ||||
| import org.aspectj.lang.JoinPoint; | ||||
|  | ||||
| import com.blogspot.miguelinlas3.aspectj.cache.marker.Cachable; | ||||
|  | ||||
| /** | ||||
|  * This simple aspect simulates the behaviour of a very simple cache | ||||
|  *   | ||||
|  * @author migue | ||||
|  * | ||||
|  */ | ||||
| public aspect CacheAspect { | ||||
|  | ||||
| 	public pointcut cache(Cachable cachable): execution(@Cachable * * (..)) && @annotation(cachable); | ||||
| 	 | ||||
| 	Object around(Cachable cachable): cache(cachable){ | ||||
| 	 | ||||
| 		String evaluatedKey = this.evaluateKey(cachable.scriptKey(), thisJoinPoint); | ||||
| 		 | ||||
| 		if(cache.containsKey(evaluatedKey)){ | ||||
| 			System.out.println("Cache hit for key " + evaluatedKey); | ||||
| 			return this.cache.get(evaluatedKey); | ||||
| 		} | ||||
| 		 | ||||
| 		System.out.println("Cache miss for key " + evaluatedKey); | ||||
| 		Object value = proceed(cachable); | ||||
| 		cache.put(evaluatedKey, value); | ||||
| 		return value; | ||||
| 	} | ||||
| 	 | ||||
| 	protected String evaluateKey(String key, JoinPoint joinPoint) { | ||||
| 		// TODO add some smart staff to allow simple scripting in @Cachable annotation | ||||
| 		return key; | ||||
| 	} | ||||
| 	 | ||||
| 	protected Map<String, Object> cache = new WeakHashMap<String, Object>(); | ||||
| } | ||||
							
								
								
									
										50
									
								
								samples/AspectJ/OptimizeRecursionCache.aj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								samples/AspectJ/OptimizeRecursionCache.aj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| package aspects.caching; | ||||
|  | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * Cache aspect for optimize recursive functions. | ||||
|  *  | ||||
|  * @author Migueli | ||||
|  * @date 05/11/2013 | ||||
|  * @version 1.0 | ||||
|  * | ||||
|  */ | ||||
| public abstract aspect OptimizeRecursionCache { | ||||
| 		 | ||||
| 	@SuppressWarnings("rawtypes") | ||||
| 	private Map _cache; | ||||
| 	 | ||||
| 	public OptimizeRecursionCache() { | ||||
| 		_cache = getCache(); | ||||
| 	} | ||||
| 	 | ||||
| 	@SuppressWarnings("rawtypes") | ||||
| 	abstract public Map getCache(); | ||||
| 	 | ||||
| 	abstract public pointcut operation(Object o); | ||||
|  | ||||
| 	pointcut topLevelOperation(Object o): operation(o) && !cflowbelow(operation(Object)); | ||||
|  | ||||
| 	before(Object o) : topLevelOperation(o) { | ||||
| 		System.out.println("Seeking value for " + o); | ||||
| 	} | ||||
|  | ||||
| 	Object around(Object o) : operation(o) { | ||||
| 		Object cachedValue = _cache.get(o); | ||||
| 		if (cachedValue != null) { | ||||
| 			System.out.println("Found cached value for " + o + ": " + cachedValue); | ||||
| 			return cachedValue; | ||||
| 		} | ||||
| 		return proceed(o); | ||||
| 	} | ||||
|  | ||||
| 	@SuppressWarnings("unchecked") | ||||
| 	after(Object o) returning(Object result) : topLevelOperation(o) { | ||||
| 		_cache.put(o, result); | ||||
| 	} | ||||
| 	 | ||||
| 	after(Object o) returning(Object result) : topLevelOperation(o) { | ||||
| 		System.out.println("cache size: " + _cache.size()); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										350
									
								
								samples/Assembly/FASM.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										350
									
								
								samples/Assembly/FASM.asm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,350 @@ | ||||
|  | ||||
| ; flat assembler interface for Win32 | ||||
| ; Copyright (c) 1999-2014, Tomasz Grysztar. | ||||
| ; All rights reserved. | ||||
|  | ||||
| 	format	PE console | ||||
|  | ||||
| section '.text' code readable executable | ||||
|  | ||||
| start: | ||||
|  | ||||
| 	mov	[con_handle],STD_OUTPUT_HANDLE | ||||
| 	mov	esi,_logo | ||||
| 	call	display_string | ||||
|  | ||||
| 	call	get_params | ||||
| 	jc	information | ||||
|  | ||||
| 	call	init_memory | ||||
|  | ||||
| 	mov	esi,_memory_prefix | ||||
| 	call	display_string | ||||
| 	mov	eax,[memory_end] | ||||
| 	sub	eax,[memory_start] | ||||
| 	add	eax,[additional_memory_end] | ||||
| 	sub	eax,[additional_memory] | ||||
| 	shr	eax,10 | ||||
| 	call	display_number | ||||
| 	mov	esi,_memory_suffix | ||||
| 	call	display_string | ||||
|  | ||||
| 	call	[GetTickCount] | ||||
| 	mov	[start_time],eax | ||||
|  | ||||
| 	call	preprocessor | ||||
| 	call	parser | ||||
| 	call	assembler | ||||
| 	call	formatter | ||||
|  | ||||
| 	call	display_user_messages | ||||
| 	movzx	eax,[current_pass] | ||||
| 	inc	eax | ||||
| 	call	display_number | ||||
| 	mov	esi,_passes_suffix | ||||
| 	call	display_string | ||||
| 	call	[GetTickCount] | ||||
| 	sub	eax,[start_time] | ||||
| 	xor	edx,edx | ||||
| 	mov	ebx,100 | ||||
| 	div	ebx | ||||
| 	or	eax,eax | ||||
| 	jz	display_bytes_count | ||||
| 	xor	edx,edx | ||||
| 	mov	ebx,10 | ||||
| 	div	ebx | ||||
| 	push	edx | ||||
| 	call	display_number | ||||
| 	mov	dl,'.' | ||||
| 	call	display_character | ||||
| 	pop	eax | ||||
| 	call	display_number | ||||
| 	mov	esi,_seconds_suffix | ||||
| 	call	display_string | ||||
|       display_bytes_count: | ||||
| 	mov	eax,[written_size] | ||||
| 	call	display_number | ||||
| 	mov	esi,_bytes_suffix | ||||
| 	call	display_string | ||||
| 	xor	al,al | ||||
| 	jmp	exit_program | ||||
|  | ||||
| information: | ||||
| 	mov	esi,_usage | ||||
| 	call	display_string | ||||
| 	mov	al,1 | ||||
| 	jmp	exit_program | ||||
|  | ||||
| get_params: | ||||
| 	mov	[input_file],0 | ||||
| 	mov	[output_file],0 | ||||
| 	mov	[symbols_file],0 | ||||
| 	mov	[memory_setting],0 | ||||
| 	mov	[passes_limit],100 | ||||
| 	call	[GetCommandLine] | ||||
| 	mov	esi,eax | ||||
| 	mov	edi,params | ||||
|     find_command_start: | ||||
| 	lodsb | ||||
| 	cmp	al,20h | ||||
| 	je	find_command_start | ||||
| 	cmp	al,22h | ||||
| 	je	skip_quoted_name | ||||
|     skip_name: | ||||
| 	lodsb | ||||
| 	cmp	al,20h | ||||
| 	je	find_param | ||||
| 	or	al,al | ||||
| 	jz	all_params | ||||
| 	jmp	skip_name | ||||
|     skip_quoted_name: | ||||
| 	lodsb | ||||
| 	cmp	al,22h | ||||
| 	je	find_param | ||||
| 	or	al,al | ||||
| 	jz	all_params | ||||
| 	jmp	skip_quoted_name | ||||
|     find_param: | ||||
| 	lodsb | ||||
| 	cmp	al,20h | ||||
| 	je	find_param | ||||
| 	cmp	al,'-' | ||||
| 	je	option_param | ||||
| 	cmp	al,0Dh | ||||
| 	je	all_params | ||||
| 	or	al,al | ||||
| 	jz	all_params | ||||
| 	cmp	[input_file],0 | ||||
| 	jne	get_output_file | ||||
| 	mov	[input_file],edi | ||||
| 	jmp	process_param | ||||
|       get_output_file: | ||||
| 	cmp	[output_file],0 | ||||
| 	jne	bad_params | ||||
| 	mov	[output_file],edi | ||||
|     process_param: | ||||
| 	cmp	al,22h | ||||
| 	je	string_param | ||||
|     copy_param: | ||||
| 	stosb | ||||
| 	lodsb | ||||
| 	cmp	al,20h | ||||
| 	je	param_end | ||||
| 	cmp	al,0Dh | ||||
| 	je	param_end | ||||
| 	or	al,al | ||||
| 	jz	param_end | ||||
| 	jmp	copy_param | ||||
|     string_param: | ||||
| 	lodsb | ||||
| 	cmp	al,22h | ||||
| 	je	string_param_end | ||||
| 	cmp	al,0Dh | ||||
| 	je	param_end | ||||
| 	or	al,al | ||||
| 	jz	param_end | ||||
| 	stosb | ||||
| 	jmp	string_param | ||||
|     option_param: | ||||
| 	lodsb | ||||
| 	cmp	al,'m' | ||||
| 	je	memory_option | ||||
| 	cmp	al,'M' | ||||
| 	je	memory_option | ||||
| 	cmp	al,'p' | ||||
| 	je	passes_option | ||||
| 	cmp	al,'P' | ||||
| 	je	passes_option | ||||
| 	cmp	al,'s' | ||||
| 	je	symbols_option | ||||
| 	cmp	al,'S' | ||||
| 	je	symbols_option | ||||
|     bad_params: | ||||
| 	stc | ||||
| 	ret | ||||
|     get_option_value: | ||||
| 	xor	eax,eax | ||||
| 	mov	edx,eax | ||||
|     get_option_digit: | ||||
| 	lodsb | ||||
| 	cmp	al,20h | ||||
| 	je	option_value_ok | ||||
| 	cmp	al,0Dh | ||||
| 	je	option_value_ok | ||||
| 	or	al,al | ||||
| 	jz	option_value_ok | ||||
| 	sub	al,30h | ||||
| 	jc	invalid_option_value | ||||
| 	cmp	al,9 | ||||
| 	ja	invalid_option_value | ||||
| 	imul	edx,10 | ||||
| 	jo	invalid_option_value | ||||
| 	add	edx,eax | ||||
| 	jc	invalid_option_value | ||||
| 	jmp	get_option_digit | ||||
|     option_value_ok: | ||||
| 	dec	esi | ||||
| 	clc | ||||
| 	ret | ||||
|     invalid_option_value: | ||||
| 	stc | ||||
| 	ret | ||||
|     memory_option: | ||||
| 	lodsb | ||||
| 	cmp	al,20h | ||||
| 	je	memory_option | ||||
| 	cmp	al,0Dh | ||||
| 	je	bad_params | ||||
| 	or	al,al | ||||
| 	jz	bad_params | ||||
| 	dec	esi | ||||
| 	call	get_option_value | ||||
| 	or	edx,edx | ||||
| 	jz	bad_params | ||||
| 	cmp	edx,1 shl (32-10) | ||||
| 	jae	bad_params | ||||
| 	mov	[memory_setting],edx | ||||
| 	jmp	find_param | ||||
|     passes_option: | ||||
| 	lodsb | ||||
| 	cmp	al,20h | ||||
| 	je	passes_option | ||||
| 	cmp	al,0Dh | ||||
| 	je	bad_params | ||||
| 	or	al,al | ||||
| 	jz	bad_params | ||||
| 	dec	esi | ||||
| 	call	get_option_value | ||||
| 	or	edx,edx | ||||
| 	jz	bad_params | ||||
| 	cmp	edx,10000h | ||||
| 	ja	bad_params | ||||
| 	mov	[passes_limit],dx | ||||
| 	jmp	find_param | ||||
|     symbols_option: | ||||
| 	mov	[symbols_file],edi | ||||
|       find_symbols_file_name: | ||||
| 	lodsb | ||||
| 	cmp	al,20h | ||||
| 	jne	process_param | ||||
| 	jmp	find_symbols_file_name | ||||
|     param_end: | ||||
| 	dec	esi | ||||
|     string_param_end: | ||||
| 	xor	al,al | ||||
| 	stosb | ||||
| 	jmp	find_param | ||||
|     all_params: | ||||
| 	cmp	[input_file],0 | ||||
| 	je	bad_params | ||||
| 	clc | ||||
| 	ret | ||||
|  | ||||
| include 'system.inc' | ||||
|  | ||||
| include '..\errors.inc' | ||||
| include '..\symbdump.inc' | ||||
| include '..\preproce.inc' | ||||
| include '..\parser.inc' | ||||
| include '..\exprpars.inc' | ||||
| include '..\assemble.inc' | ||||
| include '..\exprcalc.inc' | ||||
| include '..\formats.inc' | ||||
| include '..\x86_64.inc' | ||||
| include '..\avx.inc' | ||||
|  | ||||
| include '..\tables.inc' | ||||
| include '..\messages.inc' | ||||
|  | ||||
| section '.data' data readable writeable | ||||
|  | ||||
| include '..\version.inc' | ||||
|  | ||||
| _copyright db 'Copyright (c) 1999-2014, Tomasz Grysztar',0Dh,0Ah,0 | ||||
|  | ||||
| _logo db 'flat assembler  version ',VERSION_STRING,0 | ||||
| _usage db 0Dh,0Ah | ||||
|        db 'usage: fasm <source> [output]',0Dh,0Ah | ||||
|        db 'optional settings:',0Dh,0Ah | ||||
|        db ' -m <limit>    set the limit in kilobytes for the available memory',0Dh,0Ah | ||||
|        db ' -p <limit>    set the maximum allowed number of passes',0Dh,0Ah | ||||
|        db ' -s <file>     dump symbolic information for debugging',0Dh,0Ah | ||||
|        db 0 | ||||
| _memory_prefix db '  (',0 | ||||
| _memory_suffix db ' kilobytes memory)',0Dh,0Ah,0 | ||||
| _passes_suffix db ' passes, ',0 | ||||
| _seconds_suffix db ' seconds, ',0 | ||||
| _bytes_suffix db ' bytes.',0Dh,0Ah,0 | ||||
|  | ||||
| align 4 | ||||
|  | ||||
| include '..\variable.inc' | ||||
|  | ||||
| con_handle dd ? | ||||
| memory_setting dd ? | ||||
| start_time dd ? | ||||
| bytes_count dd ? | ||||
| displayed_count dd ? | ||||
| character db ? | ||||
| last_displayed rb 2 | ||||
|  | ||||
| params rb 1000h | ||||
| options rb 1000h | ||||
| buffer rb 4000h | ||||
|  | ||||
| stack 10000h | ||||
|  | ||||
| section '.idata' import data readable writeable | ||||
|  | ||||
|   dd 0,0,0,rva kernel_name,rva kernel_table | ||||
|   dd 0,0,0,0,0 | ||||
|  | ||||
|   kernel_table: | ||||
|     ExitProcess dd rva _ExitProcess | ||||
|     CreateFile dd rva _CreateFileA | ||||
|     ReadFile dd rva _ReadFile | ||||
|     WriteFile dd rva _WriteFile | ||||
|     CloseHandle dd rva _CloseHandle | ||||
|     SetFilePointer dd rva _SetFilePointer | ||||
|     GetCommandLine dd rva _GetCommandLineA | ||||
|     GetEnvironmentVariable dd rva _GetEnvironmentVariable | ||||
|     GetStdHandle dd rva _GetStdHandle | ||||
|     VirtualAlloc dd rva _VirtualAlloc | ||||
|     VirtualFree dd rva _VirtualFree | ||||
|     GetTickCount dd rva _GetTickCount | ||||
|     GetSystemTime dd rva _GetSystemTime | ||||
|     GlobalMemoryStatus dd rva _GlobalMemoryStatus | ||||
|     dd 0 | ||||
|  | ||||
|   kernel_name db 'KERNEL32.DLL',0 | ||||
|  | ||||
|   _ExitProcess dw 0 | ||||
|     db 'ExitProcess',0 | ||||
|   _CreateFileA dw 0 | ||||
|     db 'CreateFileA',0 | ||||
|   _ReadFile dw 0 | ||||
|     db 'ReadFile',0 | ||||
|   _WriteFile dw 0 | ||||
|     db 'WriteFile',0 | ||||
|   _CloseHandle dw 0 | ||||
|     db 'CloseHandle',0 | ||||
|   _SetFilePointer dw 0 | ||||
|     db 'SetFilePointer',0 | ||||
|   _GetCommandLineA dw 0 | ||||
|     db 'GetCommandLineA',0 | ||||
|   _GetEnvironmentVariable dw 0 | ||||
|     db 'GetEnvironmentVariableA',0 | ||||
|   _GetStdHandle dw 0 | ||||
|     db 'GetStdHandle',0 | ||||
|   _VirtualAlloc dw 0 | ||||
|     db 'VirtualAlloc',0 | ||||
|   _VirtualFree dw 0 | ||||
|     db 'VirtualFree',0 | ||||
|   _GetTickCount dw 0 | ||||
|     db 'GetTickCount',0 | ||||
|   _GetSystemTime dw 0 | ||||
|     db 'GetSystemTime',0 | ||||
|   _GlobalMemoryStatus dw 0 | ||||
|     db 'GlobalMemoryStatus',0 | ||||
|  | ||||
| section '.reloc' fixups data readable discardable | ||||
							
								
								
									
										25
									
								
								samples/BlitzMax/sample.bmx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								samples/BlitzMax/sample.bmx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| SuperStrict | ||||
|  | ||||
| Framework Brl.StandardIO | ||||
|  | ||||
| Type TMyType | ||||
| 	Field property:int | ||||
|  | ||||
| 	Function A:int(param:int) | ||||
| 		'do nothing | ||||
| 	End Function | ||||
|  | ||||
| 	Method B:int(param:int) | ||||
| 		'do nothing | ||||
| 	End Method | ||||
| End Type | ||||
|  | ||||
|  | ||||
| Global my:TMyType = new TMyType | ||||
| ?Win32 | ||||
| 	my.A() | ||||
| 	my.B() | ||||
| ?Linux | ||||
| 	my.B() | ||||
| 	my.A() | ||||
| ? | ||||
							
								
								
									
										530
									
								
								samples/C++/Math.inl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										530
									
								
								samples/C++/Math.inl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,530 @@ | ||||
| /* | ||||
| =========================================================================== | ||||
| The Open Game Libraries. | ||||
| Copyright (C) 2007-2010 Lusito Software | ||||
|  | ||||
| Author:  Santo Pfingsten (TTK-Bandit) | ||||
| Purpose: Math namespace | ||||
| ----------------------------------------- | ||||
|  | ||||
| This software is provided 'as-is', without any express or implied | ||||
| warranty. In no event will the authors be held liable for any damages | ||||
| arising from the use of this software. | ||||
|  | ||||
| Permission is granted to anyone to use this software for any purpose, | ||||
| including commercial applications, and to alter it and redistribute it | ||||
| freely, subject to the following restrictions: | ||||
|  | ||||
| 1. The origin of this software must not be misrepresented; you must not | ||||
|    claim that you wrote the original software. If you use this software | ||||
|    in a product, an acknowledgment in the product documentation would be | ||||
|    appreciated but is not required. | ||||
|  | ||||
| 2. Altered source versions must be plainly marked as such, and must not be | ||||
|    misrepresented as being the original software. | ||||
|  | ||||
| 3. This notice may not be removed or altered from any source distribution. | ||||
| =========================================================================== | ||||
| */ | ||||
|  | ||||
| #ifndef __OG_MATH_INL__ | ||||
| #define __OG_MATH_INL__ | ||||
|  | ||||
| namespace og { | ||||
|  | ||||
| /* | ||||
| ============================================================================== | ||||
|  | ||||
|   Math | ||||
|  | ||||
| ============================================================================== | ||||
| */ | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Abs | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE int Math::Abs( int i ) { | ||||
| #if 1 | ||||
| 	if ( i & 0x80000000 ) | ||||
| 		return 0x80000000 - (i & MASK_SIGNED); | ||||
| 	return i; | ||||
| #else | ||||
|    int y = x >> 31; | ||||
|    return ( ( x ^ y ) - y ); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Fabs | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::Fabs( float f ) { | ||||
| #if 1 | ||||
| 	uInt *pf = reinterpret_cast<uInt*>(&f); | ||||
| 	*(pf) &= MASK_SIGNED; | ||||
| 	return f; | ||||
| #else | ||||
| 	return fabsf( f ); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Round | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::Round( float f ) { | ||||
| 	return floorf( f + 0.5f ); | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Floor | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::Floor( float f ) { | ||||
| 	return floorf( f ); | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Ceil | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::Ceil( float f ) { | ||||
| 	return ceilf( f ); | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Ftoi | ||||
|  | ||||
| ok since this is SSE, why should the other ftoi be the faster one ? | ||||
| and: we might need to add a check for SSE extensions.. | ||||
| because sse isn't *really* faster (I actually read that GCC does not handle | ||||
| SSE extensions perfectly. I'll find the link and send it to you when you're online) | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE int Math::Ftoi( float f ) { | ||||
| 	//! @todo	needs testing | ||||
| 	// note: sse function cvttss2si | ||||
| #if OG_ASM_MSVC | ||||
| 	int i; | ||||
| #if defined(OG_FTOI_USE_SSE) | ||||
| 	if( SysInfo::cpu.general.SSE ) { | ||||
| 		__asm cvttss2si	eax, f | ||||
| 		__asm mov		i, eax | ||||
| 		return i; | ||||
| 	} else | ||||
| #endif | ||||
| 	{ | ||||
| 		__asm fld		f | ||||
| 		__asm fistp		i | ||||
| 		//__asm mov eax, i // do we need this ? O_o | ||||
| 	} | ||||
| 	return i; | ||||
| #elif OG_ASM_GNU | ||||
| 	int i; | ||||
| #if defined(OG_FTOI_USE_SSE) | ||||
| 	if( SysInfo::cpu.general.SSE ) { | ||||
| 		__asm__ __volatile__( "cvttss2si %1    \n\t" | ||||
| 			: "=m" (i) | ||||
| 			: "m" (f) | ||||
| 		); | ||||
| 	} else | ||||
| #endif | ||||
| 	{ | ||||
| 		__asm__ __volatile__( "flds %1    \n\t" | ||||
| 							  "fistpl %0  \n\t" | ||||
| 			: "=m" (i) | ||||
| 			: "m" (f) | ||||
| 		); | ||||
| 	} | ||||
| 	return i; | ||||
| #else | ||||
| 	// we use c++ cast instead of c cast (not sure why id did that) | ||||
| 	return static_cast<int>(f); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::FtoiFast | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE int Math::FtoiFast( float f ) { | ||||
| #if OG_ASM_MSVC | ||||
| 	int i; | ||||
| 	__asm fld		f | ||||
| 	__asm fistp		i | ||||
| 	//__asm mov eax, i // do we need this ? O_o | ||||
| 	return i; | ||||
| #elif OG_ASM_GNU | ||||
| 	int i; | ||||
| 	__asm__ __volatile__( "flds %1    \n\t" | ||||
| 						  "fistpl %0  \n\t" | ||||
| 		: "=m" (i) | ||||
| 		: "m" (f) | ||||
| 	); | ||||
| 	return i; | ||||
| #else | ||||
| 	// we use c++ cast instead of c cast (not sure why id did that) | ||||
| 	return static_cast<int>(f); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Ftol | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE long Math::Ftol( float f ) { | ||||
| #if OG_ASM_MSVC | ||||
| 	long i; | ||||
| 	__asm fld		f | ||||
| 	__asm fistp		i | ||||
| 	//__asm mov eax, i // do we need this ? O_o | ||||
| 	return i; | ||||
| #elif OG_ASM_GNU | ||||
| 	long i; | ||||
| 	__asm__ __volatile__( "flds %1    \n\t" | ||||
| 						  "fistpl %0  \n\t" | ||||
| 		: "=m" (i) | ||||
| 		: "m" (f) | ||||
| 	); | ||||
| 	return i; | ||||
| #else | ||||
| 	// we use c++ cast instead of c cast (not sure why id did that) | ||||
| 	return static_cast<long>(f); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Sign | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::Sign( float f )	{ | ||||
| 	if ( f > 0.0f ) | ||||
| 		return 1.0f; | ||||
| 	if ( f < 0.0f ) | ||||
| 		return -1.0f; | ||||
| 	return 0.0f; | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Fmod | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::Fmod( float numerator, float denominator ) { | ||||
| 	return fmodf( numerator, denominator ); | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Modf | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::Modf( float f, float& i ) { | ||||
| 	return modff( f, &i ); | ||||
| } | ||||
| OG_INLINE float Math::Modf( float f ) { | ||||
| 	float i; | ||||
| 	return modff( f, &i ); | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Sqrt | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::Sqrt( float f ) { | ||||
| 	return sqrtf( f ); | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::InvSqrt | ||||
|  | ||||
| Cannot be 0.0f | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::InvSqrt( float f ) { | ||||
| 	OG_ASSERT( f != 0.0f ); | ||||
| 	return 1.0f / sqrtf( f ); | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::RSqrt | ||||
|  | ||||
| Can be 0.0f | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::RSqrt( float f ) { | ||||
| 	float g = 0.5f * f; | ||||
| 	int i = *reinterpret_cast<int *>(&f); | ||||
|  | ||||
| 	// do a guess | ||||
| 	i = 0x5f375a86 - ( i>>1 ); | ||||
| 	f = *reinterpret_cast<float *>(&i); | ||||
|  | ||||
| 	// Newtons calculation | ||||
| 	f = f * ( 1.5f - g * f * f ); | ||||
| 	return f; | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Log/Log2/Log10 | ||||
|  | ||||
| Log of 0 is bad. | ||||
| I've also heard you're not really | ||||
| supposed to do log of negatives, yet | ||||
| they work fine. | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::Log( float f ) { | ||||
| 	OG_ASSERT( f != 0.0f ); | ||||
| 	return logf( f ); | ||||
| } | ||||
| OG_INLINE float Math::Log2( float f ) { | ||||
| 	OG_ASSERT( f != 0.0f ); | ||||
| 	return INV_LN_2 * logf( f ); | ||||
| } | ||||
| OG_INLINE float Math::Log10( float f ) { | ||||
| 	OG_ASSERT( f != 0.0f ); | ||||
| 	return INV_LN_10 * logf( f ); | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Pow | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::Pow( float base, float exp ) { | ||||
| 	return powf( base, exp ); | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Exp | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::Exp( float f ) { | ||||
| 	return expf( f ); | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::IsPowerOfTwo | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE bool Math::IsPowerOfTwo( int x ) { | ||||
| 	// This is the faster of the two known methods | ||||
| 	// with the x > 0 check moved to the beginning | ||||
| 	return x > 0 && ( x & ( x - 1 ) ) == 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::HigherPowerOfTwo | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE int Math::HigherPowerOfTwo( int x ) { | ||||
| 	x--; | ||||
| 	x |= x >> 1; | ||||
| 	x |= x >> 2; | ||||
| 	x |= x >> 4; | ||||
| 	x |= x >> 8; | ||||
| 	x |= x >> 16; | ||||
| 	return x + 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::LowerPowerOfTwo | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE int Math::LowerPowerOfTwo( int x ) { | ||||
| 	return HigherPowerOfTwo( x ) >> 1; | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::FloorPowerOfTwo | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE int Math::FloorPowerOfTwo( int x ) { | ||||
| 	return IsPowerOfTwo( x ) ? x : LowerPowerOfTwo( x ); | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::CeilPowerOfTwo | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE int Math::CeilPowerOfTwo( int x ) { | ||||
| 	return IsPowerOfTwo( x ) ? x : HigherPowerOfTwo( x ); | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::ClosestPowerOfTwo | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE int Math::ClosestPowerOfTwo( int x ) { | ||||
| 	if ( IsPowerOfTwo( x ) ) | ||||
| 		return x; | ||||
| 	int high = HigherPowerOfTwo( x ); | ||||
| 	int low = high >> 1; | ||||
| 	return ((high-x) < (x-low)) ? high : low; | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Digits | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE int Math::Digits( int x ) { | ||||
| 	int digits = 1; | ||||
| 	int step = 10; | ||||
| 	while (step <= x) { | ||||
| 		digits++; | ||||
| 		step *= 10; | ||||
| 	} | ||||
| 	return digits; | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Sin/ASin | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::Sin( float f ) { | ||||
| 	return sinf( f ); | ||||
| } | ||||
| OG_INLINE float Math::ASin( float f ) { | ||||
| 	if ( f <= -1.0f ) | ||||
| 		return -HALF_PI; | ||||
| 	if ( f >= 1.0f ) | ||||
| 		return HALF_PI; | ||||
| 	return asinf( f ); | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Cos/ACos | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::Cos( float f ) { | ||||
| 	return cosf( f ); | ||||
| } | ||||
| OG_INLINE float Math::ACos( float f ) { | ||||
| 	if ( f <= -1.0f ) | ||||
| 		return PI; | ||||
| 	if ( f >= 1.0f ) | ||||
| 		return 0.0f; | ||||
| 	return acosf( f ); | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Tan/ATan | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::Tan( float f ) { | ||||
| 	return tanf( f ); | ||||
| } | ||||
| OG_INLINE float Math::ATan( float f ) { | ||||
| 	return atanf( f ); | ||||
| } | ||||
| OG_INLINE float Math::ATan( float f1, float f2 ) { | ||||
| 	return atan2f( f1, f2 ); | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::SinCos | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE void Math::SinCos( float f, float &s, float &c ) { | ||||
| #if OG_ASM_MSVC | ||||
| 	// sometimes assembler is just waaayy faster | ||||
| 	_asm { | ||||
| 		fld		f | ||||
| 		fsincos | ||||
| 		mov		ecx, c | ||||
| 		mov		edx, s | ||||
| 		fstp	dword ptr [ecx] | ||||
| 		fstp	dword ptr [edx] | ||||
| 	} | ||||
| #elif OG_ASM_GNU | ||||
| 	asm ("fsincos" : "=t" (c), "=u" (s) : "0" (f)); | ||||
| #else | ||||
| 	s = Sin(f); | ||||
| 	c = Sqrt( 1.0f - s * s ); // faster than calling Cos(f) | ||||
| #endif | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Deg2Rad | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::Deg2Rad( float f ) { | ||||
| 	return f * DEG_TO_RAD; | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Rad2Deg | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::Rad2Deg( float f ) { | ||||
| 	return f * RAD_TO_DEG; | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Square | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::Square( float v ) { | ||||
| 	return v * v; | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Cube | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE float Math::Cube( float v ) { | ||||
| 	return v * v * v; | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Sec2Ms | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE int Math::Sec2Ms( int sec ) { | ||||
| 	return sec * 1000; | ||||
| } | ||||
|  | ||||
| /* | ||||
| ================ | ||||
| Math::Ms2Sec | ||||
| ================ | ||||
| */ | ||||
| OG_INLINE int Math::Ms2Sec( int ms ) { | ||||
| 	return FtoiFast( ms * 0.001f ); | ||||
| } | ||||
|  | ||||
| } | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										664
									
								
								samples/C++/epoll_reactor.ipp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										664
									
								
								samples/C++/epoll_reactor.ipp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,664 @@ | ||||
| // | ||||
| // detail/impl/epoll_reactor.ipp | ||||
| // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
| // | ||||
| // Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) | ||||
| // | ||||
| // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||
| // | ||||
|  | ||||
| #ifndef BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP | ||||
| #define BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP | ||||
|  | ||||
| #if defined(_MSC_VER) && (_MSC_VER >= 1200) | ||||
| # pragma once | ||||
| #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) | ||||
|  | ||||
| #include <boost/asio/detail/config.hpp> | ||||
|  | ||||
| #if defined(BOOST_ASIO_HAS_EPOLL) | ||||
|  | ||||
| #include <cstddef> | ||||
| #include <sys/epoll.h> | ||||
| #include <boost/asio/detail/epoll_reactor.hpp> | ||||
| #include <boost/asio/detail/throw_error.hpp> | ||||
| #include <boost/asio/error.hpp> | ||||
|  | ||||
| #if defined(BOOST_ASIO_HAS_TIMERFD) | ||||
| # include <sys/timerfd.h> | ||||
| #endif // defined(BOOST_ASIO_HAS_TIMERFD) | ||||
|  | ||||
| #include <boost/asio/detail/push_options.hpp> | ||||
|  | ||||
| namespace boost { | ||||
| namespace asio { | ||||
| namespace detail { | ||||
|  | ||||
| epoll_reactor::epoll_reactor(boost::asio::io_service& io_service) | ||||
|   : boost::asio::detail::service_base<epoll_reactor>(io_service), | ||||
|     io_service_(use_service<io_service_impl>(io_service)), | ||||
|     mutex_(), | ||||
|     interrupter_(), | ||||
|     epoll_fd_(do_epoll_create()), | ||||
|     timer_fd_(do_timerfd_create()), | ||||
|     shutdown_(false) | ||||
| { | ||||
|   // Add the interrupter's descriptor to epoll. | ||||
|   epoll_event ev = { 0, { 0 } }; | ||||
|   ev.events = EPOLLIN | EPOLLERR | EPOLLET; | ||||
|   ev.data.ptr = &interrupter_; | ||||
|   epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev); | ||||
|   interrupter_.interrupt(); | ||||
|  | ||||
|   // Add the timer descriptor to epoll. | ||||
|   if (timer_fd_ != -1) | ||||
|   { | ||||
|     ev.events = EPOLLIN | EPOLLERR; | ||||
|     ev.data.ptr = &timer_fd_; | ||||
|     epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev); | ||||
|   } | ||||
| } | ||||
|  | ||||
| epoll_reactor::~epoll_reactor() | ||||
| { | ||||
|   if (epoll_fd_ != -1) | ||||
|     close(epoll_fd_); | ||||
|   if (timer_fd_ != -1) | ||||
|     close(timer_fd_); | ||||
| } | ||||
|  | ||||
| void epoll_reactor::shutdown_service() | ||||
| { | ||||
|   mutex::scoped_lock lock(mutex_); | ||||
|   shutdown_ = true; | ||||
|   lock.unlock(); | ||||
|  | ||||
|   op_queue<operation> ops; | ||||
|  | ||||
|   while (descriptor_state* state = registered_descriptors_.first()) | ||||
|   { | ||||
|     for (int i = 0; i < max_ops; ++i) | ||||
|       ops.push(state->op_queue_[i]); | ||||
|     state->shutdown_ = true; | ||||
|     registered_descriptors_.free(state); | ||||
|   } | ||||
|  | ||||
|   timer_queues_.get_all_timers(ops); | ||||
|  | ||||
|   io_service_.abandon_operations(ops); | ||||
| } | ||||
|  | ||||
| void epoll_reactor::fork_service(boost::asio::io_service::fork_event fork_ev) | ||||
| { | ||||
|   if (fork_ev == boost::asio::io_service::fork_child) | ||||
|   { | ||||
|     if (epoll_fd_ != -1) | ||||
|       ::close(epoll_fd_); | ||||
|     epoll_fd_ = -1; | ||||
|     epoll_fd_ = do_epoll_create(); | ||||
|  | ||||
|     if (timer_fd_ != -1) | ||||
|       ::close(timer_fd_); | ||||
|     timer_fd_ = -1; | ||||
|     timer_fd_ = do_timerfd_create(); | ||||
|  | ||||
|     interrupter_.recreate(); | ||||
|  | ||||
|     // Add the interrupter's descriptor to epoll. | ||||
|     epoll_event ev = { 0, { 0 } }; | ||||
|     ev.events = EPOLLIN | EPOLLERR | EPOLLET; | ||||
|     ev.data.ptr = &interrupter_; | ||||
|     epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev); | ||||
|     interrupter_.interrupt(); | ||||
|  | ||||
|     // Add the timer descriptor to epoll. | ||||
|     if (timer_fd_ != -1) | ||||
|     { | ||||
|       ev.events = EPOLLIN | EPOLLERR; | ||||
|       ev.data.ptr = &timer_fd_; | ||||
|       epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev); | ||||
|     } | ||||
|  | ||||
|     update_timeout(); | ||||
|  | ||||
|     // Re-register all descriptors with epoll. | ||||
|     mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); | ||||
|     for (descriptor_state* state = registered_descriptors_.first(); | ||||
|         state != 0; state = state->next_) | ||||
|     { | ||||
|       ev.events = state->registered_events_; | ||||
|       ev.data.ptr = state; | ||||
|       int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, state->descriptor_, &ev); | ||||
|       if (result != 0) | ||||
|       { | ||||
|         boost::system::error_code ec(errno, | ||||
|             boost::asio::error::get_system_category()); | ||||
|         boost::asio::detail::throw_error(ec, "epoll re-registration"); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| void epoll_reactor::init_task() | ||||
| { | ||||
|   io_service_.init_task(); | ||||
| } | ||||
|  | ||||
| int epoll_reactor::register_descriptor(socket_type descriptor, | ||||
|     epoll_reactor::per_descriptor_data& descriptor_data) | ||||
| { | ||||
|   descriptor_data = allocate_descriptor_state(); | ||||
|  | ||||
|   { | ||||
|     mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); | ||||
|  | ||||
|     descriptor_data->reactor_ = this; | ||||
|     descriptor_data->descriptor_ = descriptor; | ||||
|     descriptor_data->shutdown_ = false; | ||||
|   } | ||||
|  | ||||
|   epoll_event ev = { 0, { 0 } }; | ||||
|   ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLPRI | EPOLLET; | ||||
|   descriptor_data->registered_events_ = ev.events; | ||||
|   ev.data.ptr = descriptor_data; | ||||
|   int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); | ||||
|   if (result != 0) | ||||
|     return errno; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| int epoll_reactor::register_internal_descriptor( | ||||
|     int op_type, socket_type descriptor, | ||||
|     epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op) | ||||
| { | ||||
|   descriptor_data = allocate_descriptor_state(); | ||||
|  | ||||
|   { | ||||
|     mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); | ||||
|  | ||||
|     descriptor_data->reactor_ = this; | ||||
|     descriptor_data->descriptor_ = descriptor; | ||||
|     descriptor_data->shutdown_ = false; | ||||
|     descriptor_data->op_queue_[op_type].push(op); | ||||
|   } | ||||
|  | ||||
|   epoll_event ev = { 0, { 0 } }; | ||||
|   ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLPRI | EPOLLET; | ||||
|   descriptor_data->registered_events_ = ev.events; | ||||
|   ev.data.ptr = descriptor_data; | ||||
|   int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); | ||||
|   if (result != 0) | ||||
|     return errno; | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| void epoll_reactor::move_descriptor(socket_type, | ||||
|     epoll_reactor::per_descriptor_data& target_descriptor_data, | ||||
|     epoll_reactor::per_descriptor_data& source_descriptor_data) | ||||
| { | ||||
|   target_descriptor_data = source_descriptor_data; | ||||
|   source_descriptor_data = 0; | ||||
| } | ||||
|  | ||||
| void epoll_reactor::start_op(int op_type, socket_type descriptor, | ||||
|     epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op, | ||||
|     bool is_continuation, bool allow_speculative) | ||||
| { | ||||
|   if (!descriptor_data) | ||||
|   { | ||||
|     op->ec_ = boost::asio::error::bad_descriptor; | ||||
|     post_immediate_completion(op, is_continuation); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); | ||||
|  | ||||
|   if (descriptor_data->shutdown_) | ||||
|   { | ||||
|     post_immediate_completion(op, is_continuation); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   if (descriptor_data->op_queue_[op_type].empty()) | ||||
|   { | ||||
|     if (allow_speculative | ||||
|         && (op_type != read_op | ||||
|           || descriptor_data->op_queue_[except_op].empty())) | ||||
|     { | ||||
|       if (op->perform()) | ||||
|       { | ||||
|         descriptor_lock.unlock(); | ||||
|         io_service_.post_immediate_completion(op, is_continuation); | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       if (op_type == write_op) | ||||
|       { | ||||
|         if ((descriptor_data->registered_events_ & EPOLLOUT) == 0) | ||||
|         { | ||||
|           epoll_event ev = { 0, { 0 } }; | ||||
|           ev.events = descriptor_data->registered_events_ | EPOLLOUT; | ||||
|           ev.data.ptr = descriptor_data; | ||||
|           if (epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev) == 0) | ||||
|           { | ||||
|             descriptor_data->registered_events_ |= ev.events; | ||||
|           } | ||||
|           else | ||||
|           { | ||||
|             op->ec_ = boost::system::error_code(errno, | ||||
|                 boost::asio::error::get_system_category()); | ||||
|             io_service_.post_immediate_completion(op, is_continuation); | ||||
|             return; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|       if (op_type == write_op) | ||||
|       { | ||||
|         descriptor_data->registered_events_ |= EPOLLOUT; | ||||
|       } | ||||
|  | ||||
|       epoll_event ev = { 0, { 0 } }; | ||||
|       ev.events = descriptor_data->registered_events_; | ||||
|       ev.data.ptr = descriptor_data; | ||||
|       epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   descriptor_data->op_queue_[op_type].push(op); | ||||
|   io_service_.work_started(); | ||||
| } | ||||
|  | ||||
| void epoll_reactor::cancel_ops(socket_type, | ||||
|     epoll_reactor::per_descriptor_data& descriptor_data) | ||||
| { | ||||
|   if (!descriptor_data) | ||||
|     return; | ||||
|  | ||||
|   mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); | ||||
|  | ||||
|   op_queue<operation> ops; | ||||
|   for (int i = 0; i < max_ops; ++i) | ||||
|   { | ||||
|     while (reactor_op* op = descriptor_data->op_queue_[i].front()) | ||||
|     { | ||||
|       op->ec_ = boost::asio::error::operation_aborted; | ||||
|       descriptor_data->op_queue_[i].pop(); | ||||
|       ops.push(op); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   descriptor_lock.unlock(); | ||||
|  | ||||
|   io_service_.post_deferred_completions(ops); | ||||
| } | ||||
|  | ||||
| void epoll_reactor::deregister_descriptor(socket_type descriptor, | ||||
|     epoll_reactor::per_descriptor_data& descriptor_data, bool closing) | ||||
| { | ||||
|   if (!descriptor_data) | ||||
|     return; | ||||
|  | ||||
|   mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); | ||||
|  | ||||
|   if (!descriptor_data->shutdown_) | ||||
|   { | ||||
|     if (closing) | ||||
|     { | ||||
|       // The descriptor will be automatically removed from the epoll set when | ||||
|       // it is closed. | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|       epoll_event ev = { 0, { 0 } }; | ||||
|       epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev); | ||||
|     } | ||||
|  | ||||
|     op_queue<operation> ops; | ||||
|     for (int i = 0; i < max_ops; ++i) | ||||
|     { | ||||
|       while (reactor_op* op = descriptor_data->op_queue_[i].front()) | ||||
|       { | ||||
|         op->ec_ = boost::asio::error::operation_aborted; | ||||
|         descriptor_data->op_queue_[i].pop(); | ||||
|         ops.push(op); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     descriptor_data->descriptor_ = -1; | ||||
|     descriptor_data->shutdown_ = true; | ||||
|  | ||||
|     descriptor_lock.unlock(); | ||||
|  | ||||
|     free_descriptor_state(descriptor_data); | ||||
|     descriptor_data = 0; | ||||
|  | ||||
|     io_service_.post_deferred_completions(ops); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void epoll_reactor::deregister_internal_descriptor(socket_type descriptor, | ||||
|     epoll_reactor::per_descriptor_data& descriptor_data) | ||||
| { | ||||
|   if (!descriptor_data) | ||||
|     return; | ||||
|  | ||||
|   mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); | ||||
|  | ||||
|   if (!descriptor_data->shutdown_) | ||||
|   { | ||||
|     epoll_event ev = { 0, { 0 } }; | ||||
|     epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev); | ||||
|  | ||||
|     op_queue<operation> ops; | ||||
|     for (int i = 0; i < max_ops; ++i) | ||||
|       ops.push(descriptor_data->op_queue_[i]); | ||||
|  | ||||
|     descriptor_data->descriptor_ = -1; | ||||
|     descriptor_data->shutdown_ = true; | ||||
|  | ||||
|     descriptor_lock.unlock(); | ||||
|  | ||||
|     free_descriptor_state(descriptor_data); | ||||
|     descriptor_data = 0; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void epoll_reactor::run(bool block, op_queue<operation>& ops) | ||||
| { | ||||
|   // This code relies on the fact that the task_io_service queues the reactor | ||||
|   // task behind all descriptor operations generated by this function. This | ||||
|   // means, that by the time we reach this point, any previously returned | ||||
|   // descriptor operations have already been dequeued. Therefore it is now safe | ||||
|   // for us to reuse and return them for the task_io_service to queue again. | ||||
|  | ||||
|   // Calculate a timeout only if timerfd is not used. | ||||
|   int timeout; | ||||
|   if (timer_fd_ != -1) | ||||
|     timeout = block ? -1 : 0; | ||||
|   else | ||||
|   { | ||||
|     mutex::scoped_lock lock(mutex_); | ||||
|     timeout = block ? get_timeout() : 0; | ||||
|   } | ||||
|  | ||||
|   // Block on the epoll descriptor. | ||||
|   epoll_event events[128]; | ||||
|   int num_events = epoll_wait(epoll_fd_, events, 128, timeout); | ||||
|  | ||||
| #if defined(BOOST_ASIO_HAS_TIMERFD) | ||||
|   bool check_timers = (timer_fd_ == -1); | ||||
| #else // defined(BOOST_ASIO_HAS_TIMERFD) | ||||
|   bool check_timers = true; | ||||
| #endif // defined(BOOST_ASIO_HAS_TIMERFD) | ||||
|  | ||||
|   // Dispatch the waiting events. | ||||
|   for (int i = 0; i < num_events; ++i) | ||||
|   { | ||||
|     void* ptr = events[i].data.ptr; | ||||
|     if (ptr == &interrupter_) | ||||
|     { | ||||
|       // No need to reset the interrupter since we're leaving the descriptor | ||||
|       // in a ready-to-read state and relying on edge-triggered notifications | ||||
|       // to make it so that we only get woken up when the descriptor's epoll | ||||
|       // registration is updated. | ||||
|  | ||||
| #if defined(BOOST_ASIO_HAS_TIMERFD) | ||||
|       if (timer_fd_ == -1) | ||||
|         check_timers = true; | ||||
| #else // defined(BOOST_ASIO_HAS_TIMERFD) | ||||
|       check_timers = true; | ||||
| #endif // defined(BOOST_ASIO_HAS_TIMERFD) | ||||
|     } | ||||
| #if defined(BOOST_ASIO_HAS_TIMERFD) | ||||
|     else if (ptr == &timer_fd_) | ||||
|     { | ||||
|       check_timers = true; | ||||
|     } | ||||
| #endif // defined(BOOST_ASIO_HAS_TIMERFD) | ||||
|     else | ||||
|     { | ||||
|       // The descriptor operation doesn't count as work in and of itself, so we | ||||
|       // don't call work_started() here. This still allows the io_service to | ||||
|       // stop if the only remaining operations are descriptor operations. | ||||
|       descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr); | ||||
|       descriptor_data->set_ready_events(events[i].events); | ||||
|       ops.push(descriptor_data); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (check_timers) | ||||
|   { | ||||
|     mutex::scoped_lock common_lock(mutex_); | ||||
|     timer_queues_.get_ready_timers(ops); | ||||
|  | ||||
| #if defined(BOOST_ASIO_HAS_TIMERFD) | ||||
|     if (timer_fd_ != -1) | ||||
|     { | ||||
|       itimerspec new_timeout; | ||||
|       itimerspec old_timeout; | ||||
|       int flags = get_timeout(new_timeout); | ||||
|       timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); | ||||
|     } | ||||
| #endif // defined(BOOST_ASIO_HAS_TIMERFD) | ||||
|   } | ||||
| } | ||||
|  | ||||
| void epoll_reactor::interrupt() | ||||
| { | ||||
|   epoll_event ev = { 0, { 0 } }; | ||||
|   ev.events = EPOLLIN | EPOLLERR | EPOLLET; | ||||
|   ev.data.ptr = &interrupter_; | ||||
|   epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev); | ||||
| } | ||||
|  | ||||
| int epoll_reactor::do_epoll_create() | ||||
| { | ||||
| #if defined(EPOLL_CLOEXEC) | ||||
|   int fd = epoll_create1(EPOLL_CLOEXEC); | ||||
| #else // defined(EPOLL_CLOEXEC) | ||||
|   int fd = -1; | ||||
|   errno = EINVAL; | ||||
| #endif // defined(EPOLL_CLOEXEC) | ||||
|  | ||||
|   if (fd == -1 && (errno == EINVAL || errno == ENOSYS)) | ||||
|   { | ||||
|     fd = epoll_create(epoll_size); | ||||
|     if (fd != -1) | ||||
|       ::fcntl(fd, F_SETFD, FD_CLOEXEC); | ||||
|   } | ||||
|  | ||||
|   if (fd == -1) | ||||
|   { | ||||
|     boost::system::error_code ec(errno, | ||||
|         boost::asio::error::get_system_category()); | ||||
|     boost::asio::detail::throw_error(ec, "epoll"); | ||||
|   } | ||||
|  | ||||
|   return fd; | ||||
| } | ||||
|  | ||||
| int epoll_reactor::do_timerfd_create() | ||||
| { | ||||
| #if defined(BOOST_ASIO_HAS_TIMERFD) | ||||
| # if defined(TFD_CLOEXEC) | ||||
|   int fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); | ||||
| # else // defined(TFD_CLOEXEC) | ||||
|   int fd = -1; | ||||
|   errno = EINVAL; | ||||
| # endif // defined(TFD_CLOEXEC) | ||||
|  | ||||
|   if (fd == -1 && errno == EINVAL) | ||||
|   { | ||||
|     fd = timerfd_create(CLOCK_MONOTONIC, 0); | ||||
|     if (fd != -1) | ||||
|       ::fcntl(fd, F_SETFD, FD_CLOEXEC); | ||||
|   } | ||||
|  | ||||
|   return fd; | ||||
| #else // defined(BOOST_ASIO_HAS_TIMERFD) | ||||
|   return -1; | ||||
| #endif // defined(BOOST_ASIO_HAS_TIMERFD) | ||||
| } | ||||
|  | ||||
| epoll_reactor::descriptor_state* epoll_reactor::allocate_descriptor_state() | ||||
| { | ||||
|   mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); | ||||
|   return registered_descriptors_.alloc(); | ||||
| } | ||||
|  | ||||
| void epoll_reactor::free_descriptor_state(epoll_reactor::descriptor_state* s) | ||||
| { | ||||
|   mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); | ||||
|   registered_descriptors_.free(s); | ||||
| } | ||||
|  | ||||
| void epoll_reactor::do_add_timer_queue(timer_queue_base& queue) | ||||
| { | ||||
|   mutex::scoped_lock lock(mutex_); | ||||
|   timer_queues_.insert(&queue); | ||||
| } | ||||
|  | ||||
| void epoll_reactor::do_remove_timer_queue(timer_queue_base& queue) | ||||
| { | ||||
|   mutex::scoped_lock lock(mutex_); | ||||
|   timer_queues_.erase(&queue); | ||||
| } | ||||
|  | ||||
| void epoll_reactor::update_timeout() | ||||
| { | ||||
| #if defined(BOOST_ASIO_HAS_TIMERFD) | ||||
|   if (timer_fd_ != -1) | ||||
|   { | ||||
|     itimerspec new_timeout; | ||||
|     itimerspec old_timeout; | ||||
|     int flags = get_timeout(new_timeout); | ||||
|     timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); | ||||
|     return; | ||||
|   } | ||||
| #endif // defined(BOOST_ASIO_HAS_TIMERFD) | ||||
|   interrupt(); | ||||
| } | ||||
|  | ||||
| int epoll_reactor::get_timeout() | ||||
| { | ||||
|   // By default we will wait no longer than 5 minutes. This will ensure that | ||||
|   // any changes to the system clock are detected after no longer than this. | ||||
|   return timer_queues_.wait_duration_msec(5 * 60 * 1000); | ||||
| } | ||||
|  | ||||
| #if defined(BOOST_ASIO_HAS_TIMERFD) | ||||
| int epoll_reactor::get_timeout(itimerspec& ts) | ||||
| { | ||||
|   ts.it_interval.tv_sec = 0; | ||||
|   ts.it_interval.tv_nsec = 0; | ||||
|  | ||||
|   long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); | ||||
|   ts.it_value.tv_sec = usec / 1000000; | ||||
|   ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1; | ||||
|  | ||||
|   return usec ? 0 : TFD_TIMER_ABSTIME; | ||||
| } | ||||
| #endif // defined(BOOST_ASIO_HAS_TIMERFD) | ||||
|  | ||||
| struct epoll_reactor::perform_io_cleanup_on_block_exit | ||||
| { | ||||
|   explicit perform_io_cleanup_on_block_exit(epoll_reactor* r) | ||||
|     : reactor_(r), first_op_(0) | ||||
|   { | ||||
|   } | ||||
|  | ||||
|   ~perform_io_cleanup_on_block_exit() | ||||
|   { | ||||
|     if (first_op_) | ||||
|     { | ||||
|       // Post the remaining completed operations for invocation. | ||||
|       if (!ops_.empty()) | ||||
|         reactor_->io_service_.post_deferred_completions(ops_); | ||||
|  | ||||
|       // A user-initiated operation has completed, but there's no need to | ||||
|       // explicitly call work_finished() here. Instead, we'll take advantage of | ||||
|       // the fact that the task_io_service will call work_finished() once we | ||||
|       // return. | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|       // No user-initiated operations have completed, so we need to compensate | ||||
|       // for the work_finished() call that the task_io_service will make once | ||||
|       // this operation returns. | ||||
|       reactor_->io_service_.work_started(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   epoll_reactor* reactor_; | ||||
|   op_queue<operation> ops_; | ||||
|   operation* first_op_; | ||||
| }; | ||||
|  | ||||
| epoll_reactor::descriptor_state::descriptor_state() | ||||
|   : operation(&epoll_reactor::descriptor_state::do_complete) | ||||
| { | ||||
| } | ||||
|  | ||||
| operation* epoll_reactor::descriptor_state::perform_io(uint32_t events) | ||||
| { | ||||
|   mutex_.lock(); | ||||
|   perform_io_cleanup_on_block_exit io_cleanup(reactor_); | ||||
|   mutex::scoped_lock descriptor_lock(mutex_, mutex::scoped_lock::adopt_lock); | ||||
|  | ||||
|   // Exception operations must be processed first to ensure that any | ||||
|   // out-of-band data is read before normal data. | ||||
|   static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI }; | ||||
|   for (int j = max_ops - 1; j >= 0; --j) | ||||
|   { | ||||
|     if (events & (flag[j] | EPOLLERR | EPOLLHUP)) | ||||
|     { | ||||
|       while (reactor_op* op = op_queue_[j].front()) | ||||
|       { | ||||
|         if (op->perform()) | ||||
|         { | ||||
|           op_queue_[j].pop(); | ||||
|           io_cleanup.ops_.push(op); | ||||
|         } | ||||
|         else | ||||
|           break; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // The first operation will be returned for completion now. The others will | ||||
|   // be posted for later by the io_cleanup object's destructor. | ||||
|   io_cleanup.first_op_ = io_cleanup.ops_.front(); | ||||
|   io_cleanup.ops_.pop(); | ||||
|   return io_cleanup.first_op_; | ||||
| } | ||||
|  | ||||
| void epoll_reactor::descriptor_state::do_complete( | ||||
|     io_service_impl* owner, operation* base, | ||||
|     const boost::system::error_code& ec, std::size_t bytes_transferred) | ||||
| { | ||||
|   if (owner) | ||||
|   { | ||||
|     descriptor_state* descriptor_data = static_cast<descriptor_state*>(base); | ||||
|     uint32_t events = static_cast<uint32_t>(bytes_transferred); | ||||
|     if (operation* op = descriptor_data->perform_io(events)) | ||||
|     { | ||||
|       op->complete(*owner, ec, 0); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| } // namespace detail | ||||
| } // namespace asio | ||||
| } // namespace boost | ||||
|  | ||||
| #include <boost/asio/detail/pop_options.hpp> | ||||
|  | ||||
| #endif // defined(BOOST_ASIO_HAS_EPOLL) | ||||
|  | ||||
| #endif // BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP | ||||
							
								
								
									
										304
									
								
								samples/Chapel/distributions.chpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										304
									
								
								samples/Chapel/distributions.chpl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,304 @@ | ||||
| // | ||||
| // Distributions Primer | ||||
| // | ||||
| // This primer demonstrates uses of some of Chapel's standard | ||||
| // distributions.  To use these distributions in a Chapel program, | ||||
| // the respective module must be used: | ||||
| // | ||||
| use BlockDist, CyclicDist, BlockCycDist, ReplicatedDist; | ||||
| use DimensionalDist2D, ReplicatedDim, BlockCycDim; | ||||
|  | ||||
| // | ||||
| // For each distribution, we'll create a distributed domain and array | ||||
| // and then initialize it just to give a brief flavor of how the | ||||
| // distribution maps across locales.  Running this example on 6 | ||||
| // locales does a nice job of illustrating the distribution | ||||
| // characteristics. | ||||
| // | ||||
| // All of these distributions support options to map to a different | ||||
| // virtual locale grid than the one used by default (a | ||||
| // multidimensional factoring of the built-in Locales array), as well | ||||
| // as to control the amount of parallelism used in data parallel | ||||
| // loops.  See the Standard Distributions chapter of the language spec | ||||
| // for more details. | ||||
| // | ||||
|  | ||||
| // | ||||
| // Make the program size configurable from the command line. | ||||
| // | ||||
| config const n = 8; | ||||
|  | ||||
| // | ||||
| // Declare a 2-dimensional domain Space that we will later use to | ||||
| // initialize the distributed domains. | ||||
| // | ||||
| const Space = {1..n, 1..n}; | ||||
|  | ||||
| // | ||||
| // The Block distribution distributes a bounding box from | ||||
| // n-dimensional space across the target locale array viewed as an | ||||
| // n-dimensional virtual locale grid.  The bounding box is blocked | ||||
| // into roughly equal portions across the locales.  Note that domains | ||||
| // declared over a Block distribution can also store indices outside | ||||
| // of the bounding box; the bounding box is merely used to compute | ||||
| // the blocking of space. | ||||
| // | ||||
| // In this example, we declare a 2-dimensional Block-distributed | ||||
| // domain BlockSpace and a Block-distributed array BA declared over | ||||
| // the domain. | ||||
| // | ||||
| const BlockSpace = Space dmapped Block(boundingBox=Space); | ||||
| var BA: [BlockSpace] int; | ||||
|  | ||||
| // | ||||
| // To illustrate how the index set is distributed across locales, | ||||
| // we'll use a forall loop to initialize each array element to the | ||||
| // locale ID that stores that index/element/iteration. | ||||
| // | ||||
| forall ba in BA do | ||||
|   ba = here.id; | ||||
|  | ||||
| // | ||||
| // Output the Block-distributed array to visually see how the elements | ||||
| // are partitioned across the locales. | ||||
| // | ||||
| writeln("Block Array Index Map"); | ||||
| writeln(BA); | ||||
| writeln(); | ||||
|  | ||||
| // | ||||
| // Most of Chapel's standard distributions support an optional | ||||
| // targetLocales argument that permits you to pass in your own | ||||
| // array of locales to be targeted.  In general, the targetLocales | ||||
| // argument should match the rank of the distribution.  So for | ||||
| // example, to map a Block to a [numLocales x 1] view of the | ||||
| // locale set, one could do something like this: | ||||
|  | ||||
| // | ||||
| // We start by creating our own array of the locale values.  Here | ||||
| // we use the standard array reshape function for convenience, | ||||
| // but more generally, this array could be accessed/assigned like any | ||||
| // other. | ||||
| // | ||||
|  | ||||
| var MyLocaleView = {0..#numLocales, 1..1}; | ||||
| var MyLocales: [MyLocaleView] locale = reshape(Locales, MyLocaleView); | ||||
|  | ||||
| // | ||||
| // Then we'll declare a distributed domain/array that targets | ||||
| // this view of the locales: | ||||
| //  | ||||
|  | ||||
| const BlockSpace2 = Space dmapped Block(boundingBox=Space, | ||||
|                                         targetLocales=MyLocales); | ||||
| var BA2: [BlockSpace2] int; | ||||
|  | ||||
| // | ||||
| // Then we'll do a similar computation as before to verify where | ||||
| // everything ended up: | ||||
| // | ||||
| forall ba in BA2 do | ||||
|   ba = here.id; | ||||
|  | ||||
| writeln("Block Array Index Map"); | ||||
| writeln(BA2); | ||||
| writeln(); | ||||
|  | ||||
|  | ||||
|  | ||||
| // | ||||
| // Next, we'll perform a similar computation for the Cyclic distribution. | ||||
| // Cyclic distributions start at a designated n-dimensional index and | ||||
| // distribute the n-dimensional space across an n-dimensional array | ||||
| // of locales in a round-robin fashion (in each dimension).  As with | ||||
| // the Block distribution, domains may be declared using the | ||||
| // distribution who have lower indices that the starting index; that | ||||
| // value should just be considered a parameterization of how the | ||||
| // distribution is defined. | ||||
| // | ||||
| const CyclicSpace = Space dmapped Cyclic(startIdx=Space.low); | ||||
| var CA: [CyclicSpace] int; | ||||
|  | ||||
| forall ca in CA do | ||||
|   ca = here.id; | ||||
|  | ||||
| writeln("Cyclic Array Index Map"); | ||||
| writeln(CA); | ||||
| writeln(); | ||||
|  | ||||
|  | ||||
| // | ||||
| // Next, we'll declare a Block-Cyclic distribution.  These | ||||
| // distributions also deal out indices in a round-robin fashion, | ||||
| // but rather than dealing out singleton indices, they deal out blocks | ||||
| // of indices.  Thus, the BlockCyclic distribution is parameterized | ||||
| // by a starting index (as with Cyclic) and a block size (per | ||||
| // dimension) specifying how large the chunks to be dealt out are. | ||||
| //  | ||||
| const BlkCycSpace = Space dmapped BlockCyclic(startIdx=Space.low,  | ||||
|                                               blocksize=(2, 3)); | ||||
| var BCA: [BlkCycSpace] int; | ||||
|  | ||||
| forall bca in BCA do | ||||
|   bca = here.id; | ||||
|  | ||||
| writeln("Block-Cyclic Array Index Map"); | ||||
| writeln(BCA); | ||||
| writeln(); | ||||
|  | ||||
|  | ||||
| // | ||||
| // The ReplicatedDist distribution is different: each of the | ||||
| // original domain's indices - and the corresponding array elements - | ||||
| // is replicated onto each locale. (Note: consistency among these | ||||
| // array replicands is NOT maintained automatically.) | ||||
| // | ||||
| // This replication is observable in some cases but not others, | ||||
| // as shown below. Note: this behavior may change in the future. | ||||
| // | ||||
| const ReplicatedSpace = Space dmapped ReplicatedDist(); | ||||
| var RA: [ReplicatedSpace] int; | ||||
|  | ||||
| // The replication is observable - this visits each replicand. | ||||
| forall ra in RA do | ||||
|   ra = here.id; | ||||
|  | ||||
| writeln("Replicated Array Index Map, ", RA.numElements, " elements total"); | ||||
| writeln(RA); | ||||
| writeln(); | ||||
|  | ||||
| // | ||||
| // The replication is observable when the replicated array is | ||||
| // on the left-hand side. If the right-hand side is not replicated, | ||||
| // it is copied into each replicand. | ||||
| // We illustrate this using a non-distributed array. | ||||
| // | ||||
| var A: [Space] int = [(i,j) in Space] i*100 + j; | ||||
| RA = A; | ||||
| writeln("Replicated Array after being array-assigned into"); | ||||
| writeln(RA); | ||||
| writeln(); | ||||
|  | ||||
| // | ||||
| // Analogously, each replicand will be visited and | ||||
| // other participated expressions will be computed on each locale | ||||
| // (a) when the replicated array is assigned a scalar: | ||||
| //       RA = 5; | ||||
| // (b) when it appears first in a zippered forall loop: | ||||
| //       forall (ra, a) in zip(RA, A) do ...; | ||||
| // (c) when it appears in a for loop: | ||||
| //       for ra in RA do ...; | ||||
| // | ||||
| // Zippering (RA,A) or (A,RA) in a 'for' loop will generate | ||||
| // an error due to their different number of elements. | ||||
|  | ||||
| // Let RA store the Index Map again, for the examples below. | ||||
| forall ra in RA do | ||||
|   ra = here.id; | ||||
|  | ||||
| // | ||||
| // Only the local replicand is accessed - replication is NOT observable | ||||
| // and consistency is NOT maintained - when: | ||||
| // (a) the replicated array is indexed - an individual element is read... | ||||
| // | ||||
| on Locales(0) do | ||||
|   writeln("on ", here, ": ", RA(Space.low)); | ||||
| on Locales(LocaleSpace.high) do | ||||
|   writeln("on ", here, ": ", RA(Space.low)); | ||||
| writeln(); | ||||
|  | ||||
| // ...or an individual element is written; | ||||
| on Locales(LocaleSpace.high) do | ||||
|   RA(Space.low) = 7777; | ||||
|  | ||||
| writeln("Replicated Array after being indexed into"); | ||||
| writeln(RA); | ||||
| writeln(); | ||||
|  | ||||
| // | ||||
| // (b) the replicated array is on the right-hand side of an assignment... | ||||
| // | ||||
| on Locales(LocaleSpace.high) do | ||||
|   A = RA + 4; | ||||
| writeln("Non-Replicated Array after assignment from Replicated Array + 4"); | ||||
| writeln(A); | ||||
| writeln(); | ||||
|  | ||||
| // | ||||
| // (c) ...or, generally, the replicated array or domain participates | ||||
| //     in a zippered forall loop, but not in the first position. | ||||
| //     The loop could look like: | ||||
| // | ||||
| //       forall (a, (i,j), ra) in (A, ReplicatedSpace, RA) do ...; | ||||
| // | ||||
|  | ||||
|  | ||||
| // | ||||
| // The DimensionalDist2D distribution lets us build a 2D distribution | ||||
| // as a composition of specifiers for individual dimensions. | ||||
| // Under such a "dimensional" distribution each dimension is handled | ||||
| // independently of the other. | ||||
| // | ||||
| // The dimension specifiers are similar to the corresponding multi-dimensional | ||||
| // distributions in constructor arguments and index-to-locale mapping rules. | ||||
| // However, instead of an array of locales, a specifier constructor | ||||
| // accepts just the number of locales that the indices in the corresponding | ||||
| // dimension will be distributed across. | ||||
| // | ||||
| // The DimensionalDist2D constructor requires: | ||||
| // * an [0..nl1-1, 0..nl2-1] array of locales, where | ||||
| //   nl1 and nl2 are the number of locales in each dimension, and | ||||
| // * two dimension specifiers, created for nl1 and nl2 locale counts, resp. | ||||
| // | ||||
| // Presently, the following dimension specifiers are available | ||||
| // (shown here with their constructor arguments): | ||||
| // | ||||
| // * ReplicatedDim(numLocales) | ||||
| // * BlockDim(numLocales, boundingBoxLow, boundingBoxHigh) | ||||
| // * BlockCyclicDim(lowIdx, blockSize, numLocales) | ||||
| // | ||||
|  | ||||
| // | ||||
| // The following example creates a dimensional distribution that | ||||
| // replicates over 2 locales (when available) in the first dimemsion | ||||
| // and distributes using block-cyclic distribution in the second dimension. | ||||
| // The example computes nl1 and nl2 and reshapes MyLocales correspondingly. | ||||
| // | ||||
|  | ||||
| var (nl1, nl2) = if numLocales == 1 then (1, 1) else (2, numLocales/2); | ||||
| MyLocaleView = {0..#nl1, 0..#nl2}; | ||||
| MyLocales = reshape(Locales[0..#nl1*nl2], MyLocaleView); | ||||
|  | ||||
| const DimReplicatedBlockcyclicSpace = Space | ||||
|   dmapped DimensionalDist2D(MyLocales, | ||||
|                             new ReplicatedDim(numLocales = nl1), | ||||
|                             new BlockCyclicDim(numLocales = nl2, | ||||
|                                                lowIdx = 1, blockSize = 2)); | ||||
|  | ||||
| var DRBA: [DimReplicatedBlockcyclicSpace] int; | ||||
|  | ||||
| // The ReplicatedDim specifier always accesses the local replicand. | ||||
| // (This differs from how the ReplicatedDist distribution works.) | ||||
| // | ||||
| // This example visits each replicand. The behavior is the same | ||||
| // regardless of the second index into MyLocales below. | ||||
|  | ||||
| for locId1 in 0..#nl1 do on MyLocales[locId1, 0] { | ||||
|  | ||||
|   forall drba in DRBA do | ||||
|     drba = here.id; | ||||
|  | ||||
|   writeln("Dimensional2D(Replicated,BlockCyclic) Array Index Map", | ||||
|           " from ", here); | ||||
|  | ||||
|   // Technicality: 'writeln(DRBA)' would read DRBA always on Locale 0. | ||||
|   // Since we want to see what DRBA contains on the current locale, | ||||
|   // we use 'Helper' that is mapped using the default distribution. | ||||
|   // 'Helper = DRBA' captures the view of DRBA on the current locale, | ||||
|   // which we then print out. | ||||
|  | ||||
|   const Helper: [Space] int = DRBA; | ||||
|   writeln(Helper); | ||||
|   writeln(); | ||||
|  | ||||
| } | ||||
							
								
								
									
										1
									
								
								samples/Chapel/hello.chpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								samples/Chapel/hello.chpl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| writeln("Hello, world!");    // print 'Hello, world!' to the console | ||||
							
								
								
									
										1692
									
								
								samples/Chapel/lulesh.chpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1692
									
								
								samples/Chapel/lulesh.chpl
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										147
									
								
								samples/Chapel/nbody.chpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								samples/Chapel/nbody.chpl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | ||||
| /* The Computer Language Benchmarks Game | ||||
|    http://benchmarksgame.alioth.debian.org/ | ||||
|  | ||||
|    contributed by Albert Sidelnik | ||||
|    modified by Brad Chamberlain | ||||
| */ | ||||
|  | ||||
|  | ||||
| // | ||||
| // The number of timesteps to simulate; may be set via the command-line | ||||
| // | ||||
| config const n = 10000; | ||||
|  | ||||
| // | ||||
| // Constants representing pi, the solar mass, and the number of days per year | ||||
| // | ||||
| const pi = 3.141592653589793, | ||||
|       solarMass = 4 * pi**2, | ||||
|       daysPerYear = 365.24; | ||||
|  | ||||
| // | ||||
| // a record representing one of the bodies in the solar system | ||||
| // | ||||
| record body { | ||||
|   var pos: 3*real; | ||||
|   var v: 3*real; | ||||
|   var mass: real;  // does not change after it is set up | ||||
| } | ||||
|  | ||||
| // | ||||
| // the array of bodies that we'll be simulating | ||||
| // | ||||
| var bodies = [/* sun */ | ||||
|               new body(mass = solarMass), | ||||
|  | ||||
|               /* jupiter */ | ||||
|               new body(pos = ( 4.84143144246472090e+00, | ||||
|                               -1.16032004402742839e+00, | ||||
|                               -1.03622044471123109e-01), | ||||
|                          v = ( 1.66007664274403694e-03 * daysPerYear, | ||||
|                                7.69901118419740425e-03 * daysPerYear, | ||||
|                               -6.90460016972063023e-05 * daysPerYear), | ||||
|                       mass =   9.54791938424326609e-04 * solarMass), | ||||
|    | ||||
|               /* saturn */ | ||||
|               new body(pos = ( 8.34336671824457987e+00, | ||||
|                                4.12479856412430479e+00, | ||||
|                               -4.03523417114321381e-01), | ||||
|                          v = (-2.76742510726862411e-03 * daysPerYear, | ||||
|                                4.99852801234917238e-03 * daysPerYear, | ||||
|                                2.30417297573763929e-05 * daysPerYear), | ||||
|                       mass =   2.85885980666130812e-04 * solarMass), | ||||
|  | ||||
|               /* uranus */ | ||||
|               new body(pos = ( 1.28943695621391310e+01, | ||||
|                               -1.51111514016986312e+01, | ||||
|                               -2.23307578892655734e-01), | ||||
|                          v = ( 2.96460137564761618e-03 * daysPerYear, | ||||
|                                2.37847173959480950e-03 * daysPerYear, | ||||
|                               -2.96589568540237556e-05 * daysPerYear), | ||||
|                       mass =   4.36624404335156298e-05 * solarMass), | ||||
|  | ||||
|               /* neptune */ | ||||
|               new body(pos = ( 1.53796971148509165e+01, | ||||
|                               -2.59193146099879641e+01, | ||||
|                                1.79258772950371181e-01), | ||||
|                          v = ( 2.68067772490389322e-03 * daysPerYear, | ||||
|                                1.62824170038242295e-03 * daysPerYear, | ||||
|                               -9.51592254519715870e-05 * daysPerYear), | ||||
|                       mass =   5.15138902046611451e-05 * solarMass) | ||||
|               ]; | ||||
|  | ||||
| // | ||||
| // the number of bodies to be simulated | ||||
| // | ||||
| const numbodies = bodies.numElements; | ||||
|  | ||||
| // | ||||
| // The computation involves initializing the sun's velocity, | ||||
| // writing the initial energy, advancing the system through 'n' | ||||
| // timesteps, and writing the final energy. | ||||
| // | ||||
| proc main() { | ||||
|   initSun(); | ||||
|  | ||||
|   writef("%.9r\n", energy()); | ||||
|   for 1..n do | ||||
|     advance(0.01); | ||||
|   writef("%.9r\n", energy()); | ||||
| } | ||||
|  | ||||
| // | ||||
| // compute the sun's initial velocity | ||||
| // | ||||
| proc initSun() { | ||||
|   const p = + reduce (for b in bodies do (b.v * b.mass)); | ||||
|   bodies[1].v = -p / solarMass; | ||||
| } | ||||
|  | ||||
| // | ||||
| // advance the positions and velocities of all the bodies | ||||
| // | ||||
| proc advance(dt) { | ||||
|   for i in 1..numbodies { | ||||
|     for j in i+1..numbodies { | ||||
|       updateVelocities(bodies[i], bodies[j]); | ||||
|        | ||||
|       inline proc updateVelocities(ref b1, ref b2) { | ||||
|         const dpos = b1.pos - b2.pos, | ||||
|                mag = dt / sqrt(sumOfSquares(dpos))**3; | ||||
|          | ||||
|         b1.v -= dpos * b2.mass * mag; | ||||
|         b2.v += dpos * b1.mass * mag; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   for b in bodies do | ||||
|     b.pos += dt * b.v; | ||||
| } | ||||
|  | ||||
| // | ||||
| // compute the energy of the bodies | ||||
| // | ||||
| proc energy() { | ||||
|   var e = 0.0; | ||||
|    | ||||
|   for i in 1..numbodies { | ||||
|     const b1 = bodies[i]; | ||||
|      | ||||
|     e += 0.5 * b1.mass * sumOfSquares(b1.v); | ||||
|      | ||||
|     for j in i+1..numbodies { | ||||
|       const b2 = bodies[j]; | ||||
|        | ||||
|       e -= (b1.mass * b2.mass) / sqrt(sumOfSquares(b1.pos - b2.pos)); | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   return e; | ||||
| } | ||||
|  | ||||
| // | ||||
| // a helper routine to compute the sum of squares of a 3-tuple's components | ||||
| // | ||||
| inline proc sumOfSquares(x) | ||||
|   return x(1)**2 + x(2)**2 + x(3)**2; | ||||
							
								
								
									
										145
									
								
								samples/Chapel/quicksort.chpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								samples/Chapel/quicksort.chpl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,145 @@ | ||||
| // | ||||
| // An example of a parallel quick sort implementation that uses | ||||
| // "cobegin" to make each recursive call in parallel and "serial" to | ||||
| // limit the number of threads. | ||||
| // | ||||
|  | ||||
| use Random, Time; // for random number generation and the Timer class | ||||
|  | ||||
| var timer: Timer; // to time the sort | ||||
|  | ||||
| config var n: int = 2**15;      // the size of the array to be sorted | ||||
| config var thresh: int = 1;     // the recursive depth to serialize | ||||
| config var verbose: int = 0;    // print out this many elements in array | ||||
| config var timing: bool = true; // set timing to false to disable timer | ||||
|  | ||||
| var A: [1..n] real; // array of real numbers | ||||
|  | ||||
| // | ||||
| // initialize array with random numbers | ||||
| // | ||||
| fillRandom(A); | ||||
|  | ||||
| // | ||||
| // print out front of array if verbose flag is set | ||||
| // | ||||
| if verbose > 0 then | ||||
|   writeln("A[1..", verbose, "] = ", A[1..verbose]); | ||||
|  | ||||
| // | ||||
| // start timer, call parallel quick sort routine, stop timer | ||||
| // | ||||
| if timing then timer.start(); | ||||
| pqsort(A, thresh); | ||||
| if timing then timer.stop(); | ||||
|  | ||||
| // | ||||
| // report sort time | ||||
| // | ||||
| if timing then writeln("sorted in ", timer.elapsed(), " seconds"); | ||||
|  | ||||
| // | ||||
| // print out front of array if verbose flag is set | ||||
| //   values should now be in sorted order | ||||
| // | ||||
| if verbose > 0 then | ||||
|   writeln("A[1..", verbose, "] = ", A[1..verbose]); | ||||
|  | ||||
| // | ||||
| // verify that array is sorted or halt | ||||
| // | ||||
| for i in 2..n do | ||||
|   if A(i) < A(i-1) then | ||||
|     halt("A(", i-1, ") == ", A(i-1), " > A(", i, ") == ", A(i)); | ||||
|  | ||||
| writeln("verification success"); | ||||
|  | ||||
| // | ||||
| // pqsort -- parallel quick sort | ||||
| // | ||||
| //   arr: generic 1D array of values (real, int, ...) | ||||
| //   thresh: number of recursive calls to make before serializing | ||||
| //   low: lower bound of array to start sort at, defaults to whole array | ||||
| //   high: upper bound of array to stop sort at, defaults to whole array | ||||
| // | ||||
| proc pqsort(arr: [], | ||||
|            thresh: int, | ||||
|            low: int = arr.domain.low, | ||||
|            high: int = arr.domain.high) where arr.rank == 1 { | ||||
|  | ||||
|   // | ||||
|   // base case: arr[low..high] is small enough to bubble sort | ||||
|   // | ||||
|   if high - low < 8 { | ||||
|     bubbleSort(arr, low, high); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   // | ||||
|   // determine pivot and partition arr[low..high] | ||||
|   // | ||||
|   const pivotVal = findPivot(); | ||||
|   const pivotLoc = partition(pivotVal); | ||||
|  | ||||
|   // | ||||
|   // make recursive calls to parallel quick sort each unsorted half of | ||||
|   // the array; if thresh is 0 or less, start executing conquer tasks | ||||
|   // serially | ||||
|   // | ||||
|   serial thresh <= 0 do cobegin { | ||||
|     pqsort(arr, thresh-1, low, pivotLoc-1); | ||||
|     pqsort(arr, thresh-1, pivotLoc+1, high); | ||||
|   } | ||||
|  | ||||
|   // | ||||
|   // findPivot -- helper routine to find pivot value using simple | ||||
|   //              median-of-3 method, returns pivot value | ||||
|   // | ||||
|   proc findPivot() { | ||||
|     const mid = low + (high-low+1) / 2; | ||||
|  | ||||
|     if arr(mid) < arr(low) then arr(mid) <=> arr(low); | ||||
|     if arr(high) < arr(low) then arr(high) <=> arr(low); | ||||
|     if arr(high) < arr(mid) then arr(high) <=> arr(mid); | ||||
|  | ||||
|     const pivotVal = arr(mid); | ||||
|     arr(mid) = arr(high-1); | ||||
|     arr(high-1) = pivotVal; | ||||
|  | ||||
|     return pivotVal; | ||||
|   } | ||||
|  | ||||
|   // | ||||
|   // partition -- helper routine to partition array such that all | ||||
|   //              values less than pivot are to its left and all | ||||
|   //              values greater than pivot are to its right, returns | ||||
|   //              pivot location | ||||
|   // | ||||
|   proc partition(pivotVal) { | ||||
|     var ilo = low, ihi = high-1; | ||||
|     while (ilo < ihi) { | ||||
|       do { ilo += 1; } while arr(ilo) < pivotVal; | ||||
|       do { ihi -= 1; } while pivotVal < arr(ihi); | ||||
|       if (ilo < ihi) { | ||||
|         arr(ilo) <=> arr(ihi); | ||||
|       } | ||||
|     } | ||||
|     arr(high-1) = arr(ilo); | ||||
|     arr(ilo) = pivotVal; | ||||
|     return ilo; | ||||
|   } | ||||
| } | ||||
|  | ||||
| // | ||||
| // bubbleSort -- bubble sort for base case of quick sort | ||||
| // | ||||
| //   arr: generic 1D array of values (real, int, ...) | ||||
| //   low: lower bound of array to start sort at | ||||
| //   high: upper bound of array to stop sort at | ||||
| // | ||||
| proc bubbleSort(arr: [], low: int, high: int) where arr.rank == 1 { | ||||
|   for i in low..high do | ||||
|     for j in low..high-1 do | ||||
|       if arr(j) > arr(j+1) then | ||||
|         arr(j) <=> arr(j+1); | ||||
| } | ||||
							
								
								
									
										146
									
								
								samples/Clojure/index.cljs.hl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								samples/Clojure/index.cljs.hl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | ||||
| ;; Copyright (c) Alan Dipert and Micha Niskin. All rights reserved. | ||||
| ;; The use and distribution terms for this software are covered by the | ||||
| ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) | ||||
| ;; which can be found in the file epl-v10.html at the root of this distribution. | ||||
| ;; By using this software in any fashion, you are agreeing to be bound by | ||||
| ;; the terms of this license. | ||||
| ;; You must not remove this notice, or any other, from this software. | ||||
|  | ||||
| (page "index.html" | ||||
|   (:refer-clojure :exclude [nth]) | ||||
|   (:require | ||||
|    [tailrecursion.hoplon.reload        :refer [reload-all]] | ||||
|    [tailrecursion.hoplon.util          :refer [nth name pluralize]] | ||||
|    [tailrecursion.hoplon.storage-atom  :refer [local-storage]])) | ||||
|  | ||||
| ;; utility functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
|  | ||||
| (declare route state editing) | ||||
|  | ||||
| (reload-all) | ||||
|  | ||||
| (def mapvi  (comp vec map-indexed)) | ||||
|  | ||||
| (defn dissocv [v i] | ||||
|   (let [z (- (dec (count v)) i)] | ||||
|     (cond (neg?  z) v | ||||
|           (zero? z) (pop v) | ||||
|           (pos?  z) (into (subvec v 0 i) (subvec v (inc i)))))) | ||||
|  | ||||
| (defn decorate [todo route editing i] | ||||
|   (let [{done? :completed text :text} todo] | ||||
|     (-> todo (assoc :editing (= editing i) | ||||
|                     :visible (and (not (empty? text)) | ||||
|                                   (or (= "#/" route) | ||||
|                                       (and (= "#/active" route) (not done?)) | ||||
|                                       (and (= "#/completed" route) done?))))))) | ||||
|  | ||||
| ;; persisted state cell (AKA: stem cell) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
|  | ||||
| (def   state        (-> (cell []) (local-storage ::store))) | ||||
|  | ||||
| ;; local state cells ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
|  | ||||
| (defc  loaded?      false) | ||||
| (defc  editing      nil) | ||||
| (def   route        (route-cell "#/")) | ||||
|  | ||||
| ;; formula cells (computed state) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
|  | ||||
| (defc= completed    (filter :completed state)) | ||||
| (defc= active       (remove :completed state)) | ||||
| (defc= plural-item  (pluralize "item" (count active))) | ||||
| (defc= todos        (mapvi #(list %1 (decorate %2 route editing %1)) state)) | ||||
|  | ||||
| ;; state transition functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
|  | ||||
| (defn  todo        [t]   {:completed false :text t}) | ||||
| (defn  destroy!    [i]   (swap! state dissocv i)) | ||||
| (defn  done!       [i v] (swap! state assoc-in [i :completed] v)) | ||||
| (defn  clear-done! [& _] (swap! state #(vec (remove :completed %)))) | ||||
| (defn  new!        [t]   (when (not (empty? t)) (swap! state conj (todo t)))) | ||||
| (defn  all-done!   [v]   (swap! state #(mapv (fn [x] (assoc x :completed v)) %))) | ||||
| (defn  editing!    [i v] (reset! editing (if v i nil))) | ||||
| (defn  text!       [i v] (if (empty? v) (destroy! i) (swap! state assoc-in [i :text] v))) | ||||
|  | ||||
| ;; page ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
|  | ||||
| (html :lang "en" | ||||
|   (head | ||||
|     (meta :charset "utf-8") | ||||
|     (meta :http-equiv "X-UA-Compatible" :content "IE=edge,chrome=1") | ||||
|     (link :rel "stylesheet" :href "base.css") | ||||
|     (title "Hoplon • TodoMVC")) | ||||
|   (body | ||||
|     (noscript | ||||
|       (div :id "noscript" | ||||
|         (p "JavaScript is required to view this page."))) | ||||
|     (div | ||||
|       (section :id "todoapp" | ||||
|         (header :id "header" | ||||
|           (h1 "todos") | ||||
|           (form :on-submit #(do (new! (val-id :new-todo)) | ||||
|                                 (do! (by-id :new-todo) :value "")) | ||||
|             (input | ||||
|               :id "new-todo" | ||||
|               :type "text" | ||||
|               :autofocus true | ||||
|               :placeholder "What needs to be done?" | ||||
|               :on-blur #(do! (by-id :new-todo) :value "")))) | ||||
|         (section | ||||
|           :id "main" | ||||
|           :do-toggle (cell= (not (and (empty? active) (empty? completed)))) | ||||
|           (input | ||||
|             :id "toggle-all" | ||||
|             :type "checkbox" | ||||
|             :do-attr (cell= {:checked (empty? active)})  | ||||
|             :on-click #(all-done! (val-id :toggle-all))) | ||||
|           (label :for "toggle-all" | ||||
|             "Mark all as complete") | ||||
|           (ul :id "todo-list" | ||||
|             (loop-tpl | ||||
|               :reverse true | ||||
|               :bind-ids [done# edit#] | ||||
|               :bindings [[i {edit? :editing done? :completed todo-text :text show? :visible}] todos]  | ||||
|               (li | ||||
|                 :do-class (cell= {:completed done? :editing edit?})  | ||||
|                 :do-toggle show? | ||||
|                 (div :class "view" :on-dblclick #(editing! @i true) | ||||
|                   (input | ||||
|                     :id done#  | ||||
|                     :type "checkbox" | ||||
|                     :class "toggle" | ||||
|                     :do-attr (cell= {:checked done?})  | ||||
|                     :on-click #(done! @i (val-id done#))) | ||||
|                   (label (text "~{todo-text}")) | ||||
|                   (button | ||||
|                     :type "submit" | ||||
|                     :class "destroy" | ||||
|                     :on-click  #(destroy! @i))) | ||||
|                 (form :on-submit #(editing! @i false) | ||||
|                   (input | ||||
|                     :id edit# | ||||
|                     :type "text" | ||||
|                     :class "edit" | ||||
|                     :do-value todo-text | ||||
|                     :do-focus edit? | ||||
|                     :on-blur #(when @edit? (editing! @i false)) | ||||
|                     :on-change #(when @edit? (text! @i (val-id edit#))))))))) | ||||
|         (footer  | ||||
|           :id "footer" | ||||
|           :do-toggle (cell= (not (and (empty? active) (empty? completed)))) | ||||
|           (span :id "todo-count" | ||||
|             (strong (text "~(count active) ")) | ||||
|             (span (text "~{plural-item} left"))) | ||||
|           (ul :id "filters" | ||||
|             (li (a :href "#/"          :do-class (cell= {:selected (= "#/" route)})          "All")) | ||||
|             (li (a :href "#/active"    :do-class (cell= {:selected (= "#/active" route)})    "Active")) | ||||
|             (li (a :href "#/completed" :do-class (cell= {:selected (= "#/completed" route)}) "Completed"))) | ||||
|           (button | ||||
|             :type      "submit" | ||||
|             :id        "clear-completed" | ||||
|             :on-click  #(clear-done!) | ||||
|             (text "Clear completed (~(count completed))")))) | ||||
|       (footer :id "info"  | ||||
|         (p "Double-click to edit a todo") | ||||
|         (p "Part of " (a :href "http://github.com/tailrecursion/hoplon-demos/" "hoplon-demos"))))))  | ||||
							
								
								
									
										239
									
								
								samples/ColdFusion CFC/exampleScript.cfc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								samples/ColdFusion CFC/exampleScript.cfc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,239 @@ | ||||
| /** | ||||
| ******************************************************************************** | ||||
| ContentBox - A Modular Content Platform | ||||
| Copyright 2012 by Luis Majano and Ortus Solutions, Corp | ||||
| www.gocontentbox.org | www.luismajano.com | www.ortussolutions.com | ||||
| ******************************************************************************** | ||||
| Apache License, Version 2.0 | ||||
|  | ||||
| Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp] | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
| http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| ******************************************************************************** | ||||
| * A generic content service for content objects | ||||
| */ | ||||
| component extends="coldbox.system.orm.hibernate.VirtualEntityService" singleton{ | ||||
|  | ||||
| 	// DI | ||||
| 	property name="settingService"			inject="id:settingService@cb"; | ||||
| 	property name="cacheBox"				inject="cachebox"; | ||||
| 	property name="log"						inject="logbox:logger:{this}"; | ||||
| 	property name="customFieldService" 	 	inject="customFieldService@cb"; | ||||
| 	property name="categoryService" 	 	inject="categoryService@cb"; | ||||
| 	property name="commentService" 	 		inject="commentService@cb"; | ||||
| 	property name="contentVersionService"	inject="contentVersionService@cb"; | ||||
| 	property name="authorService"			inject="authorService@cb"; | ||||
| 	property name="populator"				inject="wirebox:populator"; | ||||
| 	property name="systemUtil"				inject="SystemUtil@cb"; | ||||
| 	 | ||||
| 	/* | ||||
| 	* Constructor | ||||
| 	* @entityName.hint The content entity name to bind this service to. | ||||
| 	*/ | ||||
| 	ContentService function init(entityName="cbContent"){ | ||||
| 		// init it | ||||
| 		super.init(entityName=arguments.entityName, useQueryCaching=true); | ||||
|  | ||||
| 		// Test scope coloring in pygments | ||||
| 		this.colorTestVar = "Just for testing pygments!"; | ||||
| 		cookie.colorTestVar = ""; | ||||
| 		client.colorTestVar = "" | ||||
| 		session.colorTestVar = ""; | ||||
| 		application.colorTestVar = ""; | ||||
|  | ||||
| 		return this; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	* Clear all content caches | ||||
| 	* @async.hint Run it asynchronously or not, defaults to false | ||||
| 	*/ | ||||
| 	function clearAllCaches(boolean async=false){ | ||||
| 		var settings = settingService.getAllSettings(asStruct=true); | ||||
| 		// Get appropriate cache provider | ||||
| 		var cache = cacheBox.getCache( settings.cb_content_cacheName ); | ||||
| 		cache.clearByKeySnippet(keySnippet="cb-content",async=arguments.async); | ||||
| 		return this; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	* Clear all page wrapper caches | ||||
| 	* @async.hint Run it asynchronously or not, defaults to false | ||||
| 	*/ | ||||
| 	function clearAllPageWrapperCaches(boolean async=false){ | ||||
| 		var settings = settingService.getAllSettings(asStruct=true); | ||||
| 		// Get appropriate cache provider | ||||
| 		var cache = cacheBox.getCache( settings.cb_content_cacheName ); | ||||
| 		cache.clearByKeySnippet(keySnippet="cb-content-pagewrapper",async=arguments.async); | ||||
| 		return this; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	* Clear all page wrapper caches | ||||
| 	* @slug.hint The slug partial to clean on | ||||
| 	* @async.hint Run it asynchronously or not, defaults to false | ||||
| 	*/ | ||||
| 	function clearPageWrapperCaches(required any slug, boolean async=false){ | ||||
| 		var settings = settingService.getAllSettings(asStruct=true); | ||||
| 		// Get appropriate cache provider | ||||
| 		var cache = cacheBox.getCache( settings.cb_content_cacheName ); | ||||
| 		cache.clearByKeySnippet(keySnippet="cb-content-pagewrapper-#arguments.slug#",async=arguments.async); | ||||
| 		return this; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	* Clear a page wrapper cache | ||||
| 	* @slug.hint The slug to clean | ||||
| 	* @async.hint Run it asynchronously or not, defaults to false | ||||
| 	*/ | ||||
| 	function clearPageWrapper(required any slug, boolean async=false){ | ||||
| 		var settings = settingService.getAllSettings(asStruct=true); | ||||
| 		// Get appropriate cache provider | ||||
| 		var cache = cacheBox.getCache( settings.cb_content_cacheName ); | ||||
| 		cache.clear("cb-content-pagewrapper-#arguments.slug#/"); | ||||
| 		return this; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	* Searches published content with cool paramters, remember published content only | ||||
| 	* @searchTerm.hint The search term to search | ||||
| 	* @max.hint The maximum number of records to paginate | ||||
| 	* @offset.hint The offset in the pagination | ||||
| 	* @asQuery.hint Return as query or array of objects, defaults to array of objects | ||||
| 	* @sortOrder.hint The sorting of the search results, defaults to publishedDate DESC | ||||
| 	* @isPublished.hint Search for published, non-published or both content objects [true, false, 'all'] | ||||
| 	* @searchActiveContent.hint Search only content titles or both title and active content. Defaults to both. | ||||
| 	*/ | ||||
| 	function searchContent( | ||||
| 		any searchTerm="",  | ||||
| 		numeric max=0,  | ||||
| 		numeric offset=0,  | ||||
| 		boolean asQuery=false,  | ||||
| 		any sortOrder="publishedDate DESC",  | ||||
| 		any isPublished=true,  | ||||
| 		boolean searchActiveContent=true){ | ||||
|  | ||||
| 		var results = {}; | ||||
| 		var c = newCriteria(); | ||||
|  | ||||
| 		// only published content | ||||
| 		if( isBoolean( arguments.isPublished ) ){ | ||||
| 			// Published bit | ||||
| 			c.isEq( "isPublished", javaCast( "Boolean", arguments.isPublished ) ); | ||||
| 			// Published eq true evaluate other params | ||||
| 			if( arguments.isPublished ){ | ||||
| 				c.isLt("publishedDate", now() ) | ||||
| 				.$or( c.restrictions.isNull("expireDate"), c.restrictions.isGT("expireDate", now() ) ) | ||||
| 				.isEq("passwordProtection",""); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Search Criteria | ||||
| 		if( len( arguments.searchTerm ) ){ | ||||
| 			// like disjunctions | ||||
| 			c.createAlias("activeContent","ac"); | ||||
| 			// Do we search title and active content or just title? | ||||
| 			if( arguments.searchActiveContent ){ | ||||
| 				c.$or( c.restrictions.like("title","%#arguments.searchTerm#%"), | ||||
| 				  	  c.restrictions.like("ac.content", "%#arguments.searchTerm#%") ); | ||||
| 			} | ||||
| 			else{ | ||||
| 				c.like( "title", "%#arguments.searchTerm#%" );  | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// run criteria query and projections count | ||||
| 		results.count = c.count( "contentID" ); | ||||
| 		results.content = c.resultTransformer( c.DISTINCT_ROOT_ENTITY ) | ||||
| 							.list(offset=arguments.offset, max=arguments.max, sortOrder=arguments.sortOrder, asQuery=arguments.asQuery); | ||||
| 	 | ||||
| 		return results; | ||||
| 	} | ||||
|  | ||||
| /********************************************* PRIVATE *********************************************/ | ||||
| 	 | ||||
|  | ||||
| 	/** | ||||
| 	* Update the content hits | ||||
| 	* @contentID.hint The content id to update | ||||
| 	*/ | ||||
| 	private function syncUpdateHits(required contentID){ | ||||
| 		var q = new Query(sql="UPDATE cb_content SET hits = hits + 1 WHERE contentID = #arguments.contentID#").execute(); | ||||
| 		return this; | ||||
| 	} | ||||
| 	 | ||||
| 	 | ||||
| 	private function closureTest(){ | ||||
| 		methodCall( | ||||
| 			param1, | ||||
| 			function( arg1, required arg2 ){ | ||||
| 				var settings = settingService.getAllSettings(asStruct=true); | ||||
| 				// Get appropriate cache provider | ||||
| 				var cache = cacheBox.getCache( settings.cb_content_cacheName ); | ||||
| 				cache.clear("cb-content-pagewrapper-#arguments.slug#/"); | ||||
| 				return this; | ||||
| 			}, | ||||
| 			param1 | ||||
| 		); | ||||
| 	} | ||||
| 	 | ||||
| 	private function StructliteralTest(){ | ||||
| 		return { | ||||
| 			foo = bar, | ||||
| 			brad = 'Wood', | ||||
| 			func = function( arg1, required arg2 ){ | ||||
| 				var settings = settingService.getAllSettings(asStruct=true); | ||||
| 				// Get appropriate cache provider | ||||
| 				var cache = cacheBox.getCache( settings.cb_content_cacheName ); | ||||
| 				cache.clear("cb-content-pagewrapper-#arguments.slug#/"); | ||||
| 				return this; | ||||
| 			}, | ||||
| 			array = [ | ||||
| 				1, | ||||
| 				2, | ||||
| 				3, | ||||
| 				4, | ||||
| 				5, | ||||
| 				'test', | ||||
| 				'testing', | ||||
| 				'testerton', | ||||
| 				{ | ||||
| 					foo = true, | ||||
| 					brad = false, | ||||
| 					wood = null | ||||
| 				} | ||||
| 			], | ||||
| 			last = "final" | ||||
| 		}; | ||||
| 	} | ||||
| 	 | ||||
| 	private function arrayliteralTest(){ | ||||
| 		return [ | ||||
| 			1, | ||||
| 			2, | ||||
| 			3, | ||||
| 			4, | ||||
| 			5, | ||||
| 			'test', | ||||
| 			'testing', | ||||
| 			'testerton', | ||||
| 			{ | ||||
| 				foo = true, | ||||
| 				brad = false, | ||||
| 				wood = null | ||||
| 			}, | ||||
| 			'testy-von-testavich' | ||||
| 		]; | ||||
| 	} | ||||
| 	 | ||||
| } | ||||
							
								
								
									
										18
									
								
								samples/ColdFusion CFC/exampleTag.cfc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								samples/ColdFusion CFC/exampleTag.cfc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| <cfcomponent> | ||||
| 	 | ||||
| 	<cffunction name="init" access="public" returntype="any"> | ||||
| 		<cfargument name="arg1" type="any" required="true"> | ||||
| 		<cfset this.myVariable = arguments.arg1> | ||||
|  | ||||
| 		<cfreturn this> | ||||
| 	</cffunction> | ||||
|  | ||||
| 	<cffunction name="testFunc" access="private" returntype="void"> | ||||
| 		<cfargument name="arg1" type="any" required="false"> | ||||
| 		 | ||||
| 		<cfif structKeyExists(arguments, "arg1")> | ||||
| 			<cfset writeoutput("Argument exists")> | ||||
| 		</cfif> | ||||
| 	</cffunction> | ||||
| 	 | ||||
| </cfcomponent> | ||||
							
								
								
									
										50
									
								
								samples/ColdFusion/example.cfm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								samples/ColdFusion/example.cfm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| <!--- cfcomment ---> | ||||
| <!--- nested <!--- cfcomment ---> ---> | ||||
| <!--- multi-line | ||||
| nested | ||||
| <!--- | ||||
| cfcomment | ||||
| ---> | ||||
| ---> | ||||
| <!-- html comment --> | ||||
| <html> | ||||
| <head> | ||||
| <title>Date Functions</title> | ||||
| </head> | ||||
| <body> | ||||
| <cfset RightNow = Now()> | ||||
| <cfoutput> | ||||
|  #RightNow#<br /> | ||||
|  #DateFormat(RightNow)#<br /> | ||||
|  #DateFormat(RightNow,"mm/dd/yy")#<br /> | ||||
|  #TimeFormat(RightNow)#<br /> | ||||
|  #TimeFormat(RightNow,"hh:mm tt")#<br /> | ||||
|  #IsDate(RightNow)#<br /> | ||||
|  #IsDate("January 31, 2007")#<br /> | ||||
|  #IsDate("foo")#<br /> | ||||
|  #DaysInMonth(RightNow)# | ||||
| </cfoutput> | ||||
| <cfset x="x"> | ||||
| <cfset y="y"> | ||||
| <cfset z="z"> | ||||
| <cfoutput group="x"> | ||||
|     #x# | ||||
|     <cfoutput>#y#</cfoutput> | ||||
|     #z# | ||||
| </cfoutput> | ||||
| </body> | ||||
| </html> | ||||
|  | ||||
| <cfset person = "Paul"> | ||||
| <cfset greeting = "Hello #person#"> | ||||
|  | ||||
| <cfset greeting = "Hello" & " world!"> | ||||
| <cfset a = 5> | ||||
| <cfset b = 10> | ||||
| <cfset c = a^b> | ||||
| <cfset c = a MOD b> | ||||
| <cfset c = a / b> | ||||
| <cfset c = a * b> | ||||
| <cfset c = a + b> | ||||
| <cfset c = a - b> | ||||
| <!--- <!-- another <!--- nested --> ---> comment ---> | ||||
							
								
								
									
										82
									
								
								samples/Common Lisp/macros-advanced.cl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								samples/Common Lisp/macros-advanced.cl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| ;; @file macros-advanced.cl | ||||
| ;; | ||||
| ;; @breif Advanced macro practices - defining your own macros | ||||
| ;; | ||||
| ;; Macro definition skeleton: | ||||
| ;; (defmacro name (parameter*) | ||||
| ;;   "Optional documentation string" | ||||
| ;;   body-form*) | ||||
| ;; | ||||
| ;; Note that backquote expression is most often used in the `body-form` | ||||
| ;; | ||||
|  | ||||
| ; `primep` test a number for prime | ||||
| (defun primep (n) | ||||
|   "test a number for prime" | ||||
|   (if (< n 2) (return-from primep)) | ||||
|   (do ((i 2 (1+ i)) (p t (not (zerop (mod n i))))) | ||||
|       ((> i (sqrt n)) p) | ||||
|     (when (not p) (return)))) | ||||
| ; `next-prime` return the next prime bigger than the specified number | ||||
| (defun next-prime (n) | ||||
|   "return the next prime bigger than the speicified number" | ||||
|   (do ((i (1+ n) (1+ i))) | ||||
|       ((primep i) i))) | ||||
| ; | ||||
| ; The recommended procedures to writting a new macro are as follows: | ||||
| ; 1. Write a sample call to the macro and the code it should expand into | ||||
| (do-primes (p 0 19) | ||||
|   (format t "~d " p)) | ||||
| ; Expected expanded codes | ||||
| (do ((p (next-prime (- 0 1)) (next-prime p))) | ||||
|     ((> p 19)) | ||||
|   (format t "~d " p)) | ||||
| ; 2. Write code that generate the hardwritten expansion from the arguments in | ||||
| ; the sample call | ||||
| (defmacro do-primes (var-and-range &rest body) | ||||
|   (let ((var (first var-and-range)) | ||||
|         (start (second var-and-range)) | ||||
|         (end (third var-and-range))) | ||||
|     `(do ((,var (next-prime (- ,start 1)) (next-prime ,var))) | ||||
|          ((> ,var ,end)) | ||||
|       ,@body))) | ||||
| ; 2-1. More concise implementations with the 'parameter list destructuring' and | ||||
| ; '&body' synonym, it also emits more friendly messages on incorrent input. | ||||
| (defmacro do-primes ((var start end) &body body) | ||||
|   `(do ((,var (next-prime (- ,start 1)) (next-prime ,var))) | ||||
|        ((> ,var ,end)) | ||||
|     ,@body)) | ||||
| ; 2-2. Test the result of macro expansion with the `macroexpand-1` function | ||||
| (macroexpand-1 '(do-primes (p 0 19) (format t "~d " p))) | ||||
| ; 3. Make sure the macro abstraction does not "leak" | ||||
| (defmacro do-primes ((var start end) &body body) | ||||
|   (let ((end-value-name (gensym))) | ||||
|     `(do ((,var (next-prime (- ,start 1)) (next-prime ,var)) | ||||
|           (,end-value-name ,end)) | ||||
|          ((> ,var ,end-value-name)) | ||||
|       ,@body))) | ||||
| ; 3-1. Rules to observe to avoid common and possible leaks | ||||
| ;   a. include any subforms in the expansion in positions that will be evaluated | ||||
| ;      in the same order as the subforms appear in the macro call | ||||
| ;   b. make sure subforms are evaluated only once by creating a variable in the | ||||
| ;      expansion to hold the value of evaluating the argument form, and then | ||||
| ;      using that variable anywhere else the value is needed in the expansion | ||||
| ;   c. use `gensym` at macro expansion time to create variable names used in the | ||||
| ;      expansion | ||||
| ; | ||||
| ; Appendix I. Macro-writting macros, 'with-gensyms', to guranttee that rule c | ||||
| ; gets observed. | ||||
| ; Example usage of `with-gensyms` | ||||
| (defmacro do-primes-a ((var start end) &body body) | ||||
|   "do-primes implementation with macro-writting macro 'with-gensyms'" | ||||
|   (with-gensyms (end-value-name) | ||||
|     `(do ((,var (next-prime (- ,start 1)) (next-prime ,var)) | ||||
|           (,end-value-name ,end)) | ||||
|          ((> ,var ,end-value-name)) | ||||
|       ,@body))) | ||||
| ; Define the macro, note how comma is used to interpolate the value of the loop | ||||
| ; expression | ||||
| (defmacro with-gensyms ((&rest names) &body body) | ||||
|   `(let ,(loop for n in names collect `(,n (gensym))) | ||||
|     ,@body) | ||||
| ) | ||||
							
								
								
									
										475
									
								
								samples/Common Lisp/motor-inferencia.cl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										475
									
								
								samples/Common Lisp/motor-inferencia.cl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,475 @@ | ||||
| #| | ||||
| ESCUELA POLITECNICA SUPERIOR - UNIVERSIDAD AUTONOMA DE MADRID | ||||
| INTELIGENCIA ARTIFICIAL | ||||
|  | ||||
| Motor de inferencia | ||||
| Basado en parte en "Paradigms of AI Programming: Case Studies | ||||
| in Common Lisp", de Peter Norvig, 1992 | ||||
| |# | ||||
|  | ||||
|  | ||||
| ;;;;;;;;;;;;;;;;;;;;; | ||||
| ;;;; Global variables | ||||
| ;;;;;;;;;;;;;;;;;;;;; | ||||
|  | ||||
|  | ||||
| (defvar *hypothesis-list*) | ||||
| (defvar *rule-list*) | ||||
| (defvar *fact-list*) | ||||
|  | ||||
| ;;;;;;;;;;;;;;;;;;;;; | ||||
| ;;;; Constants | ||||
| ;;;;;;;;;;;;;;;;;;;;; | ||||
|  | ||||
| (defconstant +fail+ nil "Indicates unification failure") | ||||
|  | ||||
| (defconstant +no-bindings+ '((nil)) | ||||
|   "Indicates unification success, with no variables.") | ||||
|  | ||||
| (defconstant *mundo-abierto* nil) | ||||
|  | ||||
|  | ||||
|  | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;;;; Functions for the user | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
|  | ||||
|  | ||||
| ;; Resets *fact-list* to NIL | ||||
| (defun erase-facts () (setq *fact-list* nil)) | ||||
|  | ||||
| (defun set-hypothesis-list (h) (setq *hypothesis-list* h)) | ||||
|  | ||||
|  | ||||
| ;; Returns a list of solutions, each one satisfying all the hypothesis contained | ||||
| ;; in *hypothesis-list* | ||||
| (defun motor-inferencia () | ||||
|   (consulta *hypothesis-list*)) | ||||
|  | ||||
|  | ||||
|  | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;;;; Auxiliary functions | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;; | ||||
|  | ||||
| #|____________________________________________________________________________ | ||||
| FUNCTION: CONSULTA | ||||
|  | ||||
| COMMENTS: | ||||
| CONSULTA receives a list of hypothesis (variable <hypotheses>), and returns | ||||
| a list of binding lists (each binding list being a solution). | ||||
|  | ||||
| EXAMPLES: | ||||
| hypotheses is: | ||||
| ((brothers ?x ?y) (neighbours juan ?x)). | ||||
|  | ||||
| That is, we are searching the brothers of the possible neighbors of Juan. | ||||
|  | ||||
| The function can return in this case: | ||||
|   | ||||
| (((?x . sergio) (?y . javier)) ((?x . julian) (?y . mario)) ((?x . julian) (?y . pedro))). | ||||
| That is, the neighbors of Juan (Sergio and Julian) have 3 brothers in total(Javier, Mario, Pedro) | ||||
| ____________________________________________________________________________|# | ||||
|  | ||||
| (defun consulta (hypotheses) | ||||
|   (if (null hypotheses) (list +no-bindings+) | ||||
|     (mapcan #'(lambda (b) | ||||
|                 (mapcar #'(lambda (x) (une-bindings-con-bindings b x)) | ||||
|                   (consulta (subst-bindings b (rest hypotheses))))) | ||||
|       (find-hypothesis-value (first hypotheses))))) | ||||
|  | ||||
|  | ||||
|  | ||||
| #|____________________________________________________________________________ | ||||
| FUNCTION: FIND-HYPOTHESIS-VALUE | ||||
|  | ||||
| COMMENTS: | ||||
| This function manages the query a single query (only one hypothesis) given a binding list. | ||||
| It tries (in the following order) to: | ||||
| - Answer the query from *fact-list* | ||||
| - Answer the query from the rules in *rule-list* | ||||
| - Ask the user | ||||
|  | ||||
| The function returns a list of solutions (list of binding lists). | ||||
|  | ||||
| EXAMPLES: | ||||
| If hypothesis is (brothers ?x ?y) | ||||
| and the function returns: | ||||
| (((?x . sergio) (?y . javier)) ((?x . julian) (?y . maria)) ((?x . alberto) (?y . pedro))). | ||||
|  | ||||
| Means that Sergio and Javier and brothers, Julian and Mario are brothers, and Alberto and Pedro are brothers. | ||||
| ____________________________________________________________________________|# | ||||
|  | ||||
| (defun find-hypothesis-value (hypothesis) | ||||
|   (let (rules) | ||||
|    (cond | ||||
|     ((equality? hypothesis)  | ||||
|      (value-from-equality hypothesis)) | ||||
|     ((value-from-facts hypothesis)) | ||||
|     ((setq good-rules (find-rules hypothesis))  | ||||
|      (value-from-rules hypothesis good-rules)) | ||||
|     (t (ask-user hypothesis))))) | ||||
|  | ||||
|  | ||||
|  | ||||
| ; une-bindings-con-bindings takes two binding lists and returns a binding list | ||||
| ; Assumes that b1 and b2 are not +fail+ | ||||
| (defun une-bindings-con-bindings (b1 b2) | ||||
|   (cond | ||||
|    ((equal b1 +no-bindings+) b2) | ||||
|    ((equal b2 +no-bindings+) b1) | ||||
|    (T (append b1 b2)))) | ||||
|  | ||||
|  | ||||
|  | ||||
| #|____________________________________________________________________________ | ||||
| FUNCTION: VALUE-FROM-FACTS | ||||
|  | ||||
| COMMENTS: | ||||
| Returns all the solutions of <hypothesis> obtained directly from *fact-list* | ||||
|  | ||||
| EXAMPLES: | ||||
| > (setf *fact-list* '((man luis) (man pedro)(woman mart)(man daniel)(woman laura))) | ||||
|  | ||||
| > (value-from-facts '(man ?x)) | ||||
| returns: | ||||
|  | ||||
| (((?X . LUIS)) ((?X . PEDRO)) ((?X . DANIEL))) | ||||
| ____________________________________________________________________________|# | ||||
|  | ||||
| (defun value-from-facts (hypothesis) | ||||
|   (mapcan #'(lambda(x) (let ((aux (unify hypothesis x))) | ||||
|                          (when aux (list aux)))) *fact-list*)) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| #|____________________________________________________________________________ | ||||
| FUNCTION: FIND-RULES | ||||
|  | ||||
| COMMENTS: | ||||
| Returns the rules in *rule-list* whose THENs unify with the term given in <hypothesis> | ||||
| The variables in the rules that satisfy this requirement are renamed. | ||||
|  | ||||
| EXAMPLES: | ||||
| > (setq *rule-list* | ||||
|       '((R1 (pertenece ?E (?E . ?_))) | ||||
|         (R2 (pertenece ?E (?_ . ?Xs)) :- ((pertenece ?E ?Xs))))) | ||||
|  | ||||
| Then: | ||||
| > (FIND-RULES (PERTENECE 1 (2 5))) | ||||
| returns: | ||||
| ((R2 (PERTENECE ?E.1 (?_ . ?XS.2)) :- ((PERTENECE ?E.1 ?XS.2)))) | ||||
| That is, only the THEN of rule R2 unify with <hypothesis> | ||||
|  | ||||
| However, | ||||
| > (FIND-RULES (PERTENECE 1 (1 6 7))) | ||||
|  | ||||
| returns: | ||||
| ((R1 (PERTENECE ?E.6 (?E.6 . ?_))) | ||||
|  (R2 (PERTENECE ?E.7 (?_ . ?XS.8)) :- ((PERTENECE ?E.7 ?XS.8)))) | ||||
| So the THEN of both rules unify with <hypothesis> | ||||
| ____________________________________________________________________________|# | ||||
|  | ||||
| (defun find-rules (hypothesis) | ||||
|   (mapcan #'(lambda(b) (let ((renamed-rule (rename-variables b))) | ||||
|                          (when (in-then? hypothesis renamed-rule) | ||||
|                            (list renamed-rule)))) *rule-list*)) | ||||
|  | ||||
| (defun in-then? (hypothesis rule) | ||||
|   (unless (null (rule-then rule)) | ||||
|     (not (equal +fail+ (unify hypothesis (rule-then rule)))))) | ||||
|  | ||||
|  | ||||
|  | ||||
| #|____________________________________________________________________________ | ||||
| FUNCTION: VALUE-FROM-RULES | ||||
|  | ||||
| COMMENTS: | ||||
| Returns all the solutions to <hypothesis> found using all the rules given in | ||||
| the list <rules>. Note that a single rule can have multiple solutions. | ||||
| ____________________________________________________________________________|# | ||||
| (defun value-from-rules (hypothesis rules) | ||||
|   (mapcan #'(lambda (r) (eval-rule hypothesis r)) rules)) | ||||
|  | ||||
| (defun limpia-vinculos (termino bindings) | ||||
|   (unify termino (subst-bindings bindings termino))) | ||||
|  | ||||
|  | ||||
| #|____________________________________________________________________________ | ||||
| FUNCTION: EVAL-RULE | ||||
|  | ||||
| COMMENTS: | ||||
| Returns all the solutions found using the rule given as input argument. | ||||
|  | ||||
| EXAMPLES: | ||||
| > (setq *rule-list* | ||||
|       '((R1 (pertenece ?E (?E . ?_))) | ||||
|         (R2 (pertenece ?E (?_ . ?Xs)) :- ((pertenece ?E ?Xs))))) | ||||
| Then: | ||||
| > (EVAL-RULE  | ||||
|    (PERTENECE 1 (1 6 7))  | ||||
|    (R1 (PERTENECE ?E.42 (?E.42 . ?_)))) | ||||
| returns: | ||||
| (((NIL))) | ||||
| That is, the query (PERTENECE 1 (1 6 7)) can be proven from the given rule, and | ||||
| no binding in the variables in the query is necessary (in fact, the query has no variables). | ||||
| On the other hand: | ||||
| > (EVAL-RULE  | ||||
|    (PERTENECE 1 (7))  | ||||
|    (R2 (PERTENECE ?E.49 (?_ . ?XS.50)) :- ((PERTENECE ?E.49 ?XS.50)))) | ||||
| returns: | ||||
| NIL | ||||
| That is, the query can not be proven from the rule R2. | ||||
| ____________________________________________________________________________|# | ||||
|  | ||||
| (defun eval-rule (hypothesis rule) | ||||
|   (let ((bindings-then  | ||||
|           (unify (rule-then rule) hypothesis))) | ||||
|     (unless (equal +fail+ bindings-then) | ||||
|       (if (rule-ifs rule) | ||||
|           (mapcar #'(lambda(b) (limpia-vinculos hypothesis (append bindings-then b))) | ||||
|             (consulta (subst-bindings bindings-then (rule-ifs rule)))) | ||||
|         (list (limpia-vinculos hypothesis bindings-then)))))) | ||||
|  | ||||
|  | ||||
| (defun ask-user (hypothesis) | ||||
|   (let ((question hypothesis)) | ||||
|     (cond | ||||
|      ((variables-in question) +fail+) | ||||
|      ((not-in-fact-list? question) +fail+) | ||||
|      (*mundo-abierto* | ||||
|       (format t "~%Es cierto el hecho ~S? (T/nil)" question) | ||||
|       (cond | ||||
|        ((read) (add-fact question) +no-bindings+) | ||||
|        (T (add-fact (list 'NOT question)) +fail+))) | ||||
|      (T +fail+)))) | ||||
|  | ||||
|  | ||||
| ; value-from-equality: | ||||
| (defun value-from-equality (hypothesis) | ||||
|   (let ((new-bindings (unify (second hypothesis) (third hypothesis)))) | ||||
|     (if (not (equal +fail+ new-bindings))  | ||||
| 	(list new-bindings)))) | ||||
|  | ||||
|  | ||||
|  | ||||
| #|____________________________________________________________________________ | ||||
| FUNCTION: UNIFY | ||||
|  | ||||
| COMMENTS: | ||||
| Finds the most general unifier of two input expressions, taking into account the | ||||
| bindings specified in the input <bingings> | ||||
| In case the two expressions can unify, the function returns the total bindings necessary | ||||
| for that unification. Otherwise, returns +fail+ | ||||
|  | ||||
| EXAMPLES: | ||||
| > (unify '1 '1) | ||||
| ((NIL)) ;; which is the constant +no-bindings+ | ||||
| > (unify 1 '2) | ||||
| nil     ;; which is the constant +fail+ | ||||
| > (unify '?x 1) | ||||
| ((?x . 1)) | ||||
| > (unify '(1 1) ?x) | ||||
| ((? x 1 1)) | ||||
| > (unify '?_ '?x) | ||||
| ((NIL)) | ||||
| > (unify '(p ?x 1 2) '(p ?y ?_ ?_)) | ||||
| ((?x . ?y)) | ||||
| > (unify '(?a . ?_) '(1 2 3))  | ||||
| ((?a . 1))  | ||||
| > (unify '(?_ ?_) '(1 2)) | ||||
| ((nil)) | ||||
| > (unify '(?a . ?b) '(1 2 3))  | ||||
| ((?b 2 3) (?a . 1))  | ||||
| > (unify '(?a . ?b) '(?v . ?d))  | ||||
| ((?b . ?d) (?a . ?v))  | ||||
| > (unify '(?eval (+ 1 1)) '1)  | ||||
| nil | ||||
| > (unify '(?eval (+ 1 1)) '2)  | ||||
| (nil))  | ||||
| ____________________________________________________________________________|# | ||||
|  | ||||
| (defun unify (x y &optional (bindings +no-bindings+)) | ||||
|   "See if x and y match with given bindings.  If they do, | ||||
|   return a binding list that would make them equal [p 303]." | ||||
|   (cond ((eq bindings +fail+) +fail+) | ||||
|         ((eql x y) bindings) | ||||
|         ((eval? x) (unify-eval x y bindings)) | ||||
|         ((eval? y) (unify-eval y x bindings)) | ||||
|         ((variable? x) (unify-var x y bindings)) | ||||
|         ((variable? y) (unify-var y x bindings)) | ||||
|         ((and (consp x) (consp y)) | ||||
|          (unify (rest x) (rest y)  | ||||
|                 (unify (first x) (first y) bindings))) | ||||
|         (t +fail+))) | ||||
|  | ||||
|  | ||||
| ;; rename-variables: renombra ?X por ?X.1, ?Y por ?Y.2 etc. salvo ?_ que no se renombra | ||||
| (defun rename-variables (x) | ||||
|   "Replace all variables in x with new ones. Excepto ?_" | ||||
|   (sublis (mapcar #'(lambda (var)  | ||||
| 		      (if (anonymous-var? var) | ||||
| 			  (make-binding var var) | ||||
| 			(make-binding var (new-variable var)))) | ||||
| 		  (variables-in x)) | ||||
| 	  x)) | ||||
|  | ||||
|  | ||||
|  | ||||
| ;;;; Auxiliary Functions | ||||
|  | ||||
| (defun unify-var (var x bindings) | ||||
|   "Unify var with x, using (and maybe extending) bindings [p 303]." | ||||
|   (cond ((or (anonymous-var? var)(anonymous-var? x)) bindings) | ||||
| 	((get-binding var bindings) | ||||
| 	 (unify (lookup var bindings) x bindings)) | ||||
| 	((and (variable? x) (get-binding x bindings)) | ||||
| 	 (unify var (lookup x bindings) bindings)) | ||||
| 	((occurs-in? var x bindings) | ||||
| 	 +fail+) | ||||
| 	(t (extend-bindings var x bindings)))) | ||||
|  | ||||
| (defun variable? (x) | ||||
|   "Is x a variable (a symbol starting with ?)?" | ||||
|   (and (symbolp x) (eql (char (symbol-name x) 0) #\?))) | ||||
|  | ||||
| (defun get-binding (var bindings) | ||||
|   "Find a (variable . value) pair in a binding list." | ||||
|   (assoc var bindings)) | ||||
|  | ||||
| (defun binding-var (binding) | ||||
|   "Get the variable part of a single binding." | ||||
|   (car binding)) | ||||
|  | ||||
| (defun binding-val (binding) | ||||
|   "Get the value part of a single binding." | ||||
|   (cdr binding)) | ||||
|  | ||||
| (defun make-binding (var val) (cons var val)) | ||||
|  | ||||
| (defun lookup (var bindings) | ||||
|   "Get the value part (for var) from a binding list." | ||||
|   (binding-val (get-binding var bindings))) | ||||
|  | ||||
| (defun extend-bindings (var val bindings) | ||||
|   "Add a (var . value) pair to a binding list." | ||||
|   (append  | ||||
|    (unless (eq bindings +no-bindings+) bindings) | ||||
|    (list (make-binding var val)))) | ||||
|  | ||||
| (defun occurs-in? (var x bindings) | ||||
|   "Does var occur anywhere inside x?" | ||||
|   (cond ((eq var x) t) | ||||
|         ((and (variable? x) (get-binding x bindings)) | ||||
|          (occurs-in? var (lookup x bindings) bindings)) | ||||
|         ((consp x) (or (occurs-in? var (first x) bindings) | ||||
|                        (occurs-in? var (rest x) bindings))) | ||||
|         (t nil))) | ||||
|  | ||||
| (defun subst-bindings (bindings x) | ||||
|   "Substitute the value of variables in bindings into x, | ||||
|   taking recursively bound variables into account." | ||||
|   (cond ((eq bindings +fail+) +fail+) | ||||
|         ((eq bindings +no-bindings+) x) | ||||
|         ((and (listp x) (eq '?eval (car x))) | ||||
|          (subst-bindings-quote bindings x)) | ||||
|         ((and (variable? x) (get-binding x bindings)) | ||||
|          (subst-bindings bindings (lookup x bindings))) | ||||
|         ((atom x) x) | ||||
|         (t (cons (subst-bindings bindings (car x)) ;; s/reuse-cons/cons | ||||
| 		 (subst-bindings bindings (cdr x)))))) | ||||
|  | ||||
| (defun unifier (x y) | ||||
|  "Return something that unifies with both x and y (or fail)." | ||||
|  (subst-bindings (unify x y) x)) | ||||
|  | ||||
| (defun variables-in (exp) | ||||
|   "Return a list of all the variables in EXP." | ||||
|   (unique-find-anywhere-if #'variable? exp)) | ||||
|  | ||||
| (defun unique-find-anywhere-if (predicate tree &optional found-so-far) | ||||
|   "Return a list of leaves of tree satisfying predicate, | ||||
|   with duplicates removed." | ||||
|   (if (atom tree) | ||||
|       (if (funcall predicate tree) | ||||
|           (pushnew tree found-so-far) | ||||
|           found-so-far) | ||||
|     (unique-find-anywhere-if | ||||
|         predicate | ||||
|         (first tree) | ||||
|         (unique-find-anywhere-if predicate (rest tree) | ||||
|                                  found-so-far)))) | ||||
|  | ||||
| (defun find-anywhere-if (predicate tree) | ||||
|   "Does predicate apply to any atom in the tree?"   | ||||
|   (if (atom tree) | ||||
|       (funcall predicate tree) | ||||
|       (or (find-anywhere-if predicate (first tree)) | ||||
|           (find-anywhere-if predicate (rest tree))))) | ||||
|  | ||||
| (defun new-variable (var) | ||||
|   "Create a new variable.  Assumes user never types variables of form ?X.9" | ||||
|   (gentemp (format nil "~S." var))) | ||||
| ;  (gentemp "?") ) | ||||
| ;;; | ||||
|  | ||||
| (defun anonymous-var? (x) | ||||
|   (eq x '?_)) | ||||
|  | ||||
| (defun subst-bindings-quote (bindings x) | ||||
|   "Substitute the value of variables in bindings into x, | ||||
|   taking recursively bound variables into account." | ||||
|   (cond ((eq bindings +fail+) +fail+) | ||||
|         ((eq bindings +no-bindings+) x) | ||||
|         ((and (variable? x) (get-binding x bindings)) | ||||
|          (if (variable? (lookup x bindings)) | ||||
|              (subst-bindings-quote bindings (lookup x bindings)) | ||||
|              (subst-bindings-quote bindings (list 'quote (lookup x bindings))) | ||||
|          ) | ||||
|         )      | ||||
|         ((atom x) x) | ||||
|         (t (cons (subst-bindings-quote bindings (car x)) ;; s/reuse-cons/cons | ||||
| 		 (subst-bindings-quote bindings (cdr x)))))) | ||||
|  | ||||
| (defun eval? (x) | ||||
|   (and (consp x) (eq (first x) '?eval))) | ||||
|  | ||||
| (defun unify-eval (x y bindings) | ||||
|   (let ((exp (subst-bindings-quote bindings (second x)))) | ||||
|     (if (variables-in exp) | ||||
| 	+fail+ | ||||
|       (unify (eval exp) y bindings)))) | ||||
|  | ||||
|  | ||||
|  | ||||
| (defun rule-ifs (rule) (fourth rule)) | ||||
| (defun rule-then (rule) (second rule)) | ||||
|  | ||||
|  | ||||
| (defun equality? (term) | ||||
|   (and (consp term) (eql (first term) '?=))) | ||||
|  | ||||
|  | ||||
| (defun in-fact-list? (expresion) | ||||
|   (some #'(lambda(x) (equal x expresion)) *fact-list*)) | ||||
|                       | ||||
| (defun not-in-fact-list? (expresion) | ||||
|   (if (eq (car expresion) 'NOT) | ||||
|       (in-fact-list? (second expresion)) | ||||
|     (in-fact-list? (list 'NOT expresion)))) | ||||
|  | ||||
|  | ||||
| ;; add-fact: | ||||
|  | ||||
| (defun add-fact (fact) | ||||
|   (setq *fact-list* (cons fact *fact-list*))) | ||||
|  | ||||
|  | ||||
| (defun variable? (x) | ||||
|   "Is x a variable (a symbol starting with ?) except ?eval and ?=" | ||||
|   (and (not (equal x '?eval)) (not (equal x '?=))  | ||||
|        (symbolp x) (eql (char (symbol-name x) 0) #\?))) | ||||
|  | ||||
|  | ||||
| ;; EOF | ||||
							
								
								
									
										130
									
								
								samples/Component Pascal/Example.cp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								samples/Component Pascal/Example.cp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | ||||
| MODULE ObxControls; | ||||
| (** | ||||
|     project         = "BlackBox" | ||||
|     organization    = "www.oberon.ch" | ||||
|     contributors    = "Oberon microsystems" | ||||
|     version         = "System/Rsrc/About" | ||||
|     copyright       = "System/Rsrc/About" | ||||
|     license         = "Docu/BB-License" | ||||
|     changes         = "" | ||||
|     issues          = "" | ||||
|  | ||||
| **) | ||||
|  | ||||
| IMPORT Dialog, Ports, Properties, Views; | ||||
|  | ||||
| CONST beginner = 0; advanced = 1; expert = 2; guru = 3;    (* user classes *) | ||||
|  | ||||
| TYPE | ||||
|     View = POINTER TO RECORD (Views.View) | ||||
|         size: INTEGER    (* border size in mm *) | ||||
|     END; | ||||
|  | ||||
| VAR | ||||
|     data*: RECORD | ||||
|         class*: INTEGER;    (* current user class *) | ||||
|         list*: Dialog.List;    (* list of currently available sizes, derived from class *) | ||||
|         width*: INTEGER    (* width of next view to be opened. Derived from | ||||
|                                     class, or entered through a text entry field *) | ||||
|     END; | ||||
|  | ||||
|     predef: ARRAY 6 OF INTEGER;    (* table of predefined sizes *) | ||||
|  | ||||
|  | ||||
| PROCEDURE SetList; | ||||
| BEGIN | ||||
|     IF data.class = beginner THEN | ||||
|         data.list.SetLen(1); | ||||
|         data.list.SetItem(0, "default") | ||||
|     ELSIF data.class = advanced THEN | ||||
|         data.list.SetLen(4); | ||||
|         data.list.SetItem(0, "default"); | ||||
|         data.list.SetItem(1, "small"); | ||||
|         data.list.SetItem(2, "medium"); | ||||
|         data.list.SetItem(3, "large"); | ||||
|     ELSE | ||||
|         data.list.SetLen(6); | ||||
|         data.list.SetItem(0, "default"); | ||||
|         data.list.SetItem(1, "small"); | ||||
|         data.list.SetItem(2, "medium"); | ||||
|         data.list.SetItem(3, "large"); | ||||
|         data.list.SetItem(4, "tiny"); | ||||
|         data.list.SetItem(5, "huge"); | ||||
|     END | ||||
| END SetList; | ||||
|  | ||||
| (* View *) | ||||
|  | ||||
| PROCEDURE (v: View) CopyFromSimpleView (source: Views.View); | ||||
| BEGIN | ||||
|     v.size := source(View).size | ||||
| END CopyFromSimpleView; | ||||
|  | ||||
| PROCEDURE (v: View) Restore (f: Views.Frame; l, t, r, b: INTEGER); | ||||
| BEGIN    (* fill view with a red square of size v.size *) | ||||
|     IF v.size = 0 THEN v.size := predef[0] END;    (* lazy initialization of size *) | ||||
|     f.DrawRect(0, 0, v.size, v.size, Ports.fill, Ports.red) | ||||
| END Restore; | ||||
|  | ||||
| PROCEDURE (v: View) HandlePropMsg (VAR msg: Views.PropMessage); | ||||
| BEGIN | ||||
|     WITH msg: Properties.SizePref DO | ||||
|         IF v.size = 0 THEN v.size := predef[0] END;    (* lazy initialization of size *) | ||||
|         msg.w := v.size; msg.h := v.size    (* tell environment about desired width and height *) | ||||
|     ELSE    (* ignore other messages *) | ||||
|     END | ||||
| END HandlePropMsg; | ||||
|  | ||||
| (* notifiers *) | ||||
|  | ||||
| PROCEDURE ClassNotify* (op, from, to: INTEGER); | ||||
| BEGIN    (* react to change in data.class *) | ||||
|     IF op = Dialog.changed THEN | ||||
|         IF (to = beginner) OR (to = advanced) & (data.list.index > 3) THEN | ||||
|             (* if class is reduced, make sure that selection contains legal elements *) | ||||
|             data.list.index := 0; data.width := predef[0];    (* modify interactor *) | ||||
|             Dialog.Update(data)    (* redraw controls where necessary *) | ||||
|         END; | ||||
|         SetList; | ||||
|         Dialog.UpdateList(data.list)    (* reconstruct list box contents *) | ||||
|     END | ||||
| END ClassNotify; | ||||
|  | ||||
| PROCEDURE ListNotify* (op, from, to: INTEGER); | ||||
| BEGIN    (* reacto to change in data.list (index to was selected) *) | ||||
|     IF op = Dialog.changed THEN | ||||
|         data.width := predef[to];    (* modify interactor *) | ||||
|         Dialog.Update(data)    (* redraw controls where necessary *) | ||||
|     END | ||||
| END ListNotify; | ||||
|  | ||||
| (* guards *) | ||||
|  | ||||
| PROCEDURE ListGuard* (VAR par: Dialog.Par); | ||||
| BEGIN    (* disable list box for a beginner *) | ||||
|     par.disabled := data.class = beginner | ||||
| END ListGuard; | ||||
|  | ||||
| PROCEDURE WidthGuard* (VAR par: Dialog.Par); | ||||
| BEGIN    (* make text entry field read-only if user is not guru *) | ||||
|     par.readOnly := data.class # guru | ||||
| END WidthGuard; | ||||
|  | ||||
| (* commands *) | ||||
|  | ||||
| PROCEDURE Open*; | ||||
|     VAR v: View; | ||||
| BEGIN | ||||
|     NEW(v);    (* create and initialize a new view *) | ||||
|     v.size := data.width * Ports.mm;    (* define view's size in function of class *) | ||||
|     Views.OpenAux(v, "Example")    (* open the view in a window *) | ||||
| END Open; | ||||
|  | ||||
| BEGIN    (* initialization of global variables *) | ||||
|     predef[0] := 40; predef[1] := 30; predef[2] := 50;    (* predefined sizes *) | ||||
|     predef[3] := 70; predef[4] := 20; predef[5] := 100; | ||||
|     data.class := beginner;    (* default values *) | ||||
|     data.list.index := 0; | ||||
|     data.width := predef[0]; | ||||
|     SetList | ||||
| END ObxControls. | ||||
							
								
								
									
										71
									
								
								samples/Component Pascal/Example2.cps
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								samples/Component Pascal/Example2.cps
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| MODULE ObxFact; | ||||
| (** | ||||
|     project         = "BlackBox" | ||||
|     organization    = "www.oberon.ch" | ||||
|     contributors    = "Oberon microsystems" | ||||
|     version         = "System/Rsrc/About" | ||||
|     copyright       = "System/Rsrc/About" | ||||
|     license         = "Docu/BB-License" | ||||
|     changes         = "" | ||||
|     issues          = "" | ||||
|  | ||||
| **) | ||||
|  | ||||
| IMPORT | ||||
|     Stores, Models, TextModels, TextControllers, Integers; | ||||
|  | ||||
| PROCEDURE Read(r: TextModels.Reader; VAR x: Integers.Integer); | ||||
|     VAR i, len, beg: INTEGER; ch: CHAR; buf: POINTER TO ARRAY OF CHAR; | ||||
| BEGIN | ||||
|     r.ReadChar(ch); | ||||
|     WHILE ~r.eot & (ch <= " ") DO r.ReadChar(ch) END; | ||||
|     ASSERT(~r.eot & (((ch >= "0") & (ch <= "9")) OR (ch = "-"))); | ||||
|     beg := r.Pos() - 1; len := 0; | ||||
|     REPEAT INC(len); r.ReadChar(ch) UNTIL r.eot OR (ch < "0") OR (ch > "9"); | ||||
|     NEW(buf, len + 1); | ||||
|     i := 0; r.SetPos(beg); | ||||
|     REPEAT r.ReadChar(buf[i]); INC(i) UNTIL i = len; | ||||
|     buf[i] := 0X; | ||||
|     Integers.ConvertFromString(buf^, x) | ||||
| END Read; | ||||
|  | ||||
| PROCEDURE Write(w: TextModels.Writer; x: Integers.Integer); | ||||
|     VAR i: INTEGER; | ||||
| BEGIN | ||||
|     IF Integers.Sign(x) < 0 THEN w.WriteChar("-") END; | ||||
|     i := Integers.Digits10Of(x); | ||||
|     IF i # 0 THEN | ||||
|         REPEAT DEC(i); w.WriteChar(Integers.ThisDigit10(x, i)) UNTIL i = 0 | ||||
|     ELSE w.WriteChar("0") | ||||
|     END | ||||
| END Write; | ||||
|  | ||||
| PROCEDURE Compute*; | ||||
|     VAR beg, end, i, n: INTEGER; ch: CHAR; | ||||
|         s: Stores.Operation; | ||||
|         r: TextModels.Reader; w: TextModels.Writer; attr: TextModels.Attributes; | ||||
|         c: TextControllers.Controller; | ||||
|         x: Integers.Integer; | ||||
| BEGIN | ||||
|     c := TextControllers.Focus(); | ||||
|     IF (c # NIL) & c.HasSelection() THEN | ||||
|         c.GetSelection(beg, end); | ||||
|         r := c.text.NewReader(NIL); r.SetPos(beg); r.ReadChar(ch); | ||||
|         WHILE ~r.eot & (beg < end) & (ch <= " ") DO r.ReadChar(ch); INC(beg) END; | ||||
|         IF ~r.eot & (beg < end) THEN | ||||
|             r.ReadPrev; Read(r, x); | ||||
|             end := r.Pos(); r.ReadPrev; attr :=r.attr; | ||||
|             IF (Integers.Sign(x) > 0) & (Integers.Compare(x, Integers.Long(MAX(LONGINT))) <= 0) THEN | ||||
|                 n := SHORT(Integers.Short(x)); i := 2; x := Integers.Long(1); | ||||
|                 WHILE i <= n DO x := Integers.Product(x, Integers.Long(i)); INC(i) END; | ||||
|                 Models.BeginScript(c.text, "computation", s); | ||||
|                 c.text.Delete(beg, end); | ||||
|                 w := c.text.NewWriter(NIL); w.SetPos(beg); w.SetAttr(attr); | ||||
|                 Write(w, x); | ||||
|                 Models.EndScript(c.text, s) | ||||
|             END | ||||
|         END | ||||
|     END | ||||
| END Compute; | ||||
|  | ||||
| END ObxFact. | ||||
							
								
								
									
										169
									
								
								samples/Crystal/const_spec.cr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								samples/Crystal/const_spec.cr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | ||||
| #!/usr/bin/env bin/crystal --run | ||||
| require "../../spec_helper" | ||||
|  | ||||
| describe "Codegen: const" do | ||||
|   it "define a constant" do | ||||
|     run("A = 1; A").to_i.should eq(1) | ||||
|   end | ||||
|  | ||||
|   it "support nested constant" do | ||||
|     run("class B; A = 1; end; B::A").to_i.should eq(1) | ||||
|   end | ||||
|  | ||||
|   it "support constant inside a def" do | ||||
|     run(" | ||||
|       class Foo | ||||
|         A = 1 | ||||
|  | ||||
|         def foo | ||||
|           A | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       Foo.new.foo | ||||
|     ").to_i.should eq(1) | ||||
|   end | ||||
|  | ||||
|   it "finds nearest constant first" do | ||||
|     run(" | ||||
|       A = 1 | ||||
|  | ||||
|       class Foo | ||||
|         A = 2.5_f32 | ||||
|  | ||||
|         def foo | ||||
|           A | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       Foo.new.foo | ||||
|     ").to_f32.should eq(2.5) | ||||
|   end | ||||
|  | ||||
|   it "allows constants with same name" do | ||||
|     run(" | ||||
|       A = 1 | ||||
|  | ||||
|       class Foo | ||||
|         A = 2.5_f32 | ||||
|  | ||||
|         def foo | ||||
|           A | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       A | ||||
|       Foo.new.foo | ||||
|     ").to_f32.should eq(2.5) | ||||
|   end | ||||
|  | ||||
|   it "constants with expression" do | ||||
|     run(" | ||||
|       A = 1 + 1 | ||||
|       A | ||||
|     ").to_i.should eq(2) | ||||
|   end | ||||
|  | ||||
|   it "finds global constant" do | ||||
|     run(" | ||||
|       A = 1 | ||||
|  | ||||
|       class Foo | ||||
|         def foo | ||||
|           A | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       Foo.new.foo | ||||
|     ").to_i.should eq(1) | ||||
|   end | ||||
|  | ||||
|   it "define a constant in lib" do | ||||
|     run("lib Foo; A = 1; end; Foo::A").to_i.should eq(1) | ||||
|   end | ||||
|  | ||||
|   it "invokes block in const" do | ||||
|     run("require \"prelude\"; A = [\"1\"].map { |x| x.to_i }; A[0]").to_i.should eq(1) | ||||
|   end | ||||
|  | ||||
|   it "declare constants in right order" do | ||||
|     run("A = 1 + 1; B = true ? A : 0; B").to_i.should eq(2) | ||||
|   end | ||||
|  | ||||
|   it "uses correct types lookup" do | ||||
|     run(" | ||||
|       module A | ||||
|         class B | ||||
|           def foo | ||||
|             1 | ||||
|           end | ||||
|         end | ||||
|  | ||||
|         C = B.new; | ||||
|       end | ||||
|  | ||||
|       def foo | ||||
|         A::C.foo | ||||
|       end | ||||
|  | ||||
|       foo | ||||
|       ").to_i.should eq(1) | ||||
|   end | ||||
|  | ||||
|   it "codegens variable assignment in const" do | ||||
|     run(" | ||||
|       class Foo | ||||
|         def initialize(@x) | ||||
|         end | ||||
|  | ||||
|         def x | ||||
|           @x | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       A = begin | ||||
|             f = Foo.new(1) | ||||
|             f | ||||
|           end | ||||
|  | ||||
|       def foo | ||||
|         A.x | ||||
|       end | ||||
|  | ||||
|       foo | ||||
|       ").to_i.should eq(1) | ||||
|   end | ||||
|  | ||||
|   it "declaring var" do | ||||
|     run(" | ||||
|       BAR = begin | ||||
|         a = 1 | ||||
|         while 1 == 2 | ||||
|           b = 2 | ||||
|         end | ||||
|         a | ||||
|       end | ||||
|       class Foo | ||||
|         def compile | ||||
|           BAR | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       Foo.new.compile | ||||
|       ").to_i.should eq(1) | ||||
|   end | ||||
|  | ||||
|   it "initialize const that might raise an exception" do | ||||
|     run(" | ||||
|       require \"prelude\" | ||||
|       CONST = (raise \"OH NO\" if 1 == 2) | ||||
|  | ||||
|       def doit | ||||
|         CONST | ||||
|       rescue | ||||
|       end | ||||
|  | ||||
|       doit.nil? | ||||
|     ").to_b.should be_true | ||||
|   end | ||||
| end | ||||
							
								
								
									
										79
									
								
								samples/Crystal/declare_var_spec.cr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								samples/Crystal/declare_var_spec.cr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | ||||
| #!/usr/bin/env bin/crystal --run | ||||
| require "../../spec_helper" | ||||
|  | ||||
| describe "Type inference: declare var" do | ||||
|   it "types declare var" do | ||||
|     assert_type("a :: Int32") { int32 } | ||||
|   end | ||||
|  | ||||
|   it "types declare var and reads it" do | ||||
|     assert_type("a :: Int32; a") { int32 } | ||||
|   end | ||||
|  | ||||
|   it "types declare var and changes its type" do | ||||
|     assert_type("a :: Int32; while 1 == 2; a = 'a'; end; a") { union_of(int32, char) } | ||||
|   end | ||||
|  | ||||
|   it "declares instance var which appears in initialize" do | ||||
|     result = assert_type(" | ||||
|       class Foo | ||||
|         @x :: Int32 | ||||
|       end | ||||
|  | ||||
|       Foo.new") { types["Foo"] } | ||||
|  | ||||
|     mod = result.program | ||||
|  | ||||
|     foo = mod.types["Foo"] as NonGenericClassType | ||||
|     foo.instance_vars["@x"].type.should eq(mod.int32) | ||||
|   end | ||||
|  | ||||
|   it "declares instance var of generic class" do | ||||
|     result = assert_type(" | ||||
|       class Foo(T) | ||||
|         @x :: T | ||||
|       end | ||||
|  | ||||
|       Foo(Int32).new") do | ||||
|         foo = types["Foo"] as GenericClassType | ||||
|         foo_i32 = foo.instantiate([int32] of Type | ASTNode) | ||||
|         foo_i32.lookup_instance_var("@x").type.should eq(int32) | ||||
|         foo_i32 | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   it "declares instance var of generic class after reopen" do | ||||
|     result = assert_type(" | ||||
|       class Foo(T) | ||||
|       end | ||||
|  | ||||
|       f = Foo(Int32).new | ||||
|  | ||||
|       class Foo(T) | ||||
|         @x :: T | ||||
|       end | ||||
|  | ||||
|       f") do | ||||
|         foo = types["Foo"] as GenericClassType | ||||
|         foo_i32 = foo.instantiate([int32] of Type | ASTNode) | ||||
|         foo_i32.lookup_instance_var("@x").type.should eq(int32) | ||||
|         foo_i32 | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   it "declares an instance variable in initialize" do | ||||
|     assert_type(" | ||||
|       class Foo | ||||
|         def initialize | ||||
|           @x :: Int32 | ||||
|         end | ||||
|  | ||||
|         def x | ||||
|           @x | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       Foo.new.x | ||||
|       ") { int32 } | ||||
|   end | ||||
| end | ||||
							
								
								
									
										515
									
								
								samples/Crystal/transformer.cr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										515
									
								
								samples/Crystal/transformer.cr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,515 @@ | ||||
| module Crystal | ||||
|   class ASTNode | ||||
|     def transform(transformer) | ||||
|       transformer.before_transform self | ||||
|       node = transformer.transform self | ||||
|       transformer.after_transform self | ||||
|       node | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   class Transformer | ||||
|     def before_transform(node) | ||||
|     end | ||||
|  | ||||
|     def after_transform(node) | ||||
|     end | ||||
|  | ||||
|     def transform(node : Expressions) | ||||
|       exps = [] of ASTNode | ||||
|       node.expressions.each do |exp| | ||||
|         new_exp = exp.transform(self) | ||||
|         if new_exp | ||||
|           if new_exp.is_a?(Expressions) | ||||
|             exps.concat new_exp.expressions | ||||
|           else | ||||
|             exps << new_exp | ||||
|           end | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       if exps.length == 1 | ||||
|         exps[0] | ||||
|       else | ||||
|         node.expressions = exps | ||||
|         node | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     def transform(node : Call) | ||||
|       if node_obj = node.obj | ||||
|         node.obj = node_obj.transform(self) | ||||
|       end | ||||
|       transform_many node.args | ||||
|  | ||||
|       if node_block = node.block | ||||
|         node.block = node_block.transform(self) | ||||
|       end | ||||
|  | ||||
|       if node_block_arg = node.block_arg | ||||
|         node.block_arg = node_block_arg.transform(self) | ||||
|       end | ||||
|  | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : And) | ||||
|       node.left = node.left.transform(self) | ||||
|       node.right = node.right.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Or) | ||||
|       node.left = node.left.transform(self) | ||||
|       node.right = node.right.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : StringInterpolation) | ||||
|       transform_many node.expressions | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : ArrayLiteral) | ||||
|       transform_many node.elements | ||||
|  | ||||
|       if node_of = node.of | ||||
|         node.of = node_of.transform(self) | ||||
|       end | ||||
|  | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : HashLiteral) | ||||
|       transform_many node.keys | ||||
|       transform_many node.values | ||||
|  | ||||
|       if of_key = node.of_key | ||||
|         node.of_key = of_key.transform(self) | ||||
|       end | ||||
|  | ||||
|       if of_value = node.of_value | ||||
|         node.of_value = of_value.transform(self) | ||||
|       end | ||||
|  | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : If) | ||||
|       node.cond = node.cond.transform(self) | ||||
|       node.then = node.then.transform(self) | ||||
|       node.else = node.else.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Unless) | ||||
|       node.cond = node.cond.transform(self) | ||||
|       node.then = node.then.transform(self) | ||||
|       node.else = node.else.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : IfDef) | ||||
|       node.cond = node.cond.transform(self) | ||||
|       node.then = node.then.transform(self) | ||||
|       node.else = node.else.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : MultiAssign) | ||||
|       transform_many node.targets | ||||
|       transform_many node.values | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : SimpleOr) | ||||
|       node.left = node.left.transform(self) | ||||
|       node.right = node.right.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Def) | ||||
|       transform_many node.args | ||||
|       node.body = node.body.transform(self) | ||||
|  | ||||
|       if receiver = node.receiver | ||||
|         node.receiver = receiver.transform(self) | ||||
|       end | ||||
|  | ||||
|       if block_arg = node.block_arg | ||||
|         node.block_arg = block_arg.transform(self) | ||||
|       end | ||||
|  | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Macro) | ||||
|       transform_many node.args | ||||
|       node.body = node.body.transform(self) | ||||
|  | ||||
|       if receiver = node.receiver | ||||
|         node.receiver = receiver.transform(self) | ||||
|       end | ||||
|  | ||||
|       if block_arg = node.block_arg | ||||
|         node.block_arg = block_arg.transform(self) | ||||
|       end | ||||
|  | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : PointerOf) | ||||
|       node.exp = node.exp.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : SizeOf) | ||||
|       node.exp = node.exp.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : InstanceSizeOf) | ||||
|       node.exp = node.exp.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : IsA) | ||||
|       node.obj = node.obj.transform(self) | ||||
|       node.const = node.const.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : RespondsTo) | ||||
|       node.obj = node.obj.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Case) | ||||
|       node.cond = node.cond.transform(self) | ||||
|       transform_many node.whens | ||||
|  | ||||
|       if node_else = node.else | ||||
|         node.else = node_else.transform(self) | ||||
|       end | ||||
|  | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : When) | ||||
|       transform_many node.conds | ||||
|       node.body = node.body.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : ImplicitObj) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : ClassDef) | ||||
|       node.body = node.body.transform(self) | ||||
|  | ||||
|       if superclass = node.superclass | ||||
|         node.superclass = superclass.transform(self) | ||||
|       end | ||||
|  | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : ModuleDef) | ||||
|       node.body = node.body.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : While) | ||||
|       node.cond = node.cond.transform(self) | ||||
|       node.body = node.body.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Generic) | ||||
|       node.name = node.name.transform(self) | ||||
|       transform_many node.type_vars | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : ExceptionHandler) | ||||
|       node.body = node.body.transform(self) | ||||
|       transform_many node.rescues | ||||
|  | ||||
|       if node_ensure = node.ensure | ||||
|         node.ensure = node_ensure.transform(self) | ||||
|       end | ||||
|  | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Rescue) | ||||
|       node.body = node.body.transform(self) | ||||
|       transform_many node.types | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Union) | ||||
|       transform_many node.types | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Hierarchy) | ||||
|       node.name = node.name.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Metaclass) | ||||
|       node.name = node.name.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Arg) | ||||
|       if default_value = node.default_value | ||||
|         node.default_value = default_value.transform(self) | ||||
|       end | ||||
|  | ||||
|       if restriction = node.restriction | ||||
|         node.restriction = restriction.transform(self) | ||||
|       end | ||||
|  | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : BlockArg) | ||||
|       node.fun = node.fun.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Fun) | ||||
|       transform_many node.inputs | ||||
|  | ||||
|       if output = node.output | ||||
|         node.output = output.transform(self) | ||||
|       end | ||||
|  | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Block) | ||||
|       node.args.map! { |exp| exp.transform(self) as Var } | ||||
|       node.body = node.body.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : FunLiteral) | ||||
|       node.def.body = node.def.body.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : FunPointer) | ||||
|       if obj = node.obj | ||||
|         node.obj = obj.transform(self) | ||||
|       end | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Return) | ||||
|       transform_many node.exps | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Break) | ||||
|       transform_many node.exps | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Next) | ||||
|       transform_many node.exps | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Yield) | ||||
|       if scope = node.scope | ||||
|         node.scope = scope.transform(self) | ||||
|       end | ||||
|       transform_many node.exps | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Include) | ||||
|       node.name = node.name.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Extend) | ||||
|       node.name = node.name.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : RangeLiteral) | ||||
|       node.from = node.from.transform(self) | ||||
|       node.to = node.to.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Assign) | ||||
|       node.target = node.target.transform(self) | ||||
|       node.value = node.value.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Nop) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : NilLiteral) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : BoolLiteral) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : NumberLiteral) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : CharLiteral) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : StringLiteral) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : SymbolLiteral) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : RegexLiteral) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Var) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : MetaVar) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : InstanceVar) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : ClassVar) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Global) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Require) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Path) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : LibDef) | ||||
|       node.body = node.body.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : FunDef) | ||||
|       if body = node.body | ||||
|         node.body = body.transform(self) | ||||
|       end | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : TypeDef) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : StructDef) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : UnionDef) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : EnumDef) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : ExternalVar) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : IndirectRead) | ||||
|       node.obj = node.obj.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : IndirectWrite) | ||||
|       node.obj = node.obj.transform(self) | ||||
|       node.value = node.value.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : TypeOf) | ||||
|       transform_many node.expressions | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Primitive) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Not) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : TypeFilteredNode) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : TupleLiteral) | ||||
|       transform_many node.exps | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Cast) | ||||
|       node.obj = node.obj.transform(self) | ||||
|       node.to = node.to.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : DeclareVar) | ||||
|       node.var = node.var.transform(self) | ||||
|       node.declared_type = node.declared_type.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Alias) | ||||
|       node.value = node.value.transform(self) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : TupleIndexer) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform(node : Attribute) | ||||
|       node | ||||
|     end | ||||
|  | ||||
|     def transform_many(exps) | ||||
|       exps.map! { |exp| exp.transform(self) } if exps | ||||
|     end | ||||
|   end | ||||
| end | ||||
							
								
								
									
										580
									
								
								samples/Cycript/utils.cy
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										580
									
								
								samples/Cycript/utils.cy
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,580 @@ | ||||
| (function(utils) { | ||||
| 	// Load C functions declared in utils.loadFuncs | ||||
| 	var shouldLoadCFuncs = true; | ||||
| 	// Expose the C functions to cycript's global scope | ||||
| 	var shouldExposeCFuncs = true; | ||||
| 	// Expose C constants to cycript's global scope | ||||
| 	var shouldExposeConsts = true; | ||||
| 	// Expose functions defined here to cycript's global scope | ||||
| 	var shouldExposeFuncs = true; | ||||
| 	// Which functions to expose | ||||
| 	var funcsToExpose = ["exec", "include", "sizeof", "logify", "apply", "str2voidPtr", "voidPtr2str", "double2voidPtr", "voidPtr2double", "isMemoryReadable", "isObject", "makeStruct"]; | ||||
| 	 | ||||
| 	// C functions that utils.loadFuncs loads | ||||
| 	var CFuncsDeclarations = [ | ||||
| 		// <stdlib.h> | ||||
| 		"void *calloc(size_t num, size_t size)", | ||||
| 		// <string.h> | ||||
| 		"char *strcpy(char *restrict dst, const char *restrict src)", | ||||
| 		"char *strdup(const char *s1)", | ||||
| 		"void* memset(void* dest, int ch, size_t count)", | ||||
| 		// <stdio.h> | ||||
| 		"FILE *fopen(const char *, const char *)", | ||||
| 		"int fclose(FILE *)", | ||||
| 		"size_t fread(void *restrict, size_t, size_t, FILE *restrict)", | ||||
| 		"size_t fwrite(const void *restrict, size_t, size_t, FILE *restrict)", | ||||
| 		// <mach.h> | ||||
| 		"mach_port_t mach_task_self()", | ||||
| 		"kern_return_t task_for_pid(mach_port_name_t target_tport, int pid, mach_port_name_t *tn)", | ||||
| 		"kern_return_t mach_vm_protect(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, boolean_t set_maximum, vm_prot_t new_protection)", | ||||
| 		"kern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt)", | ||||
| 		"kern_return_t mach_vm_read(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, vm_offset_t *data, mach_msg_type_number_t *dataCnt)", | ||||
| 	]; | ||||
| 	 | ||||
| 	/* | ||||
| 		Replacement for eval that can handle @encode etc. | ||||
| 		 | ||||
| 		Usage: | ||||
| 			cy# utils.exec("@encode(void *(int, char))") | ||||
| 			@encode(void*(int,char)) | ||||
| 	*/ | ||||
| 	utils.exec = function(str) { | ||||
| 		var mkdir = @encode(int (const char *, int))(dlsym(RTLD_DEFAULT, "mkdir")); | ||||
| 		var tempnam = @encode(char *(const char *, const char *))(dlsym(RTLD_DEFAULT, "tempnam")); | ||||
| 		var fopen = @encode(void *(const char *, const char *))(dlsym(RTLD_DEFAULT, "fopen")); | ||||
| 		var fclose = @encode(int (void *))(dlsym(RTLD_DEFAULT, "fclose")); | ||||
| 		var fwrite = @encode(int (const char *, int, int, void *))(dlsym(RTLD_DEFAULT, "fwrite")); | ||||
| 		var symlink = @encode(int (const char *, const char *))(dlsym(RTLD_DEFAULT, "symlink")); | ||||
| 		var unlink = @encode(int (const char *))(dlsym(RTLD_DEFAULT, "unlink")); | ||||
| 		var getenv = @encode(const char *(const char *))(dlsym(RTLD_DEFAULT, "getenv")); | ||||
| 		var setenv = @encode(int (const char *, const char *, int))(dlsym(RTLD_DEFAULT, "setenv")); | ||||
| 		 | ||||
| 		var libdir = "/usr/lib/cycript0.9"; | ||||
| 		var dir = libdir + "/tmp"; | ||||
|  | ||||
| 		mkdir(dir, 0777); | ||||
| 		 | ||||
| 		// This is needed because tempnam seems to ignore the first argument on i386 | ||||
| 		var old_tmpdir = getenv("TMPDIR"); | ||||
| 		setenv("TMPDIR", dir, 1); | ||||
|  | ||||
| 		// No freeing :( | ||||
| 		var f = tempnam(dir, "exec-"); | ||||
| 		setenv("TMPDIR", old_tmpdir, 1); | ||||
| 		if(!f) { | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		symlink(f, f + ".cy"); | ||||
| 		 | ||||
| 		str = "exports.result = " + str; | ||||
|  | ||||
| 		var handle = fopen(f, "w"); | ||||
| 		fwrite(str, str.length, 1, handle); | ||||
| 		fclose(handle); | ||||
| 		 | ||||
| 		var r; | ||||
| 		var except = null; | ||||
| 		try { | ||||
| 			r = require(f.replace(libdir + "/", "")); | ||||
| 		} catch(e) { | ||||
| 			except = e; | ||||
| 		} | ||||
|  | ||||
| 		unlink(f + ".cy"); | ||||
| 		unlink(f); | ||||
| 		 | ||||
| 		if(except !== null) { | ||||
| 			throw except; | ||||
| 		} | ||||
|  | ||||
| 		return r.result; | ||||
| 	}; | ||||
| 	 | ||||
| 	/* | ||||
| 		Applies known typedefs | ||||
| 		Used in utils.include and utils.makeStruct | ||||
| 		 | ||||
| 		Usage: | ||||
| 			cy# utils.applyTypedefs("mach_vm_address_t") | ||||
| 			"uint64_t" | ||||
| 	*/ | ||||
| 	utils.applyTypedefs = function(str) { | ||||
| 		var typedefs = { | ||||
| 			"struct": "", | ||||
| 			"restrict": "", | ||||
| 			"FILE": "void", | ||||
| 			"size_t": "uint64_t", | ||||
| 			"uintptr_t": "unsigned long", | ||||
| 			"kern_return_t": "int", | ||||
| 			"mach_port_t": "unsigned int", | ||||
| 			"mach_port_name_t": "unsigned int", | ||||
| 			"vm_offset_t": "unsigned long", | ||||
| 			"vm_size_t": "unsigned long", | ||||
| 			"mach_vm_address_t": "uint64_t", | ||||
| 			"mach_vm_offset_t": "uint64_t", | ||||
| 			"mach_vm_size_t": "uint64_t", | ||||
| 			"vm_map_offset_t": "uint64_t", | ||||
| 			"vm_map_address_t": "uint64_t", | ||||
| 			"vm_map_size_t": "uint64_t", | ||||
| 			"mach_port_context_t": "uint64_t", | ||||
| 			"vm_map_t": "unsigned int", | ||||
| 			"boolean_t": "unsigned int", | ||||
| 			"vm_prot_t": "int", | ||||
| 			"mach_msg_type_number_t": "unsigned int", | ||||
| 			"cpu_type_t": "int", | ||||
| 			"cpu_subtype_t": "int", | ||||
| 			"cpu_threadtype_t": "int", | ||||
| 		}; | ||||
| 		 | ||||
| 		for(var k in typedefs) { | ||||
| 			str = str.replace(new RegExp("(\\s|\\*|,|\\(|^)" + k + "(\\s|\\*|,|\\)|$)", "g"), "$1" + typedefs[k] + "$2"); | ||||
| 		} | ||||
| 		 | ||||
| 		return str; | ||||
| 	}; | ||||
| 	 | ||||
| 	/* | ||||
| 		Parses a C function declaration and returns the function name and cycript type | ||||
| 		If load is true, tries to load it into cycript using utils.exec | ||||
| 		 | ||||
| 		Usage: | ||||
| 			cy# var str = "void *calloc(size_t num, size_t size)"; | ||||
| 			"void *calloc(size_t num, size_t size)" | ||||
| 			cy# utils.include(str) | ||||
| 			["calloc","@encode(void *(uint64_t num,  uint64_t size))(140735674376857)"] | ||||
| 			cy# var ret = utils.include(str, true) | ||||
| 			["calloc",0x7fff93e0e299] | ||||
| 			cy# ret[1].type | ||||
| 			@encode(void*(unsigned long long int,unsigned long long int)) | ||||
| 			cy# ret[1](100, 1) | ||||
| 			0x100444100 | ||||
| 	*/ | ||||
| 	utils.include = function(str, load) { | ||||
| 		var re = /^\s*([^(]*(?:\s+|\*))(\w*)\s*\(([^)]*)\)\s*;?\s*$/; | ||||
| 		var match = re.exec(str); | ||||
| 		if(!match) { | ||||
| 			return -1; | ||||
| 		} | ||||
| 		var rType = utils.applyTypedefs(match[1]); | ||||
| 		var name = match[2]; | ||||
| 		var args = match[3]; | ||||
|  | ||||
| 		var argsRe = /([^,]+)(?:,|$)/g; | ||||
| 		var argsTypes = []; | ||||
| 		while((match = argsRe.exec(args)) !== null) { | ||||
| 			var type = utils.applyTypedefs(match[1]); | ||||
| 			argsTypes.push(type); | ||||
| 		} | ||||
| 		 | ||||
| 		var encodeString = "@encode("; | ||||
| 		encodeString += rType + "("; | ||||
| 		encodeString += argsTypes.join(", ") + "))"; | ||||
|  | ||||
| 		var fun = dlsym(RTLD_DEFAULT, name); | ||||
| 		if(fun !== null) { | ||||
| 			encodeString += "(" + fun + ")"; | ||||
| 			if(load) { | ||||
| 				return [name, utils.exec(encodeString)]; | ||||
| 			} | ||||
| 		} else if(load) { | ||||
| 			throw "Function couldn't be found with dlsym!"; | ||||
| 		} | ||||
|  | ||||
| 		return [name, encodeString]; | ||||
| 	}; | ||||
| 	 | ||||
| 	/* | ||||
| 		Loads the function declaration in the defs array using utils.exec and exposes to cycript's global scope | ||||
| 		Is automatically called if shouldLoadCFuncs is true | ||||
| 	*/ | ||||
| 	utils.funcs = {}; | ||||
| 	utils.loadfuncs = function(expose) { | ||||
| 		for(var i = 0; i < CFuncsDeclarations.length; i++) { | ||||
| 			try { | ||||
| 				var o = utils.include(CFuncsDeclarations[i], true); | ||||
| 				utils.funcs[o[0]] = o[1]; | ||||
| 				if(expose) { | ||||
| 					Cycript.all[o[0]] = o[1]; | ||||
| 				} | ||||
| 			} catch(e) { | ||||
| 				system.print("Failed to load function: " + i); | ||||
| 				try { | ||||
| 					system.print(utils.include(CFuncsDeclarations[i])); | ||||
| 				} catch(e2) { | ||||
| 					 | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	}; | ||||
| 	 | ||||
| 	/* | ||||
| 		Calculates the size of a type like the C operator sizeof | ||||
| 		 | ||||
| 		Usage: | ||||
| 			cy# utils.sizeof(int) | ||||
| 			4 | ||||
| 			cy# utils.sizeof(@encode(void *)) | ||||
| 			8 | ||||
| 			cy# utils.sizeof("mach_vm_address_t") | ||||
| 			8 | ||||
| 	*/ | ||||
| 	utils.sizeof = function(type) { | ||||
| 		if(typeof type === "string") { | ||||
| 			type = utils.applyTypedefs(type); | ||||
| 			type = utils.exec("@encode(" + type + ")"); | ||||
| 		} | ||||
| 		 | ||||
| 		// (const) char * has "infinite" preceision | ||||
| 		if(type.toString().slice(-1) === "*") { | ||||
| 			return utils.sizeof(@encode(void *)); | ||||
| 		} | ||||
| 		 | ||||
| 		// float and double | ||||
| 		if(type.toString() === @encode(float).toString()) { | ||||
| 			return 4; | ||||
| 		} else if (type.toString() === @encode(double).toString()) { | ||||
| 			return 8; | ||||
| 		} | ||||
|  | ||||
| 		var typeInstance = type(0); | ||||
| 		 | ||||
| 		if(typeInstance instanceof Object) { | ||||
| 			// Arrays | ||||
| 			if("length" in typeInstance) { | ||||
| 				return typeInstance.length * utils.sizeof(typeInstance.type); | ||||
| 			} | ||||
| 			 | ||||
| 			// Structs | ||||
| 			if(typeInstance.toString() === "[object Struct]") { | ||||
| 				var typeStr = type.toString(); | ||||
| 				var arrayTypeStr = "[2" + typeStr + "]"; | ||||
| 				var arrayType = new Type(arrayTypeStr); | ||||
| 				 | ||||
| 				var arrayInstance = new arrayType; | ||||
| 				 | ||||
| 				return @encode(void *)(&(arrayInstance[1])) - @encode(void *)(&(arrayInstance[0])); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		for(var i = 0; i < 5; i++) { | ||||
| 			var maxSigned = Math.pow(2, 8 * Math.pow(2, i) - 1) - 1; | ||||
| 			if(i === 3) { | ||||
| 				// Floating point fix ;^) | ||||
| 				maxSigned /= 1000; | ||||
| 			} | ||||
|  | ||||
| 			// can't use !== or sizeof(void *) === 0.5 | ||||
| 			if(type(maxSigned) != maxSigned) { | ||||
| 				return Math.pow(2, i - 1); | ||||
| 			} | ||||
| 		} | ||||
| 	}; | ||||
| 	 | ||||
| 	/* | ||||
| 		Logs a specific message sent to an instance of a class like logify.pl in theos | ||||
| 		Requires Cydia Substrate (com.saurik.substrate.MS) and NSLog (org.cycript.NSLog) modules | ||||
| 		Returns the old message returned by MS.hookMessage (Note: this is not just the old message!) | ||||
| 		 | ||||
| 		Usage: | ||||
| 			cy# var oldm = utils.logify(objc_getMetaClass(NSNumber), @selector(numberWithDouble:)) | ||||
| 			... | ||||
| 			cy# var n = [NSNumber numberWithDouble:1.5] | ||||
| 			2014-07-28 02:26:39.805 cycript[71213:507] +[<NSNumber: 0x10032d0c4> numberWithDouble:1.5] | ||||
| 			2014-07-28 02:26:39.806 cycript[71213:507]  = 1.5 | ||||
| 			@1.5 | ||||
| 	*/ | ||||
| 	utils.logify = function(cls, sel) { | ||||
| 		@import com.saurik.substrate.MS; | ||||
| 		@import org.cycript.NSLog; | ||||
| 		 | ||||
| 		var oldm = {}; | ||||
| 		 | ||||
| 		MS.hookMessage(cls, sel, function() { | ||||
| 			var args = [].slice.call(arguments); | ||||
| 			 | ||||
| 			var selFormat = sel.toString().replace(/:/g, ":%@ ").trim(); | ||||
| 			var logFormat = "%@[<%@: 0x%@> " + selFormat + "]"; | ||||
| 			 | ||||
| 			var standardArgs = [logFormat, class_isMetaClass(cls)? "+": "-", cls.toString(), (&this).valueOf().toString(16)]; | ||||
| 			var logArgs = standardArgs.concat(args); | ||||
| 			 | ||||
| 			NSLog.apply(null, logArgs); | ||||
| 			 | ||||
| 			var r = oldm->apply(this, arguments); | ||||
| 			 | ||||
| 			if(r !== undefined) { | ||||
| 				NSLog(" = %@", r); | ||||
| 			} | ||||
| 			 | ||||
| 			return r; | ||||
| 		}, oldm); | ||||
| 		 | ||||
| 		return oldm; | ||||
| 	}; | ||||
| 	 | ||||
| 	/* | ||||
| 		Calls a C function by providing its name and arguments | ||||
| 		Doesn't support structs | ||||
| 		Return value is always a void pointer | ||||
| 		 | ||||
| 		Usage: | ||||
| 			cy# utils.apply("printf", ["%s %.3s, %d -> %c, float: %f\n", "foo", "barrrr", 97, 97, 1.5]) | ||||
| 			foo bar, 97 -> a, float: 1.500000 | ||||
| 			0x22 | ||||
| 	*/ | ||||
| 	utils.apply = function(fun, args) { | ||||
| 		if(!(args instanceof Array)) { | ||||
| 			throw "Args needs to be an array!"; | ||||
| 		} | ||||
| 		 | ||||
| 		var argc = args.length; | ||||
| 		var voidPtr = @encode(void *); | ||||
| 		var argTypes = []; | ||||
| 		for(var i = 0; i < argc; i++) { | ||||
| 			var argType = voidPtr; | ||||
| 			 | ||||
| 			var arg = args[i]; | ||||
| 			if(typeof arg === "string") { | ||||
| 				argType = @encode(char *); | ||||
| 			} | ||||
| 			if(typeof arg === "number" && arg % 1 !== 0) { | ||||
| 				argType = @encode(double); | ||||
| 			} | ||||
| 			 | ||||
| 			argTypes.push(argType); | ||||
| 		} | ||||
| 		 | ||||
| 		var type = voidPtr.functionWith.apply(voidPtr, argTypes); | ||||
| 		 | ||||
| 		if(typeof fun === "string") { | ||||
| 			fun = dlsym(RTLD_DEFAULT, fun); | ||||
| 		} | ||||
| 		 | ||||
| 		if(!fun) { | ||||
| 			throw "Function not found!"; | ||||
| 		} | ||||
|  | ||||
| 		return type(fun).apply(null, args); | ||||
| 	}; | ||||
| 	 | ||||
| 	/* | ||||
| 		Converts a string (char *) to a void pointer (void *) | ||||
| 		You can't cast to strings to void pointers and vice versa in cycript. Blame saurik. | ||||
| 		 | ||||
| 		Usage: | ||||
| 			cy# var voidPtr = utils.str2voidPtr("foobar") | ||||
| 			0x100331590 | ||||
| 			cy# utils.voidPtr2str(voidPtr) | ||||
| 			"foobar" | ||||
| 	*/ | ||||
| 	utils.str2voidPtr = function(str) { | ||||
| 		var strdup = @encode(void *(char *))(dlsym(RTLD_DEFAULT, "strdup")); | ||||
| 		return strdup(str); | ||||
| 	}; | ||||
| 	 | ||||
| 	/* | ||||
| 		The inverse function of str2voidPtr | ||||
| 	*/ | ||||
| 	utils.voidPtr2str = function(voidPtr) { | ||||
| 		var strdup = @encode(char *(void *))(dlsym(RTLD_DEFAULT, "strdup")); | ||||
| 		return strdup(voidPtr); | ||||
| 	}; | ||||
| 	 | ||||
| 	/* | ||||
| 		Converts a double into a void pointer | ||||
| 		This can be used to view the binary representation of a floating point number | ||||
| 		 | ||||
| 		Usage: | ||||
| 			cy# var n = utils.double2voidPtr(-1.5) | ||||
| 			0xbff8000000000000 | ||||
| 			cy# utils.voidPtr2double(n) | ||||
| 			-1.5 | ||||
| 	*/ | ||||
| 	utils.double2voidPtr = function(n) { | ||||
| 		var doublePtr = new double; | ||||
| 		*doublePtr = n; | ||||
| 		 | ||||
| 		var voidPtrPtr = @encode(void **)(doublePtr); | ||||
| 		 | ||||
| 		return *voidPtrPtr; | ||||
| 	}; | ||||
| 	 | ||||
| 	/* | ||||
| 		The inverse function of double2voidPtr | ||||
| 	*/ | ||||
| 	utils.voidPtr2double = function(voidPtr) { | ||||
| 		var voidPtrPtr = new @encode(void **); | ||||
| 		*voidPtrPtr = voidPtr; | ||||
| 		 | ||||
| 		var doublePtr = @encode(double *)(voidPtrPtr); | ||||
| 		 | ||||
| 		return *doublePtr; | ||||
| 	}; | ||||
| 	 | ||||
| 	/* | ||||
| 		Determines in a safe way if a memory location is readable | ||||
| 		 | ||||
| 		Usage: | ||||
| 			cy# utils.isMemoryReadable(0) | ||||
| 			false | ||||
| 			cy# utils.isMemoryReadable(0x1337) | ||||
| 			false | ||||
| 			cy# utils.isMemoryReadable(NSObject) | ||||
| 			true | ||||
| 			cy# var a = malloc(100); utils.isMemoryReadable(a) | ||||
| 			true | ||||
| 	*/ | ||||
| 	utils.isMemoryReadable = function(ptr) { | ||||
| 		if(typeof ptr === "string") { | ||||
| 			return true; | ||||
| 		} | ||||
| 		 | ||||
| 		var fds = new @encode(int [2]); | ||||
| 		utils.apply("pipe", [fds]); | ||||
| 		var result = utils.apply("write", [fds[1], ptr, 1]) == 1; | ||||
| 		 | ||||
| 		utils.apply("close", [fds[0]]); | ||||
| 		utils.apply("close", [fds[1]]); | ||||
| 		 | ||||
| 		return result; | ||||
| 	}; | ||||
| 	 | ||||
| 	/* | ||||
| 		Determines in a safe way if the memory location contains an Objective-C object | ||||
|  | ||||
| 		Usage: | ||||
| 			cy# utils.isObject(0) | ||||
| 			false | ||||
| 			cy# utils.isObject(0x1337) | ||||
| 			false | ||||
| 			cy# utils.isObject(NSObject) | ||||
| 			true | ||||
| 			cy# utils.isObject(objc_getMetaClass(NSObject)) | ||||
| 			true | ||||
| 			cy# utils.isObject([new NSObject init]) | ||||
| 			true | ||||
| 			cy# var a = malloc(100); utils.isObject(a) | ||||
| 			false | ||||
| 			cy# *@encode(void **)(a) = NSObject; utils.isObject(a) | ||||
| 			true | ||||
| 	*/ | ||||
| 	utils.isObject = function(obj) { | ||||
| 		obj = @encode(void *)(obj); | ||||
| 		var lastObj = -1; | ||||
| 		 | ||||
| 		function objc_isa_ptr(obj) { | ||||
| 			// See http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html | ||||
| 			var objc_debug_isa_class_mask = 0x00000001fffffffa; | ||||
| 			obj = (obj & 1)? (obj & objc_debug_isa_class_mask): obj; | ||||
| 			 | ||||
| 			if((obj & (utils.sizeof(@encode(void *)) - 1)) != 0) { | ||||
| 				return null; | ||||
| 			} else { | ||||
| 				return obj; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		function ptrValue(obj) { | ||||
| 			return obj? obj.valueOf(): null; | ||||
| 		} | ||||
| 		 | ||||
| 		var foundMetaClass = false; | ||||
| 		 | ||||
| 		for(obj = objc_isa_ptr(obj); utils.isMemoryReadable(obj); ) { | ||||
| 			obj = *@encode(void **)(obj); | ||||
| 			 | ||||
| 			if(ptrValue(obj) == ptrValue(lastObj)) { | ||||
| 				foundMetaClass = true; | ||||
| 				break; | ||||
| 			} | ||||
| 			 | ||||
| 			lastObj = obj; | ||||
| 		} | ||||
| 		 | ||||
| 		if(!foundMetaClass) { | ||||
| 			return false; | ||||
| 		} | ||||
| 		 | ||||
| 		if(lastObj === -1 || lastObj === null) { | ||||
| 			return false; | ||||
| 		} | ||||
| 		 | ||||
| 		var obj_class = objc_isa_ptr(@encode(void **)(obj)[1]); | ||||
| 		 | ||||
| 		if(!utils.isMemoryReadable(obj_class)) { | ||||
| 			return false; | ||||
| 		} | ||||
| 		 | ||||
| 		var metaclass = objc_isa_ptr(@encode(void **)(obj_class)[0]); | ||||
| 		var superclass = objc_isa_ptr(@encode(void **)(obj_class)[1]); | ||||
| 		 | ||||
| 		return ptrValue(obj) == ptrValue(metaclass) && superclass == null; | ||||
| 	}; | ||||
| 	 | ||||
| 	/* | ||||
| 		Creates a cycript struct type from a C struct definition | ||||
| 		 | ||||
| 		Usage: | ||||
| 			cy# var foo = makeStruct("int a; short b; char c; uint64_t d; double e;", "foo"); | ||||
| 			@encode(foo) | ||||
| 			cy# var f = new foo | ||||
| 			&{a:0,b:0,c:0,d:0,e:0} | ||||
| 			cy# f->a = 100; f | ||||
| 			&{a:100,b:0,c:0,d:0,e:0} | ||||
| 			cy# *@encode(int *)(f) | ||||
| 			100 | ||||
| 	*/ | ||||
| 	utils.makeStruct = function(str, name) {		 | ||||
| 		var fieldRe = /(?:\s|\n)*([^;]+\s*(?:\s|\*))([^;]+)\s*;/g; | ||||
| 		 | ||||
| 		if(!name) { | ||||
| 			name = "struct" + Math.floor(Math.random() * 100000); | ||||
| 		} | ||||
| 		var typeStr = "{" + name + "="; | ||||
| 		 | ||||
| 		while((match = fieldRe.exec(str)) !== null) { | ||||
| 			var fieldType = utils.applyTypedefs(match[1]); | ||||
| 			var fieldName = match[2]; | ||||
| 			var encodedType = utils.exec("@encode(" + fieldType + ")").toString(); | ||||
| 			 | ||||
| 			typeStr += '"' + fieldName + '"' + encodedType; | ||||
| 		} | ||||
| 		 | ||||
| 		typeStr += "}"; | ||||
| 		 | ||||
| 		return new Type(typeStr); | ||||
| 	}; | ||||
| 	 | ||||
| 	// Various constants | ||||
| 	utils.constants = { | ||||
| 		VM_PROT_NONE:       0x0, | ||||
| 		VM_PROT_READ:       0x1, | ||||
| 		VM_PROT_WRITE:      0x2, | ||||
| 		VM_PROT_EXECUTE:    0x4, | ||||
| 		VM_PROT_NO_CHANGE:  0x8, | ||||
| 		VM_PROT_COPY:       0x10, | ||||
| 		VM_PROT_WANTS_COPY: 0x10, | ||||
| 		VM_PROT_IS_MASK:    0x40, | ||||
| 	}; | ||||
| 	var c = utils.constants; | ||||
| 	c.VM_PROT_DEFAULT = c.VM_PROT_READ | c.VM_PROT_WRITE; | ||||
| 	c.VM_PROT_ALL =     c.VM_PROT_READ | c.VM_PROT_WRITE | c.VM_PROT_EXECUTE; | ||||
| 	 | ||||
| 	if(shouldExposeConsts) { | ||||
| 		for(var k in c) { | ||||
| 			Cycript.all[k] = c[k]; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	if(shouldExposeFuncs) { | ||||
| 		for(var i = 0; i < funcsToExpose.length; i++) { | ||||
| 			var name = funcsToExpose[i]; | ||||
| 			Cycript.all[name] = utils[name]; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	if(shouldLoadCFuncs) { | ||||
| 		utils.loadfuncs(shouldExposeCFuncs); | ||||
| 	} | ||||
| })(exports); | ||||
							
								
								
									
										16
									
								
								samples/Dogescript/example.djs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								samples/Dogescript/example.djs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| quiet | ||||
|  wow  | ||||
|     such language | ||||
|   very syntax | ||||
|         github recognized wow | ||||
| loud | ||||
|  | ||||
| such language much friendly | ||||
|     rly friendly is true | ||||
|         plz console.loge with 'such friend, very inclusive' | ||||
|     but | ||||
|         plz console.loge with 'no love for doge' | ||||
|     wow | ||||
| wow | ||||
|  | ||||
| module.exports is language | ||||
							
								
								
									
										31
									
								
								samples/E/Extends.E
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								samples/E/Extends.E
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| # from | ||||
| # http://wiki.erights.org/wiki/Walnut/Ordinary_Programming/Objects_and_Functions | ||||
| def makeVehicle(self) { | ||||
|     def vehicle { | ||||
|         to milesTillEmpty() { | ||||
|             return self.milesPerGallon() * self.getFuelRemaining() | ||||
|         } | ||||
|     } | ||||
|     return vehicle | ||||
| } | ||||
|  | ||||
| def makeCar() { | ||||
|     var fuelRemaining := 20 | ||||
|     def car extends makeVehicle(car) { | ||||
|         to milesPerGallon() {return 19} | ||||
|         to getFuelRemaining() {return fuelRemaining} | ||||
|     } | ||||
|     return car | ||||
| } | ||||
|  | ||||
| def makeJet() { | ||||
|     var fuelRemaining := 2000 | ||||
|     def jet extends makeVehicle(jet) { | ||||
|         to milesPerGallon() {return 2} | ||||
|         to getFuelRemaining() {return fuelRemaining} | ||||
|     } | ||||
|     return jet | ||||
| } | ||||
|  | ||||
| def car := makeCar() | ||||
| println(`The car can go ${car.milesTillEmpty()} miles.`) | ||||
							
								
								
									
										21
									
								
								samples/E/Functions.E
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								samples/E/Functions.E
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| # from | ||||
| # http://wiki.erights.org/wiki/Walnut/Ordinary_Programming/Objects_and_Functions | ||||
| def makeCar(var name) { | ||||
|     var x := 0 | ||||
|     var y := 0 | ||||
|     def car { | ||||
|         to moveTo(newX,newY) { | ||||
|             x := newX | ||||
|             y := newY | ||||
|         } | ||||
|         to getX() {return x} | ||||
|         to getY() {return y} | ||||
|         to setName(newName) {name := newName} | ||||
|         to getName() {return name} | ||||
|     }  | ||||
|     return car | ||||
| } | ||||
| # Now use the makeCar function to make a car, which we will move and print | ||||
| def sportsCar := makeCar("Ferrari") | ||||
| sportsCar.moveTo(10,20) | ||||
| println(`The car ${sportsCar.getName()} is at X location ${sportsCar.getX()}`) | ||||
							
								
								
									
										69
									
								
								samples/E/Guards.E
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								samples/E/Guards.E
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| # from | ||||
| # http://wiki.erights.org/wiki/Walnut/Advanced_Topics/Build_your_Own_Guards | ||||
| def makeVOCPair(brandName :String) :near { | ||||
|  | ||||
|     var myTempContents := def none {} | ||||
|  | ||||
|     def brand { | ||||
|         to __printOn(out :TextWriter) :void { | ||||
|             out.print(brandName) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     def ProveAuth { | ||||
|         to __printOn(out :TextWriter) :void { | ||||
|             out.print(`<$brandName prover>`) | ||||
|         } | ||||
|         to getBrand() :near { return brand } | ||||
|         to coerce(specimen, optEjector) :near { | ||||
|             def sealedBox { | ||||
|                 to getBrand() :near { return brand } | ||||
|                 to offerContent() :void { | ||||
|                     myTempContents := specimen | ||||
|                 } | ||||
|             } | ||||
|             return sealedBox | ||||
|         } | ||||
|     } | ||||
|     def CheckAuth { | ||||
|         to __printOn(out :TextWriter) :void { | ||||
|             out.print(`<$brandName checker template>`) | ||||
|         } | ||||
|         to getBrand() :near { return brand } | ||||
|         match [`get`, authList :any[]] { | ||||
|             def checker { | ||||
|                 to __printOn(out :TextWriter) :void { | ||||
|                     out.print(`<$brandName checker>`) | ||||
|                 } | ||||
|                 to getBrand() :near { return brand } | ||||
|                 to coerce(specimenBox, optEjector) :any { | ||||
|                     myTempContents := null | ||||
|                     if (specimenBox.__respondsTo("offerContent", 0)) { | ||||
|                       # XXX Using __respondsTo/2 here is a kludge | ||||
|                         specimenBox.offerContent() | ||||
|                     } else { | ||||
|                         myTempContents := specimenBox | ||||
|                     } | ||||
|                     for auth in authList { | ||||
|                         if (auth == myTempContents) { | ||||
|                             return auth | ||||
|                         } | ||||
|                     } | ||||
|                     myTempContents := none | ||||
|                     throw.eject(optEjector, | ||||
|                                 `Unmatched $brandName authorization`) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         match [`__respondsTo`, [`get`, _]] { | ||||
|             true | ||||
|         } | ||||
|         match [`__respondsTo`, [_, _]] { | ||||
|             false | ||||
|         } | ||||
|         match [`__getAllegedType`, []] { | ||||
|             null.__getAllegedType() | ||||
|         } | ||||
|     } | ||||
|     return [ProveAuth, CheckAuth] | ||||
| } | ||||
							
								
								
									
										14
									
								
								samples/E/IO.E
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								samples/E/IO.E
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| # E sample from | ||||
| # http://wiki.erights.org/wiki/Walnut/Ordinary_Programming/InputOutput | ||||
| #File objects for hardwired files: | ||||
| def file1 := <file:myFile.txt> | ||||
| def file2 := <file:/home/marcs/myFile.txt> | ||||
|  | ||||
| #Using a variable for a file name: | ||||
| def filePath := "c:\\docs\\myFile.txt" | ||||
| def file3 := <file>[filePath] | ||||
|  | ||||
| #Using a single character to specify a Windows drive | ||||
| def file4 := <file:c:/docs/myFile.txt> | ||||
| def file5 := <c:/docs/myFile.txt> | ||||
| def file6 := <c:\docs\myFile.txt> | ||||
							
								
								
									
										9
									
								
								samples/E/Promises.E
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								samples/E/Promises.E
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| # E snippet from | ||||
| # http://wiki.erights.org/wiki/Walnut/Distributed_Computing/Promises | ||||
| when (tempVow) -> { | ||||
|     #...use tempVow | ||||
| } catch prob { | ||||
|     #.... report problem | ||||
| } finally { | ||||
|     #....log event | ||||
| } | ||||
							
								
								
									
										18
									
								
								samples/E/minChat.E
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								samples/E/minChat.E
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| # from | ||||
| # http://wiki.erights.org/wiki/Walnut/Secure_Distributed_Computing/Auditing_minChat | ||||
| pragma.syntax("0.9") | ||||
| to send(message) { | ||||
|     when (friend<-receive(message)) -> { | ||||
|         chatUI.showMessage("self", message) | ||||
|     } catch prob {chatUI.showMessage("system", "connection lost")} | ||||
| } | ||||
| to receive(message) {chatUI.showMessage("friend", message)} | ||||
| to receiveFriend(friendRcvr) { | ||||
|     bind friend := friendRcvr         | ||||
|     chatUI.showMessage("system", "friend has arrived") | ||||
| } | ||||
| to save(file) {file.setText(makeURIFromObject(chatController))} | ||||
| to load(file) { | ||||
|     bind friend := getObjectFromURI(file.getText()) | ||||
|     friend <- receiveFriend(chatController) | ||||
| } | ||||
							
								
								
									
										1396
									
								
								samples/Eagle/Eagle.brd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1396
									
								
								samples/Eagle/Eagle.brd
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										3612
									
								
								samples/Eagle/Eagle.sch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3612
									
								
								samples/Eagle/Eagle.sch
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										23
									
								
								samples/EmberScript/momentComponent.em
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								samples/EmberScript/momentComponent.em
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| class App.FromNowView extends Ember.View | ||||
|     tagName: 'time' | ||||
|     template: Ember.Handlebars.compile '{{view.output}}' | ||||
|     output: ~> | ||||
|         return moment(@value).fromNow() | ||||
|  | ||||
|     didInsertElement: -> | ||||
|         @tick() | ||||
|  | ||||
|     tick: -> | ||||
|         f = -> | ||||
|             @notifyPropertyChange 'output' | ||||
|             @tick() | ||||
|  | ||||
|         nextTick = Ember.run.later(this, f, 1000) | ||||
|         @set 'nextTick', nextTick | ||||
|  | ||||
|     willDestroyElement: -> | ||||
|         nextTick = @nextTick | ||||
|         Ember.run.cancel nextTick | ||||
|  | ||||
| Ember.Handlebars.helper 'fromNow', App.FromNowView | ||||
|  | ||||
							
								
								
									
										44
									
								
								samples/Frege/CommandLineClock.fr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								samples/Frege/CommandLineClock.fr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| {--  | ||||
|     This program displays the | ||||
|     current time on stdandard output | ||||
|     every other second. | ||||
|     -} | ||||
|      | ||||
| module examples.CommandLineClock where | ||||
|  | ||||
| data Date = native java.util.Date where | ||||
|     native new :: () -> IO (MutableIO Date)     -- new Date() | ||||
|     native toString :: Mutable s Date -> ST s String    -- d.toString() | ||||
|  | ||||
| --- 'IO' action to give us the current time as 'String' | ||||
| current :: IO String | ||||
| current = do | ||||
|     d <- Date.new () | ||||
|     d.toString | ||||
|  | ||||
| {-  | ||||
|     "java.lang.Thread.sleep" takes a "long" and | ||||
|     returns nothing, but may throw an InterruptedException. | ||||
|     This is without doubt an IO action. | ||||
|      | ||||
|     public static void sleep(long millis) | ||||
|                   throws InterruptedException | ||||
|      | ||||
|     Encoded in Frege: | ||||
|     - argument type  long   Long | ||||
|     - result         void   () | ||||
|     - does IO               IO () | ||||
|     - throws ...            throws .... | ||||
|       | ||||
| -} | ||||
| -- .... defined in frege.java.Lang | ||||
| -- native sleep java.lang.Thread.sleep :: Long -> IO () throws InterruptedException | ||||
|  | ||||
|        | ||||
| main args =   | ||||
|     forever do | ||||
|         current >>= print | ||||
|         print "\r" | ||||
|         stdout.flush | ||||
|         Thread.sleep 999 | ||||
|                  | ||||
							
								
								
									
										147
									
								
								samples/Frege/Concurrent.fr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								samples/Frege/Concurrent.fr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | ||||
| module examples.Concurrent where | ||||
|  | ||||
| import System.Random | ||||
| import Java.Net (URL) | ||||
| import Control.Concurrent as C | ||||
|  | ||||
| main2 args = do | ||||
|     m <- newEmptyMVar | ||||
|     forkIO do | ||||
|         m.put 'x' | ||||
|         m.put 'y'  | ||||
|         m.put 'z' | ||||
|     replicateM_ 3 do | ||||
|         c <- m.take | ||||
|         print "got: " | ||||
|         println c   | ||||
|          | ||||
|              | ||||
| example1 = do | ||||
|     forkIO (replicateM_ 100000 (putChar 'a')) | ||||
|     replicateM_ 100000 (putChar 'b') | ||||
|  | ||||
| example2 =  do | ||||
|     s <- getLine | ||||
|     case s.long of | ||||
|         Right n -> forkIO (setReminder n) >> example2 | ||||
|         Left _  -> println ("exiting ...") | ||||
|      | ||||
| setReminder :: Long -> IO () | ||||
| setReminder n = do | ||||
|         println ("Ok, I remind you in " ++ show n ++ " seconds") | ||||
|         Thread.sleep (1000L*n) | ||||
|         println (show n ++ " seconds is up!") | ||||
|  | ||||
| table = "table" | ||||
|              | ||||
| mainPhil _ = do | ||||
|     [fork1,fork2,fork3,fork4,fork5] <- mapM MVar.new [1..5] | ||||
|     forkIO (philosopher "Kant" fork5 fork1) | ||||
|     forkIO (philosopher "Locke" fork1 fork2) | ||||
|     forkIO (philosopher "Wittgenstein" fork2 fork3) | ||||
|     forkIO (philosopher "Nozick" fork3 fork4) | ||||
|     forkIO (philosopher "Mises" fork4 fork5) | ||||
|     return ()     | ||||
|  | ||||
| philosopher :: String -> MVar Int -> MVar Int -> IO () | ||||
| philosopher me left right = do | ||||
|     g <- Random.newStdGen | ||||
|     let phil g  = do | ||||
|             let (tT,g1) = Random.randomR (60L, 120L) g | ||||
|                 (eT, g2)  = Random.randomR (80L, 160L) g1 | ||||
|                 thinkTime = 300L * tT | ||||
|                 eatTime   = 300L * eT | ||||
|      | ||||
|             println(me ++ " is going to the dining room and takes his seat.")  | ||||
|             fl <- left.take             | ||||
|             println (me ++ " takes up left fork (" ++ show fl ++ ")") | ||||
|             rFork <- right.poll | ||||
|             case rFork of | ||||
|                 Just fr -> do  | ||||
|                     println (me ++ " takes up right fork. (" ++ show fr ++ ")")  | ||||
|                     println (me ++ " is going to eat for " ++ show eatTime ++ "ms") | ||||
|                     Thread.sleep eatTime | ||||
|                     println (me ++ " finished eating.") | ||||
|                     right.put fr | ||||
|                     println (me ++ " took down right fork.") | ||||
|                     left.put fl | ||||
|                     println (me ++ " took down left fork.") | ||||
|                     table.notifyAll  | ||||
|                     println(me ++ " is going to think for " ++ show thinkTime ++ "ms.") | ||||
|                     Thread.sleep thinkTime | ||||
|                     phil g2 | ||||
|                 Nothing -> do | ||||
|                     println (me ++ " finds right fork is already in use.") | ||||
|                     left.put fl | ||||
|                     println (me ++ " took down left fork.") | ||||
|                     table.notifyAll | ||||
|                     println (me ++ " is going to the bar to await notifications from table.") | ||||
|                     table.wait | ||||
|                     println (me ++ " got notice that something changed at the table.") | ||||
|                     phil g2 | ||||
|              | ||||
|         inter :: InterruptedException -> IO () | ||||
|         inter _ = return ()         | ||||
|      | ||||
|     phil g `catch` inter | ||||
|  | ||||
|      | ||||
| getURL xx = do | ||||
|         url <- URL.new xx  | ||||
|         con <- url.openConnection | ||||
|         con.connect | ||||
|         is  <- con.getInputStream | ||||
|         typ <- con.getContentType | ||||
|         -- stderr.println ("content-type is " ++ show typ)  | ||||
|         ir  <- InputStreamReader.new is (fromMaybe "UTF-8" (charset typ)) | ||||
|             `catch` unsupportedEncoding is  | ||||
|         br  <- BufferedReader.new ir | ||||
|         br.getLines | ||||
|     where | ||||
|         unsupportedEncoding :: InputStream -> UnsupportedEncodingException -> IO InputStreamReader | ||||
|         unsupportedEncoding is x = do | ||||
|             stderr.println x.catched | ||||
|             InputStreamReader.new is "UTF-8" | ||||
|              | ||||
|         charset ctyp = do | ||||
|             typ <- ctyp | ||||
|             case typ of | ||||
|                 m~´charset=(\S+)´ -> m.group 1 | ||||
|                 _ -> Nothing | ||||
|  | ||||
|      | ||||
| type SomeException = Throwable | ||||
|  | ||||
| main ["dining"] = mainPhil [] | ||||
|          | ||||
| main _ =  do | ||||
|     m1 <- MVar.newEmpty | ||||
|     m2 <- MVar.newEmpty | ||||
|     m3 <- MVar.newEmpty | ||||
|      | ||||
|     forkIO do | ||||
|         r <- (catchAll . getURL) "http://www.wikipedia.org/wiki/Haskell" | ||||
|         m1.put r | ||||
|      | ||||
|     forkIO do | ||||
|         r <- (catchAll . getURL) "htto://www.wikipedia.org/wiki/Java" | ||||
|         m2.put r | ||||
|      | ||||
|     forkIO do | ||||
|         r <- (catchAll . getURL) "http://www.wikipedia.org/wiki/Frege" | ||||
|         m3.put r | ||||
|      | ||||
|     r1 <- m1.take | ||||
|     r2 <- m2.take | ||||
|     r3 <- m3.take | ||||
|     println (result r1, result r2, result r3) | ||||
|     -- case r3 of | ||||
|     --     Right ss -> mapM_ putStrLn ss | ||||
|     --     Left _   -> return () | ||||
|   where | ||||
|     result :: (SomeException|[String]) -> (String|Int) | ||||
|     result (Left x)  = Left x.getClass.getName | ||||
|     result (Right y) = (Right . sum . map length)  y | ||||
|     -- mapM_ putStrLn r2 | ||||
|  | ||||
|          | ||||
							
								
								
									
										561
									
								
								samples/Frege/Sudoku.fr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										561
									
								
								samples/Frege/Sudoku.fr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,561 @@ | ||||
| package examples.Sudoku where | ||||
|  | ||||
| import Data.TreeMap (Tree, keys) | ||||
| import Data.List as DL hiding (find, union) | ||||
|  | ||||
|  | ||||
| type Element    = Int           -- 1,2,3,4,5,6,7,8,9 | ||||
| type Zelle      = [Element]     -- set of candidates | ||||
| type Position   = Int           -- 0..80 | ||||
| type Feld       = (Position, Zelle) | ||||
| type Brett      = [Feld] | ||||
|  | ||||
| --- data type for assumptions and conclusions | ||||
| data Assumption = | ||||
|               !ISNOT Position Element | ||||
|             | !IS    Position Element | ||||
|  | ||||
|  | ||||
| derive Eq Assumption | ||||
| derive Ord Assumption | ||||
| instance Show Assumption where | ||||
|     show (IS p e)    = pname p ++ "=" ++ e.show | ||||
|     show (ISNOT p e) = pname p ++ "/" ++ e.show | ||||
|  | ||||
| showcs cs = joined " " (map Assumption.show cs) | ||||
|  | ||||
| elements :: [Element]           -- all possible elements | ||||
| elements = [1 .. 9] | ||||
|  | ||||
| {- | ||||
|     a  b  c   d  e  f   g  h  i | ||||
|      0  1  2 | 3  4  5 | 6  7  8    1 | ||||
|      9 10 11 |12 13 14 |15 16 17    2 | ||||
|     18 19 20 |21 22 23 |24 25 26    3 | ||||
|     ---------|---------|-------- | ||||
|     27 28 29 |30 31 32 |33 34 35    4 | ||||
|     36 37 38 |39 40 41 |42 43 44    5 | ||||
|     45 46 47 |48 49 50 |51 52 53    6 | ||||
|     ---------|---------|-------- | ||||
|     54 55 56 |57 58 59 |60 61 62    7 | ||||
|     63 64 65 |66 67 68 |69 70 71    8 | ||||
|     72 73 74 |75 76 77 |78 79 80    9 | ||||
| -} | ||||
|  | ||||
| positions :: [Position]         -- all possible positions | ||||
| positions = [0..80] | ||||
| rowstarts :: [Position]         -- all positions where a row is starting | ||||
| rowstarts =  [0,9,18,27,36,45,54,63,72] | ||||
| colstarts :: [Position]         -- all positions where a column is starting | ||||
| colstarts =  [0,1,2,3,4,5,6,7,8] | ||||
| boxstarts :: [Position]         -- all positions where a box is starting | ||||
| boxstarts =  [0,3,6,27,30,33,54,57,60] | ||||
| boxmuster :: [Position]         -- pattern for a box, by adding upper left position results in real box | ||||
| boxmuster =  [0,1,2,9,10,11,18,19,20] | ||||
|  | ||||
|  | ||||
| --- extract field for position | ||||
| getf :: Brett -> Position  -> Feld | ||||
| getf (f:fs) p | ||||
|     | fst f == p = f | ||||
|     | otherwise  = getf fs p | ||||
| getf [] p = (p,[]) | ||||
|  | ||||
|  | ||||
| --- extract cell for position | ||||
| getc :: Brett -> Position -> Zelle | ||||
| getc b p = snd (getf b p) | ||||
|  | ||||
| --- compute the list of all positions that belong to the same row as a given position | ||||
| row :: Position -> [Position] | ||||
| row p = [z..(z+8)] where z = (p `quot` 9) * 9 | ||||
|  | ||||
| --- compute the list of all positions that belong to the same col as a given position | ||||
| col :: Position -> [Position] | ||||
| col p = map (c+) rowstarts where c = p `mod` 9 | ||||
|  | ||||
| --- compute the list of all positions that belong to the same box as a given position | ||||
| box :: Position -> [Position] | ||||
| box p  = map (z+) boxmuster where | ||||
|     ri = p `div` 27 * 27    -- 0, 27 or 54, depending on row | ||||
|     ci = p `mod` 9          -- column index 0..8, 0,1,2 is left, 3,4,5 is middle, 6,7,8 is right | ||||
|     cs = ci `div` 3 * 3     -- 0, 3 or 6 | ||||
|     z  = ri + cs | ||||
|  | ||||
| --- check if candidate set has exactly one member, i.e. field has been solved | ||||
| single :: Zelle -> Bool | ||||
| single [_] = true | ||||
| single _   = false | ||||
|  | ||||
| unsolved :: Zelle -> Bool | ||||
| unsolved [_] = false | ||||
| unsolved _   = true | ||||
|  | ||||
| -- list of rows, cols, boxes | ||||
| allrows = map row rowstarts | ||||
| allcols = map col colstarts | ||||
| allboxs = map box boxstarts | ||||
| allrcb  = zip (repeat "row") allrows | ||||
|           ++ zip (repeat "col") allcols | ||||
|           ++ zip (repeat "box") allboxs | ||||
|  | ||||
|  | ||||
| containers :: [(Position -> [Position], String)] | ||||
| containers = [(row, "row"), (col, "col"), (box, "box")] | ||||
|  | ||||
| -- ----------------- PRINTING ------------------------------------ | ||||
| -- printable coordinate of field, upper left is a1, lower right is i9 | ||||
| pname p = packed [chr (ord 'a' + p `mod` 9), chr (ord '1' + p `div` 9)] | ||||
|  | ||||
| -- print board | ||||
| printb b = mapM_ p1line allrows >> println "" | ||||
|     where | ||||
|         p1line row = do | ||||
|                 print (joined "" (map pfld line)) | ||||
|             where line = map (getc b) row | ||||
|  | ||||
| -- print field (brief) | ||||
| --   ? = no candidate | ||||
| --   5 = field is 5 | ||||
| --   . = some candidates | ||||
| pfld [] = "?" | ||||
| pfld [x] = show x | ||||
| pfld zs = "0" | ||||
|  | ||||
| -- print initial/final board | ||||
| result msg b = do | ||||
|         println ("Result: " ++ msg) | ||||
|         print   ("Board: ") | ||||
|         printb b | ||||
|         return b | ||||
|  | ||||
| res012 b = case concatMap (getc b) [0,1,2] of | ||||
|     [a,b,c] -> a*100+b*10+c | ||||
|     _ -> 9999999 | ||||
|  | ||||
| -- -------------------------- BOARD ALTERATION ACTIONS --------------------------------- | ||||
| -- print a message about what is done to the board and return the new board | ||||
| turnoff1 :: Position -> Zelle -> Brett -> IO Brett | ||||
| turnoff1 i off b | ||||
|     | single nc = do | ||||
|             -- print (pname i) | ||||
|             -- print ": set to " | ||||
|             -- print (head nc) | ||||
|             -- println " (naked single)" | ||||
|             return newb | ||||
|     | otherwise = return newb | ||||
|     where | ||||
|         cell   = getc b i | ||||
|         nc     = filter (`notElem` off) cell | ||||
|         newb   = (i, nc) : [ f | f <- b, fst f != i ] | ||||
|  | ||||
| turnoff :: Int -> Zelle -> String -> Brett -> IO Brett | ||||
| turnoff i off msg b = do | ||||
|         -- print (pname i) | ||||
|         -- print ": set to " | ||||
|         -- print nc | ||||
|         -- print " by clearing " | ||||
|         -- print off | ||||
|         -- print " " | ||||
|         -- println  msg | ||||
|         return newb | ||||
|     where | ||||
|         cell   = getc b i | ||||
|         nc     = filter (`notElem` off) cell | ||||
|         newb   = (i, nc) : [ f | f <- b, fst f != i ] | ||||
|  | ||||
| turnoffh ps off msg b = foldM toh b ps | ||||
|     where | ||||
|         toh b p = turnoff p off msg b | ||||
|  | ||||
| setto :: Position -> Element -> String -> Brett -> IO Brett | ||||
| setto i n cname b = do | ||||
|         -- print (pname i) | ||||
|         -- print ": set to " | ||||
|         -- print n | ||||
|         -- print " (hidden single in " | ||||
|         -- print cname | ||||
|         -- println ")" | ||||
|         return newb | ||||
|     where | ||||
|         nf     = [n] | ||||
|         newb   = (i, nf) : [ f | f <- b, fst f != i ] | ||||
|  | ||||
|  | ||||
| -- ----------------------------- SOLVING STRATEGIES --------------------------------------------- | ||||
| -- reduce candidate sets that contains numbers already in same row, col or box | ||||
| -- This finds (and logs) NAKED SINGLEs in passing. | ||||
| reduce b = [  turnoff1 p sss | (p,cell) <- b,               -- for each field | ||||
|                 unsolved cell,                              --  with more than 1 candidate | ||||
|                 --       single fields in containers that are candidates of that field | ||||
|                 sss = [ s | (rcb, _) <- containers, [s] <- map (getc b) (rcb p), s `elem` cell], | ||||
|                 sss != [] ]                                     -- collect field index, elements to remove from candidate set | ||||
|  | ||||
| -- look for a number that appears in exactly 1 candidate set of a container | ||||
| -- this number can go in no other place (HIDDEN SINGLE) | ||||
| hiddenSingle b = [ setto i n cname |                     -- select index, number, containername | ||||
|             (cname, rcb) <- allrcb,                 -- FOR rcb IN allrcb | ||||
|             n <- elements,                          --  FOR n IN elements | ||||
|             fs     = filter (unsolved • snd) (map (getf b) rcb), | ||||
|             occurs  = filter ((n `elem`) • snd) fs, | ||||
|             length occurs == 1, | ||||
|             (i, _) <- occurs ] | ||||
|  | ||||
| -- look for NAKED PAIRS, TRIPLES, QUADS | ||||
| nakedPair n b = [ turnoff p t ("(naked tuple in " ++ nm ++ ")") |           -- SELECT pos, tuple, name | ||||
|             -- n <- [2,3,4],                    //  FOR n IN [2,3,4] | ||||
|             (nm, rcb) <- allrcb,             --    FOR rcb IN containers | ||||
|             fs = map (getf b) rcb,              --      let fs = fields for rcb positions | ||||
|             u  = (fold union [] . filter unsolved . map snd) fs,   -- let u = union of non single candidates | ||||
|             t <- n `outof` u,                   --      FOR t IN n-tuples | ||||
|             hit = (filter ((`subset` t) . snd) . filter (unsolved . snd)) fs, | ||||
|             length hit == n, | ||||
|             (p, cell) <- fs, | ||||
|             p `notElem` map fst hit, | ||||
|             any (`elem` cell) t | ||||
|             ] | ||||
|  | ||||
| -- look for HIDDEN PAIRS, TRIPLES or QUADS | ||||
| hiddenPair n b = [ turnoff p off ("(hidden " ++ show t ++ " in " ++ nm ++ ")") |           -- SELECT pos, tuple, name | ||||
|             -- n <- [2,3,4],                    //  FOR n IN [2,3,4] | ||||
|             (nm, rcb) <- allrcb,             --    FOR rcb IN containers | ||||
|             fs = map (getf b) rcb,              --      let fs = fields for rcb positions | ||||
|             u  = (fold union [] . filter ((>1) . length) . map snd) fs,   -- let u = union of non single candidates | ||||
|             t <- n `outof` u,                   --      FOR t IN n-tuples | ||||
|             hit = (filter (any ( `elem` t) . snd) . filter (unsolved . snd)) fs, | ||||
|             length hit == n, | ||||
|             off = (fold union [] . map snd) hit `minus` t, | ||||
|             off != [], | ||||
|             (p, cell) <- hit, | ||||
|             ! (cell `subset` t) | ||||
|             ] | ||||
|  | ||||
| a `subset` b = all (`elem` b) a | ||||
| a `union`  b = uniq (sort (a ++ b)) | ||||
| a `minus`  b = filter (`notElem` b) a | ||||
| a `common` b = filter (`elem` b) a | ||||
| n `outof` as | ||||
|     | length as < n = [] | ||||
|     | [] <- as      = [] | ||||
|     | 1 >= n        = map (:[]) as | ||||
|     | (a:bs) <- as  = map (a:) ((n-1) `outof` bs) ++ (n `outof` bs) | ||||
|     | otherwise     = undefined  -- cannot happen because either as is empty or not | ||||
|  | ||||
| same f a b = b `elem` f a | ||||
|  | ||||
| intersectionlist = [(allboxs, row, "box/row intersection"), (allboxs, col, "box/col intersection"), | ||||
|                     (allrows ++ allcols, box, "line/box intersection")] | ||||
| intersections b = [ | ||||
|     turnoff pos [c] reason |    -- SELECT position, candidate, reson | ||||
|         (from, container, reason) <- intersectionlist, | ||||
|         rcb <- from, | ||||
|         fs = (filter (unsolved . snd) . map (getf b)) rcb,        -- fs = fields in from with more than 1 candidate | ||||
|         c <- (fold union [] • map snd) fs,                          -- FOR c IN union of candidates | ||||
|         cpos = (map fst • filter ((c `elem`) • snd)) fs,            -- cpos = positions where c occurs | ||||
|         cpos != [],                                                 -- WHERE cpos is not empty | ||||
|         all (same container (head cpos)) (tail cpos),               -- WHERE all positions are in the intersection | ||||
|         -- we can remove all occurences of c that are in container, but not in from | ||||
|         (pos, cell) <- map (getf b) (container (head cpos)), | ||||
|         c `elem` cell, | ||||
|         pos `notElem` rcb ] | ||||
|  | ||||
|  | ||||
| -- look for an XY Wing | ||||
| --  - there exists a cell A with candidates X and Y | ||||
| --  - there exists a cell B with candidates X and Z that shares a container with A | ||||
| --  - there exists a cell C with candidates Y and Z that shares a container with A | ||||
| -- reasoning | ||||
| --  - if A is X, B will be Z | ||||
| --  - if A is Y, C will be Z | ||||
| --  - since A will indeed be X or Y -> B or C will be Z | ||||
| --  - thus, no cell that can see B and C can be Z | ||||
| xyWing board = [ turnoff p [z] ("xy wing " ++ pname b ++ " " ++ pname c ++ " because of " ++ pname a) | | ||||
|         (a, [x,y]) <- board,                            -- there exists a cell a with candidates x and y | ||||
|         rcba = map (getf board) (row a ++ col a ++ box a),  -- rcba = all fields that share a container with a | ||||
|         (b, [b1, b2]) <- rcba, | ||||
|         b != a, | ||||
|         b1 == x && b2 != y || b2 == x && b1 != y,       -- there exists a cell B with candidates x and z | ||||
|         z = if b1 == x then b2 else b1, | ||||
|         (c, [c1, c2]) <- rcba, | ||||
|         c != a, c!= b, | ||||
|         c1 == y && c2 == z || c1 == z && c2 == y,       -- there exists a cell C with candidates y and z | ||||
|         ps = (uniq . sort) ((row b ++ col b ++ box b) `common` (row c ++ col c ++ box c)), | ||||
|         -- remove z in ps | ||||
|         (p, cs) <- map (getf board) ps, | ||||
|         p != b, p != c, | ||||
|         z `elem` cs ] | ||||
|  | ||||
| -- look for a N-Fish (2: X-Wing, 3: Swordfish, 4: Jellyfish) | ||||
| -- When all candidates for a particular digit in N rows are located | ||||
| -- in only N columns, we can eliminate all candidates from those N columns | ||||
| --  which are not located on those N rows | ||||
| fish n board = fish "row" allrows row col ++ fish "col" allcols col row where | ||||
|     fishname 2 = "X-Wing" | ||||
|     fishname 3 = "Swordfish" | ||||
|     fishname 4 = "Jellyfish" | ||||
|     fishname _ = "unknown fish" | ||||
|     fish nm allrows row col = [ turnoff p [x] (fishname n ++ " in " ++ nm ++ " " ++ show (map (pname . head) rset)) | | ||||
|         rset <- n `outof` allrows,          -- take n rows (or cols) | ||||
|         x <- elements,                      -- look for certain number | ||||
|         rflds = map (filter ((>1) . length . snd) . map (getf board)) rset,       -- unsolved fields in the rowset | ||||
|         colss  = (map (map (head . col . fst) . filter ((x `elem`) . snd)) rflds),   -- where x occurs in candidates | ||||
|         all ((>1) . length) colss,         -- x must appear in at least 2 cols | ||||
|         cols = fold union [] colss, | ||||
|         length cols == n, | ||||
|         cstart <- cols, | ||||
|         (p, cell) <- map (getf board) (col cstart), | ||||
|         x `elem` cell, | ||||
|         all (p `notElem`) rset] | ||||
|  | ||||
|  | ||||
| -- compute immediate consequences of an assumption of the form (p `IS` e) or (p `ISNOT` e) | ||||
| conseq board (IS p e) = uniq (sort ([ p `ISNOT` x | x <- getc board p, x != e ] ++ | ||||
|     [ a `ISNOT` e | | ||||
|         (a,cs) <- map (getf board) (row p ++ col p ++ box p), | ||||
|         a != p, | ||||
|         e `elem` cs | ||||
|     ])) | ||||
| conseq board (ISNOT p  e) = uniq (sort ([ p `IS` x | cs = getc board p, length cs == 2, x <- cs, x != e ] ++ | ||||
|     [ a `IS` e | | ||||
|         cp <- [row p, box p, col p], | ||||
|         as = (filter ((e `elem`) . getc board) . filter (p!=)) cp, | ||||
|         length as == 1, | ||||
|         a = head as | ||||
|     ])) | ||||
|  | ||||
| -- check if two assumptions contradict each other | ||||
| contradicts (IS a x)    (IS b y)    = a==b && x!=y | ||||
| contradicts (IS a x)    (ISNOT b y) = a==b && x==y | ||||
| contradicts (ISNOT a x) (IS b y)    = a==b && x==y | ||||
| contradicts (ISNOT _ _) (ISNOT _ _) = false | ||||
|  | ||||
| -- get the Position of an Assumption | ||||
| aPos (IS p _)    = p | ||||
| aPos (ISNOT p _) = p | ||||
|  | ||||
| -- get List of elements that must be turned off when assumption is true/false | ||||
| toClear board true  (IS p x)    = filter (x!=) (getc board p) | ||||
| toClear board false (IS p x)    = [x] | ||||
| toClear board true  (ISNOT p x) = [x] | ||||
| toClear board false (ISNOT p x) = filter (x!=) (getc board p) | ||||
|  | ||||
|  | ||||
| -- look for assumptions whose implications contradict themself | ||||
| chain board paths = [ solution a (head cs) (reverse cs) | | ||||
|         (a, css) <-  paths, | ||||
|         cs <- take 1 [ cs | cs <- css, contradicts a (head cs) ] | ||||
|         ] | ||||
|     where | ||||
|         solution a c cs = turnoff (aPos a) (toClear board false a) reason where | ||||
|             reason = "Assumption " ++ show a ++ " implies " ++ show c ++ "\n\t" | ||||
|                 ++ showcs cs ++ "\n\t" | ||||
|                 ++ "Therefore, " ++ show a ++ " must be false." | ||||
|  | ||||
| -- look for an assumption that yields to contradictory implications | ||||
| -- this assumption must be false | ||||
| chainContra board paths = [ solution a (reverse pro) (reverse contra) | | ||||
|         (a, css) <- paths,          -- FOR ALL assumptions "a" with list of conlusions "css" | ||||
|         (pro, contra) <- take 1 [ (pro, contra) | | ||||
|             pro <- (uniqBy (using head) . sortBy (comparing head)) css,                 -- FOR ALL conslusion chains "pro" | ||||
|             c = head pro,               -- LET "c" BE the final conclusion | ||||
|             contra <- take 1 (filter ((contradicts c) . head) css)   -- THE FIRST conclusion that contradicts c | ||||
|         ] | ||||
|       ] | ||||
|     where | ||||
|         solution a pro con = turnoff (aPos a) (toClear board false a) reason where | ||||
|             reason = ("assumption " ++ show a ++ " leads to contradictory conclusions\n\t" | ||||
|                         ++ showcs pro ++ "\n\t" ++ showcs con) | ||||
|  | ||||
|  | ||||
|  | ||||
| -- look for a common implication c of some assumptions ai, where at least 1 ai is true | ||||
| -- so that (a0 OR a1 OR a2 OR ...) IMPLIES c | ||||
| -- For all cells pi in same container that have x as candidate, we can construct (p0==x OR p1==x OR ... OR pi==x) | ||||
| -- For a cell p with candidates ci, we can construct (p==c0 OR p==c1) | ||||
| cellRegionChain board paths = [ solution b as (map head os) | | ||||
|         as <- cellas ++ regionas,           -- one of as must be true | ||||
|         iss = filter ((`elem` as) . fst) paths,    -- the implications for as | ||||
|         (a, ass) <- take 1 iss,             -- implications for first assumption | ||||
|         fs <- (uniqBy (using head) . sortBy (comparing head)) ass, | ||||
|         b = head fs,                        -- final conclusions of first assumption | ||||
|         os = [fs] : map (take 1 . filter ((b==) . head) . snd) (tail iss), -- look for implications with same conclusion | ||||
|         all ([]!=) os] | ||||
|     where | ||||
|         cellas   = [ map (p `IS`) candidates | (p, candidates@(_:_:_)) <- board ] | ||||
|         regionas = [ map (`IS` e) ps | | ||||
|             region <- map (map (getf board)) (allrows ++ allcols ++ allboxs), | ||||
|             e <- elements, | ||||
|             ps = map fst (filter ((e `elem`) . snd) region), | ||||
|             length ps > 1 ] | ||||
|         solution b as oss = turnoff (aPos b) (toClear board true b) reason where | ||||
|             reason = "all of the assumptions " ++ joined ", " (map show as) ++ " imply " ++ show b ++ "\n\t" | ||||
|                 ++ joined "\n\t" (map (showcs . reverse) oss) ++ "\n\t" | ||||
|                 ++ "One of them must be true, so " ++ show b ++ " must be true." | ||||
|  | ||||
|  | ||||
| {- | ||||
|     Wir brauchen für einige Funktionen eine Datenstruktur wie | ||||
|         [ (Assumption, [[Assumption]]) ] | ||||
|     d.i. eine Liste von möglichen Annahmen samt aller Schlußketten. | ||||
|     Idealerweise sollte die Schlußkette in umgekehrter Reihenfolge vorliegen, | ||||
|     dann kann man einfach finden: | ||||
|     - Annahmen, die zum Selbstwiderspruch führen. | ||||
|     - alles, was aus einer bestimmten Annahme folgt (map (map head) [[a]]) | ||||
|     -... | ||||
| -} | ||||
| --- Liste aller Annahmen für ein bestimmtes Brett | ||||
| assumptions :: Brett -> [Assumption] | ||||
| assumptions board = [ a | | ||||
|                 (p, cs) <- board, | ||||
|                 !(single cs), | ||||
|                 a <- map (ISNOT p) cs ++ map (IS p) cs ] | ||||
|  | ||||
| consequences :: Brett -> [Assumption] -> [[Assumption]] | ||||
| consequences board as = map (conseq board) as | ||||
|  | ||||
| acstree :: Brett -> Tree Assumption [Assumption] | ||||
| acstree board = Tree.fromList (zip as cs) | ||||
|     where | ||||
|         as = assumptions  board | ||||
|         cs = consequences board as | ||||
|  | ||||
| -- bypass maybe on tree lookup | ||||
| find :: Tree Assumption [Assumption] -> Assumption -> [Assumption] | ||||
| find t a | ||||
|     | Just cs <- t.lookup a = cs | ||||
|     | otherwise = error ("no consequences for " ++ show a) | ||||
|  | ||||
| -- for performance resons, we confine ourselves to implication chains of length 20 per assumption | ||||
| mkPaths :: Tree Assumption [Assumption] -> [ (Assumption, [[Assumption]]) ] | ||||
| mkPaths acst = map impl  (keys acst)   -- {[a1], [a2], [a3] ] | ||||
|     where | ||||
|         -- [Assumption] -> [(a, [chains, ordered by length] | ||||
|         impl a = (a, impls [[a]]) | ||||
|         impls ns = (take 1000 • concat • takeUntil null • iterate expandchain) ns | ||||
|         -- expandchain :: [[Assumption]] -> [[Assumption]] | ||||
|         expandchain css = [ (n:a:as) | | ||||
|             (a : as) <- css,               -- list of assumptions | ||||
|             n <- find acst a,              -- consequences of a | ||||
|             n `notElem` as                 -- avoid loops | ||||
|           ] | ||||
|         -- uni (a:as) = a : uni (filter ((head a !=) • head) as) | ||||
|         -- uni [] = empty | ||||
|         -- empty = [] | ||||
|  | ||||
|  | ||||
| -- ------------------ SOLVE A SUDOKU -------------------------- | ||||
| -- Apply all available strategies until nothing changes anymore | ||||
| -- Strategy functions are supposed to return a list of | ||||
| -- functions, which, when applied to a board, give a changed board. | ||||
| -- When a strategy does not find anything to alter, | ||||
| -- it returns [], and the next strategy can be tried. | ||||
| solve b | ||||
|     | all (single . snd) b       = result "Solved" b | ||||
|     | any (([]==) . snd) b       = result "not solvable" b | ||||
|     | res@(_:_) <- reduce b       = apply b res >>=solve       -- compute smallest candidate sets | ||||
|     -- comment "candidate sets are up to date" = () | ||||
|     | res@(_:_) <- hiddenSingle b  = apply b res >>= solve     -- find HIDDEN SINGLES | ||||
|     -- comment "no more hidden singles" = () | ||||
|     | res@(_:_) <- intersections b = apply b res >>= solve     -- find locked candidates | ||||
|     -- comment "no more intersections" = () | ||||
|     | res@(_:_) <- nakedPair 2 b     = apply b res >>= solve     -- find NAKED PAIRS, TRIPLES or QUADRUPELS | ||||
|     -- comment "no more naked pairs" = () | ||||
|     | res@(_:_) <- hiddenPair  2 b   = apply b res >>= solve      -- find HIDDEN PAIRS, TRIPLES or QUADRUPELS | ||||
|     -- comment "no more hidden pairs" = () | ||||
|     -- res@(_:_) <- nakedPair 3 b     = apply b res >>= solve       // find NAKED PAIRS, TRIPLES or QUADRUPELS | ||||
|     -- | comment "no more naked triples" = () | ||||
|     -- res@(_:_) <- hiddenPair  3 b    = apply b res >>= solve      // find HIDDEN PAIRS, TRIPLES or QUADRUPELS | ||||
|     -- | comment "no more hidden triples" = () | ||||
|     -- res@(_:_) <- nakedPair 4 b     = apply b res >>=solve       // find NAKED PAIRS, TRIPLES or QUADRUPELS | ||||
|     -- | comment "no more naked quadruples" = () | ||||
|     -- res@(_:_) <- hiddenPair  4 b    = apply b res >>=solve      // find HIDDEN PAIRS, TRIPLES or QUADRUPELS | ||||
|     -- | comment "no more hidden quadruples" = () | ||||
|     | res@(_:_) <- xyWing b            = apply b res >>=solve      -- find XY WINGS | ||||
|     -- comment "no more xy wings"       = () | ||||
|     | res@(_:_) <- fish 2 b            = apply b res >>=solve      -- find 2-FISH | ||||
|     -- comment "no more x-wings"        = () | ||||
|     -- res@(_:_) <- fish 3 b            = apply b res >>=solve      // find 3-FISH | ||||
|     -- | comment "no more swordfish"      = () | ||||
|     -- res@(_:_) <- fish 4 b            = apply b res >>=solve      // find 4-FISH | ||||
|     -- | comment "no more jellyfish"      = () | ||||
|     -- | comment pcomment                 = () | ||||
|     | res@(_:_) <- chain b paths             = apply b (take 9 res) >>= solve  -- find forcing chains | ||||
|     | res@(_:_) <- cellRegionChain b paths   = apply b (take 9 res) >>= solve  -- find common conclusion for true assumption | ||||
|     | res@(_:_) <- chainContra b paths       = apply b (take 9 res) >>= solve  -- find assumptions that allow to infer both a and !a | ||||
|     -- comment "consistent conclusions only"       = () | ||||
|  | ||||
|     | otherwise = result "ambiguous" b | ||||
|     where | ||||
|         apply brd fs = foldM (\b\f -> f b) brd fs | ||||
|         paths = mkPaths (acstree b) | ||||
|         -- pcomment = show (length paths) ++ " assumptions with " ++ show (fold (+) 0 (map (length <~ snd) paths)) | ||||
|         --    ++ " implication chains" | ||||
|  | ||||
| -- comment com = do stderr << com << "\n" for false | ||||
| -- log com     = do stderr << com << "\n" for true | ||||
|  | ||||
| --- turn a string into a row | ||||
| mkrow :: String -> [Zelle] | ||||
| mkrow s = mkrow1 xs | ||||
|     where | ||||
|         xs = s ++ "---------" -- make sure at least 9 elements | ||||
|         mkrow1 xs = (take 9 • filter ([]!=) • map f • unpacked) xs | ||||
|         f x | x >= '1' && x <= '9'  =  [ord x - ord '0'] | ||||
|             | x == ' '  = []    -- ignored | ||||
|             | otherwise = elements | ||||
|  | ||||
| main ["-h"]    = main [] | ||||
| main ["-help"] = main [] | ||||
| main [] = do | ||||
|         mapM_ stderr.println [ | ||||
|             "usage: java Sudoku file ...", | ||||
|             "       java Sudoku position", | ||||
|             "where position is a 81 char string consisting of digits", | ||||
|             "One can get such a string by going to", | ||||
|             "http://www.sudokuoftheday.com/pages/s-o-t-d.php", | ||||
|             "Right click on the puzzle and open it in new tab", | ||||
|             "Copy the 81 digits from the URL in the address field of your browser.", | ||||
|             "", | ||||
|             "There is also a file with hard sudokus in examples/top95.txt\n"] | ||||
|         return () | ||||
|  | ||||
|  | ||||
| main [s@#^[0-9\W]{81}$#] = solve board >> return () | ||||
|     where | ||||
|         board = zip positions felder | ||||
|         felder = decode s | ||||
|  | ||||
| main files = forM_ files sudoku | ||||
|     where | ||||
|         sudoku file = do | ||||
|             br <- openReader file | ||||
|             lines <- BufferedReader.getLines br | ||||
|             bs <- process lines | ||||
|             ss <- mapM (\b -> print "Puzzle: " >> printb b >> solve b) bs | ||||
|             println ("Euler: " ++ show (sum (map res012 ss))) | ||||
|             return () | ||||
|  | ||||
| -- "--3-" => [1..9, 1..9, [3], 1..9] | ||||
| decode s = map candi (unpacked s) where | ||||
|         candi c | c >= '1' && c <= '9'  = [(ord c - ord '0')] | ||||
|                 | otherwise = elements | ||||
| process [] = return [] | ||||
| process (s:ss) | ||||
|     | length s == 81 = consider b1 | ||||
|     | length s == 9, | ||||
|       length acht == 8, | ||||
|       all ((9==) • length) acht = consider b2 | ||||
|     | otherwise = do | ||||
|             stderr.println ("skipped line: " ++ s) | ||||
|             process ss | ||||
|     where | ||||
|         acht = take 8 ss | ||||
|         neun = fold (++) "" (s:acht) | ||||
|         b1 = zip positions (decode s) | ||||
|         b2 = zip positions (decode neun) | ||||
|         consider b = do | ||||
|             -- print "Puzzle: " | ||||
|             -- printb b | ||||
|             bs <- process ss | ||||
|             return (b:bs) | ||||
|  | ||||
							
								
								
									
										79
									
								
								samples/Frege/SwingExamples.fr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								samples/Frege/SwingExamples.fr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | ||||
| package examples.SwingExamples where | ||||
|  | ||||
| import Java.Awt  (ActionListener) | ||||
| import Java.Swing | ||||
|  | ||||
|  | ||||
| main _ = do | ||||
|     rs <- mapM Runnable.new [helloWorldGUI, buttonDemoGUI, celsiusConverterGUI] | ||||
|     mapM_ invokeLater rs | ||||
|     println "Hit enter to end ...." | ||||
|     s <- getLine | ||||
|     return () | ||||
|  | ||||
| celsiusConverterGUI = do | ||||
|     tempTextField   <- JTextField.new() | ||||
|     celsiusLabel    <- JLabel.new () | ||||
|     convertButton   <- JButton.new () | ||||
|     fahrenheitLabel <- JLabel.new ()  | ||||
|     frame           <- JFrame.new () | ||||
|     frame.setDefaultCloseOperation JFrame.dispose_on_close | ||||
|     frame.setTitle "Celsius Converter" | ||||
|     celsiusLabel.setText  "Celsius" | ||||
|     convertButton.setText "Convert" | ||||
|     let convertButtonActionPerformed _ = do | ||||
|             celsius <- tempTextField.getText | ||||
|             case celsius.double of | ||||
|                 Left _  -> fahrenheitLabel.setText ("not a valid number: " ++ celsius) | ||||
|                 Right c -> fahrenheitLabel.setText (show (c*1.8 + 32.0).long ++ " Fahrenheit")  | ||||
|             return () | ||||
|     ActionListener.new convertButtonActionPerformed >>= convertButton.addActionListener | ||||
|     fahrenheitLabel.setText "Fahrenheit" | ||||
|     contentPane <- frame.getContentPane | ||||
|     layout      <- GroupLayout.new contentPane | ||||
|     contentPane.setLayout layout | ||||
|     -- TODO continue | ||||
|     -- http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/uiswing/examples/learn/CelsiusConverterProject/src/learn/CelsiusConverterGUI.java | ||||
|     frame.pack | ||||
|     frame.setVisible true | ||||
|  | ||||
| helloWorldGUI = do | ||||
|     frame <- JFrame.new "Hello World Frege" | ||||
|     frame.setDefaultCloseOperation(JFrame.dispose_on_close) | ||||
|     label <- JLabel.new "Hello World!" | ||||
|     cp <- frame.getContentPane | ||||
|     cp.add label | ||||
|     frame.pack | ||||
|     frame.setVisible true | ||||
|  | ||||
| buttonDemoGUI = do | ||||
|     frame <- JFrame.new "Button Demo" | ||||
|     frame.setDefaultCloseOperation(JFrame.dispose_on_close) | ||||
|     newContentPane <- JPanel.new () | ||||
|     b1::JButton <- JButton.new "Disable middle button" | ||||
|     b1.setVerticalTextPosition   SwingConstants.center | ||||
|     b1.setHorizontalTextPosition SwingConstants.leading | ||||
|     b2::JButton <- JButton.new "Middle button" | ||||
|     b2.setVerticalTextPosition   SwingConstants.center | ||||
|     b2.setHorizontalTextPosition SwingConstants.leading | ||||
|     b3::JButton <- JButton.new "Enable middle button" | ||||
|     b3.setVerticalTextPosition   SwingConstants.center | ||||
|     b3.setHorizontalTextPosition SwingConstants.leading | ||||
|     b3.setEnabled false | ||||
|     let action1 _ = do | ||||
|             b2.setEnabled false | ||||
|             b1.setEnabled false | ||||
|             b3.setEnabled true | ||||
|         action3 _ = do | ||||
|             b2.setEnabled true | ||||
|             b1.setEnabled true | ||||
|             b3.setEnabled false | ||||
|     ActionListener.new action1  >>= b1.addActionListener | ||||
|     ActionListener.new action3  >>= b3.addActionListener  | ||||
|     newContentPane.add b1 | ||||
|     newContentPane.add b2 | ||||
|     newContentPane.add b3 | ||||
|     newContentPane.setOpaque true | ||||
|     frame.setContentPane newContentPane | ||||
|     frame.pack | ||||
|     frame.setVisible true | ||||
							
								
								
									
										57
									
								
								samples/G-code/duettest.g
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								samples/G-code/duettest.g
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| ; RepRapPro Ormerod | ||||
| ; Board test GCodes | ||||
| M111 S1; Debug on | ||||
| G21 ; mm | ||||
| G90 ; Absolute positioning | ||||
| M83 ; Extrusion relative | ||||
| M906 X800 Y800 Z800 E800 ; Motor currents (mA) | ||||
| T0 ; Extruder 0 | ||||
| G1 X50 F500 | ||||
| G1 X0 | ||||
| G4 P500 | ||||
| G1 Y50 F500 | ||||
| G1 Y0 | ||||
| G4 P500 | ||||
| G1 Z20 F200 | ||||
| G1 Z0 | ||||
| G4 P500 | ||||
| G1 E20 F200 | ||||
| G1 E-20 | ||||
| G4 P500 | ||||
| M106 S255 | ||||
| G4 P500 | ||||
| M106 S0 | ||||
| G4 P500 | ||||
| M105 | ||||
| G10 P0 S100 | ||||
| T0 | ||||
| M140 S100 | ||||
| G4 P5000 | ||||
| M105 | ||||
| G4 P5000 | ||||
| M105 | ||||
| G4 P5000 | ||||
| M105 | ||||
| G4 P5000 | ||||
| M105 | ||||
| G4 P5000 | ||||
| M105 | ||||
| G4 P5000 | ||||
| M105 | ||||
| G4 P5000 | ||||
| M105 | ||||
| G4 P5000 | ||||
| M105 | ||||
| G4 P5000 | ||||
| M105 | ||||
| G4 P5000 | ||||
| M105 | ||||
| G4 P5000 | ||||
| M105 | ||||
| G4 P5000 | ||||
| M105 | ||||
| M0 | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
							
								
								
									
										25912
									
								
								samples/G-code/lm.g
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25912
									
								
								samples/G-code/lm.g
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										29735
									
								
								samples/G-code/rm.g
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29735
									
								
								samples/G-code/rm.g
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										13
									
								
								samples/G-code/square.g
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								samples/G-code/square.g
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| G28 X0 Y0 | ||||
| G1 X55 Y5 F2000 | ||||
| G1 Y180 | ||||
| G1 X180 | ||||
| G1 Y5 | ||||
| G1 X55 | ||||
| G1 Y180 | ||||
| G1 X180 | ||||
| G1 Y5 | ||||
| G1 X55 | ||||
| M0 | ||||
|  | ||||
|  | ||||
							
								
								
									
										76
									
								
								samples/GAMS/transport.gms
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								samples/GAMS/transport.gms
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| *Basic example of transport model from GAMS model library | ||||
|  | ||||
| $Title  A Transportation Problem (TRNSPORT,SEQ=1) | ||||
| $Ontext | ||||
|  | ||||
| This problem finds a least cost shipping schedule that meets | ||||
| requirements at markets and supplies at factories. | ||||
|  | ||||
|  | ||||
| Dantzig, G B, Chapter 3.3. In Linear Programming and Extensions. | ||||
| Princeton University Press, Princeton, New Jersey, 1963. | ||||
|  | ||||
| This formulation is described in detail in: | ||||
| Rosenthal, R E, Chapter 2: A GAMS Tutorial. In GAMS: A User's Guide. | ||||
| The Scientific Press, Redwood City, California, 1988. | ||||
|  | ||||
| The line numbers will not match those in the book because of these | ||||
| comments. | ||||
|  | ||||
| $Offtext | ||||
|  | ||||
|  | ||||
|   Sets | ||||
|        i   canning plants   / seattle, san-diego / | ||||
|        j   markets          / new-york, chicago, topeka / ; | ||||
|   Parameters | ||||
|        a(i)  capacity of plant i in cases | ||||
|          /    seattle     350 | ||||
|               san-diego   600  / | ||||
|        b(j)  demand at market j in cases | ||||
|          /    new-york    325 | ||||
|               chicago     300 | ||||
|               topeka      275  / ; | ||||
|   Table d(i,j)  distance in thousands of miles | ||||
|                     new-york       chicago      topeka | ||||
|       seattle          2.5           1.7          1.8 | ||||
|       san-diego        2.5           1.8          1.4  ; | ||||
|   Scalar f  freight in dollars per case per thousand miles  /90/ ; | ||||
|   Parameter c(i,j)  transport cost in thousands of dollars per case ; | ||||
|             c(i,j) = f * d(i,j) / 1000 ; | ||||
|   Variables | ||||
|        x(i,j)  shipment quantities in cases | ||||
|        z       total transportation costs in thousands of dollars ; | ||||
|  | ||||
|   Positive Variable x ; | ||||
|  | ||||
|   Equations | ||||
|        cost        define objective function | ||||
|        supply(i)   observe supply limit at plant i | ||||
|        demand(j)   satisfy demand at market j ; | ||||
|  | ||||
|   cost ..        z  =e=  sum((i,j), c(i,j)*x(i,j)) ; | ||||
|  | ||||
|   supply(i) ..   sum(j, x(i,j))  =l=  a(i) ; | ||||
|  | ||||
|   demand(j) ..   sum(i, x(i,j))  =g=  b(j) ; | ||||
|  | ||||
|   Model transport /all/ ; | ||||
|  | ||||
|   Solve transport using lp minimizing z ; | ||||
|  | ||||
|   Display x.l, x.m ; | ||||
|  | ||||
| $ontext | ||||
| #user model library stuff | ||||
| Main topic Basic GAMS | ||||
| Featured item 1 Trnsport model | ||||
| Featured item 2 | ||||
| Featured item 3 | ||||
| Featured item 4 | ||||
| Description | ||||
| Basic example of transport model from GAMS model library | ||||
|  | ||||
|  | ||||
|  | ||||
| $offtext | ||||
							
								
								
									
										307
									
								
								samples/GAP/Magic.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										307
									
								
								samples/GAP/Magic.gd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,307 @@ | ||||
| ############################################################################# | ||||
| ## | ||||
| ##  Magic.gd                                         AutoDoc package | ||||
| ## | ||||
| ##  Copyright 2013, Max Horn, JLU Giessen | ||||
| ##                  Sebastian Gutsche, University of Kaiserslautern | ||||
| ## | ||||
| ############################################################################# | ||||
|  | ||||
|  | ||||
| #! @Description | ||||
| #! This is the main function of the &AutoDoc; package. It can perform | ||||
| #! any combination of the following three tasks: | ||||
| #! <Enum> | ||||
| #! <Item> | ||||
| #!     It can (re)generate a scaffold for your package manual. | ||||
| #!     That is, it can produce two XML files in &GAPDoc; format to be used as part | ||||
| #!     of your manual: First, a file named <F>doc/PACKAGENAME.xml</F> | ||||
| #!     (with your package's name substituted) which is used as | ||||
| #!     main file for the package manual, i.e. this file sets the | ||||
| #!     XML DOCTYPE and defines various XML entities, includes | ||||
| #!     other XML files (both those generated by &AutoDoc; as well | ||||
| #!     as additional files created by other means), tells &GAPDoc; | ||||
| #!     to generate a table of content and an index, and more. | ||||
| #!     Secondly, it creates a file <F>doc/title.xml</F> containing a title | ||||
| #!     page for your documentation, with information about your package | ||||
| #!     (name, description, version), its authors and more, based | ||||
| #!     on the data in your <F>PackageInfo.g</F>. | ||||
| #! </Item> | ||||
| #! <Item> | ||||
| #!     It can scan your package for &AutoDoc; based documentation (by using &AutoDoc; | ||||
| #!     tags and the Autodoc command. | ||||
| #!     This will | ||||
| #!     produce further XML files to be used as part of the package manual. | ||||
| #! </Item> | ||||
| #! <Item> | ||||
| #!     It can use &GAPDoc; to generate PDF, text and HTML (with | ||||
| #!     MathJaX enabled) documentation from the &GAPDoc; XML files it | ||||
| #!     generated as well as additional such files provided by you. For | ||||
| #!     this, it invokes <Ref Func='MakeGAPDocDoc' BookName='gapdoc'/> | ||||
| #!     to convert the XML sources, and it also instructs &GAPDoc; to copy | ||||
| #!     supplementary files (such as CSS style files) into your doc directory | ||||
| #!     (see <Ref Func='CopyHTMLStyleFiles' BookName='gapdoc'/>). | ||||
| #! </Item> | ||||
| #! </Enum> | ||||
| #! For more information and some examples, please refer to Chapter <Ref Label='Tutorials'/>. | ||||
| #! <P/> | ||||
| #! The parameters have the following meanings: | ||||
| #! <List> | ||||
| #! | ||||
| #! <Mark><A>package_name</A></Mark> | ||||
| #! <Item> | ||||
| #!     The name of the package whose documentation should be(re)generated. | ||||
| #! </Item> | ||||
| #! | ||||
| #! | ||||
| #! <Mark><A>option_record</A></Mark> | ||||
| #! <Item> | ||||
| #!     <A>option_record</A> can be a record with some additional options. | ||||
| #!     The following are currently supported: | ||||
| #!     <List> | ||||
| #!     <Mark><A>dir</A></Mark> | ||||
| #!     <Item> | ||||
| #!         This should be a string containing a (relative) path or a | ||||
| #!         Directory() object specifying where the package documentation | ||||
| #!         (i.e. the &GAPDoc; XML files) are stored. | ||||
| #!         <Br/> | ||||
| #!         <E>Default value: <C>"doc/"</C>.</E> | ||||
| #!     </Item> | ||||
| #!     <Mark><A>scaffold</A></Mark> | ||||
| #!     <Item> | ||||
| #!         This controls whether and how to generate scaffold XML files | ||||
| #!         for the main and title page of the package's documentation.  | ||||
| #!         <P/> | ||||
| #!         The value should be either <K>true</K>, <K>false</K> or a | ||||
| #!         record. If it is a record or <K>true</K> (the latter is | ||||
| #!         equivalent to specifying an empty record), then this feature is | ||||
| #!         enabled. It is also enabled if <A>opt.scaffold</A> is missing but the | ||||
| #!         package's info record in <F>PackageInfo.g</F> has an <C>AutoDoc</C> entry. | ||||
| #!         In all other cases (in particular if <A>opt.scaffold</A> is | ||||
| #!         <K>false</K>), scaffolding is disabled. | ||||
| #!         <P/> | ||||
| #! | ||||
| #!         If <A>opt.scaffold</A> is a record, it may contain the following entries. | ||||
| #! | ||||
| #### TODO: mention merging with PackageInfo.AutoDoc! | ||||
| #!         <List> | ||||
| #! | ||||
| #!         <Mark><A>includes</A></Mark> | ||||
| #!         <Item> | ||||
| #!             A list of XML files to be included in the body of the main XML file. | ||||
| #!             If you specify this list and also are using &AutoDoc; to document | ||||
| #!             your operations with &AutoDoc; comments, | ||||
| #!             you can add <F>AutoDocMainFile.xml</F> to this list | ||||
| #!             to control at which point the documentation produced by &AutoDoc; | ||||
| #!             is inserted. If you do not do this, it will be added after the last | ||||
| #!             of your own XML files. | ||||
| #!         </Item> | ||||
| #! | ||||
| #!         <Mark><A>appendix</A></Mark> | ||||
| #!         <Item> | ||||
| #!             This entry is similar to <A>opt.scaffold.includes</A> but is used | ||||
| #!             to specify files to include after the main body of the manual, | ||||
| #!             i.e. typically appendices. | ||||
| #!         </Item> | ||||
| #! | ||||
| #!         <Mark><A>bib</A></Mark> | ||||
| #!         <Item> | ||||
| #!             The name of a bibliography file, in Bibtex or XML format. | ||||
| #!             If this key is not set, but there is a file <F>doc/PACKAGENAME.bib</F> | ||||
| #!             then it is assumed that you want to use this as your bibliography. | ||||
| #!         </Item> | ||||
| #! | ||||
| #### TODO: The 'entities' param is a bit strange. We should probably change it to be a bit more | ||||
| #### general, as one might want to define other entities... For now, we do not document it | ||||
| #### to leave us the choice of revising how it works. | ||||
| #### | ||||
| ####                 <Mark><A>entities</A></Mark> | ||||
| ####                 <Item> | ||||
| ####                     A list of package names or other entities which are used to define corresponding XML entities. | ||||
| ####                     For example, if set to a list containing the string <Q>SomePackage</Q>, | ||||
| ####                     then the following is added to the XML preamble: | ||||
| ####                     <Listing><![CDATA[<!ENTITY SomePackage '<Package>SomePackage</Package>'>]]></Listing> | ||||
| ####                     This allows you to write <Q>&SomePackage;</Q> in your documentation | ||||
| ####                     to reference that package. If another type of entity is desired, one can simply add, | ||||
| ####                     instead of a string, add a two entry list <A>a</A> to the list. It will be handled as | ||||
| ####                     <Listing><![CDATA[<!ENTITY a[ 2 ] '<a[ 1 ]>a[ 2 ]</a[ 1 ]>'>]]></Listing>, | ||||
| ####                     so please be careful. | ||||
| ####                 </Item> | ||||
| #! | ||||
| #!         <Mark><A>TitlePage</A></Mark> | ||||
| #!         <Item> | ||||
| #!             A record whose entries are used to embellish the generated titlepage | ||||
| #!             for the package manual with extra information, such as a copyright | ||||
| #!             statement or acknowledgments. To this end, the names of the record | ||||
| #!             components are used as XML element names, and the values of the | ||||
| #!             components are outputted as content of these XML elements. For | ||||
| #!             example, you could pass the following record to set a custom | ||||
| #!             acknowledgements text: | ||||
| #!             <Listing><![CDATA[ | ||||
| #!             rec( Acknowledgements := "Many thanks to ..." )]]></Listing> | ||||
| #!             For a list of valid entries in the titlepage, please refer to the | ||||
| #!             &GAPDoc; manual, specifically section <Ref Subsect='Title' BookName='gapdoc'/> | ||||
| #!             and following. | ||||
| #!         </Item> | ||||
| #!         <Mark><A>document_class</A></Mark> | ||||
| #!         <Item> | ||||
| #!             Sets the document class of the resulting pdf. The value can either be a string | ||||
| #!             which has to be the name of the new document class, a list containing this string, or | ||||
| #!             a list of two strings. Then the first one has to be the document class name, the second one | ||||
| #!             the option string ( contained in [ ] ) in LaTeX. | ||||
| #!         </Item> | ||||
| #!         <Mark><A>latex_header_file</A></Mark> | ||||
| #!         <Item> | ||||
| #!             Replaces the standard header from &GAPDoc; completely with the header in this LaTeX file. | ||||
| #!             Please be careful here, and look at GAPDoc's latexheader.tex file for an example. | ||||
| #!         </Item> | ||||
| #!         <Mark><A>gapdoc_latex_options</A></Mark> | ||||
| #!         <Item> | ||||
| #!             Must be a record with entries which can be understood by SetGapDocLaTeXOptions. Each entry can be a string, which | ||||
| #!             will be given to &GAPDoc; directly, or a list containing of two entries: The first one must be the string "file", | ||||
| #!             the second one a filename. This file will be read and then its content is passed to &GAPDoc; as option with the name | ||||
| #!             of the entry. | ||||
| #!         </Item> | ||||
| #! | ||||
| #!         </List> | ||||
| #!     </Item> | ||||
| #! | ||||
| #! | ||||
| #!     <Mark><A>autodoc</A></Mark> | ||||
| #!     <Item> | ||||
| #!         This controls whether and how to generate addition XML documentation files | ||||
| #!         by scanning for &AutoDoc; documentation comments. | ||||
| #!         <P/> | ||||
| #!         The value should be either <K>true</K>, <K>false</K> or a | ||||
| #!         record. If it is a record or <K>true</K> (the latter is | ||||
| #!         equivalent to specifying an empty record), then this feature is | ||||
| #!         enabled. It is also enabled if <A>opt.autodoc</A> is missing but the | ||||
| #!         package depends (directly) on the &AutoDoc; package. | ||||
| #!         In all other cases (in particular if <A>opt.autodoc</A> is | ||||
| #!         <K>false</K>), this feature is disabled. | ||||
| #!         <P/> | ||||
| #! | ||||
| #!         If <A>opt.autodoc</A> is a record, it may contain the following entries. | ||||
| #! | ||||
| #!         <List> | ||||
| #! | ||||
| #!         <Mark><A>files</A></Mark> | ||||
| #!         <Item> | ||||
| #!             A list of files (given by paths relative to the package directory) | ||||
| #!             to be scanned for &AutoDoc; documentation comments. | ||||
| #!             Usually it is more convenient to use <A>autodoc.scan_dirs</A>, see below. | ||||
| #!         </Item> | ||||
| #! | ||||
| #!         <Mark><A>scan_dirs</A></Mark> | ||||
| #!         <Item> | ||||
| #!             A list of subdirectories of the package directory (given as relative paths) | ||||
| #!             which &AutoDoc; then scans for .gi, .gd and .g files; all of these files | ||||
| #!             are then scanned for &AutoDoc; documentation comments. | ||||
| #!             <Br/> | ||||
| #!             <E>Default value: <C>[ "gap", "lib", "examples", "examples/doc" ]</C>.</E> | ||||
| #!         </Item> | ||||
| #! | ||||
| #!         <Mark><A>level</A></Mark> | ||||
| #!         <Item> | ||||
| #!             This defines the level of the created documentation. The default value is 0. | ||||
| #!             When parts of the manual are declared with a higher value | ||||
| #!             they will not be printed into the manual. | ||||
| #!         </Item> | ||||
| #! | ||||
| #### TODO: Document section_intros later on. | ||||
| #### However, note that thanks to the new AutoDoc comment syntax, the only remaining | ||||
| #### use for this seems to be the ability to specify the order of chapters and | ||||
| #### sections. | ||||
| ####                 <Mark><A>section_intros</A></Mark> | ||||
| ####                 <Item> | ||||
| ####                     TODO. | ||||
| ####                 </Item> | ||||
| #! | ||||
| #!         </List> | ||||
| #!     </Item> | ||||
| #! | ||||
| #! | ||||
| #!     <Mark><A>gapdoc</A></Mark> | ||||
| #!     <Item> | ||||
| #!         This controls whether and how to invoke &GAPDoc; to create HTML, PDF and text | ||||
| #!         files from your various XML files. | ||||
| #!         <P/> | ||||
| #!         The value should be either <K>true</K>, <K>false</K> or a | ||||
| #!         record. If it is a record or <K>true</K> (the latter is | ||||
| #!         equivalent to specifying an empty record), then this feature is | ||||
| #!         enabled. It is also enabled if <A>opt.gapdoc</A> is missing. | ||||
| #!         In all other cases (in particular if <A>opt.gapdoc</A> is | ||||
| #!         <K>false</K>), this feature is disabled. | ||||
| #!         <P/> | ||||
| #! | ||||
| #!         If <A>opt.gapdoc</A> is a record, it may contain the following entries. | ||||
| #! | ||||
| #!         <List> | ||||
| #! | ||||
| #! | ||||
| #### Note: 'main' is strictly speaking also used for the scaffold. | ||||
| #### However, if one uses the scaffolding mechanism, then it is not | ||||
| #### really necessary to specify a custom name for the main XML file. | ||||
| #### Thus, the purpose of this parameter is to cater for packages | ||||
| #### that have existing documentation using a different XML name, | ||||
| #### and which do not wish to use scaffolding. | ||||
| #### | ||||
| #### This explain why we only allow specifying gapdoc.main. | ||||
| #### The scaffolding code will still honor it, though, just in case. | ||||
| #!         <Mark><A>main</A></Mark> | ||||
| #!         <Item> | ||||
| #!             The name of the main XML file of the package manual. | ||||
| #!             This exists primarily to support packages with existing manual | ||||
| #!             which use a filename here which differs from the default. | ||||
| #!             In particular, specifying this is unnecessary when using scaffolding. | ||||
| #!             <Br/> | ||||
| #!             <E>Default value: <C>PACKAGENAME.xml</C></E>. | ||||
| #!         </Item> | ||||
| #! | ||||
| #!         <Mark><A>files</A></Mark> | ||||
| #!         <Item> | ||||
| #!             A list of files (given by paths relative to the package directory) | ||||
| #!             to be scanned for &GAPDoc; documentation comments. | ||||
| #!             Usually it is more convenient to use <A>gapdoc.scan_dirs</A>, see below. | ||||
| #!         </Item> | ||||
| #! | ||||
| #!         <Mark><A>scan_dirs</A></Mark> | ||||
| #!         <Item> | ||||
| #!             A list of subdirectories of the package directory (given as relative paths) | ||||
| #!             which &AutoDoc; then scans for .gi, .gd and .g files; all of these files | ||||
| #!             are then scanned for &GAPDoc; documentation comments. | ||||
| #!             <Br/> | ||||
| #!             <E>Default value: <C>[ "gap", "lib", "examples", "examples/doc" ]</C>.</E> | ||||
| #!         </Item> | ||||
| #! | ||||
| #!         </List> | ||||
| #!     </Item> | ||||
| ## This is the maketest part. Still under construction. | ||||
| #!        <Mark><A>maketest</A></Mark> | ||||
| #!        <Item> | ||||
| #!          The maketest item can be true or a record. When it is true, | ||||
| #!          a simple maketest.g is created in the main package directory, | ||||
| #!          which can be used to test the examples from the manual. As a record, | ||||
| #!          the entry can have the following entries itself, to specify some options. | ||||
| #!          <List> | ||||
| #!          <Mark>filename</Mark> | ||||
| #!          <Item> | ||||
| #!            Sets the name of the test file. | ||||
| #!          </Item> | ||||
| #!          <Mark>commands</Mark> | ||||
| #!          <Item> | ||||
| #!            A list of strings, each one a command, which | ||||
| #!            will be executed at the beginning of the test file. | ||||
| #!          </Item> | ||||
| #!          </List> | ||||
| #!        </Item> | ||||
| #! | ||||
| #!     </List> | ||||
| #! </Item> | ||||
| #! </List> | ||||
| #! | ||||
| #! @Returns nothing | ||||
| #! @Arguments package_name[, option_record ] | ||||
| #! @ChapterInfo AutoDoc, The AutoDoc() function | ||||
| DeclareGlobalFunction( "AutoDoc" ); | ||||
|  | ||||
							
								
								
									
										534
									
								
								samples/GAP/Magic.gi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										534
									
								
								samples/GAP/Magic.gi
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,534 @@ | ||||
| ############################################################################# | ||||
| ## | ||||
| ##  Magic.gi                                         AutoDoc package | ||||
| ## | ||||
| ##  Copyright 2013, Max Horn, JLU Giessen | ||||
| ##                  Sebastian Gutsche, University of Kaiserslautern | ||||
| ## | ||||
| ############################################################################# | ||||
|  | ||||
| # Check if a string has the given suffix or not. Another | ||||
| # name for this would "StringEndsWithOtherString". | ||||
| # For example, AUTODOC_HasSuffix("file.gi", ".gi") returns | ||||
| # true while AUTODOC_HasSuffix("file.txt", ".gi") returns false. | ||||
| BindGlobal( "AUTODOC_HasSuffix", | ||||
| function(str, suffix) | ||||
|     local n, m; | ||||
|     n := Length(str); | ||||
|     m := Length(suffix); | ||||
|     return n >= m and str{[n-m+1..n]} = suffix; | ||||
| end ); | ||||
|  | ||||
| # Given a string containing a ".", , return its suffix, | ||||
| # i.e. the bit after the last ".". For example, given "test.txt", | ||||
| # it returns "txt". | ||||
| BindGlobal( "AUTODOC_GetSuffix", | ||||
| function(str) | ||||
|     local i; | ||||
|     i := Length(str); | ||||
|     while i > 0 and str[i] <> '.' do i := i - 1; od; | ||||
|     if i < 0 then return ""; fi; | ||||
|     return str{[i+1..Length(str)]}; | ||||
| end ); | ||||
|  | ||||
| # Check whether the given directory exists, and if not, attempt | ||||
| # to create it. | ||||
| BindGlobal( "AUTODOC_CreateDirIfMissing", | ||||
| function(d) | ||||
|     local tmp; | ||||
|     if not IsDirectoryPath(d) then | ||||
|         tmp := CreateDir(d); # Note: CreateDir is currently undocumented | ||||
|         if tmp = fail then | ||||
|             Error("Cannot create directory ", d, "\n", | ||||
|                   "Error message: ", LastSystemError().message, "\n"); | ||||
|             return false; | ||||
|         fi; | ||||
|     fi; | ||||
|     return true; | ||||
| end ); | ||||
|  | ||||
|  | ||||
| # Scan the given (by name) subdirs of a package dir for | ||||
| # files with one of the given extensions, and return the corresponding | ||||
| # filenames, as relative paths (relative to the package dir). | ||||
| # | ||||
| # For example, the invocation | ||||
| #   AUTODOC_FindMatchingFiles("AutoDoc", [ "gap/" ], [ "gi", "gd" ]); | ||||
| # might return a list looking like | ||||
| #  [ "gap/AutoDocMainFunction.gd", "gap/AutoDocMainFunction.gi", ... ] | ||||
| BindGlobal( "AUTODOC_FindMatchingFiles", | ||||
| function (pkg, subdirs, extensions) | ||||
|     local d_rel, d, tmp, files, result; | ||||
|  | ||||
|     result := []; | ||||
|  | ||||
|     for d_rel in subdirs do | ||||
|         # Get the absolute path to the directory in side the package... | ||||
|         d := DirectoriesPackageLibrary( pkg, d_rel ); | ||||
|         if IsEmpty( d ) then | ||||
|             continue; | ||||
|         fi; | ||||
|         d := d[1]; | ||||
|         # ... but also keep the relative path (such as "gap") | ||||
|         d_rel := Directory( d_rel ); | ||||
|  | ||||
|         files := DirectoryContents( d ); | ||||
|         Sort( files ); | ||||
|         for tmp in files do | ||||
|             if not AUTODOC_GetSuffix( tmp ) in [ "g", "gi", "gd", "autodoc" ] then | ||||
|                 continue; | ||||
|             fi; | ||||
|             if not IsReadableFile( Filename( d, tmp ) ) then | ||||
|                 continue; | ||||
|             fi; | ||||
|             Add( result, Filename( d_rel, tmp ) ); | ||||
|         od; | ||||
|     od; | ||||
|     return result; | ||||
| end ); | ||||
|  | ||||
|  | ||||
| # AutoDoc(pkg[, opt]) | ||||
| # | ||||
| ## Make this function callable with the package_name AutoDocWorksheet. | ||||
| ## Which will then create a worksheet! | ||||
| InstallGlobalFunction( AutoDoc, | ||||
| function( arg ) | ||||
|     local pkg, package_info, opt, scaffold, gapdoc, maketest, | ||||
|           autodoc, pkg_dir, doc_dir, doc_dir_rel, d, tmp, | ||||
|           title_page, tree, is_worksheet, position_document_class, i, gapdoc_latex_option_record; | ||||
|      | ||||
|     pkg := arg[1]; | ||||
|      | ||||
|     if LowercaseString( pkg ) = "autodocworksheet" then | ||||
|         is_worksheet := true; | ||||
|         package_info := rec( ); | ||||
|         pkg_dir := DirectoryCurrent( ); | ||||
|     else | ||||
|         is_worksheet := false; | ||||
|         package_info := PackageInfo( pkg )[ 1 ]; | ||||
|         pkg_dir := DirectoriesPackageLibrary( pkg, "" )[1]; | ||||
|     fi; | ||||
|  | ||||
|     if Length(arg) >= 2 then | ||||
|         opt := arg[2]; | ||||
|     else | ||||
|         opt := rec(); | ||||
|     fi; | ||||
|  | ||||
|     # Check for certain user supplied options, and if present, add them | ||||
|     # to the opt record. | ||||
|     tmp := function( key ) | ||||
|         local val; | ||||
|         val := ValueOption( key ); | ||||
|         if val <> fail then | ||||
|             opt.(key) := val; | ||||
|         fi; | ||||
|     end; | ||||
|      | ||||
|     tmp( "dir" ); | ||||
|     tmp( "scaffold" ); | ||||
|     tmp( "autodoc" ); | ||||
|     tmp( "gapdoc" ); | ||||
|     tmp( "maketest" ); | ||||
|      | ||||
|     # | ||||
|     # Setup the output directory | ||||
|     # | ||||
|     if not IsBound( opt.dir ) then | ||||
|         doc_dir := "doc"; | ||||
|     elif IsString( opt.dir ) or IsDirectory( opt.dir ) then | ||||
|         doc_dir := opt.dir; | ||||
|     else | ||||
|         Error( "opt.dir must be a string containing a path, or a directory object" ); | ||||
|     fi; | ||||
|      | ||||
|     if IsString( doc_dir ) then | ||||
|         # Record the relative version of the path | ||||
|         doc_dir_rel := Directory( doc_dir ); | ||||
|  | ||||
|         # We intentionally do not use | ||||
|         #   DirectoriesPackageLibrary( pkg, "doc" ) | ||||
|         # because it returns an empty list if the subdirectory is missing. | ||||
|         # But we want to handle that case by creating the directory. | ||||
|         doc_dir := Filename(pkg_dir, doc_dir); | ||||
|         doc_dir := Directory(doc_dir); | ||||
|  | ||||
|     else | ||||
|         # TODO: doc_dir_rel = ... ? | ||||
|     fi; | ||||
|  | ||||
|     # Ensure the output directory exists, create it if necessary | ||||
|     AUTODOC_CreateDirIfMissing(Filename(doc_dir, "")); | ||||
|      | ||||
|     # Let the developer know where we are generating the documentation. | ||||
|     # This helps diagnose problems where multiple instances of a package | ||||
|     # are visible to GAP and the wrong one is used for generating the | ||||
|     # documentation. | ||||
|     # TODO: Using Info() instead of Print? | ||||
|     Print( "Generating documentation in ", doc_dir, "\n" ); | ||||
|  | ||||
|     # | ||||
|     # Extract scaffolding settings, which can be controlled via | ||||
|     # opt.scaffold or package_info.AutoDoc. The former has precedence. | ||||
|     # | ||||
|     if not IsBound(opt.scaffold) then | ||||
|         # Default: enable scaffolding if and only if package_info.AutoDoc is present | ||||
|         if IsBound( package_info.AutoDoc ) then | ||||
|             scaffold := rec( ); | ||||
|         fi; | ||||
|     elif IsRecord(opt.scaffold) then | ||||
|         scaffold := opt.scaffold; | ||||
|     elif IsBool(opt.scaffold) then | ||||
|         if opt.scaffold = true then | ||||
|             scaffold := rec(); | ||||
|         fi; | ||||
|     else | ||||
|         Error("opt.scaffold must be a bool or a record"); | ||||
|     fi; | ||||
|  | ||||
|     # Merge package_info.AutoDoc into scaffold | ||||
|     if IsBound(scaffold) and IsBound( package_info.AutoDoc ) then | ||||
|         AUTODOC_APPEND_RECORD_WRITEONCE( scaffold, package_info.AutoDoc ); | ||||
|     fi; | ||||
|      | ||||
|     if IsBound( scaffold ) then | ||||
|         AUTODOC_WriteOnce( scaffold, "TitlePage", true ); | ||||
|         AUTODOC_WriteOnce( scaffold, "MainPage", true ); | ||||
|     fi; | ||||
|  | ||||
|      | ||||
|     # | ||||
|     # Extract AutoDoc settings | ||||
|     # | ||||
|     if not IsBound(opt.autodoc) and not is_worksheet then | ||||
|         # Enable AutoDoc support if the package depends on AutoDoc. | ||||
|         tmp := Concatenation( package_info.Dependencies.NeededOtherPackages, | ||||
|                               package_info.Dependencies.SuggestedOtherPackages ); | ||||
|         if ForAny( tmp, x -> LowercaseString(x[1]) = "autodoc" ) then | ||||
|             autodoc := rec(); | ||||
|         fi; | ||||
|     elif IsRecord(opt.autodoc) then | ||||
|         autodoc := opt.autodoc; | ||||
|     elif IsBool(opt.autodoc) and opt.autodoc = true then | ||||
|         autodoc := rec(); | ||||
|     fi; | ||||
|      | ||||
|     if IsBound(autodoc) then | ||||
|         if not IsBound( autodoc.files ) then | ||||
|             autodoc.files := [ ]; | ||||
|         fi; | ||||
|          | ||||
|         if not IsBound( autodoc.scan_dirs ) and not is_worksheet then | ||||
|             autodoc.scan_dirs := [ "gap", "lib", "examples", "examples/doc" ]; | ||||
|         elif not IsBound( autodoc.scan_dirs ) and is_worksheet then | ||||
|             autodoc.scan_dirs := [ ]; | ||||
|         fi; | ||||
|          | ||||
|         if not IsBound( autodoc.level ) then | ||||
|             autodoc.level := 0; | ||||
|         fi; | ||||
|          | ||||
|         PushOptions( rec( level_value := autodoc.level ) ); | ||||
|          | ||||
|         if not is_worksheet then | ||||
|             Append( autodoc.files, AUTODOC_FindMatchingFiles(pkg, autodoc.scan_dirs, [ "g", "gi", "gd" ]) ); | ||||
|         fi; | ||||
|     fi; | ||||
|  | ||||
|     # | ||||
|     # Extract GAPDoc settings | ||||
|     # | ||||
|     if not IsBound( opt.gapdoc ) then | ||||
|         # Enable GAPDoc support by default | ||||
|         gapdoc := rec(); | ||||
|     elif IsRecord( opt.gapdoc ) then | ||||
|         gapdoc := opt.gapdoc; | ||||
|     elif IsBool( opt.gapdoc ) and opt.gapdoc = true then | ||||
|         gapdoc := rec(); | ||||
|     fi; | ||||
|      | ||||
|     # | ||||
|     # Extract test settings | ||||
|     # | ||||
|      | ||||
|     if IsBound( opt.maketest ) then | ||||
|         if IsRecord( opt.maketest ) then | ||||
|             maketest := opt.maketest; | ||||
|         elif opt.maketest = true then | ||||
|             maketest := rec( ); | ||||
|         fi; | ||||
|     fi; | ||||
|      | ||||
|     if IsBound( gapdoc ) then | ||||
|  | ||||
|         if not IsBound( gapdoc.main ) then | ||||
|             gapdoc.main := pkg; | ||||
|         fi; | ||||
|  | ||||
|         # FIXME: the following may break if a package uses more than one book | ||||
|         if IsBound( package_info.PackageDoc ) and IsBound( package_info.PackageDoc[1].BookName ) then | ||||
|             gapdoc.bookname := package_info.PackageDoc[1].BookName; | ||||
|         elif not is_worksheet then | ||||
|             # Default: book name = package name | ||||
|             gapdoc.bookname := pkg; | ||||
|  | ||||
|             Print("\n"); | ||||
|             Print("WARNING: PackageInfo.g is missing a PackageDoc entry!\n"); | ||||
|             Print("Without this, your package manual will not be recognized by the GAP help system.\n"); | ||||
|             Print("You can correct this by adding the following to your PackageInfo.g:\n"); | ||||
|             Print("PackageDoc := rec(\n"); | ||||
|             Print("  BookName  := ~.PackageName,\n"); | ||||
|             #Print("  BookName  := \"", pkg, "\",\n"); | ||||
|             Print("  ArchiveURLSubset := [\"doc\"],\n"); | ||||
|             Print("  HTMLStart := \"doc/chap0.html\",\n"); | ||||
|             Print("  PDFFile   := \"doc/manual.pdf\",\n"); | ||||
|             Print("  SixFile   := \"doc/manual.six\",\n"); | ||||
|             Print("  LongTitle := ~.Subtitle,\n"); | ||||
|             Print("),\n"); | ||||
|             Print("\n"); | ||||
|         fi; | ||||
|  | ||||
|         if not IsBound( gapdoc.files ) then | ||||
|             gapdoc.files := []; | ||||
|         fi; | ||||
|  | ||||
|         if not IsBound( gapdoc.scan_dirs ) and not is_worksheet then | ||||
|             gapdoc.scan_dirs := [ "gap", "lib", "examples", "examples/doc" ]; | ||||
|         fi; | ||||
|          | ||||
|         if not is_worksheet then | ||||
|             Append( gapdoc.files, AUTODOC_FindMatchingFiles(pkg, gapdoc.scan_dirs, [ "g", "gi", "gd" ]) ); | ||||
|         fi; | ||||
|  | ||||
|         # Attempt to weed out duplicates as they may confuse GAPDoc (this | ||||
|         # won't work if there are any non-normalized paths in the list). | ||||
|         gapdoc.files := Set( gapdoc.files ); | ||||
|          | ||||
|         # Convert the file paths in gapdoc.files, which are relative to | ||||
|         # the package directory, to paths which are relative to the doc directory. | ||||
|         # For this, we assume that doc_dir_rel is normalized (e.g. | ||||
|         # it does not contains '//') and relative. | ||||
|         d := Number( Filename( doc_dir_rel, "" ), x -> x = '/' ); | ||||
|         d := Concatenation( ListWithIdenticalEntries(d, "../") ); | ||||
|         gapdoc.files := List( gapdoc.files, f -> Concatenation( d, f ) ); | ||||
|     fi; | ||||
|      | ||||
|      | ||||
|     # read tree | ||||
|     # FIXME: shouldn't tree be declared inside of an 'if IsBound(autodoc)' section? | ||||
|     tree := DocumentationTree( ); | ||||
|      | ||||
|     if IsBound( autodoc ) then | ||||
|         if IsBound( autodoc.section_intros ) then | ||||
|             AUTODOC_PROCESS_INTRO_STRINGS( autodoc.section_intros : Tree := tree ); | ||||
|         fi; | ||||
|      | ||||
|         AutoDocScanFiles( autodoc.files : PackageName := pkg, Tree := tree ); | ||||
|     fi; | ||||
|      | ||||
|     if is_worksheet then | ||||
|         # FIXME: We use scaffold and autodoc here without checking whether | ||||
|         # they are bound. Does that mean worksheets always use them? | ||||
|         if IsRecord( scaffold.TitlePage ) and IsBound( scaffold.TitlePage.Title ) then | ||||
|             pkg := scaffold.TitlePage.Title; | ||||
|  | ||||
|         elif IsBound( tree!.TitlePage.Title ) then | ||||
|             pkg := tree!.TitlePage.Title; | ||||
|  | ||||
|         elif IsBound( autodoc.files ) and Length( autodoc.files ) > 0  then | ||||
|             pkg := autodoc.files[ 1 ]; | ||||
|              | ||||
|             while Position( pkg, '/' ) <> fail do | ||||
|                 Remove( pkg, 1 ); | ||||
|             od; | ||||
|              | ||||
|             while Position( pkg, '.' ) <> fail do | ||||
|                 Remove( pkg, Length( pkg ) ); | ||||
|             od; | ||||
|  | ||||
|         else | ||||
|             Error( "could not figure out a title." ); | ||||
|         fi; | ||||
|          | ||||
|         if not IsString( pkg ) then | ||||
|             pkg := JoinStringsWithSeparator( pkg, " " ); | ||||
|         fi; | ||||
|          | ||||
|         gapdoc.main := ReplacedString( pkg, " ", "_" ); | ||||
|         gapdoc.bookname := ReplacedString( pkg, " ", "_" ); | ||||
|     fi; | ||||
|      | ||||
|     # | ||||
|     # Generate scaffold | ||||
|     # | ||||
|     gapdoc_latex_option_record := rec( ); | ||||
|      | ||||
|     if IsBound( scaffold ) then | ||||
|         ## Syntax is [ "class", [ "options" ] ] | ||||
|         if IsBound( scaffold.document_class ) then | ||||
|             position_document_class := PositionSublist( GAPDoc2LaTeXProcs.Head, "documentclass" ); | ||||
|              | ||||
|             if IsString( scaffold.document_class ) then | ||||
|                 scaffold.document_class := [ scaffold.document_class ]; | ||||
|             fi; | ||||
|              | ||||
|             if position_document_class = fail then | ||||
|                 Error( "something is wrong with the LaTeX header" ); | ||||
|             fi; | ||||
|              | ||||
|             GAPDoc2LaTeXProcs.Head := Concatenation( | ||||
|                   GAPDoc2LaTeXProcs.Head{[ 1 .. PositionSublist( GAPDoc2LaTeXProcs.Head, "{", position_document_class ) ]}, | ||||
|                   scaffold.document_class[ 1 ], | ||||
|                   GAPDoc2LaTeXProcs.Head{[ PositionSublist( GAPDoc2LaTeXProcs.Head, "}", position_document_class ) .. Length( GAPDoc2LaTeXProcs.Head ) ]} ); | ||||
|              | ||||
|             if Length( scaffold.document_class ) = 2 then | ||||
|                  | ||||
|                 GAPDoc2LaTeXProcs.Head := Concatenation( | ||||
|                       GAPDoc2LaTeXProcs.Head{[ 1 .. PositionSublist( GAPDoc2LaTeXProcs.Head, "[", position_document_class ) ]}, | ||||
|                       scaffold.document_class[ 2 ], | ||||
|                       GAPDoc2LaTeXProcs.Head{[ PositionSublist( GAPDoc2LaTeXProcs.Head, "]", position_document_class ) .. Length( GAPDoc2LaTeXProcs.Head ) ]} ); | ||||
|             fi; | ||||
|         fi; | ||||
|          | ||||
|         if IsBound( scaffold.latex_header_file ) then | ||||
|             GAPDoc2LaTeXProcs.Head := StringFile( scaffold.latex_header_file ); | ||||
|         fi; | ||||
|          | ||||
|         if IsBound( scaffold.gapdoc_latex_options ) then | ||||
|             if IsRecord( scaffold.gapdoc_latex_options ) then | ||||
|                 for i in RecNames( scaffold.gapdoc_latex_options ) do | ||||
|                     if not IsString( scaffold.gapdoc_latex_options.( i ) ) | ||||
|                        and IsList( scaffold.gapdoc_latex_options.( i ) ) | ||||
|                        and LowercaseString( scaffold.gapdoc_latex_options.( i )[ 1 ] ) = "file" then | ||||
|                         scaffold.gapdoc_latex_options.( i ) := StringFile( scaffold.gapdoc_latex_options.( i )[ 2 ] ); | ||||
|                     fi; | ||||
|                 od; | ||||
|                  | ||||
|                 gapdoc_latex_option_record := scaffold.gapdoc_latex_options; | ||||
|             fi; | ||||
|         fi; | ||||
|          | ||||
|         if not IsBound( scaffold.includes ) then | ||||
|             scaffold.includes := [ ]; | ||||
|         fi; | ||||
|  | ||||
|         if IsBound( autodoc ) then | ||||
|             # If scaffold.includes is already set, then we add | ||||
|             # AutoDocMainFile.xml to it, but *only* if it not already | ||||
|             # there. This way, package authors can control where | ||||
|             # it is put in their includes list. | ||||
|             if not "AutoDocMainFile.xml" in scaffold.includes then | ||||
|                 Add( scaffold.includes, "AutoDocMainFile.xml" ); | ||||
|             fi; | ||||
|         fi; | ||||
|  | ||||
|         if IsBound( scaffold.bib ) and IsBool( scaffold.bib ) then | ||||
|             if scaffold.bib = true then | ||||
|                 scaffold.bib := Concatenation( pkg, ".bib" ); | ||||
|             else | ||||
|                 Unbind( scaffold.bib ); | ||||
|             fi; | ||||
|         elif not IsBound( scaffold.bib ) then | ||||
|             # If there is a doc/PKG.bib file, assume that we want to reference it in the scaffold. | ||||
|             if IsReadableFile( Filename( doc_dir, Concatenation( pkg, ".bib" ) ) ) then | ||||
|                 scaffold.bib := Concatenation( pkg, ".bib" ); | ||||
|             fi; | ||||
|         fi; | ||||
|          | ||||
|         AUTODOC_WriteOnce( scaffold, "index", true ); | ||||
|  | ||||
|         if IsBound( gapdoc ) then | ||||
|             if AUTODOC_GetSuffix( gapdoc.main ) = "xml" then | ||||
|                 scaffold.main_xml_file := gapdoc.main; | ||||
|             else | ||||
|                 scaffold.main_xml_file := Concatenation( gapdoc.main, ".xml" ); | ||||
|             fi; | ||||
|         fi; | ||||
|  | ||||
|         # TODO: It should be possible to only rebuild the title page. (Perhaps also only the main page? but this is less important) | ||||
|         if IsBound( scaffold.TitlePage ) then | ||||
|             if IsRecord( scaffold.TitlePage ) then | ||||
|                 title_page := scaffold.TitlePage; | ||||
|             else | ||||
|                 title_page := rec( ); | ||||
|             fi; | ||||
|              | ||||
|             AUTODOC_WriteOnce( title_page, "dir", doc_dir ); | ||||
|             AUTODOC_APPEND_RECORD_WRITEONCE( title_page, tree!.TitlePage ); | ||||
|              | ||||
|             if not is_worksheet then | ||||
|                 AUTODOC_APPEND_RECORD_WRITEONCE( title_page, ExtractTitleInfoFromPackageInfo( pkg ) ); | ||||
|             fi; | ||||
|              | ||||
|             CreateTitlePage( title_page ); | ||||
|         fi; | ||||
|          | ||||
|         if IsBound( scaffold.MainPage ) and scaffold.MainPage <> false then | ||||
|             scaffold.dir := doc_dir; | ||||
|             scaffold.book_name := pkg; | ||||
|             CreateMainPage( scaffold ); | ||||
|         fi; | ||||
|     fi; | ||||
|      | ||||
|     # | ||||
|     # Run AutoDoc | ||||
|     # | ||||
|     if IsBound( autodoc ) then | ||||
|         WriteDocumentation( tree, doc_dir ); | ||||
|     fi; | ||||
|      | ||||
|      | ||||
|     # | ||||
|     # Run GAPDoc | ||||
|     # | ||||
|     if IsBound( gapdoc ) then | ||||
|  | ||||
|         # Ask GAPDoc to use UTF-8 as input encoding for LaTeX, as the XML files | ||||
|         # of the documentation are also in UTF-8 encoding, and may contain characters | ||||
|         # not contained in the default Latin 1 encoding. | ||||
|         SetGapDocLaTeXOptions( "utf8", gapdoc_latex_option_record ); | ||||
|  | ||||
|         MakeGAPDocDoc( doc_dir, gapdoc.main, gapdoc.files, gapdoc.bookname, "MathJax" ); | ||||
|  | ||||
|         CopyHTMLStyleFiles( Filename( doc_dir, "" ) ); | ||||
|  | ||||
|         # The following (undocumented) API is there for compatibility | ||||
|         # with old-style gapmacro.tex based package manuals. It | ||||
|         # produces a manual.lab file which those packages can use if | ||||
|         # they wish to link to things in the manual we are currently | ||||
|         # generating. This can probably be removed eventually, but for | ||||
|         # now, doing it does not hurt. | ||||
|          | ||||
|         # FIXME: It seems that this command does not work if pdflatex | ||||
|         #        is not present. Maybe we should remove it. | ||||
|          | ||||
|         if not is_worksheet then | ||||
|             GAPDocManualLab( pkg ); | ||||
|         fi; | ||||
|  | ||||
|     fi; | ||||
|      | ||||
|     if IsBound( maketest ) then | ||||
|          | ||||
|         AUTODOC_WriteOnce( maketest, "filename", "maketest.g" ); | ||||
|         AUTODOC_WriteOnce( maketest, "folder", pkg_dir ); | ||||
|         AUTODOC_WriteOnce( maketest, "scan_dir", doc_dir ); | ||||
|         AUTODOC_WriteOnce( maketest, "files_to_scan", gapdoc.files ); | ||||
|  | ||||
|         if IsString( maketest.folder ) then | ||||
|             maketest.folder := Directory( maketest.folder ); | ||||
|         fi; | ||||
|          | ||||
|         if IsString( maketest.scan_dir ) then | ||||
|             maketest.scan_dir := Directory( maketest.scan_dir ); | ||||
|         fi; | ||||
|          | ||||
|         AUTODOC_WriteOnce( maketest, "commands", [ ] ); | ||||
|         AUTODOC_WriteOnce( maketest, "book_name", gapdoc.main ); | ||||
|          | ||||
|         CreateMakeTest( maketest ); | ||||
|     fi; | ||||
|  | ||||
|     return true; | ||||
| end ); | ||||
							
								
								
									
										115
									
								
								samples/GAP/PackageInfo.g
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								samples/GAP/PackageInfo.g
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,115 @@ | ||||
| ############################################################################# | ||||
| ##   | ||||
| ##  PackageInfo.g for the package `cvec'                      Max Neunhoeffer | ||||
| ## | ||||
| ##  (created from Frank Lübeck's PackageInfo.g template file) | ||||
| ##   | ||||
|  | ||||
| SetPackageInfo( rec( | ||||
|  | ||||
| PackageName := "cvec", | ||||
| Subtitle := "Compact vectors over finite fields", | ||||
| Version := "2.5.1", | ||||
| Date := "04/04/2014", # dd/mm/yyyy format | ||||
|  | ||||
| ##  Information about authors and maintainers. | ||||
| Persons := [ | ||||
|   rec(  | ||||
|     LastName      := "Neunhoeffer", | ||||
|     FirstNames    := "Max", | ||||
|     IsAuthor      := true, | ||||
|     IsMaintainer  := false, | ||||
|     Email         := "neunhoef@mcs.st-and.ac.uk", | ||||
|     WWWHome       := "http://www-groups.mcs.st-and.ac.uk/~neunhoef/", | ||||
|     PostalAddress := Concatenation( [ | ||||
|                        "School of Mathematics and Statistics\n", | ||||
|                        "University of St Andrews\n", | ||||
|                        "Mathematical Institute\n", | ||||
|                        "North Haugh\n", | ||||
|                        "St Andrews, Fife KY16 9SS\n", | ||||
|                        "Scotland, UK" ] ), | ||||
|     Place         := "St Andrews", | ||||
|     Institution   := "University of St Andrews" | ||||
|   ), | ||||
| ], | ||||
|  | ||||
| ##  Status information. Currently the following cases are recognized: | ||||
| ##    "accepted"      for successfully refereed packages | ||||
| ##    "deposited"     for packages for which the GAP developers agreed  | ||||
| ##                    to distribute them with the core GAP system | ||||
| ##    "dev"           for development versions of packages  | ||||
| ##    "other"         for all other packages | ||||
| ## | ||||
| # Status := "accepted", | ||||
| Status := "deposited", | ||||
|  | ||||
| ##  You must provide the next two entries if and only if the status is  | ||||
| ##  "accepted" because is was successfully refereed: | ||||
| # format: 'name (place)' | ||||
| # CommunicatedBy := "Mike Atkinson (St. Andrews)", | ||||
| #CommunicatedBy := "", | ||||
| # format: mm/yyyy | ||||
| # AcceptDate := "08/1999", | ||||
| #AcceptDate := "", | ||||
|  | ||||
| PackageWWWHome := "http://neunhoef.github.io/cvec/", | ||||
| README_URL     := Concatenation(~.PackageWWWHome, "README"), | ||||
| PackageInfoURL := Concatenation(~.PackageWWWHome, "PackageInfo.g"), | ||||
| ArchiveURL     := Concatenation("https://github.com/neunhoef/cvec/", | ||||
|                                 "releases/download/v", ~.Version, | ||||
|                                 "/cvec-", ~.Version), | ||||
| ArchiveFormats := ".tar.gz .tar.bz2", | ||||
|  | ||||
| ##  Here you  must provide a short abstract explaining the package content  | ||||
| ##  in HTML format (used on the package overview Web page) and an URL  | ||||
| ##  for a Webpage with more detailed information about the package | ||||
| ##  (not more than a few lines, less is ok): | ||||
| ##  Please, use '<span class="pkgname">GAP</span>' and | ||||
| ##  '<span class="pkgname">MyPKG</span>' for specifing package names. | ||||
| ##   | ||||
| AbstractHTML :=  | ||||
|   "This package provides an implementation of compact vectors over finite\ | ||||
|    fields. Contrary to earlier implementations no table lookups are used\ | ||||
|    but only word-based processor arithmetic. This allows for bigger finite\ | ||||
|    fields and higher speed.", | ||||
|  | ||||
| PackageDoc := rec( | ||||
|   BookName  := "cvec", | ||||
|   ArchiveURLSubset := ["doc"], | ||||
|   HTMLStart := "doc/chap0.html", | ||||
|   PDFFile   := "doc/manual.pdf", | ||||
|   SixFile   := "doc/manual.six", | ||||
|   LongTitle := "Compact vectors over finite fields", | ||||
| ), | ||||
|  | ||||
| Dependencies := rec( | ||||
|   GAP := ">=4.5.5", | ||||
|   NeededOtherPackages := [ | ||||
|     ["GAPDoc", ">= 1.2"], | ||||
|     ["IO", ">= 4.1"], | ||||
|     ["orb", ">= 4.2"], | ||||
|   ], | ||||
|   SuggestedOtherPackages := [], | ||||
|   ExternalConditions := [] | ||||
| ), | ||||
|  | ||||
| AvailabilityTest := function() | ||||
|   if not "cvec" in SHOW_STAT() and | ||||
|      Filename(DirectoriesPackagePrograms("cvec"), "cvec.so") = fail then | ||||
|     #Info(InfoWarning, 1, "cvec: kernel cvec functions not available."); | ||||
|     return fail; | ||||
|   fi; | ||||
|   return true; | ||||
| end, | ||||
|  | ||||
| ##  *Optional*, but recommended: path relative to package root to a file which  | ||||
| ##  contains as many tests of the package functionality as sensible. | ||||
| #TestFile := "tst/testall.g", | ||||
|  | ||||
| ##  *Optional*: Here you can list some keyword related to the topic  | ||||
| ##  of the package. | ||||
| Keywords := [] | ||||
|  | ||||
| )); | ||||
|  | ||||
|  | ||||
							
								
								
									
										23
									
								
								samples/GAP/example.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								samples/GAP/example.gd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| ############################################################################# | ||||
| ## | ||||
| #W  example.gd | ||||
| ## | ||||
| ##  This file contains a sample of a GAP declaration file. | ||||
| ## | ||||
| DeclareProperty( "SomeProperty", IsLeftModule ); | ||||
| DeclareGlobalFunction( "SomeGlobalFunction" ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #C  IsQuuxFrobnicator(<R>) | ||||
| ## | ||||
| ##  <ManSection> | ||||
| ##  <Filt Name="IsQuuxFrobnicator" Arg='R' Type='Category'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  Tests whether R is a quux frobnicator. | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ## | ||||
| DeclareSynonym( "IsQuuxFrobnicator", IsField and IsGroup ); | ||||
							
								
								
									
										64
									
								
								samples/GAP/example.gi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								samples/GAP/example.gi
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| ############################################################################# | ||||
| ## | ||||
| #W  example.gd | ||||
| ## | ||||
| ##  This file contains a sample of a GAP implementation file. | ||||
| ## | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  SomeOperation( <val> ) | ||||
| ## | ||||
| ##  performs some operation on <val> | ||||
| ## | ||||
| InstallMethod( SomeProperty, | ||||
|     "for left modules", | ||||
|     [ IsLeftModule ], 0, | ||||
|     function( M ) | ||||
|     if IsFreeLeftModule( M ) and not IsTrivial( M ) then | ||||
|       return true; | ||||
|     fi; | ||||
|     TryNextMethod(); | ||||
|     end ); | ||||
|  | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #F  SomeGlobalFunction( ) | ||||
| ## | ||||
| ##  A global variadic funfion. | ||||
| ## | ||||
| InstallGlobalFunction( SomeGlobalFunction, function( arg ) | ||||
|     if Length( arg ) = 3 then | ||||
|       return arg[1] + arg[2] * arg[3]; | ||||
|     elif Length( arg ) = 2 then | ||||
|       return arg[1] - arg[2] | ||||
|     else | ||||
|       Error( "usage: SomeGlobalFunction( <x>, <y>[, <z>] )" ); | ||||
|     fi; | ||||
|     end ); | ||||
|  | ||||
|  | ||||
| # | ||||
| # A plain function. | ||||
| # | ||||
| SomeFunc := function(x, y) | ||||
|     local z, func, tmp, j; | ||||
|     z := x * 1.0; | ||||
|     y := 17^17 - y; | ||||
|     func := a -> a mod 5; | ||||
|     tmp := List( [1..50], func ); | ||||
|     while y > 0 do | ||||
|         for j in tmp do | ||||
|             Print(j, "\n"); | ||||
|         od; | ||||
|         repeat | ||||
|             y := y - 1; | ||||
|         until 0 < 1; | ||||
|         y := y -1; | ||||
|     od; | ||||
|     return z; | ||||
| end; | ||||
|          | ||||
							
								
								
									
										822
									
								
								samples/GAP/vspc.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										822
									
								
								samples/GAP/vspc.gd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,822 @@ | ||||
| ############################################################################# | ||||
| ## | ||||
| #W  vspc.gd                     GAP library                     Thomas Breuer | ||||
| ## | ||||
| ## | ||||
| #Y  Copyright (C)  1997,  Lehrstuhl D für Mathematik,  RWTH Aachen,  Germany | ||||
| #Y  (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland | ||||
| #Y  Copyright (C) 2002 The GAP Group | ||||
| ## | ||||
| ##  This file declares the operations for vector spaces. | ||||
| ## | ||||
| ##  The operations for bases of free left modules can be found in the file | ||||
| ##  <F>lib/basis.gd<F>. | ||||
| ## | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #C  IsLeftOperatorRing(<R>) | ||||
| ## | ||||
| ##  <ManSection> | ||||
| ##  <Filt Name="IsLeftOperatorRing" Arg='R' Type='Category'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ## | ||||
| DeclareSynonym( "IsLeftOperatorRing", | ||||
|     IsLeftOperatorAdditiveGroup and IsRing and IsAssociativeLOpDProd ); | ||||
| #T really? | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #C  IsLeftOperatorRingWithOne(<R>) | ||||
| ## | ||||
| ##  <ManSection> | ||||
| ##  <Filt Name="IsLeftOperatorRingWithOne" Arg='R' Type='Category'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ## | ||||
| DeclareSynonym( "IsLeftOperatorRingWithOne", | ||||
|     IsLeftOperatorAdditiveGroup and IsRingWithOne | ||||
|     and IsAssociativeLOpDProd ); | ||||
| #T really? | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #C  IsLeftVectorSpace( <V> ) | ||||
| #C  IsVectorSpace( <V> ) | ||||
| ## | ||||
| ##  <#GAPDoc Label="IsLeftVectorSpace"> | ||||
| ##  <ManSection> | ||||
| ##  <Filt Name="IsLeftVectorSpace" Arg='V' Type='Category'/> | ||||
| ##  <Filt Name="IsVectorSpace" Arg='V' Type='Category'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  A <E>vector space</E> in &GAP; is a free left module | ||||
| ##  (see <Ref Func="IsFreeLeftModule"/>) over a division ring | ||||
| ##  (see Chapter <Ref Chap="Fields and Division Rings"/>). | ||||
| ##  <P/> | ||||
| ##  Whenever we talk about an <M>F</M>-vector space <A>V</A> then <A>V</A> is | ||||
| ##  an additive group (see <Ref Func="IsAdditiveGroup"/>) on which the | ||||
| ##  division ring <M>F</M> acts via multiplication from the left such that | ||||
| ##  this action and the addition in <A>V</A> are left and right distributive. | ||||
| ##  The division ring <M>F</M> can be accessed as value of the attribute | ||||
| ##  <Ref Func="LeftActingDomain"/>. | ||||
| ##  <P/> | ||||
| ##  Vector spaces in &GAP; are always <E>left</E> vector spaces, | ||||
| ##  <Ref Filt="IsLeftVectorSpace"/> and <Ref Filt="IsVectorSpace"/> are | ||||
| ##  synonyms. | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ##  <#/GAPDoc> | ||||
| ## | ||||
| DeclareSynonym( "IsLeftVectorSpace", | ||||
|     IsLeftModule and IsLeftActedOnByDivisionRing ); | ||||
|  | ||||
| DeclareSynonym( "IsVectorSpace", IsLeftVectorSpace ); | ||||
|  | ||||
| InstallTrueMethod( IsFreeLeftModule, | ||||
|     IsLeftModule and IsLeftActedOnByDivisionRing ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #F  IsGaussianSpace( <V> ) | ||||
| ## | ||||
| ##  <#GAPDoc Label="IsGaussianSpace"> | ||||
| ##  <ManSection> | ||||
| ##  <Func Name="IsGaussianSpace" Arg='V'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  The filter <Ref Filt="IsGaussianSpace"/> (see <Ref Sect="Filters"/>) | ||||
| ##  for the row space (see <Ref Func="IsRowSpace"/>) | ||||
| ##  or matrix space (see <Ref Func="IsMatrixSpace"/>) <A>V</A> | ||||
| ##  over the field <M>F</M>, say, | ||||
| ##  indicates that the entries of all row vectors or matrices in <A>V</A>, | ||||
| ##  respectively, are all contained in <M>F</M>. | ||||
| ##  In this case, <A>V</A> is called a <E>Gaussian</E> vector space. | ||||
| ##  Bases for Gaussian spaces can be computed using Gaussian elimination for | ||||
| ##  a given list of vector space generators. | ||||
| ##  <Example><![CDATA[ | ||||
| ##  gap> mats:= [ [[1,1],[2,2]], [[3,4],[0,1]] ];; | ||||
| ##  gap> V:= VectorSpace( Rationals, mats );; | ||||
| ##  gap> IsGaussianSpace( V ); | ||||
| ##  true | ||||
| ##  gap> mats[1][1][1]:= E(4);;   # an element in an extension field | ||||
| ##  gap> V:= VectorSpace( Rationals, mats );; | ||||
| ##  gap> IsGaussianSpace( V ); | ||||
| ##  false | ||||
| ##  gap> V:= VectorSpace( Field( Rationals, [ E(4) ] ), mats );; | ||||
| ##  gap> IsGaussianSpace( V ); | ||||
| ##  true | ||||
| ##  ]]></Example> | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ##  <#/GAPDoc> | ||||
| ## | ||||
| DeclareFilter( "IsGaussianSpace", IsVectorSpace ); | ||||
|  | ||||
| InstallTrueMethod( IsGaussianSpace, | ||||
|     IsVectorSpace and IsFullMatrixModule ); | ||||
|  | ||||
| InstallTrueMethod( IsGaussianSpace, | ||||
|     IsVectorSpace and IsFullRowModule ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #C  IsDivisionRing( <D> ) | ||||
| ## | ||||
| ##  <#GAPDoc Label="IsDivisionRing"> | ||||
| ##  <ManSection> | ||||
| ##  <Filt Name="IsDivisionRing" Arg='D' Type='Category'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  A <E>division ring</E> in &GAP; is a nontrivial associative algebra | ||||
| ##  <A>D</A> with a multiplicative inverse for each nonzero element. | ||||
| ##  In &GAP; every division ring is a vector space over a division ring | ||||
| ##  (possibly over itself). | ||||
| ##  Note that being a division ring is thus not a property that a ring can | ||||
| ##  get, because a ring is usually not represented as a vector space. | ||||
| ##  <P/> | ||||
| ##  The field of coefficients is stored as the value of the attribute | ||||
| ##  <Ref Func="LeftActingDomain"/> of <A>D</A>. | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ##  <#/GAPDoc> | ||||
| ## | ||||
| DeclareSynonymAttr( "IsDivisionRing", | ||||
|         IsMagmaWithInversesIfNonzero | ||||
|     and IsLeftOperatorRingWithOne | ||||
|     and IsLeftVectorSpace | ||||
|     and IsNonTrivial | ||||
|     and IsAssociative | ||||
|     and IsEuclideanRing ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #A  GeneratorsOfLeftVectorSpace( <V> ) | ||||
| #A  GeneratorsOfVectorSpace( <V> ) | ||||
| ## | ||||
| ##  <#GAPDoc Label="GeneratorsOfLeftVectorSpace"> | ||||
| ##  <ManSection> | ||||
| ##  <Attr Name="GeneratorsOfLeftVectorSpace" Arg='V'/> | ||||
| ##  <Attr Name="GeneratorsOfVectorSpace" Arg='V'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  For an <M>F</M>-vector space <A>V</A>, | ||||
| ##  <Ref Attr="GeneratorsOfLeftVectorSpace"/> returns a list of vectors in | ||||
| ##  <A>V</A> that generate <A>V</A> as an <M>F</M>-vector space. | ||||
| ##  <Example><![CDATA[ | ||||
| ##  gap> GeneratorsOfVectorSpace( FullRowSpace( Rationals, 3 ) ); | ||||
| ##  [ [ 1, 0, 0 ], [ 0, 1, 0 ], [ 0, 0, 1 ] ] | ||||
| ##  ]]></Example> | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ##  <#/GAPDoc> | ||||
| ## | ||||
| DeclareSynonymAttr( "GeneratorsOfLeftVectorSpace", | ||||
|     GeneratorsOfLeftOperatorAdditiveGroup ); | ||||
|  | ||||
| DeclareSynonymAttr( "GeneratorsOfVectorSpace", | ||||
|     GeneratorsOfLeftOperatorAdditiveGroup ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #A  CanonicalBasis( <V> ) | ||||
| ## | ||||
| ##  <#GAPDoc Label="CanonicalBasis"> | ||||
| ##  <ManSection> | ||||
| ##  <Attr Name="CanonicalBasis" Arg='V'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  If the vector space <A>V</A> supports a <E>canonical basis</E> then | ||||
| ##  <Ref Attr="CanonicalBasis"/> returns this basis, | ||||
| ##  otherwise <K>fail</K> is returned. | ||||
| ##  <P/> | ||||
| ##  The defining property of a canonical basis is that its vectors are | ||||
| ##  uniquely determined by the vector space. | ||||
| ##  If canonical bases exist for two vector spaces over the same left acting | ||||
| ##  domain (see <Ref Func="LeftActingDomain"/>) then the equality of | ||||
| ##  these vector spaces can be decided by comparing the canonical bases. | ||||
| ##  <P/> | ||||
| ##  The exact meaning of a canonical basis depends on the type of <A>V</A>. | ||||
| ##  Canonical bases are defined for example for Gaussian row and matrix | ||||
| ##  spaces (see <Ref Sect="Row and Matrix Spaces"/>). | ||||
| ##  <P/> | ||||
| ##  If one designs a new kind of vector spaces | ||||
| ##  (see <Ref Sect="How to Implement New Kinds of Vector Spaces"/>) and | ||||
| ##  defines a canonical basis for these spaces then the | ||||
| ##  <Ref Attr="CanonicalBasis"/> method one installs | ||||
| ##  (see <Ref Func="InstallMethod"/>) | ||||
| ##  must <E>not</E> call <Ref Func="Basis"/>. | ||||
| ##  On the other hand, one probably should install a <Ref Func="Basis"/> | ||||
| ##  method that simply calls <Ref Attr="CanonicalBasis"/>, | ||||
| ##  the value of the method | ||||
| ##  (see <Ref Sect="Method Installation"/> and | ||||
| ##  <Ref Sect="Applicable Methods and Method Selection"/>) | ||||
| ##  being <C>CANONICAL_BASIS_FLAGS</C>. | ||||
| ##  <Example><![CDATA[ | ||||
| ##  gap> vecs:= [ [ 1, 2, 3 ], [ 1, 1, 1 ], [ 1, 1, 1 ] ];; | ||||
| ##  gap> V:= VectorSpace( Rationals, vecs );; | ||||
| ##  gap> B:= CanonicalBasis( V ); | ||||
| ##  CanonicalBasis( <vector space over Rationals, with 3 generators> ) | ||||
| ##  gap> BasisVectors( B ); | ||||
| ##  [ [ 1, 0, -1 ], [ 0, 1, 2 ] ] | ||||
| ##  ]]></Example> | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ##  <#/GAPDoc> | ||||
| ## | ||||
| DeclareAttribute( "CanonicalBasis", IsFreeLeftModule ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #F  IsRowSpace( <V> ) | ||||
| ## | ||||
| ##  <#GAPDoc Label="IsRowSpace"> | ||||
| ##  <ManSection> | ||||
| ##  <Func Name="IsRowSpace" Arg='V'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  A <E>row space</E> in &GAP; is a vector space that consists of | ||||
| ##  row vectors (see Chapter <Ref Chap="Row Vectors"/>). | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ##  <#/GAPDoc> | ||||
| ## | ||||
| DeclareSynonym( "IsRowSpace", IsRowModule and IsVectorSpace ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #F  IsGaussianRowSpace( <V> ) | ||||
| ## | ||||
| ##  <ManSection> | ||||
| ##  <Func Name="IsGaussianRowSpace" Arg='V'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  A row space is <E>Gaussian</E> if the left acting domain contains all | ||||
| ##  scalars that occur in the vectors. | ||||
| ##  Thus one can use Gaussian elimination in the calculations. | ||||
| ##  <P/> | ||||
| ##  (Otherwise the space is non-Gaussian. | ||||
| ##  We will need a flag for this to write down methods that delegate from | ||||
| ##  non-Gaussian spaces to Gaussian ones.) | ||||
| ##  <!-- reformulate this when it becomes documented --> | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ## | ||||
| DeclareSynonym( "IsGaussianRowSpace", IsGaussianSpace and IsRowSpace ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #F  IsNonGaussianRowSpace( <V> ) | ||||
| ## | ||||
| ##  <ManSection> | ||||
| ##  <Func Name="IsNonGaussianRowSpace" Arg='V'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  If an <M>F</M>-vector space <A>V</A> is in the filter | ||||
| ##  <Ref Func="IsNonGaussianRowSpace"/> then this expresses that <A>V</A> | ||||
| ##  consists of row vectors (see <Ref Func="IsRowVector"/>) such | ||||
| ##  that not all entries in these row vectors are contained in <M>F</M> | ||||
| ##  (so Gaussian elimination cannot be used to compute an <M>F</M>-basis | ||||
| ##  from a list of vector space generators), | ||||
| ##  and that <A>V</A> is handled via the mechanism of nice bases | ||||
| ##  (see <Ref ???="..."/>) in the following way. | ||||
| ##  Let <M>K</M> be the field spanned by the entries of all vectors in | ||||
| ##  <A>V</A>. | ||||
| ##  Then the <Ref Attr="NiceFreeLeftModuleInfo"/> value of <A>V</A> is | ||||
| ##  a basis <M>B</M> of the field extension <M>K / ( K \cap F )</M>, | ||||
| ##  and the <Ref Func="NiceVector"/> value of <M>v \in <A>V</A></M> | ||||
| ##  is defined by replacing each entry of <M>v</M> by the list of its | ||||
| ##  <M>B</M>-coefficients, and then forming the concatenation. | ||||
| ##  <P/> | ||||
| ##  So the associated nice vector space is a Gaussian row space | ||||
| ##  (see <Ref Func="IsGaussianRowSpace"/>). | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ## | ||||
| DeclareHandlingByNiceBasis( "IsNonGaussianRowSpace", | ||||
|     "for non-Gaussian row spaces" ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #F  IsMatrixSpace( <V> ) | ||||
| ## | ||||
| ##  <#GAPDoc Label="IsMatrixSpace"> | ||||
| ##  <ManSection> | ||||
| ##  <Func Name="IsMatrixSpace" Arg='V'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  A <E>matrix space</E> in &GAP; is a vector space that consists of matrices | ||||
| ##  (see Chapter <Ref Chap="Matrices"/>). | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ##  <#/GAPDoc> | ||||
| ## | ||||
| DeclareSynonym( "IsMatrixSpace", IsMatrixModule and IsVectorSpace ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #F  IsGaussianMatrixSpace( <V> ) | ||||
| ## | ||||
| ##  <ManSection> | ||||
| ##  <Func Name="IsGaussianMatrixSpace" Arg='V'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  A matrix space is Gaussian if the left acting domain contains all | ||||
| ##  scalars that occur in the vectors. | ||||
| ##  Thus one can use Gaussian elimination in the calculations. | ||||
| ##  <P/> | ||||
| ##  (Otherwise the space is non-Gaussian. | ||||
| ##  We will need a flag for this to write down methods that delegate from | ||||
| ##  non-Gaussian spaces to Gaussian ones.) | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ## | ||||
| DeclareSynonym( "IsGaussianMatrixSpace", IsGaussianSpace and IsMatrixSpace ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #F  IsNonGaussianMatrixSpace( <V> ) | ||||
| ## | ||||
| ##  <ManSection> | ||||
| ##  <Func Name="IsNonGaussianMatrixSpace" Arg='V'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  If an <M>F</M>-vector space <A>V</A> is in the filter | ||||
| ##  <Ref Func="IsNonGaussianMatrixSpace"/> | ||||
| ##  then this expresses that <A>V</A> consists of matrices | ||||
| ##  (see <Ref Func="IsMatrix"/>) | ||||
| ##  such that not all entries in these matrices are contained in <M>F</M> | ||||
| ##  (so Gaussian elimination cannot be used to compute an <M>F</M>-basis | ||||
| ##  from a list of vector space generators), | ||||
| ##  and that <A>V</A> is handled via the mechanism of nice bases | ||||
| ##  (see <Ref ???="..."/>) in the following way. | ||||
| ##  Let <M>K</M> be the field spanned by the entries of all vectors in <A>V</A>. | ||||
| ##  The <Ref Attr="NiceFreeLeftModuleInfo"/> value of <A>V</A> is irrelevant, | ||||
| ##  and the <Ref Func="NiceVector"/> value of <M>v \in <A>V</A></M> | ||||
| ##  is defined as the concatenation of the rows of <M>v</M>. | ||||
| ##  <P/> | ||||
| ##  So the associated nice vector space is a (not necessarily Gaussian) | ||||
| ##  row space (see <Ref Func="IsRowSpace"/>). | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ## | ||||
| DeclareHandlingByNiceBasis( "IsNonGaussianMatrixSpace", | ||||
|     "for non-Gaussian matrix spaces" ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #A  NormedRowVectors( <V> ) . . .  normed vectors in a Gaussian row space <V> | ||||
| ## | ||||
| ##  <#GAPDoc Label="NormedRowVectors"> | ||||
| ##  <ManSection> | ||||
| ##  <Attr Name="NormedRowVectors" Arg='V'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  For a finite Gaussian row space <A>V</A> | ||||
| ##  (see <Ref Func="IsRowSpace"/>, <Ref Func="IsGaussianSpace"/>), | ||||
| ##  <Ref Attr="NormedRowVectors"/> returns a list of those nonzero | ||||
| ##  vectors in <A>V</A> that have a one in the first nonzero component. | ||||
| ##  <P/> | ||||
| ##  The result list can be used as action domain for the action of a matrix | ||||
| ##  group via <Ref Func="OnLines"/>, which yields the natural action on | ||||
| ##  one-dimensional subspaces of <A>V</A> | ||||
| ##  (see also <Ref Func="Subspaces"/>). | ||||
| ##  <Example><![CDATA[ | ||||
| ##  gap> vecs:= NormedRowVectors( GF(3)^2 ); | ||||
| ##  [ [ 0*Z(3), Z(3)^0 ], [ Z(3)^0, 0*Z(3) ], [ Z(3)^0, Z(3)^0 ],  | ||||
| ##    [ Z(3)^0, Z(3) ] ] | ||||
| ##  gap> Action( GL(2,3), vecs, OnLines ); | ||||
| ##  Group([ (3,4), (1,2,4) ]) | ||||
| ##  ]]></Example> | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ##  <#/GAPDoc> | ||||
| ## | ||||
| DeclareAttribute( "NormedRowVectors", IsGaussianSpace ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #A  TrivialSubspace( <V> ) | ||||
| ## | ||||
| ##  <#GAPDoc Label="TrivialSubspace"> | ||||
| ##  <ManSection> | ||||
| ##  <Attr Name="TrivialSubspace" Arg='V'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  For a vector space <A>V</A>, <Ref Attr="TrivialSubspace"/> returns the | ||||
| ##  subspace of <A>V</A> that consists of the zero vector in <A>V</A>. | ||||
| ##  <Example><![CDATA[ | ||||
| ##  gap> V:= GF(3)^3;; | ||||
| ##  gap> triv:= TrivialSubspace( V ); | ||||
| ##  <vector space over GF(3), with 0 generators> | ||||
| ##  gap> AsSet( triv ); | ||||
| ##  [ [ 0*Z(3), 0*Z(3), 0*Z(3) ] ] | ||||
| ##  ]]></Example> | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ##  <#/GAPDoc> | ||||
| ## | ||||
| DeclareSynonymAttr( "TrivialSubspace", TrivialSubmodule ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #F  VectorSpace( <F>, <gens>[, <zero>][, "basis"] ) | ||||
| ## | ||||
| ##  <#GAPDoc Label="VectorSpace"> | ||||
| ##  <ManSection> | ||||
| ##  <Func Name="VectorSpace" Arg='F, gens[, zero][, "basis"]'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  For a field <A>F</A> and a collection <A>gens</A> of vectors, | ||||
| ##  <Ref Func="VectorSpace"/> returns the <A>F</A>-vector space spanned by | ||||
| ##  the elements in <A>gens</A>. | ||||
| ##  <P/> | ||||
| ##  The optional argument <A>zero</A> can be used to specify the zero element | ||||
| ##  of the space; <A>zero</A> <E>must</E> be given if <A>gens</A> is empty. | ||||
| ##  The optional string <C>"basis"</C> indicates that <A>gens</A> is known to | ||||
| ##  be linearly independent over <A>F</A>, in particular the dimension of the | ||||
| ##  vector space is immediately set; | ||||
| ##  note that <Ref Func="Basis"/> need <E>not</E> return the basis formed by | ||||
| ##  <A>gens</A> if the string <C>"basis"</C> is given as an argument. | ||||
| ##  <!-- crossref. to <C>FreeLeftModule</C> as soon as the modules chapter | ||||
| ##       is reliable!--> | ||||
| ##  <Example><![CDATA[ | ||||
| ##  gap> V:= VectorSpace( Rationals, [ [ 1, 2, 3 ], [ 1, 1, 1 ] ] ); | ||||
| ##  <vector space over Rationals, with 2 generators> | ||||
| ##  ]]></Example> | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ##  <#/GAPDoc> | ||||
| ## | ||||
| DeclareGlobalFunction( "VectorSpace" ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #F  Subspace( <V>, <gens>[, "basis"] )  . subspace of <V> generated by <gens> | ||||
| #F  SubspaceNC( <V>, <gens>[, "basis"] ) | ||||
| ## | ||||
| ##  <#GAPDoc Label="Subspace"> | ||||
| ##  <ManSection> | ||||
| ##  <Func Name="Subspace" Arg='V, gens[, "basis"]'/> | ||||
| ##  <Func Name="SubspaceNC" Arg='V, gens[, "basis"]'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  For an <M>F</M>-vector space <A>V</A> and a list or collection | ||||
| ##  <A>gens</A> that is a subset of <A>V</A>, | ||||
| ##  <Ref Func="Subspace"/> returns the <M>F</M>-vector space spanned by | ||||
| ##  <A>gens</A>; if <A>gens</A> is empty then the trivial subspace | ||||
| ##  (see <Ref Func="TrivialSubspace"/>) of <A>V</A> is returned. | ||||
| ##  The parent (see <Ref Sect="Parents"/>) of the returned vector space | ||||
| ##  is set to <A>V</A>. | ||||
| ##  <P/> | ||||
| ##  <Ref Func="SubspaceNC"/> does the same as <Ref Func="Subspace"/>, | ||||
| ##  except that it omits the check whether <A>gens</A> is a subset of | ||||
| ##  <A>V</A>. | ||||
| ##  <P/> | ||||
| ##  The optional string <A>"basis"</A> indicates that <A>gens</A> is known to | ||||
| ##  be linearly independent over <M>F</M>. | ||||
| ##  In this case the dimension of the subspace is immediately set, | ||||
| ##  and both <Ref Func="Subspace"/> and <Ref Func="SubspaceNC"/> do | ||||
| ##  <E>not</E> check whether <A>gens</A> really is linearly independent and | ||||
| ##  whether <A>gens</A> is a subset of <A>V</A>. | ||||
| ##  <!-- crossref. to <C>Submodule</C> as soon as the modules chapter | ||||
| ##       is reliable!--> | ||||
| ##  <Example><![CDATA[ | ||||
| ##  gap> V:= VectorSpace( Rationals, [ [ 1, 2, 3 ], [ 1, 1, 1 ] ] );; | ||||
| ##  gap> W:= Subspace( V, [ [ 0, 1, 2 ] ] ); | ||||
| ##  <vector space over Rationals, with 1 generators> | ||||
| ##  ]]></Example> | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ##  <#/GAPDoc> | ||||
| ## | ||||
| DeclareSynonym( "Subspace", Submodule ); | ||||
|  | ||||
| DeclareSynonym( "SubspaceNC", SubmoduleNC ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #O  AsVectorSpace( <F>, <D> ) . . . . . . . . .  view <D> as <F>-vector space | ||||
| ## | ||||
| ##  <#GAPDoc Label="AsVectorSpace"> | ||||
| ##  <ManSection> | ||||
| ##  <Oper Name="AsVectorSpace" Arg='F, D'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  Let <A>F</A> be a division ring and <A>D</A> a domain. | ||||
| ##  If the elements in <A>D</A> form an <A>F</A>-vector space then | ||||
| ##  <Ref Oper="AsVectorSpace"/> returns this <A>F</A>-vector space, | ||||
| ##  otherwise <K>fail</K> is returned. | ||||
| ##  <P/> | ||||
| ##  <Ref Oper="AsVectorSpace"/> can be used for example to view a given | ||||
| ##  vector space as a vector space over a smaller or larger division ring. | ||||
| ##  <Example><![CDATA[ | ||||
| ##  gap> V:= FullRowSpace( GF( 27 ), 3 ); | ||||
| ##  ( GF(3^3)^3 ) | ||||
| ##  gap> Dimension( V );  LeftActingDomain( V ); | ||||
| ##  3 | ||||
| ##  GF(3^3) | ||||
| ##  gap> W:= AsVectorSpace( GF( 3 ), V ); | ||||
| ##  <vector space over GF(3), with 9 generators> | ||||
| ##  gap> Dimension( W );  LeftActingDomain( W ); | ||||
| ##  9 | ||||
| ##  GF(3) | ||||
| ##  gap> AsVectorSpace( GF( 9 ), V ); | ||||
| ##  fail | ||||
| ##  ]]></Example> | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ##  <#/GAPDoc> | ||||
| ## | ||||
| DeclareSynonym( "AsVectorSpace", AsLeftModule ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #O  AsSubspace( <V>, <U> )  . . . . . . . . . . . view <U> as subspace of <V> | ||||
| ## | ||||
| ##  <#GAPDoc Label="AsSubspace"> | ||||
| ##  <ManSection> | ||||
| ##  <Oper Name="AsSubspace" Arg='V, U'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  Let <A>V</A> be an <M>F</M>-vector space, and <A>U</A> a collection. | ||||
| ##  If <A>U</A> is a subset of <A>V</A> such that the elements of <A>U</A> | ||||
| ##  form an <M>F</M>-vector space then <Ref Oper="AsSubspace"/> returns this | ||||
| ##  vector space, with parent set to <A>V</A> | ||||
| ##  (see <Ref Func="AsVectorSpace"/>). | ||||
| ##  Otherwise <K>fail</K> is returned. | ||||
| ##  <Example><![CDATA[ | ||||
| ##  gap> V:= VectorSpace( Rationals, [ [ 1, 2, 3 ], [ 1, 1, 1 ] ] );; | ||||
| ##  gap> W:= VectorSpace( Rationals, [ [ 1/2, 1/2, 1/2 ] ] );; | ||||
| ##  gap> U:= AsSubspace( V, W ); | ||||
| ##  <vector space over Rationals, with 1 generators> | ||||
| ##  gap> Parent( U ) = V; | ||||
| ##  true | ||||
| ##  gap> AsSubspace( V, [ [ 1, 1, 1 ] ] ); | ||||
| ##  fail | ||||
| ##  ]]></Example> | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ##  <#/GAPDoc> | ||||
| ## | ||||
| DeclareOperation( "AsSubspace", [ IsVectorSpace, IsCollection ] ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #F  Intersection2Spaces( <AsStruct>, <Substruct>, <Struct> ) | ||||
| ## | ||||
| ##  <ManSection> | ||||
| ##  <Func Name="Intersection2Spaces" Arg='AsStruct, Substruct, Struct'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  is a function that takes two arguments <A>V</A> and <A>W</A> which must | ||||
| ##  be finite dimensional vector spaces, | ||||
| ##  and returns the intersection of <A>V</A> and <A>W</A>. | ||||
| ##  <P/> | ||||
| ##  If the left acting domains are different then let <M>F</M> be their | ||||
| ##  intersection. | ||||
| ##  The intersection of <A>V</A> and <A>W</A> is computed as intersection of | ||||
| ##  <C><A>AsStruct</A>( <A>F</A>, <A>V</A> )</C> and | ||||
| ##  <C><A>AsStruct</A>( <A>F</A>, <A>V</A> )</C>. | ||||
| ##  <P/> | ||||
| ##  If the left acting domains are equal to <M>F</M> then the intersection of | ||||
| ##  <A>V</A> and <A>W</A> is returned either as <M>F</M>-<A>Substruct</A> | ||||
| ##  with the common parent of <A>V</A> and <A>W</A> or as | ||||
| ##  <M>F</M>-<A>Struct</A>, in both cases with known basis. | ||||
| ##  <P/> | ||||
| ##  This function is used to handle the intersections of two vector spaces, | ||||
| ##  two algebras, two algebras-with-one, two left ideals, two right ideals, | ||||
| ##  two two-sided ideals. | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ## | ||||
| DeclareGlobalFunction( "Intersection2Spaces" ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #F  FullRowSpace( <F>, <n> ) | ||||
| ## | ||||
| ##  <#GAPDoc Label="FullRowSpace"> | ||||
| ##  <ManSection> | ||||
| ##  <Func Name="FullRowSpace" Arg='F, n'/> | ||||
| ##  <Meth Name="\^" Arg='F, n' Label="for a field and an integer"/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  For a field <A>F</A> and a nonnegative integer <A>n</A>, | ||||
| ##  <Ref Func="FullRowSpace"/> returns the <A>F</A>-vector space that | ||||
| ##  consists of all row vectors (see <Ref Func="IsRowVector"/>) of | ||||
| ##  length <A>n</A> with entries in <A>F</A>. | ||||
| ##  <P/> | ||||
| ##  An alternative to construct this vector space is via | ||||
| ##  <A>F</A><C>^</C><A>n</A>. | ||||
| ##  <Example><![CDATA[ | ||||
| ##  gap> FullRowSpace( GF( 9 ), 3 ); | ||||
| ##  ( GF(3^2)^3 ) | ||||
| ##  gap> GF(9)^3;           # the same as above | ||||
| ##  ( GF(3^2)^3 ) | ||||
| ##  ]]></Example> | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ##  <#/GAPDoc> | ||||
| ## | ||||
| DeclareSynonym( "FullRowSpace", FullRowModule ); | ||||
| DeclareSynonym( "RowSpace", FullRowModule ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #F  FullMatrixSpace( <F>, <m>, <n> ) | ||||
| ## | ||||
| ##  <#GAPDoc Label="FullMatrixSpace"> | ||||
| ##  <ManSection> | ||||
| ##  <Func Name="FullMatrixSpace" Arg='F, m, n'/> | ||||
| ##  <Meth Name="\^" Arg='F, dims' | ||||
| ##   Label="for a field and a pair of integers"/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  For a field <A>F</A> and two positive integers <A>m</A> and <A>n</A>, | ||||
| ##  <Ref Func="FullMatrixSpace"/> returns the <A>F</A>-vector space that | ||||
| ##  consists of all <A>m</A> by <A>n</A> matrices | ||||
| ##  (see <Ref Func="IsMatrix"/>) with entries in <A>F</A>. | ||||
| ##  <P/> | ||||
| ##  If <A>m</A><C> = </C><A>n</A> then the result is in fact an algebra | ||||
| ##  (see <Ref Func="FullMatrixAlgebra"/>). | ||||
| ##  <P/> | ||||
| ##  An alternative to construct this vector space is via | ||||
| ##  <A>F</A><C>^[</C><A>m</A>,<A>n</A><C>]</C>. | ||||
| ##  <Example><![CDATA[ | ||||
| ##  gap> FullMatrixSpace( GF(2), 4, 5 ); | ||||
| ##  ( GF(2)^[ 4, 5 ] ) | ||||
| ##  gap> GF(2)^[ 4, 5 ];    # the same as above | ||||
| ##  ( GF(2)^[ 4, 5 ] ) | ||||
| ##  ]]></Example> | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ##  <#/GAPDoc> | ||||
| ## | ||||
| DeclareSynonym( "FullMatrixSpace", FullMatrixModule ); | ||||
| DeclareSynonym( "MatrixSpace", FullMatrixModule ); | ||||
| DeclareSynonym( "MatSpace", FullMatrixModule ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #C  IsSubspacesVectorSpace( <D> ) | ||||
| ## | ||||
| ##  <#GAPDoc Label="IsSubspacesVectorSpace"> | ||||
| ##  <ManSection> | ||||
| ##  <Filt Name="IsSubspacesVectorSpace" Arg='D' Type='Category'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  The domain of all subspaces of a (finite) vector space or of all | ||||
| ##  subspaces of fixed dimension, as returned by <Ref Func="Subspaces"/> | ||||
| ##  (see <Ref Func="Subspaces"/>) lies in the category | ||||
| ##  <Ref Filt="IsSubspacesVectorSpace"/>. | ||||
| ##  <Example><![CDATA[ | ||||
| ##  gap> D:= Subspaces( GF(3)^3 ); | ||||
| ##  Subspaces( ( GF(3)^3 ) ) | ||||
| ##  gap> Size( D ); | ||||
| ##  28 | ||||
| ##  gap> iter:= Iterator( D );; | ||||
| ##  gap> NextIterator( iter ); | ||||
| ##  <vector space over GF(3), with 0 generators> | ||||
| ##  gap> NextIterator( iter ); | ||||
| ##  <vector space of dimension 1 over GF(3)> | ||||
| ##  gap> IsSubspacesVectorSpace( D ); | ||||
| ##  true | ||||
| ##  ]]></Example> | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ##  <#/GAPDoc> | ||||
| ## | ||||
| DeclareCategory( "IsSubspacesVectorSpace", IsDomain ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  IsFinite( <D> ) . . . . . . . . . . . . . . . . .  for a subspaces domain | ||||
| ## | ||||
| ##  Returns `true' if <D> is finite. | ||||
| ##  We allow subspaces domains in `IsSubspacesVectorSpace' only for finite | ||||
| ##  vector spaces. | ||||
| ## | ||||
| InstallTrueMethod( IsFinite, IsSubspacesVectorSpace ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #A  Subspaces( <V>[, <k>] ) | ||||
| ## | ||||
| ##  <#GAPDoc Label="Subspaces"> | ||||
| ##  <ManSection> | ||||
| ##  <Attr Name="Subspaces" Arg='V[, k]'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  Called with a finite vector space <A>v</A>, | ||||
| ##  <Ref Oper="Subspaces"/> returns the domain of all subspaces of <A>V</A>. | ||||
| ##  <P/> | ||||
| ##  Called with <A>V</A> and a nonnegative integer <A>k</A>, | ||||
| ##  <Ref Oper="Subspaces"/> returns the domain of all <A>k</A>-dimensional | ||||
| ##  subspaces of <A>V</A>. | ||||
| ##  <P/> | ||||
| ##  Special <Ref Attr="Size"/> and <Ref Oper="Iterator"/> methods are | ||||
| ##  provided for these domains. | ||||
| ##  <!-- <C>Enumerator</C> would also be good ... | ||||
| ##       (special treatment for full row spaces, | ||||
| ##       other spaces delegate to this)--> | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ##  <#/GAPDoc> | ||||
| ## | ||||
| DeclareAttribute( "Subspaces", IsLeftModule ); | ||||
| DeclareOperation( "Subspaces", [ IsLeftModule, IsInt ] ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #F  IsSubspace( <V>, <U> ) | ||||
| ## | ||||
| ##  <ManSection> | ||||
| ##  <Func Name="IsSubspace" Arg='V, U'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  check that <A>U</A> is a vector space that is contained in <A>V</A> | ||||
| ##  <!-- Must also <A>V</A> be a vector space? | ||||
| ##       If yes then must <A>V</A> and <A>U</A> have same left acting domain? | ||||
| ##       (Is this function useful at all?) --> | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ## | ||||
| DeclareGlobalFunction( "IsSubspace" ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #A  OrthogonalSpaceInFullRowSpace( <U> ) | ||||
| ## | ||||
| ##  <ManSection> | ||||
| ##  <Attr Name="OrthogonalSpaceInFullRowSpace" Arg='U'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  For a Gaussian row space <A>U</A> over <M>F</M>, | ||||
| ##  <Ref Attr="OrthogonalSpaceInFullRowSpace"/> | ||||
| ##  returns a complement of <A>U</A> in the full row space of same vector | ||||
| ##  dimension as <A>U</A> over <M>F</M>. | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ## | ||||
| DeclareAttribute( "OrthogonalSpaceInFullRowSpace", IsGaussianSpace ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #P  IsVectorSpaceHomomorphism( <map> ) | ||||
| ## | ||||
| ##  <ManSection> | ||||
| ##  <Prop Name="IsVectorSpaceHomomorphism" Arg='map'/> | ||||
| ## | ||||
| ##  <Description> | ||||
| ##  A mapping <M>f</M> is a vector space homomorphism (or linear mapping) | ||||
| ##  if the source and range are vector spaces | ||||
| ##  (see <Ref Func="IsVectorSpace"/>) | ||||
| ##  over the same division ring <M>D</M> | ||||
| ##  (see <Ref Func="LeftActingDomain"/>), | ||||
| ##  and if <M>f( a + b ) = f(a) + f(b)</M> and <M>f( s * a ) = s * f(a)</M> | ||||
| ##  hold for all elements <M>a</M>, <M>b</M> in the source of <M>f</M> and | ||||
| ##  <M>s \in D</M>. | ||||
| ##  </Description> | ||||
| ##  </ManSection> | ||||
| ## | ||||
| DeclareProperty( "IsVectorSpaceHomomorphism", IsGeneralMapping ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #E | ||||
|  | ||||
							
								
								
									
										651
									
								
								samples/GAP/vspc.gi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										651
									
								
								samples/GAP/vspc.gi
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,651 @@ | ||||
| ############################################################################# | ||||
| ## | ||||
| #W  vspc.gi                     GAP library                     Thomas Breuer | ||||
| ## | ||||
| ## | ||||
| #Y  Copyright (C)  1997,  Lehrstuhl D für Mathematik,  RWTH Aachen,  Germany | ||||
| #Y  (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland | ||||
| #Y  Copyright (C) 2002 The GAP Group | ||||
| ## | ||||
| ##  This file contains generic methods for vector spaces. | ||||
| ## | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  SetLeftActingDomain( <extL>, <D> ) | ||||
| ## | ||||
| ##  check whether the left acting domain <D> of the external left set <extL> | ||||
| ##  knows that it is a division ring. | ||||
| ##  This is used, e.g.,  to tell a free module over a division ring | ||||
| ##  that it is a vector space. | ||||
| ## | ||||
| InstallOtherMethod( SetLeftActingDomain, | ||||
|     "method to set also 'IsLeftActedOnByDivisionRing'", | ||||
|     [ IsAttributeStoringRep and IsLeftActedOnByRing, IsObject ],0, | ||||
|     function( extL, D ) | ||||
|     if HasIsDivisionRing( D ) and IsDivisionRing( D ) then | ||||
|       SetIsLeftActedOnByDivisionRing( extL, true ); | ||||
|     fi; | ||||
|     TryNextMethod(); | ||||
|     end ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  IsLeftActedOnByDivisionRing( <M> ) | ||||
| ## | ||||
| InstallMethod( IsLeftActedOnByDivisionRing, | ||||
|     "method for external left set that is left acted on by a ring", | ||||
|     [ IsExtLSet and IsLeftActedOnByRing ], | ||||
|     function( M ) | ||||
|     if IsIdenticalObj( M, LeftActingDomain( M ) ) then | ||||
|       TryNextMethod(); | ||||
|     else | ||||
|       return IsDivisionRing( LeftActingDomain( M ) ); | ||||
|     fi; | ||||
|     end ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #F  VectorSpace( <F>, <gens>[, <zero>][, "basis"] ) | ||||
| ## | ||||
| ##  The only difference between `VectorSpace' and `FreeLeftModule' shall be | ||||
| ##  that the left acting domain of a vector space must be a division ring. | ||||
| ## | ||||
| InstallGlobalFunction( VectorSpace, function( arg ) | ||||
|     if Length( arg ) = 0 or not IsDivisionRing( arg[1] ) then | ||||
|       Error( "usage: VectorSpace( <F>, <gens>[, <zero>][, \"basis\"] )" ); | ||||
|     fi; | ||||
|     return CallFuncList( FreeLeftModule, arg ); | ||||
|     end ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  AsSubspace( <V>, <C> )  . . . . . . . for a vector space and a collection | ||||
| ## | ||||
| InstallMethod( AsSubspace, | ||||
|     "for a vector space and a collection", | ||||
|     [ IsVectorSpace, IsCollection ], | ||||
|     function( V, C ) | ||||
|     local newC; | ||||
|  | ||||
|     if not IsSubset( V, C ) then | ||||
|       return fail; | ||||
|     fi; | ||||
|     newC:= AsVectorSpace( LeftActingDomain( V ), C ); | ||||
|     if newC = fail then | ||||
|       return fail; | ||||
|     fi; | ||||
|     SetParent( newC, V ); | ||||
|     UseIsomorphismRelation( C, newC ); | ||||
|     UseSubsetRelation( C, newC ); | ||||
|  | ||||
|     return newC; | ||||
|     end ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  AsLeftModule( <F>, <V> )  . . . . . .  for division ring and vector space | ||||
| ## | ||||
| ##  View the vector space <V> as a vector space over the division ring <F>. | ||||
| ## | ||||
| InstallMethod( AsLeftModule, | ||||
|     "method for a division ring and a vector space", | ||||
|     [ IsDivisionRing, IsVectorSpace ], | ||||
|     function( F, V ) | ||||
|  | ||||
|     local W,        # the space, result | ||||
|           base,     # basis vectors of field extension | ||||
|           gen,      # loop over generators of 'V' | ||||
|           b,        # loop over 'base' | ||||
|           gens,     # generators of 'V' | ||||
|           newgens;  # extended list of generators | ||||
|  | ||||
|     if Characteristic( F ) <> Characteristic( LeftActingDomain( V ) ) then | ||||
|  | ||||
|       # This is impossible. | ||||
|       return fail; | ||||
|  | ||||
|     elif F = LeftActingDomain( V ) then | ||||
|  | ||||
|       # No change of the left acting domain is necessary. | ||||
|       return V; | ||||
|  | ||||
|     elif IsSubset( F, LeftActingDomain( V ) ) then | ||||
|  | ||||
|       # Check whether 'V' is really a space over the bigger field, | ||||
|       # that is, whether the set of elements does not change. | ||||
|       base:= BasisVectors( Basis( AsField( LeftActingDomain( V ), F ) ) ); | ||||
|       for gen in GeneratorsOfLeftModule( V ) do | ||||
|         for b in base do | ||||
|           if not b * gen in V then | ||||
|  | ||||
|             # The field extension would change the set of elements. | ||||
|             return fail; | ||||
|  | ||||
|           fi; | ||||
|         od; | ||||
|       od; | ||||
|  | ||||
|       # Construct the space. | ||||
|       W:= LeftModuleByGenerators( F, GeneratorsOfLeftModule(V), Zero(V) ); | ||||
|  | ||||
|     elif IsSubset( LeftActingDomain( V ), F ) then | ||||
|  | ||||
|       # View 'V' as a space over a smaller field. | ||||
|       # For that, the list of generators must be extended. | ||||
|       gens:= GeneratorsOfLeftModule( V ); | ||||
|       if IsEmpty( gens ) then | ||||
|         W:= LeftModuleByGenerators( F, [], Zero( V ) ); | ||||
|       else | ||||
|  | ||||
|         base:= BasisVectors( Basis( AsField( F, LeftActingDomain( V ) ) ) ); | ||||
|         newgens:= []; | ||||
|         for b in base do | ||||
|           for gen in gens do | ||||
|             Add( newgens, b * gen ); | ||||
|           od; | ||||
|         od; | ||||
|         W:= LeftModuleByGenerators( F, newgens ); | ||||
|  | ||||
|       fi; | ||||
|  | ||||
|     else | ||||
|  | ||||
|       # View 'V' first as space over the intersection of fields, | ||||
|       # and then over the desired field. | ||||
|       return AsLeftModule( F, | ||||
|                  AsLeftModule( Intersection( F, | ||||
|                      LeftActingDomain( V ) ), V ) ); | ||||
|  | ||||
|     fi; | ||||
|  | ||||
|     UseIsomorphismRelation( V, W ); | ||||
|     UseSubsetRelation( V, W ); | ||||
|     return W; | ||||
|     end ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  ViewObj( <V> )  . . . . . . . . . . . . . . . . . . . view a vector space | ||||
| ## | ||||
| ##  print left acting domain, if known also dimension or no. of generators | ||||
| ## | ||||
| InstallMethod( ViewObj, | ||||
|     "for vector space with known generators", | ||||
|     [ IsVectorSpace and HasGeneratorsOfLeftModule ], | ||||
|     function( V ) | ||||
|     Print( "<vector space over ", LeftActingDomain( V ), ", with ", | ||||
|            Length( GeneratorsOfLeftModule( V ) ), " generators>" ); | ||||
|     end ); | ||||
|  | ||||
| InstallMethod( ViewObj, | ||||
|     "for vector space with known dimension", | ||||
|     [ IsVectorSpace and HasDimension ], | ||||
|     1, # override method for known generators | ||||
|     function( V ) | ||||
|     Print( "<vector space of dimension ", Dimension( V ), | ||||
|            " over ", LeftActingDomain( V ), ">" ); | ||||
|     end ); | ||||
|  | ||||
| InstallMethod( ViewObj, | ||||
|     "for vector space", | ||||
|     [ IsVectorSpace ], | ||||
|     function( V ) | ||||
|     Print( "<vector space over ", LeftActingDomain( V ), ">" ); | ||||
|     end ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  PrintObj( <V> ) . . . . . . . . . . . . . . . . . . .  for a vector space | ||||
| ## | ||||
| InstallMethod( PrintObj, | ||||
|     "method for vector space with left module generators", | ||||
|     [ IsVectorSpace and HasGeneratorsOfLeftModule ], | ||||
|     function( V ) | ||||
|     Print( "VectorSpace( ", LeftActingDomain( V ), ", ", | ||||
|            GeneratorsOfLeftModule( V ) ); | ||||
|     if IsEmpty( GeneratorsOfLeftModule( V ) ) and HasZero( V ) then | ||||
|       Print( ", ", Zero( V ), " )" ); | ||||
|     else | ||||
|       Print( " )" ); | ||||
|     fi; | ||||
|     end ); | ||||
|  | ||||
| InstallMethod( PrintObj, | ||||
|     "method for vector space", | ||||
|     [ IsVectorSpace ], | ||||
|     function( V ) | ||||
|     Print( "VectorSpace( ", LeftActingDomain( V ), ", ... )" ); | ||||
|     end ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  \/( <V>, <W> )  . . . . . . . . .  factor of a vector space by a subspace | ||||
| #M  \/( <V>, <vectors> )  . . . . . .  factor of a vector space by a subspace | ||||
| ## | ||||
| InstallOtherMethod( \/, | ||||
|     "method for vector space and collection", | ||||
|     IsIdenticalObj, | ||||
|     [ IsVectorSpace, IsCollection ], | ||||
|     function( V, vectors ) | ||||
|     if IsVectorSpace( vectors ) then | ||||
|       TryNextMethod(); | ||||
|     else | ||||
|       return V / Subspace( V, vectors ); | ||||
|     fi; | ||||
|     end ); | ||||
|  | ||||
| InstallOtherMethod( \/, | ||||
|     "generic method for two vector spaces", | ||||
|     IsIdenticalObj, | ||||
|     [ IsVectorSpace, IsVectorSpace ], | ||||
|     function( V, W ) | ||||
|     return ImagesSource( NaturalHomomorphismBySubspace( V, W ) ); | ||||
|     end ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  Intersection2Spaces( <AsStruct>, <Substruct>, <Struct> ) | ||||
| ## | ||||
| InstallGlobalFunction( Intersection2Spaces, | ||||
|     function( AsStructure, Substructure, Structure ) | ||||
|     return function( V, W ) | ||||
|     local inters,  # intersection, result | ||||
|           F,       # coefficients field | ||||
|           gensV,   # list of generators of 'V' | ||||
|           gensW,   # list of generators of 'W' | ||||
|           VW,      # sum of 'V' and 'W' | ||||
|           B;       # basis of 'VW' | ||||
|  | ||||
|     if LeftActingDomain( V ) <> LeftActingDomain( W ) then | ||||
|  | ||||
|       # Compute the intersection as vector space over the intersection | ||||
|       # of the coefficients fields. | ||||
|       # (Note that the characteristic is the same.) | ||||
|       F:= Intersection2( LeftActingDomain( V ), LeftActingDomain( W ) ); | ||||
|       return Intersection2( AsStructure( F, V ), AsStructure( F, W ) ); | ||||
|  | ||||
|     elif IsFiniteDimensional( V ) and IsFiniteDimensional( W ) then | ||||
|  | ||||
|       # Compute the intersection of two spaces over the same field. | ||||
|       gensV:= GeneratorsOfLeftModule( V ); | ||||
|       gensW:= GeneratorsOfLeftModule( W ); | ||||
|       if   IsEmpty( gensV ) then | ||||
|         if Zero( V ) in W then | ||||
|           inters:= V; | ||||
|         else | ||||
|           inters:= []; | ||||
|         fi; | ||||
|       elif IsEmpty( gensW ) then | ||||
|         if Zero( V ) in W then | ||||
|           inters:= W; | ||||
|         else | ||||
|           inters:= []; | ||||
|         fi; | ||||
|       else | ||||
|         # Compute a common coefficient space. | ||||
|         VW:= LeftModuleByGenerators( LeftActingDomain( V ), | ||||
|                                      Concatenation( gensV, gensW ) ); | ||||
|         B:= Basis( VW ); | ||||
|  | ||||
|         # Construct the coefficient subspaces corresponding to 'V' and 'W'. | ||||
|         gensV:= List( gensV, x -> Coefficients( B, x ) ); | ||||
|         gensW:= List( gensW, x -> Coefficients( B, x ) ); | ||||
|  | ||||
|         # Construct the intersection of row spaces, and carry back to VW. | ||||
|         inters:= List( SumIntersectionMat( gensV, gensW )[2], | ||||
|                        x -> LinearCombination( B, x ) ); | ||||
|  | ||||
|         # Construct the intersection space, if possible with a parent. | ||||
|         if     HasParent( V ) and HasParent( W ) | ||||
|            and IsIdenticalObj( Parent( V ), Parent( W ) ) then | ||||
|           inters:= Substructure( Parent( V ), inters, "basis" ); | ||||
|         elif IsEmpty( inters ) then | ||||
|           inters:= Substructure( V, inters, "basis" ); | ||||
|           SetIsTrivial( inters, true ); | ||||
|         else | ||||
|           inters:= Structure( LeftActingDomain( V ), inters, "basis" ); | ||||
|         fi; | ||||
|  | ||||
|         # Run implications by the subset relation. | ||||
|         UseSubsetRelation( V, inters ); | ||||
|         UseSubsetRelation( W, inters ); | ||||
|       fi; | ||||
|  | ||||
|       # Return the result. | ||||
|       return inters; | ||||
|  | ||||
|     else | ||||
|       TryNextMethod(); | ||||
|     fi; | ||||
|     end; | ||||
| end ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  Intersection2( <V>, <W> ) . . . . . . . . . . . . . for two vector spaces | ||||
| ## | ||||
| InstallMethod( Intersection2, | ||||
|     "method for two vector spaces", | ||||
|     IsIdenticalObj, | ||||
|     [ IsVectorSpace, IsVectorSpace ], | ||||
|     Intersection2Spaces( AsLeftModule, SubspaceNC, VectorSpace ) ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  ClosureLeftModule( <V>, <a> ) . . . . . . . . . closure of a vector space | ||||
| ## | ||||
| InstallMethod( ClosureLeftModule, | ||||
|     "method for a vector space with basis, and a vector", | ||||
|     IsCollsElms, | ||||
|     [ IsVectorSpace and HasBasis, IsVector ], | ||||
|     function( V, w ) | ||||
|     local   B; # basis of 'V' | ||||
|  | ||||
|     # We can test membership easily. | ||||
|     B:= Basis( V ); | ||||
| #T why easily? | ||||
|     if Coefficients( B, w ) = fail then | ||||
|  | ||||
|       # In the case of a vector space, we know a basis of the closure. | ||||
|       B:= Concatenation( BasisVectors( B ), [ w ] ); | ||||
|       V:= LeftModuleByGenerators( LeftActingDomain( V ), B ); | ||||
|       UseBasis( V, B ); | ||||
|  | ||||
|     fi; | ||||
|     return V; | ||||
|     end ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| ##  Methods for collections of subspaces of a vector space | ||||
| ## | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #R  IsSubspacesVectorSpaceDefaultRep( <D> ) | ||||
| ## | ||||
| ##  is the representation of domains of subspaces of a vector space <V>, | ||||
| ##  with the components 'structure' (with value <V>) and 'dimension' | ||||
| ##  (with value either the dimension of the subspaces in the domain | ||||
| ##  or the string '\"all\"', which means that the domain contains all | ||||
| ##  subspaces of <V>). | ||||
| ## | ||||
| DeclareRepresentation( | ||||
|     "IsSubspacesVectorSpaceDefaultRep", | ||||
|     IsComponentObjectRep, | ||||
|     [ "dimension", "structure" ] ); | ||||
| #T not IsAttributeStoringRep? | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  PrintObj( <D> )  . . . . . . . . . . . . . . . . . for a subspaces domain | ||||
| ## | ||||
| InstallMethod( PrintObj, | ||||
|     "method for a subspaces domain", | ||||
|     [ IsSubspacesVectorSpace and IsSubspacesVectorSpaceDefaultRep ], | ||||
|     function( D ) | ||||
|     if IsInt( D!.dimension ) then | ||||
|       Print( "Subspaces( ", D!.structure, ", ", D!.dimension, " )" ); | ||||
|     else | ||||
|       Print( "Subspaces( ", D!.structure, " )" ); | ||||
|     fi; | ||||
|     end ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  Size( <D> ) . . . . . . . . . . . . . . . . . . .  for a subspaces domain | ||||
| ## | ||||
| ##  The number of $k$-dimensional subspaces in a $n$-dimensional space over | ||||
| ##  the field with $q$ elements is | ||||
| ##  $$ | ||||
| ##  a(n,k) = \prod_{i=0}^{k-1} \frac{q^n-q^i}{q^k-q^i} = | ||||
| ##           \prod_{i=0}^{k-1} \frac{q^{n-i}-1}{q^{k-i}-1}. | ||||
| ##  $$ | ||||
| ##  We have the recursion | ||||
| ##  $$ | ||||
| ##  a(n,k+1) = a(n,k) \frac{q^{n-i}-1}{q^{i+1}-1}. | ||||
| ##  $$ | ||||
| ## | ||||
| ##  (The number of all subspaces is $\sum_{k=0}^n a(n,k)$.) | ||||
| ## | ||||
| InstallMethod( Size, | ||||
|     "method for a subspaces domain", | ||||
|     [ IsSubspacesVectorSpace and IsSubspacesVectorSpaceDefaultRep ], | ||||
|     function( D ) | ||||
|  | ||||
|     local k, | ||||
|           n, | ||||
|           q, | ||||
|           size, | ||||
|           qn, | ||||
|           qd, | ||||
|           ank, | ||||
|           i; | ||||
|  | ||||
|     if D!.dimension = "all" then | ||||
|  | ||||
|       # all subspaces of the space | ||||
|       n:= Dimension( D!.structure ); | ||||
|  | ||||
|       q:= Size( LeftActingDomain( D!.structure ) ); | ||||
|       size:= 1; | ||||
|       qn:= q^n; | ||||
|       qd:= q; | ||||
|  | ||||
|       # $a(n,0)$ | ||||
|       ank:= 1; | ||||
|  | ||||
|       for k in [ 1 .. Int( (n-1)/2 ) ] do | ||||
|  | ||||
|         # Compute $a(n,k)$. | ||||
|         ank:= ank * ( qn - 1 ) / ( qd - 1 ); | ||||
|         qn:= qn / q; | ||||
|         qd:= qd * q; | ||||
|  | ||||
|         size:= size + ank; | ||||
|  | ||||
|       od; | ||||
|  | ||||
|       size:= 2 * size; | ||||
|  | ||||
|       if n mod 2 = 0 then | ||||
|  | ||||
|         # Add the number of spaces of dimension $n/2$. | ||||
|         size:= size + ank * ( qn - 1 ) / ( qd - 1 ); | ||||
|       fi; | ||||
|  | ||||
|     else | ||||
|  | ||||
|       # number of spaces of dimension 'k' only | ||||
|       n:= Dimension( D!.structure ); | ||||
|       if   D!.dimension < 0 or | ||||
|            n < D!.dimension then | ||||
|         return 0; | ||||
|       elif n / 2 < D!.dimension then | ||||
|         k:= n - D!.dimension; | ||||
|       else | ||||
|         k:= D!.dimension; | ||||
|       fi; | ||||
|  | ||||
|       q:= Size( LeftActingDomain( D!.structure ) ); | ||||
|       size:= 1; | ||||
|  | ||||
|       qn:= q^n; | ||||
|       qd:= q; | ||||
|       for i in [ 1 .. k ] do | ||||
|         size:= size * ( qn - 1 ) / ( qd - 1 ); | ||||
|         qn:= qn / q; | ||||
|         qd:= qd * q; | ||||
|       od; | ||||
|  | ||||
|     fi; | ||||
|  | ||||
|     # Return the result. | ||||
|     return size; | ||||
|     end ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  Enumerator( <D> ) . . . . . . . . . . . . . . . .  for a subspaces domain | ||||
| ## | ||||
| ##  Use the iterator to compute the elements list. | ||||
| #T This is not allowed! | ||||
| ## | ||||
| InstallMethod( Enumerator, | ||||
|     "method for a subspaces domain", | ||||
|     [ IsSubspacesVectorSpace and IsSubspacesVectorSpaceDefaultRep ], | ||||
|     function( D ) | ||||
|     local iter,    # iterator for 'D' | ||||
|           elms;    # elements list, result | ||||
|  | ||||
|     iter:= Iterator( D ); | ||||
|     elms:= []; | ||||
|     while not IsDoneIterator( iter ) do | ||||
|       Add( elms, NextIterator( iter ) ); | ||||
|     od; | ||||
|     return elms; | ||||
|     end ); | ||||
| #T necessary? | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  Iterator( <D> ) . . . . . . . . . . . . . . . . .  for a subspaces domain | ||||
| ## | ||||
| ##  uses the subspaces iterator for full row spaces and the mechanism of | ||||
| ##  associated row spaces. | ||||
| ## | ||||
| BindGlobal( "IsDoneIterator_Subspaces", | ||||
|     iter -> IsDoneIterator( iter!.associatedIterator ) ); | ||||
|  | ||||
| BindGlobal( "NextIterator_Subspaces", function( iter ) | ||||
|     local next; | ||||
|     next:= NextIterator( iter!.associatedIterator ); | ||||
|     next:= List( GeneratorsOfLeftModule( next ), | ||||
|                  x -> LinearCombination( iter!.basis, x ) ); | ||||
|     return Subspace( iter!.structure, next, "basis" ); | ||||
|     end ); | ||||
|  | ||||
| BindGlobal( "ShallowCopy_Subspaces", | ||||
|     iter -> rec( structure          := iter!.structure, | ||||
|                  basis              := iter!.basis, | ||||
|                  associatedIterator := ShallowCopy( | ||||
|                                            iter!.associatedIterator ) ) ); | ||||
|  | ||||
| InstallMethod( Iterator, | ||||
|     "for a subspaces domain", | ||||
|     [ IsSubspacesVectorSpace and IsSubspacesVectorSpaceDefaultRep ], | ||||
|     function( D ) | ||||
|     local V;      # the vector space | ||||
|  | ||||
|     V:= D!.structure; | ||||
|     return IteratorByFunctions( rec( | ||||
|                IsDoneIterator     := IsDoneIterator_Subspaces, | ||||
|                NextIterator       := NextIterator_Subspaces, | ||||
|                ShallowCopy        := ShallowCopy_Subspaces, | ||||
|                structure          := V, | ||||
|                basis              := Basis( V ), | ||||
|                associatedIterator := Iterator( | ||||
|                       Subspaces( FullRowSpace( LeftActingDomain( V ), | ||||
|                                                Dimension( V ) ), | ||||
|                                  D!.dimension ) ) ) ); | ||||
|     end ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  Subspaces( <V>, <dim> ) | ||||
| ## | ||||
| InstallMethod( Subspaces, | ||||
|     "for a vector space, and an integer", | ||||
|     [ IsVectorSpace, IsInt ], | ||||
|     function( V, dim ) | ||||
|     if IsFinite( V ) then | ||||
|       return Objectify( NewType( CollectionsFamily( FamilyObj( V ) ), | ||||
|                                      IsSubspacesVectorSpace | ||||
|                                  and IsSubspacesVectorSpaceDefaultRep ), | ||||
|                         rec( | ||||
|                              structure  := V, | ||||
|                              dimension  := dim | ||||
|                            ) | ||||
|                       ); | ||||
|     else | ||||
|       TryNextMethod(); | ||||
|     fi; | ||||
|     end ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  Subspaces( <V> ) | ||||
| ## | ||||
| InstallMethod( Subspaces, | ||||
|     "for a vector space", | ||||
|     [ IsVectorSpace ], | ||||
|     function( V ) | ||||
|     if IsFinite( V ) then | ||||
|       return Objectify( NewType( CollectionsFamily( FamilyObj( V ) ), | ||||
|                                      IsSubspacesVectorSpace | ||||
|                                  and IsSubspacesVectorSpaceDefaultRep ), | ||||
|                         rec( | ||||
|                              structure  := V, | ||||
|                              dimension  := "all" | ||||
|                            ) | ||||
|                       ); | ||||
|     else | ||||
|       TryNextMethod(); | ||||
|     fi; | ||||
|     end ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #F  IsSubspace( <V>, <U> ) . . . . . . . . . . . . . . . . . check <U> <= <V> | ||||
| ## | ||||
| InstallGlobalFunction( IsSubspace, function( V, U ) | ||||
|     return IsVectorSpace( U ) and IsSubset( V, U ); | ||||
| end ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #M  IsVectorSpaceHomomorphism( <map> ) | ||||
| ## | ||||
| InstallMethod( IsVectorSpaceHomomorphism, | ||||
|     [ IsGeneralMapping ], | ||||
|     function( map ) | ||||
|     local S, R, F; | ||||
|     S:= Source( map ); | ||||
|     if not IsVectorSpace( S ) then | ||||
|       return false; | ||||
|     fi; | ||||
|     R:= Range( map ); | ||||
|     if not IsVectorSpace( R ) then | ||||
|       return false; | ||||
|     fi; | ||||
|     F:= LeftActingDomain( S ); | ||||
|     return ( F = LeftActingDomain( R ) ) and IsLinearMapping( F, map ); | ||||
|     end ); | ||||
|  | ||||
|  | ||||
| ############################################################################# | ||||
| ## | ||||
| #E | ||||
|  | ||||
							
								
								
									
										57
									
								
								samples/GDScript/example.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								samples/GDScript/example.gd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| # Taken from https://github.com/okamstudio/godot/wiki/gdscript | ||||
| # a file is a class! | ||||
|  | ||||
| # inheritance | ||||
|  | ||||
| extends BaseClass | ||||
|  | ||||
| # member variables | ||||
|  | ||||
| var a = 5  | ||||
| var s = "Hello" | ||||
| var arr = [1, 2, 3] | ||||
| var dict = {"key":"value", 2:3} | ||||
|  | ||||
| # constants | ||||
|  | ||||
| const answer = 42 | ||||
| const thename = "Charly" | ||||
|  | ||||
| # built-in vector types | ||||
|  | ||||
| var v2 = Vector2(1, 2) | ||||
| var v3 = Vector3(1, 2, 3) | ||||
|  | ||||
| # function | ||||
|  | ||||
| func some_function(param1, param2): | ||||
|     var local_var = 5 | ||||
|  | ||||
|     if param1 < local_var: | ||||
|         print(param1) | ||||
|     elif param2 > 5: | ||||
|         print(param2) | ||||
|     else: | ||||
|         print("fail!") | ||||
|  | ||||
|     for i in range(20): | ||||
|         print(i) | ||||
|  | ||||
|     while(param2 != 0): | ||||
|         param2 -= 1 | ||||
|  | ||||
|     var local_var2 = param1+3 | ||||
|     return local_var2 | ||||
|  | ||||
|  | ||||
| # subclass | ||||
|  | ||||
| class Something: | ||||
|     var a = 10 | ||||
|  | ||||
| # constructor | ||||
|  | ||||
| func _init(): | ||||
|     print("constructed!") | ||||
|     var lv = Something.new() | ||||
|     print(lv.a) | ||||
							
								
								
									
										216
									
								
								samples/GDScript/grid.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								samples/GDScript/grid.gd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,216 @@ | ||||
|  | ||||
|  | ||||
| extends Control | ||||
|  | ||||
| # Simple Tetris-like demo, (c) 2012 Juan Linietsky | ||||
| # Implemented by using a regular Control and drawing on it during the _draw() callback. | ||||
| # The drawing surface is updated only when changes happen (by calling update()) | ||||
|  | ||||
|  | ||||
| var score = 0 | ||||
| var score_label=null | ||||
|  | ||||
| const MAX_SHAPES = 7 | ||||
|  | ||||
| var block = preload("block.png") | ||||
|  | ||||
| var block_colors=[ | ||||
| 	Color(1,0.5,0.5), | ||||
| 	Color(0.5,1,0.5), | ||||
| 	Color(0.5,0.5,1), | ||||
| 	Color(0.8,0.4,0.8), | ||||
| 	Color(0.8,0.8,0.4), | ||||
| 	Color(0.4,0.8,0.8), | ||||
| 	Color(0.7,0.7,0.7)] | ||||
|  | ||||
| var	block_shapes=[ | ||||
| 	[ Vector2(0,-1),Vector2(0,0),Vector2(0,1),Vector2(0,2) ], # I | ||||
| 	[ Vector2(0,0),Vector2(1,0),Vector2(1,1),Vector2(0,1) ], # O | ||||
| 	[ Vector2(-1,1),Vector2(0,1),Vector2(0,0),Vector2(1,0) ], # S | ||||
| 	[ Vector2(1,1),Vector2(0,1),Vector2(0,0),Vector2(-1,0) ], # Z | ||||
| 	[ Vector2(-1,1),Vector2(-1,0),Vector2(0,0),Vector2(1,0) ], # L | ||||
| 	[ Vector2(1,1),Vector2(1,0),Vector2(0,0),Vector2(-1,0) ], # J | ||||
| 	[ Vector2(0,1),Vector2(1,0),Vector2(0,0),Vector2(-1,0) ]] # T | ||||
| 	 | ||||
|  | ||||
| var block_rotations=[ | ||||
| 	Matrix32( Vector2(1,0),Vector2(0,1), Vector2() ), | ||||
| 	Matrix32( Vector2(0,1),Vector2(-1,0), Vector2() ), | ||||
| 	Matrix32( Vector2(-1,0),Vector2(0,-1), Vector2() ), | ||||
| 	Matrix32( Vector2(0,-1),Vector2(1,0), Vector2() ) | ||||
| ] | ||||
| 	 | ||||
|  | ||||
| var width=0 | ||||
| var height=0 | ||||
|  | ||||
| var cells={} | ||||
|  | ||||
| var piece_active=false | ||||
| var piece_shape=0 | ||||
| var piece_pos=Vector2() | ||||
| var piece_rot=0 | ||||
|  | ||||
|  | ||||
| func piece_cell_xform(p,er=0): | ||||
| 	var r = (4+er+piece_rot)%4 | ||||
| 	return piece_pos+block_rotations[r].xform(p) | ||||
|  | ||||
| func _draw(): | ||||
|  | ||||
| 	var sb = get_stylebox("bg","Tree") # use line edit bg | ||||
| 	draw_style_box(sb,Rect2(Vector2(),get_size()).grow(3)) | ||||
| 	 | ||||
| 	var bs = block.get_size() | ||||
| 	for y in range(height): | ||||
| 		for x in range(width): | ||||
| 			if (Vector2(x,y) in cells): | ||||
| 				draw_texture_rect(block,Rect2(Vector2(x,y)*bs,bs),false,block_colors[cells[Vector2(x,y)]]) | ||||
| 				 | ||||
| 	if (piece_active): | ||||
| 		 | ||||
| 		for c in block_shapes[piece_shape]: | ||||
| 			draw_texture_rect(block,Rect2(piece_cell_xform(c)*bs,bs),false,block_colors[piece_shape]) | ||||
| 			 | ||||
|  | ||||
| func piece_check_fit(ofs,er=0): | ||||
|  | ||||
| 	for c in block_shapes[piece_shape]: | ||||
| 		var pos = piece_cell_xform(c,er)+ofs | ||||
| 		if (pos.x < 0): | ||||
| 			return false | ||||
| 		if (pos.y < 0): | ||||
| 			return false | ||||
| 		if (pos.x >= width): | ||||
| 			return false | ||||
| 		if (pos.y >= height): | ||||
| 			return false | ||||
| 		if (pos in cells): | ||||
| 			return false | ||||
| 	 | ||||
| 	return true	 | ||||
|  | ||||
| func new_piece(): | ||||
|  | ||||
| 	piece_shape = randi() % MAX_SHAPES	 | ||||
| 	piece_pos = Vector2(width/2,0) | ||||
| 	piece_active=true | ||||
| 	piece_rot=0 | ||||
| 	if (piece_shape==0): | ||||
| 		piece_pos.y+=1 | ||||
| 		 | ||||
| 	if (not piece_check_fit(Vector2())): | ||||
| 		#game over | ||||
| 		#print("GAME OVER!") | ||||
| 		game_over() | ||||
| 		 | ||||
| 	update() | ||||
| 		 | ||||
| 	 | ||||
| func test_collapse_rows(): | ||||
| 	var accum_down=0 | ||||
| 	for i in range(height): | ||||
| 		var y = height - i - 1 | ||||
| 		var collapse = true | ||||
| 		for x in range(width): | ||||
| 			if (Vector2(x,y) in cells): | ||||
| 				if (accum_down): | ||||
| 					cells[ Vector2(x,y+accum_down) ] = cells[Vector2(x,y)] | ||||
| 			else: | ||||
| 				collapse=false | ||||
| 				if (accum_down): | ||||
| 					cells.erase( Vector2(x,y+accum_down) ) | ||||
| 						 | ||||
| 		if (collapse): | ||||
| 			accum_down+=1 | ||||
| 		 | ||||
| 			 | ||||
| 	score+=accum_down*100 | ||||
| 	score_label.set_text(str(score)) | ||||
| 			 | ||||
| 		 | ||||
| func game_over(): | ||||
|  | ||||
| 		piece_active=false | ||||
| 		get_node("gameover").set_text("Game Over")		 | ||||
| 		update() | ||||
| 				 | ||||
| 		 | ||||
| func restart_pressed(): | ||||
|  | ||||
| 		score=0 | ||||
| 		score_label.set_text("0") | ||||
| 		cells.clear() | ||||
| 		get_node("gameover").set_text("")		 | ||||
| 		piece_active=true | ||||
| 		update() | ||||
| 		 | ||||
| 		 | ||||
|  | ||||
| func piece_move_down(): | ||||
|  | ||||
| 	if (!piece_active): | ||||
| 		return | ||||
| 	if (piece_check_fit(Vector2(0,1))): | ||||
| 		piece_pos.y+=1 | ||||
| 		update()		 | ||||
| 	else: | ||||
|  | ||||
| 		for c in block_shapes[piece_shape]: | ||||
| 			var pos = piece_cell_xform(c) | ||||
| 			cells[pos]=piece_shape | ||||
| 		test_collapse_rows() | ||||
| 		new_piece() | ||||
| 		 | ||||
|  | ||||
| func piece_rotate(): | ||||
|  | ||||
| 	var adv = 1 | ||||
| 	if (not piece_check_fit(Vector2(),1)): | ||||
| 		return | ||||
| 	piece_rot = (piece_rot + adv) % 4 | ||||
| 	update() | ||||
| 	 | ||||
| 	 | ||||
|  | ||||
| func _input(ie): | ||||
|  | ||||
|  | ||||
| 	if (not piece_active): | ||||
| 		return | ||||
| 	if (!ie.is_pressed()): | ||||
| 		return | ||||
|  | ||||
| 	if (ie.is_action("move_left")): | ||||
| 		if (piece_check_fit(Vector2(-1,0))): | ||||
| 			piece_pos.x-=1 | ||||
| 			update() | ||||
| 	elif (ie.is_action("move_right")): | ||||
| 		if (piece_check_fit(Vector2(1,0))): | ||||
| 			piece_pos.x+=1 | ||||
| 			update() | ||||
| 	elif (ie.is_action("move_down")): | ||||
| 		piece_move_down() | ||||
| 	elif (ie.is_action("rotate")): | ||||
| 		piece_rotate() | ||||
| 		 | ||||
| 		 | ||||
| func setup(w,h): | ||||
| 	width=w | ||||
| 	height=h | ||||
| 	set_size( Vector2(w,h)*block.get_size() ) | ||||
| 	new_piece() | ||||
| 	get_node("timer").start() | ||||
| 	 | ||||
|  | ||||
| func _ready(): | ||||
| 	# Initalization here | ||||
|  | ||||
| 	setup(10,20) | ||||
| 	score_label = get_node("../score") | ||||
|  | ||||
| 	set_process_input(true) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
							
								
								
									
										243
									
								
								samples/GDScript/player.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										243
									
								
								samples/GDScript/player.gd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,243 @@ | ||||
|  | ||||
| extends RigidBody | ||||
|  | ||||
| # member variables here, example: | ||||
| # var a=2 | ||||
| # var b="textvar" | ||||
|  | ||||
| #var dir=Vector3() | ||||
|  | ||||
| const ANIM_FLOOR = 0 | ||||
| const ANIM_AIR_UP = 1 | ||||
| const ANIM_AIR_DOWN = 2 | ||||
|  | ||||
| const SHOOT_TIME = 1.5 | ||||
| const SHOOT_SCALE = 2 | ||||
|  | ||||
| const CHAR_SCALE = Vector3(0.3,0.3,0.3) | ||||
|  | ||||
| var facing_dir = Vector3(1, 0, 0) | ||||
| var movement_dir = Vector3() | ||||
|  | ||||
| var jumping=false | ||||
|  | ||||
| var turn_speed=40 | ||||
| var keep_jump_inertia = true | ||||
| var air_idle_deaccel = false | ||||
| var accel=19.0 | ||||
| var deaccel=14.0 | ||||
| var sharp_turn_threshhold = 140 | ||||
|  | ||||
| var max_speed=3.1 | ||||
| var on_floor = false | ||||
|  | ||||
| var prev_shoot = false | ||||
|  | ||||
| var last_floor_velocity = Vector3() | ||||
|  | ||||
| var shoot_blend = 0 | ||||
|  | ||||
| func adjust_facing(p_facing, p_target,p_step, p_adjust_rate,current_gn): | ||||
|  | ||||
| 	var n = p_target # normal | ||||
| 	var t = n.cross(current_gn).normalized() | ||||
| 	 | ||||
| 	var x = n.dot(p_facing) | ||||
| 	var y = t.dot(p_facing) | ||||
| 	 | ||||
| 	var ang = atan2(y,x) | ||||
| 	 | ||||
| 	if (abs(ang)<0.001): # too small | ||||
| 		return p_facing | ||||
| 	 | ||||
| 	var s = sign(ang) | ||||
| 	ang = ang * s | ||||
| 	var turn = ang * p_adjust_rate * p_step | ||||
| 	var a | ||||
| 	if (ang<turn): | ||||
| 		a=ang | ||||
| 	else: | ||||
| 		a=turn | ||||
| 	ang = (ang - a) * s | ||||
| 	 | ||||
| 	return ((n * cos(ang)) + (t * sin(ang))) * p_facing.length() | ||||
|  | ||||
|  | ||||
|  | ||||
| func _integrate_forces( state ): | ||||
|  | ||||
| 	var lv = state.get_linear_velocity() # linear velocity | ||||
| 	var g = state.get_total_gravity() | ||||
| 	var delta = state.get_step() | ||||
| 	var d = 1.0 - delta*state.get_total_density() | ||||
| 	if (d<0): | ||||
| 		d=0 | ||||
| 	lv += g * delta #apply gravity | ||||
|  | ||||
| 	var anim = ANIM_FLOOR | ||||
|  | ||||
| 	var up = -g.normalized() # (up is against gravity) | ||||
| 	var vv = up.dot(lv) # vertical velocity | ||||
| 	var hv = lv - (up*vv) # horizontal velocity | ||||
|  | ||||
|  | ||||
|  | ||||
| 	var hdir = hv.normalized() # horizontal direction | ||||
| 	var hspeed = hv.length()	#horizontal speed | ||||
|  | ||||
| 	var floor_velocity | ||||
| 	var onfloor = false | ||||
|  | ||||
| 	if (state.get_contact_count() == 0): | ||||
| 		floor_velocity = last_floor_velocity | ||||
| 	else: | ||||
| 		for i in range(state.get_contact_count()): | ||||
| 			if (state.get_contact_local_shape(i) != 1): | ||||
| 				continue | ||||
| 			 | ||||
| 			onfloor = true | ||||
| 			floor_velocity = state.get_contact_collider_velocity_at_pos(i) | ||||
| 			break | ||||
| 		 | ||||
|  | ||||
| 	var dir = Vector3() #where does the player intend to walk to | ||||
| 	var cam_xform = get_node("target/camera").get_global_transform() | ||||
| 	 | ||||
| 	if (Input.is_action_pressed("move_forward")): | ||||
| 		dir+=-cam_xform.basis[2]  | ||||
| 	if (Input.is_action_pressed("move_backwards")): | ||||
| 		dir+=cam_xform.basis[2]  | ||||
| 	if (Input.is_action_pressed("move_left")): | ||||
| 		dir+=-cam_xform.basis[0]  | ||||
| 	if (Input.is_action_pressed("move_right")): | ||||
| 		dir+=cam_xform.basis[0]  | ||||
| 		 | ||||
| 	var jump_attempt = Input.is_action_pressed("jump") | ||||
| 	var shoot_attempt = Input.is_action_pressed("shoot") | ||||
| 		 | ||||
| 	var target_dir = (dir - up*dir.dot(up)).normalized() | ||||
| 	 | ||||
| 	if (onfloor): | ||||
|  | ||||
| 		var sharp_turn = hspeed > 0.1 and rad2deg(acos(target_dir.dot(hdir))) > sharp_turn_threshhold | ||||
|  | ||||
| 		if (dir.length()>0.1 and !sharp_turn) : | ||||
| 			if (hspeed > 0.001) : | ||||
|  | ||||
| 				#linear_dir = linear_h_velocity/linear_vel | ||||
| 				#if (linear_vel > brake_velocity_limit and linear_dir.dot(ctarget_dir)<-cos(Math::deg2rad(brake_angular_limit))) | ||||
| 				#	brake=true | ||||
| 				#else | ||||
| 				hdir = adjust_facing(hdir,target_dir,delta,1.0/hspeed*turn_speed,up) | ||||
| 				facing_dir = hdir | ||||
| 			else: | ||||
|  | ||||
| 				hdir = target_dir | ||||
| 			 | ||||
| 			if (hspeed<max_speed): | ||||
| 				hspeed+=accel*delta | ||||
|  | ||||
| 		else: | ||||
| 			hspeed-=deaccel*delta | ||||
| 			if (hspeed<0): | ||||
| 				hspeed=0 | ||||
| 		 | ||||
| 		hv = hdir*hspeed | ||||
| 		 | ||||
| 		var mesh_xform = get_node("Armature").get_transform()  | ||||
| 		var facing_mesh=-mesh_xform.basis[0].normalized() | ||||
| 		facing_mesh = (facing_mesh - up*facing_mesh.dot(up)).normalized() | ||||
| 		facing_mesh = adjust_facing(facing_mesh,target_dir,delta,1.0/hspeed*turn_speed,up) | ||||
| 		var m3 = Matrix3(-facing_mesh,up,-facing_mesh.cross(up).normalized()).scaled( CHAR_SCALE ) | ||||
| 		 | ||||
| 		get_node("Armature").set_transform(Transform(m3,mesh_xform.origin)) | ||||
| 				 | ||||
| 		if (not jumping and jump_attempt): | ||||
| 			vv = 7.0 | ||||
| 			jumping = true		 | ||||
| 			get_node("sfx").play("jump") | ||||
| 	else: | ||||
|  | ||||
| 		if (vv>0): | ||||
| 			anim=ANIM_AIR_UP | ||||
| 		else: | ||||
| 			anim=ANIM_AIR_DOWN | ||||
| 			 | ||||
| 		var hs | ||||
| 		if (dir.length()>0.1): | ||||
|  | ||||
| 			hv += target_dir * (accel * 0.2) * delta | ||||
| 			if (hv.length() > max_speed): | ||||
| 				hv = hv.normalized() * max_speed | ||||
|  | ||||
| 		else: | ||||
|  | ||||
| 			if (air_idle_deaccel): | ||||
| 				hspeed = hspeed - (deaccel * 0.2) * delta | ||||
| 				if (hspeed<0): | ||||
| 					hspeed=0 | ||||
|  | ||||
| 				hv = hdir*hspeed | ||||
| 			 | ||||
| 		 | ||||
| 	if (jumping and vv < 0): | ||||
| 		jumping=false | ||||
|  | ||||
| 	lv = hv+up*vv | ||||
| 	 | ||||
| 	 | ||||
|  | ||||
| 	if (onfloor): | ||||
|  | ||||
| 		movement_dir = lv | ||||
| 		#lv += floor_velocity | ||||
| 		last_floor_velocity = floor_velocity | ||||
| 	else: | ||||
|  | ||||
| 		if (on_floor) : | ||||
|  | ||||
| 			#if (keep_jump_inertia): | ||||
| 			#	lv += last_floor_velocity | ||||
| 			pass | ||||
| 		 | ||||
| 		last_floor_velocity = Vector3() | ||||
| 		movement_dir = lv | ||||
| 	 | ||||
| 	on_floor = onfloor | ||||
|  | ||||
| 	state.set_linear_velocity(lv) | ||||
| 	 | ||||
| 	if (shoot_blend>0): | ||||
| 		shoot_blend -= delta * SHOOT_SCALE | ||||
| 		if (shoot_blend<0): | ||||
| 			shoot_blend=0 | ||||
| 	 | ||||
| 	if (shoot_attempt and not prev_shoot): | ||||
| 		shoot_blend = SHOOT_TIME		 | ||||
| 		var bullet = preload("res://bullet.scn").instance() | ||||
| 		bullet.set_transform( get_node("Armature/bullet").get_global_transform().orthonormalized() ) | ||||
| 		get_parent().add_child( bullet ) | ||||
| 		bullet.set_linear_velocity( get_node("Armature/bullet").get_global_transform().basis[2].normalized() * 20 ) | ||||
| 		PS.body_add_collision_exception( bullet.get_rid(), get_rid() ) #add it to bullet | ||||
| 		get_node("sfx").play("shoot") | ||||
| 		 | ||||
| 	prev_shoot = shoot_attempt | ||||
| 	 | ||||
| 	if (onfloor): | ||||
| 		get_node("AnimationTreePlayer").blend2_node_set_amount("walk",hspeed / max_speed) | ||||
| 		 | ||||
| 	get_node("AnimationTreePlayer").transition_node_set_current("state",anim) | ||||
| 	get_node("AnimationTreePlayer").blend2_node_set_amount("gun",min(shoot_blend,1.0)) | ||||
| #	state.set_angular_velocity(Vector3())	 | ||||
| 	 | ||||
| 	 | ||||
|  | ||||
|  | ||||
| func _ready(): | ||||
|  | ||||
|  | ||||
| 	# Initalization here | ||||
| 	get_node("AnimationTreePlayer").set_active(true) | ||||
| 	pass | ||||
|  | ||||
|  | ||||
							
								
								
									
										73
									
								
								samples/GDScript/pong.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								samples/GDScript/pong.gd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
|  | ||||
| extends Node2D | ||||
|  | ||||
| # member variables here, example: | ||||
| # var a=2 | ||||
| # var b="textvar" | ||||
| const INITIAL_BALL_SPEED = 80 | ||||
| var ball_speed = INITIAL_BALL_SPEED | ||||
| var screen_size = Vector2(640,400) | ||||
| #default ball direction | ||||
| var direction = Vector2(-1,0) | ||||
| var pad_size = Vector2(8,32) | ||||
| const PAD_SPEED = 150 | ||||
|  | ||||
|  | ||||
| func _process(delta): | ||||
|  | ||||
|  | ||||
| 	# get ball positio and pad rectangles | ||||
| 	var ball_pos = get_node("ball").get_pos() | ||||
| 	var left_rect = Rect2( get_node("left").get_pos() - pad_size*0.5, pad_size ) | ||||
| 	var right_rect = Rect2( get_node("right").get_pos() - pad_size*0.5, pad_size ) | ||||
| 	 | ||||
| 	#integrate new ball postion | ||||
| 	ball_pos+=direction*ball_speed*delta | ||||
| 	 | ||||
| 	#flip when touching roof or floor | ||||
| 	if ( (ball_pos.y<0 and direction.y <0) or (ball_pos.y>screen_size.y and direction.y>0)): | ||||
| 		direction.y = -direction.y | ||||
| 		 | ||||
| 	#flip, change direction and increase speed when touching pads	 | ||||
| 	if ( (left_rect.has_point(ball_pos) and direction.x < 0) or (right_rect.has_point(ball_pos) and direction.x > 0)): | ||||
| 		direction.x=-direction.x | ||||
| 		ball_speed*=1.1 | ||||
| 		direction.y=randf()*2.0-1 | ||||
| 		direction = direction.normalized() | ||||
|  | ||||
| 	#check gameover | ||||
| 	if (ball_pos.x<0 or ball_pos.x>screen_size.x): | ||||
| 		ball_pos=screen_size*0.5 | ||||
| 		ball_speed=INITIAL_BALL_SPEED | ||||
| 		direction=Vector2(-1,0) | ||||
| 			 | ||||
| 						 | ||||
| 	get_node("ball").set_pos(ball_pos) | ||||
|  | ||||
| 	#move left pad	 | ||||
| 	var left_pos = get_node("left").get_pos() | ||||
| 	 | ||||
| 	if (left_pos.y > 0 and Input.is_action_pressed("left_move_up")): | ||||
| 		left_pos.y+=-PAD_SPEED*delta | ||||
| 	if (left_pos.y < screen_size.y and Input.is_action_pressed("left_move_down")): | ||||
| 		left_pos.y+=PAD_SPEED*delta | ||||
| 		 | ||||
| 	get_node("left").set_pos(left_pos) | ||||
| 		 | ||||
| 	#move right pad	 | ||||
| 	var right_pos = get_node("right").get_pos() | ||||
| 	 | ||||
| 	if (right_pos.y > 0 and Input.is_action_pressed("right_move_up")): | ||||
| 		right_pos.y+=-PAD_SPEED*delta | ||||
| 	if (right_pos.y < screen_size.y and Input.is_action_pressed("right_move_down")): | ||||
| 		right_pos.y+=PAD_SPEED*delta | ||||
| 		 | ||||
| 	get_node("right").set_pos(right_pos) | ||||
| 	 | ||||
| 	  | ||||
|  | ||||
| func _ready(): | ||||
| 	screen_size = get_viewport_rect().size # get actual size | ||||
| 	pad_size = get_node("left").get_texture().get_size() | ||||
| 	set_process(true) | ||||
|  | ||||
							
								
								
									
										9
									
								
								samples/GLSL/SimpleLighting.gl2.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								samples/GLSL/SimpleLighting.gl2.frag
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| static const char* SimpleFragmentShader = STRINGIFY( | ||||
|  | ||||
| varying vec4 FrontColor; | ||||
|  | ||||
| void main(void) | ||||
| { | ||||
|     gl_FragColor = FrontColor; | ||||
| } | ||||
| ); | ||||
							
								
								
									
										6
									
								
								samples/GLSL/myfragment.frg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								samples/GLSL/myfragment.frg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| varying vec4 v_color; | ||||
|  | ||||
| void main() | ||||
| { | ||||
| 	gl_FragColor = v_color; | ||||
| } | ||||
							
								
								
									
										12
									
								
								samples/GLSL/myvertex.vrx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								samples/GLSL/myvertex.vrx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| uniform mat4 u_MVPMatrix; | ||||
|  | ||||
| attribute vec4 a_position; | ||||
| attribute vec4 a_color; | ||||
|  | ||||
| varying vec4 v_color; | ||||
|  | ||||
| void main() | ||||
| { | ||||
| 	v_color = a_color; | ||||
| 	gl_Position =  u_MVPMatrix * pos; | ||||
| } | ||||
							
								
								
									
										48
									
								
								samples/GLSL/recurse1.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								samples/GLSL/recurse1.frag
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| #version 330 core | ||||
|  | ||||
| // cross-unit recursion | ||||
|  | ||||
| void main() {} | ||||
|  | ||||
| // two-level recursion | ||||
|  | ||||
| float cbar(int); | ||||
|  | ||||
| void cfoo(float) | ||||
| { | ||||
| 	cbar(2); | ||||
| } | ||||
|  | ||||
| // four-level, out of order | ||||
|  | ||||
| void CB(); | ||||
| void CD(); | ||||
| void CA() { CB(); } | ||||
| void CC() { CD(); } | ||||
|  | ||||
| // high degree | ||||
|  | ||||
| void CBT(); | ||||
| void CDT(); | ||||
| void CAT() { CBT(); CBT(); CBT(); } | ||||
| void CCT() { CDT(); CDT(); CBT(); } | ||||
|  | ||||
| // not recursive | ||||
|  | ||||
| void norA() {} | ||||
| void norB() { norA(); } | ||||
| void norC() { norA(); } | ||||
| void norD() { norA(); } | ||||
| void norE() { norB(); } | ||||
| void norF() { norB(); } | ||||
| void norG() { norE(); } | ||||
| void norH() { norE(); } | ||||
| void norI() { norE(); } | ||||
|  | ||||
| // not recursive, but with a call leading into a cycle if ignoring direction | ||||
|  | ||||
| void norcA() { } | ||||
| void norcB() { norcA(); } | ||||
| void norcC() { norcB(); } | ||||
| void norcD() { norcC(); norcB(); } // head of cycle | ||||
| void norcE() { norcD(); } // lead into cycle | ||||
							
								
								
									
										642
									
								
								samples/Game Maker Language/ClientBeginStep.gml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										642
									
								
								samples/Game Maker Language/ClientBeginStep.gml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,642 @@ | ||||
| /* | ||||
|     Originally from /Source/gg2/Scripts/Client/ClientBeginStep.gml in Gang Garrison 2 | ||||
|  | ||||
|     Copyright (C) 2008-2013 Faucet Software | ||||
|     http://www.ganggarrison.com | ||||
|  | ||||
|     This program is free software;  | ||||
|     you can redistribute it and/or modify it under the terms of the GNU General Public License | ||||
|     as published by the Free Software Foundation; either version 3 of the License, or (at your option) | ||||
|     any later version. | ||||
|     This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;  | ||||
|     without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  | ||||
|     See the GNU General Public License for more details. | ||||
|     You should have received a copy of the GNU General Public License along with this program; if not, | ||||
|     see <http://www.gnu.org/licenses>. | ||||
|  | ||||
|     Additional permission under GNU GPL version 3 section 7 | ||||
|     If you modify this Program, or any covered work, by linking or combining it with the Game Maker runtime library,  | ||||
|     the 39dll library/extension, Hobbel's Download Manager DLL, or modified versions of these libraries, | ||||
|     the licensors of this Program grant you additional permission to convey the resulting work. | ||||
| */ | ||||
|  | ||||
| // receive and interpret the server's message(s) | ||||
| var i, playerObject, playerID, player, otherPlayerID, otherPlayer, sameVersion, buffer, plugins, pluginsRequired, usePlugins; | ||||
|  | ||||
| if(tcp_eof(global.serverSocket)) { | ||||
|     if(gotServerHello) | ||||
|         show_message("You have been disconnected from the server."); | ||||
|     else | ||||
|         show_message("Unable to connect to the server."); | ||||
|     instance_destroy(); | ||||
|     exit; | ||||
| } | ||||
|  | ||||
| if(room == DownloadRoom and keyboard_check(vk_escape)) | ||||
| { | ||||
|     instance_destroy(); | ||||
|     exit; | ||||
| } | ||||
|  | ||||
| if(downloadingMap) | ||||
| { | ||||
|     while(tcp_receive(global.serverSocket, min(1024, downloadMapBytes-buffer_size(downloadMapBuffer)))) | ||||
|     { | ||||
|         write_buffer(downloadMapBuffer, global.serverSocket); | ||||
|         if(buffer_size(downloadMapBuffer) == downloadMapBytes) | ||||
|         { | ||||
|             write_buffer_to_file(downloadMapBuffer, "Maps/" + downloadMapName + ".png"); | ||||
|             downloadingMap = false; | ||||
|             buffer_destroy(downloadMapBuffer); | ||||
|             downloadMapBuffer = -1; | ||||
|             exit; | ||||
|         } | ||||
|     } | ||||
|     exit; | ||||
| } | ||||
|  | ||||
| roomchange = false; | ||||
| do { | ||||
|     if(tcp_receive(global.serverSocket,1)) { | ||||
|         switch(read_ubyte(global.serverSocket)) { | ||||
|         case HELLO: | ||||
|             gotServerHello = true; | ||||
|             global.joinedServerName = receivestring(global.serverSocket, 1); | ||||
|             downloadMapName = receivestring(global.serverSocket, 1); | ||||
|             advertisedMapMd5 = receivestring(global.serverSocket, 1); | ||||
|             receiveCompleteMessage(global.serverSocket, 1, global.tempBuffer); | ||||
|             pluginsRequired = read_ubyte(global.tempBuffer); | ||||
|             plugins = receivestring(global.serverSocket, 1); | ||||
|             if(string_pos("/", downloadMapName) != 0 or string_pos("\", downloadMapName) != 0) | ||||
|             { | ||||
|                 show_message("Server sent illegal map name: "+downloadMapName); | ||||
|                 instance_destroy(); | ||||
|                 exit; | ||||
|             } | ||||
|  | ||||
|             if (!noReloadPlugins && string_length(plugins)) | ||||
|             { | ||||
|                 usePlugins = pluginsRequired || !global.serverPluginsPrompt; | ||||
|                 if (global.serverPluginsPrompt) | ||||
|                 { | ||||
|                     var prompt; | ||||
|                     if (pluginsRequired) | ||||
|                     { | ||||
|                         prompt = show_question( | ||||
|                             "This server requires the following plugins to play on it: " | ||||
|                             + string_replace_all(plugins, ",", "#") | ||||
|                             + '#They are downloaded from the source: "' | ||||
|                             + PLUGIN_SOURCE | ||||
|                             + '"#The source states: "' | ||||
|                             + PLUGIN_SOURCE_NOTICE | ||||
|                             + '"#Do you wish to download them and continue connecting?' | ||||
|                         ); | ||||
|                         if (!prompt) | ||||
|                         { | ||||
|                             instance_destroy(); | ||||
|                             exit; | ||||
|                         } | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         prompt = show_question( | ||||
|                             "This server suggests the following optional plugins to play on it: " | ||||
|                             + string_replace_all(plugins, ",", "#") | ||||
|                             + '#They are downloaded from the source: "' | ||||
|                             + PLUGIN_SOURCE | ||||
|                             + '"#The source states: "' | ||||
|                             + PLUGIN_SOURCE_NOTICE | ||||
|                             + '"#Do you wish to download them and use them?' | ||||
|                         ); | ||||
|                         if (prompt) | ||||
|                         { | ||||
|                             usePlugins = true; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 if (usePlugins) | ||||
|                 { | ||||
|                     if (!loadserverplugins(plugins)) | ||||
|                     { | ||||
|                         show_message("Error ocurred loading server-sent plugins."); | ||||
|                         instance_destroy(); | ||||
|                         exit; | ||||
|                     } | ||||
|                     global.serverPluginsInUse = true; | ||||
|                 } | ||||
|             } | ||||
|             noReloadPlugins = false; | ||||
|              | ||||
|             if(advertisedMapMd5 != "") | ||||
|             { | ||||
|                 var download; | ||||
|                 download = not file_exists("Maps/" + downloadMapName + ".png"); | ||||
|                 if(!download and CustomMapGetMapMD5(downloadMapName) != advertisedMapMd5) | ||||
|                 { | ||||
|                     if(show_question("The server's copy of the map (" + downloadMapName + ") differs from ours.#Would you like to download this server's version of the map?")) | ||||
|                         download = true; | ||||
|                     else | ||||
|                     { | ||||
|                         instance_destroy(); | ||||
|                         exit; | ||||
|                     } | ||||
|                 } | ||||
|                  | ||||
|                 if(download) | ||||
|                 { | ||||
|                     write_ubyte(global.serverSocket, DOWNLOAD_MAP); | ||||
|                     socket_send(global.serverSocket); | ||||
|                     receiveCompleteMessage(global.serverSocket,4,global.tempBuffer); | ||||
|                     downloadMapBytes = read_uint(global.tempBuffer); | ||||
|                     downloadMapBuffer = buffer_create(); | ||||
|                     downloadingMap = true; | ||||
|                     roomchange=true; | ||||
|                 } | ||||
|             } | ||||
|             ClientPlayerJoin(global.serverSocket); | ||||
|             if(global.rewardKey != "" and global.rewardId != "") | ||||
|             { | ||||
|                 var rewardId; | ||||
|                 rewardId = string_copy(global.rewardId, 0, 255); | ||||
|                 write_ubyte(global.serverSocket, REWARD_REQUEST); | ||||
|                 write_ubyte(global.serverSocket, string_length(rewardId)); | ||||
|                 write_string(global.serverSocket, rewardId); | ||||
|             } | ||||
|             if(global.queueJumping == true) | ||||
|             { | ||||
|                 write_ubyte(global.serverSocket, CLIENT_SETTINGS); | ||||
|                 write_ubyte(global.serverSocket, global.queueJumping); | ||||
|             } | ||||
|             socket_send(global.serverSocket); | ||||
|             break; | ||||
|              | ||||
|         case JOIN_UPDATE: | ||||
|             receiveCompleteMessage(global.serverSocket,2,global.tempBuffer); | ||||
|             global.playerID = read_ubyte(global.tempBuffer); | ||||
|             global.currentMapArea = read_ubyte(global.tempBuffer); | ||||
|             break; | ||||
|          | ||||
|         case FULL_UPDATE: | ||||
|             deserializeState(FULL_UPDATE); | ||||
|             break; | ||||
|          | ||||
|         case QUICK_UPDATE: | ||||
|             deserializeState(QUICK_UPDATE); | ||||
|             break; | ||||
|               | ||||
|         case CAPS_UPDATE: | ||||
|             deserializeState(CAPS_UPDATE); | ||||
|             break; | ||||
|                    | ||||
|         case INPUTSTATE: | ||||
|             deserializeState(INPUTSTATE); | ||||
|             break;              | ||||
|          | ||||
|         case PLAYER_JOIN: | ||||
|             player = instance_create(0,0,Player); | ||||
|             player.name = receivestring(global.serverSocket, 1); | ||||
|                    | ||||
|             ds_list_add(global.players, player); | ||||
|             if(ds_list_size(global.players)-1 == global.playerID) { | ||||
|                 global.myself = player; | ||||
|                 instance_create(0,0,PlayerControl); | ||||
|             } | ||||
|             break; | ||||
|              | ||||
|         case PLAYER_LEAVE: | ||||
|             // Delete player from the game, adjust own ID accordingly | ||||
|             receiveCompleteMessage(global.serverSocket,1,global.tempBuffer); | ||||
|             playerID = read_ubyte(global.tempBuffer); | ||||
|             player = ds_list_find_value(global.players, playerID); | ||||
|             removePlayer(player); | ||||
|             if(playerID < global.playerID) { | ||||
|                 global.playerID -= 1; | ||||
|             } | ||||
|             break; | ||||
|                                     | ||||
|         case PLAYER_DEATH: | ||||
|             var causeOfDeath, assistantPlayerID, assistantPlayer; | ||||
|             receiveCompleteMessage(global.serverSocket,4,global.tempBuffer); | ||||
|             playerID = read_ubyte(global.tempBuffer); | ||||
|             otherPlayerID = read_ubyte(global.tempBuffer); | ||||
|             assistantPlayerID = read_ubyte(global.tempBuffer); | ||||
|             causeOfDeath = read_ubyte(global.tempBuffer); | ||||
|                    | ||||
|             player = ds_list_find_value(global.players, playerID); | ||||
|              | ||||
|             otherPlayer = noone; | ||||
|             if(otherPlayerID != 255) | ||||
|                 otherPlayer = ds_list_find_value(global.players, otherPlayerID); | ||||
|              | ||||
|             assistantPlayer = noone; | ||||
|             if(assistantPlayerID != 255) | ||||
|                 assistantPlayer = ds_list_find_value(global.players, assistantPlayerID); | ||||
|              | ||||
|             doEventPlayerDeath(player, otherPlayer, assistantPlayer, causeOfDeath); | ||||
|             break; | ||||
|               | ||||
|         case BALANCE: | ||||
|             receiveCompleteMessage(global.serverSocket,1,global.tempBuffer); | ||||
|             balanceplayer=read_ubyte(global.tempBuffer); | ||||
|             if balanceplayer == 255 { | ||||
|                 if !instance_exists(Balancer) instance_create(x,y,Balancer); | ||||
|                 with(Balancer) notice=0; | ||||
|             } else { | ||||
|                 player = ds_list_find_value(global.players, balanceplayer); | ||||
|                 if(player.object != -1) { | ||||
|                     with(player.object) { | ||||
|                         instance_destroy(); | ||||
|                     } | ||||
|                     player.object = -1; | ||||
|                 } | ||||
|                 if(player.team==TEAM_RED) { | ||||
|                     player.team = TEAM_BLUE; | ||||
|                 } else { | ||||
|                     player.team = TEAM_RED; | ||||
|                 } | ||||
|                 if !instance_exists(Balancer) instance_create(x,y,Balancer); | ||||
|                 Balancer.name=player.name; | ||||
|                 with (Balancer) notice=1; | ||||
|             } | ||||
|             break; | ||||
|                    | ||||
|         case PLAYER_CHANGETEAM: | ||||
|             receiveCompleteMessage(global.serverSocket,2,global.tempBuffer); | ||||
|             player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer)); | ||||
|             if(player.object != -1) { | ||||
|                 with(player.object) { | ||||
|                     instance_destroy(); | ||||
|                 } | ||||
|                 player.object = -1; | ||||
|             } | ||||
|             player.team = read_ubyte(global.tempBuffer); | ||||
|             break; | ||||
|               | ||||
|         case PLAYER_CHANGECLASS: | ||||
|             receiveCompleteMessage(global.serverSocket,2,global.tempBuffer); | ||||
|             player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer)); | ||||
|             if(player.object != -1) { | ||||
|                 with(player.object) { | ||||
|                     instance_destroy(); | ||||
|                 } | ||||
|                 player.object = -1; | ||||
|             } | ||||
|             player.class = read_ubyte(global.tempBuffer); | ||||
|             break;              | ||||
|          | ||||
|         case PLAYER_CHANGENAME: | ||||
|             receiveCompleteMessage(global.serverSocket,1,global.tempBuffer); | ||||
|             player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer)); | ||||
|             player.name = receivestring(global.serverSocket, 1); | ||||
|             if player=global.myself { | ||||
|                 global.playerName=player.name | ||||
|             } | ||||
|             break; | ||||
|                   | ||||
|         case PLAYER_SPAWN: | ||||
|             receiveCompleteMessage(global.serverSocket,3,global.tempBuffer); | ||||
|             player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer)); | ||||
|             doEventSpawn(player, read_ubyte(global.tempBuffer), read_ubyte(global.tempBuffer)); | ||||
|             break; | ||||
|                | ||||
|         case CHAT_BUBBLE: | ||||
|             var bubbleImage; | ||||
|             receiveCompleteMessage(global.serverSocket,2,global.tempBuffer); | ||||
|             player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer)); | ||||
|             setChatBubble(player, read_ubyte(global.tempBuffer)); | ||||
|             break; | ||||
|               | ||||
|         case BUILD_SENTRY: | ||||
|             receiveCompleteMessage(global.serverSocket,6,global.tempBuffer); | ||||
|             player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer)); | ||||
|             buildSentry(player, read_ushort(global.tempBuffer)/5, read_ushort(global.tempBuffer)/5, read_byte(global.tempBuffer)); | ||||
|             break; | ||||
|                | ||||
|         case DESTROY_SENTRY: | ||||
|             receiveCompleteMessage(global.serverSocket,4,global.tempBuffer); | ||||
|             playerID = read_ubyte(global.tempBuffer); | ||||
|             otherPlayerID = read_ubyte(global.tempBuffer); | ||||
|             assistantPlayerID = read_ubyte(global.tempBuffer); | ||||
|             causeOfDeath = read_ubyte(global.tempBuffer); | ||||
|              | ||||
|             player = ds_list_find_value(global.players, playerID); | ||||
|             if(otherPlayerID == 255) { | ||||
|                 doEventDestruction(player, noone, noone, causeOfDeath); | ||||
|             } else { | ||||
|                 otherPlayer = ds_list_find_value(global.players, otherPlayerID); | ||||
|                 if (assistantPlayerID == 255) { | ||||
|                     doEventDestruction(player, otherPlayer, noone, causeOfDeath); | ||||
|                 } else { | ||||
|                     assistantPlayer = ds_list_find_value(global.players, assistantPlayerID); | ||||
|                     doEventDestruction(player, otherPlayer, assistantPlayer, causeOfDeath); | ||||
|                 } | ||||
|             } | ||||
|             break; | ||||
|                        | ||||
|         case GRAB_INTEL: | ||||
|             receiveCompleteMessage(global.serverSocket,1,global.tempBuffer); | ||||
|             player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer)); | ||||
|             doEventGrabIntel(player); | ||||
|             break; | ||||
|        | ||||
|         case SCORE_INTEL: | ||||
|             receiveCompleteMessage(global.serverSocket,1,global.tempBuffer); | ||||
|             player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer)); | ||||
|             doEventScoreIntel(player); | ||||
|             break; | ||||
|        | ||||
|         case DROP_INTEL: | ||||
|             receiveCompleteMessage(global.serverSocket,1,global.tempBuffer); | ||||
|             player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer)); | ||||
|             doEventDropIntel(player);  | ||||
|             break; | ||||
|              | ||||
|         case RETURN_INTEL: | ||||
|             receiveCompleteMessage(global.serverSocket,1,global.tempBuffer); | ||||
|             doEventReturnIntel(read_ubyte(global.tempBuffer)); | ||||
|             break; | ||||
|    | ||||
|         case GENERATOR_DESTROY: | ||||
|             receiveCompleteMessage(global.serverSocket,1,global.tempBuffer); | ||||
|             team = read_ubyte(global.tempBuffer); | ||||
|             doEventGeneratorDestroy(team); | ||||
|             break; | ||||
|        | ||||
|         case UBER_CHARGED: | ||||
|             receiveCompleteMessage(global.serverSocket,1,global.tempBuffer); | ||||
|             player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer)); | ||||
|             doEventUberReady(player); | ||||
|             break; | ||||
|    | ||||
|         case UBER: | ||||
|             receiveCompleteMessage(global.serverSocket,1,global.tempBuffer); | ||||
|             player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer)); | ||||
|             doEventUber(player); | ||||
|             break;     | ||||
|    | ||||
|         case OMNOMNOMNOM: | ||||
|             receiveCompleteMessage(global.serverSocket,1,global.tempBuffer); | ||||
|             player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer)); | ||||
|             if(player.object != -1) { | ||||
|                 with(player.object) { | ||||
|                     omnomnomnom=true; | ||||
|                     if(hp < 200) | ||||
|                     { | ||||
|                         canEat = false; | ||||
|                         alarm[6] = eatCooldown; //10 second cooldown | ||||
|                     } | ||||
|                     if(player.team == TEAM_RED) { | ||||
|                         omnomnomnomindex=0; | ||||
|                         omnomnomnomend=31; | ||||
|                     } else if(player.team==TEAM_BLUE) { | ||||
|                         omnomnomnomindex=32; | ||||
|                         omnomnomnomend=63; | ||||
|                     } | ||||
|                     xscale=image_xscale;  | ||||
|                 }  | ||||
|             } | ||||
|             break; | ||||
|        | ||||
|         case TOGGLE_ZOOM: | ||||
|             receiveCompleteMessage(global.serverSocket,1,global.tempBuffer); | ||||
|             player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer)); | ||||
|             if player.object != -1 { | ||||
|                 toggleZoom(player.object); | ||||
|             } | ||||
|             break; | ||||
|                                           | ||||
|         case PASSWORD_REQUEST: | ||||
|             if(!usePreviousPwd) | ||||
|                 global.clientPassword = get_string("Enter Password:", ""); | ||||
|             write_ubyte(global.serverSocket, string_length(global.clientPassword)); | ||||
|             write_string(global.serverSocket, global.clientPassword); | ||||
|             socket_send(global.serverSocket); | ||||
|             break; | ||||
|         | ||||
|         case PASSWORD_WRONG:                                     | ||||
|             show_message("Incorrect Password."); | ||||
|             instance_destroy(); | ||||
|             exit; | ||||
|          | ||||
|         case INCOMPATIBLE_PROTOCOL: | ||||
|             show_message("Incompatible server protocol version."); | ||||
|             instance_destroy(); | ||||
|             exit; | ||||
|              | ||||
|         case KICK: | ||||
|             receiveCompleteMessage(global.serverSocket,1,global.tempBuffer); | ||||
|             reason = read_ubyte(global.tempBuffer); | ||||
|             if reason == KICK_NAME kickReason = "Name Exploit"; | ||||
|             else if reason == KICK_BAD_PLUGIN_PACKET kickReason = "Invalid plugin packet ID"; | ||||
|             else if reason == KICK_MULTI_CLIENT kickReason = "There are too many connections from your IP"; | ||||
|             else kickReason = ""; | ||||
|             show_message("You have been kicked from the server. "+kickReason+"."); | ||||
|             instance_destroy(); | ||||
|             exit; | ||||
|                | ||||
|         case ARENA_STARTROUND: | ||||
|             doEventArenaStartRound(); | ||||
|             break; | ||||
|              | ||||
|         case ARENA_ENDROUND: | ||||
|             with ArenaHUD clientArenaEndRound(); | ||||
|             break;    | ||||
|          | ||||
|         case ARENA_RESTART: | ||||
|             doEventArenaRestart(); | ||||
|             break; | ||||
|              | ||||
|         case UNLOCKCP: | ||||
|             doEventUnlockCP(); | ||||
|             break; | ||||
|                     | ||||
|         case MAP_END: | ||||
|             global.nextMap=receivestring(global.serverSocket, 1); | ||||
|             receiveCompleteMessage(global.serverSocket,2,global.tempBuffer); | ||||
|             global.winners=read_ubyte(global.tempBuffer); | ||||
|             global.currentMapArea=read_ubyte(global.tempBuffer); | ||||
|             global.mapchanging = true; | ||||
|             if !instance_exists(ScoreTableController) instance_create(0,0,ScoreTableController); | ||||
|             instance_create(0,0,WinBanner); | ||||
|             break; | ||||
|  | ||||
|         case CHANGE_MAP: | ||||
|             roomchange=true; | ||||
|             global.mapchanging = false; | ||||
|             global.currentMap = receivestring(global.serverSocket, 1); | ||||
|             global.currentMapMD5 = receivestring(global.serverSocket, 1); | ||||
|             if(global.currentMapMD5 == "") { // if this is an internal map (signified by the lack of an md5) | ||||
|                 if(findInternalMapRoom(global.currentMap)) | ||||
|                     room_goto_fix(findInternalMapRoom(global.currentMap)); | ||||
|                 else | ||||
|                 { | ||||
|                     show_message("Error:#Server went to invalid internal map: " + global.currentMap + "#Exiting."); | ||||
|                     instance_destroy(); | ||||
|                     exit; | ||||
|                 } | ||||
|             } else { // it's an external map | ||||
|                 if(string_pos("/", global.currentMap) != 0 or string_pos("\", global.currentMap) != 0) | ||||
|                 { | ||||
|                     show_message("Server sent illegal map name: "+global.currentMap); | ||||
|                     instance_destroy(); | ||||
|                     exit; | ||||
|                 } | ||||
|                 if(!file_exists("Maps/" + global.currentMap + ".png") or CustomMapGetMapMD5(global.currentMap) != global.currentMapMD5) | ||||
|                 {   // Reconnect to the server to download the map | ||||
|                     var oldReturnRoom; | ||||
|                     oldReturnRoom = returnRoom; | ||||
|                     returnRoom = DownloadRoom; | ||||
|                     if (global.serverPluginsInUse) | ||||
|                         noUnloadPlugins = true; | ||||
|                     event_perform(ev_destroy,0); | ||||
|                     ClientCreate(); | ||||
|                     if (global.serverPluginsInUse) | ||||
|                         noReloadPlugins = true; | ||||
|                     returnRoom = oldReturnRoom; | ||||
|                     usePreviousPwd = true; | ||||
|                     exit; | ||||
|                 } | ||||
|                 room_goto_fix(CustomMapRoom); | ||||
|             } | ||||
|                   | ||||
|             for(i=0; i<ds_list_size(global.players); i+=1) { | ||||
|                 player = ds_list_find_value(global.players, i); | ||||
|                 if global.currentMapArea == 1 {  | ||||
|                     player.stats[KILLS] = 0; | ||||
|                     player.stats[DEATHS] = 0; | ||||
|                     player.stats[CAPS] = 0; | ||||
|                     player.stats[ASSISTS] = 0; | ||||
|                     player.stats[DESTRUCTION] = 0; | ||||
|                     player.stats[STABS] = 0; | ||||
|                     player.stats[HEALING] = 0; | ||||
|                     player.stats[DEFENSES] = 0; | ||||
|                     player.stats[INVULNS] = 0; | ||||
|                     player.stats[BONUS] = 0; | ||||
|                     player.stats[DOMINATIONS] = 0; | ||||
|                     player.stats[REVENGE] = 0; | ||||
|                     player.stats[POINTS] = 0; | ||||
|                     player.roundStats[KILLS] = 0; | ||||
|                     player.roundStats[DEATHS] = 0; | ||||
|                     player.roundStats[CAPS] = 0; | ||||
|                     player.roundStats[ASSISTS] = 0; | ||||
|                     player.roundStats[DESTRUCTION] = 0; | ||||
|                     player.roundStats[STABS] = 0; | ||||
|                     player.roundStats[HEALING] = 0; | ||||
|                     player.roundStats[DEFENSES] = 0; | ||||
|                     player.roundStats[INVULNS] = 0; | ||||
|                     player.roundStats[BONUS] = 0; | ||||
|                     player.roundStats[DOMINATIONS] = 0; | ||||
|                     player.roundStats[REVENGE] = 0; | ||||
|                     player.roundStats[POINTS] = 0; | ||||
|                     player.team = TEAM_SPECTATOR; | ||||
|                 } | ||||
|             } | ||||
|             break; | ||||
|          | ||||
|         case SERVER_FULL: | ||||
|             show_message("The server is full."); | ||||
|             instance_destroy(); | ||||
|             exit; | ||||
|          | ||||
|         case REWARD_CHALLENGE_CODE: | ||||
|             var challengeData; | ||||
|             receiveCompleteMessage(global.serverSocket,16,global.tempBuffer); | ||||
|             challengeData = read_binstring(global.tempBuffer, buffer_size(global.tempBuffer)); | ||||
|             challengeData += socket_remote_ip(global.serverSocket); | ||||
|  | ||||
|             write_ubyte(global.serverSocket, REWARD_CHALLENGE_RESPONSE); | ||||
|             write_binstring(global.serverSocket, hmac_md5_bin(global.rewardKey, challengeData)); | ||||
|             socket_send(global.serverSocket); | ||||
|             break; | ||||
|  | ||||
|         case REWARD_UPDATE: | ||||
|             receiveCompleteMessage(global.serverSocket,1,global.tempBuffer); | ||||
|             player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer)); | ||||
|             var rewardString; | ||||
|             rewardString = receivestring(global.serverSocket, 2); | ||||
|             doEventUpdateRewards(player, rewardString); | ||||
|             break; | ||||
|              | ||||
|         case MESSAGE_STRING: | ||||
|             var message, notice; | ||||
|             message = receivestring(global.serverSocket, 1); | ||||
|             with NoticeO instance_destroy(); | ||||
|             notice = instance_create(0, 0, NoticeO); | ||||
|             notice.notice = NOTICE_CUSTOM; | ||||
|             notice.message = message; | ||||
|             break; | ||||
|          | ||||
|         case SENTRY_POSITION: | ||||
|             receiveCompleteMessage(global.serverSocket,5,global.tempBuffer); | ||||
|             player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer)); | ||||
|             if(player.sentry) | ||||
|             { | ||||
|                 player.sentry.x = read_ushort(global.tempBuffer) / 5; | ||||
|                 player.sentry.y = read_ushort(global.tempBuffer) / 5; | ||||
|                 player.sentry.xprevious = player.sentry.x; | ||||
|                 player.sentry.yprevious = player.sentry.y; | ||||
|                 player.sentry.vspeed = 0; | ||||
|             } | ||||
|             break; | ||||
|            | ||||
|         case WEAPON_FIRE: | ||||
|             receiveCompleteMessage(global.serverSocket,9,global.tempBuffer); | ||||
|             player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer)); | ||||
|              | ||||
|             if(player.object) | ||||
|             { | ||||
|                 with(player.object) | ||||
|                 { | ||||
|                     x = read_ushort(global.tempBuffer)/5; | ||||
|                     y = read_ushort(global.tempBuffer)/5; | ||||
|                     hspeed = read_byte(global.tempBuffer)/8.5; | ||||
|                     vspeed = read_byte(global.tempBuffer)/8.5; | ||||
|                     xprevious = x; | ||||
|                     yprevious = y; | ||||
|                 } | ||||
|                  | ||||
|                 doEventFireWeapon(player, read_ushort(global.tempBuffer)); | ||||
|             } | ||||
|             break; | ||||
|  | ||||
|         case PLUGIN_PACKET: | ||||
|             var packetID, packetLen, buf, success; | ||||
|  | ||||
|             // fetch full packet | ||||
|             receiveCompleteMessage(global.serverSocket, 2, global.tempBuffer); | ||||
|             packetLen = read_ushort(global.tempBuffer); | ||||
|             receiveCompleteMessage(global.serverSocket, packetLen, global.tempBuffer); | ||||
|  | ||||
|             packetID = read_ubyte(global.tempBuffer); | ||||
|  | ||||
|             // get packet data | ||||
|             buf = buffer_create(); | ||||
|             write_buffer_part(buf, global.tempBuffer, packetLen - 1); | ||||
|  | ||||
|             // try to enqueue | ||||
|             // give "noone" value for client since received from server | ||||
|             success = _PluginPacketPush(packetID, buf, noone); | ||||
|              | ||||
|             // if it returned false, packetID was invalid | ||||
|             if (!success) | ||||
|             { | ||||
|                 // clear up buffer | ||||
|                 buffer_destroy(buf); | ||||
|                 show_error("ERROR when reading plugin packet: no such plugin packet ID " + string(packetID), true); | ||||
|             } | ||||
|             break; | ||||
|          | ||||
|         case CLIENT_SETTINGS: | ||||
|             receiveCompleteMessage(global.serverSocket,2,global.tempBuffer); | ||||
|             player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer)); | ||||
|             player.queueJump = read_ubyte(global.tempBuffer); | ||||
|             break; | ||||
|  | ||||
|         default: | ||||
|             promptRestartOrQuit("The Server sent unexpected data."); | ||||
|             exit; | ||||
|         } | ||||
|     } else { | ||||
|         break; | ||||
|     } | ||||
| } until(roomchange); | ||||
							
								
								
									
										141
									
								
								samples/Game Maker Language/Create.gml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								samples/Game Maker Language/Create.gml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | ||||
| /* | ||||
|     Originally from /Source/gg2/Objects/Updater.events/Create.xml in Gang Garrison 2 | ||||
|  | ||||
|     Copyright (C) 2008-2013 Faucet Software | ||||
|     http://www.ganggarrison.com | ||||
|  | ||||
|     This program is free software;  | ||||
|     you can redistribute it and/or modify it under the terms of the GNU General Public License | ||||
|     as published by the Free Software Foundation; either version 3 of the License, or (at your option) | ||||
|     any later version. | ||||
|     This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;  | ||||
|     without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  | ||||
|     See the GNU General Public License for more details. | ||||
|     You should have received a copy of the GNU General Public License along with this program; if not, | ||||
|     see <http://www.gnu.org/licenses>. | ||||
|  | ||||
|     Additional permission under GNU GPL version 3 section 7 | ||||
|     If you modify this Program, or any covered work, by linking or combining it with the Game Maker runtime library,  | ||||
|     the 39dll library/extension, Hobbel's Download Manager DLL, or modified versions of these libraries, | ||||
|     the licensors of this Program grant you additional permission to convey the resulting work. | ||||
| */ | ||||
| // Downloading code.  | ||||
|  | ||||
| var downloadHandle, url, tmpfile, window_oldshowborder, window_oldfullscreen; | ||||
| timeLeft = 0; | ||||
| counter = 0; | ||||
| AudioControlPlaySong(-1, false); | ||||
| window_oldshowborder = window_get_showborder(); | ||||
| window_oldfullscreen = window_get_fullscreen(); | ||||
| window_set_fullscreen(false); | ||||
| window_set_showborder(false); | ||||
|  | ||||
| if(global.updaterBetaChannel) | ||||
|     url = UPDATE_SOURCE_BETA; | ||||
| else | ||||
|     url = UPDATE_SOURCE; | ||||
|  | ||||
| tmpfile = temp_directory + "\gg2update.zip"; | ||||
|      | ||||
| downloadHandle = httpGet(url, -1); | ||||
|  | ||||
| while(!httpRequestStatus(downloadHandle))  | ||||
| { // while download isn't finished | ||||
|     sleep(floor(1000/30)); // sleep for the equivalent of one frame | ||||
|     io_handle(); // this prevents GameMaker from appearing locked-up | ||||
|     httpRequestStep(downloadHandle); | ||||
|      | ||||
|     // check if the user cancelled the download with the esc key | ||||
|     if(keyboard_check(vk_escape))  | ||||
|     { | ||||
|         httpRequestDestroy(downloadHandle); | ||||
|         window_set_showborder(window_oldshowborder); | ||||
|         window_set_fullscreen(window_oldfullscreen); | ||||
|         room_goto_fix(Menu); | ||||
|         exit; | ||||
|     } | ||||
|       | ||||
|     if(counter == 0 || counter mod 60 == 0) | ||||
|         timer = random(359)+1; | ||||
|     draw_sprite(UpdaterBackgroundS,0,0,0); | ||||
|     draw_set_color(c_white); | ||||
|     draw_set_halign(fa_left); | ||||
|     draw_set_valign(fa_center); | ||||
|     minutes=floor(timer/60); | ||||
|     seconds=floor(timer-minutes*60); | ||||
|     draw_text(x,y-20,string(minutes) + " minutes " + string(seconds) + " seconds Remaining..."); | ||||
|     counter+=1; | ||||
|     var progress, size; | ||||
|     progress = httpRequestResponseBodyProgress(downloadHandle); | ||||
|     size = httpRequestResponseBodySize(downloadHandle); | ||||
|     if (size != -1) | ||||
|     { | ||||
|         progressBar = floor((progress/size) * 20); | ||||
|         offset = 3; | ||||
|         for(i=0;i<progressBar;i+=1){ | ||||
|             draw_sprite(UpdaterProgressS,0,x+offset,y); | ||||
|             offset+=12; | ||||
|         } | ||||
|     } | ||||
|     screen_refresh(); | ||||
| } | ||||
| // Errored | ||||
| if (httpRequestStatus(downloadHandle) == 2) | ||||
| { | ||||
|     show_message("Downloading update failed!#" + httpRequestError(downloadHandle)); | ||||
|     httpRequestDestroy(downloadHandle); | ||||
|     window_set_showborder(window_oldshowborder); | ||||
|     window_set_fullscreen(window_oldfullscreen); | ||||
|     room_goto_fix(Menu); | ||||
|     exit; | ||||
| } | ||||
| // Request failed | ||||
| if (httpRequestStatusCode(downloadHandle) != 200) | ||||
| { | ||||
|     show_message("Downloading update failed!#" + string(httpRequestStatusCode(downloadHandle)) + " " + httpRequestReasonPhrase(downloadHandle)); | ||||
|     httpRequestDestroy(downloadHandle); | ||||
|     window_set_showborder(window_oldshowborder); | ||||
|     window_set_fullscreen(window_oldfullscreen); | ||||
|     room_goto_fix(Menu); | ||||
|     exit; | ||||
| } | ||||
|  | ||||
| write_buffer_to_file(httpRequestResponseBody(downloadHandle), tmpfile); | ||||
| httpRequestDestroy(downloadHandle); | ||||
|  | ||||
| if(!file_exists(tmpfile)) | ||||
| { | ||||
|     window_set_showborder(window_oldshowborder); | ||||
|     window_set_fullscreen(window_oldfullscreen); | ||||
|     show_message("Error updating: Missing gg2update.zip in temp directory, download failed(?)"); | ||||
|     room_goto_fix(Menu); | ||||
|     exit; | ||||
| } | ||||
|  | ||||
| // rename existing "Gang Garrison 2.exe" to avoid conflict when extracting | ||||
| if (file_exists("Gang Garrison 2.exe")) | ||||
| { | ||||
|     var newName, n; | ||||
|     n = 1; | ||||
|      | ||||
|     // increment until unused name found | ||||
|     do | ||||
|     { | ||||
|         newName = "gg2-old.delete.me." + string(n); | ||||
|         n += 1; | ||||
|     } | ||||
|     until(!file_exists(newName)); | ||||
|  | ||||
|     file_rename("Gang Garrison 2.exe", newName); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| // let's extract the downloaded file now. | ||||
| extractzip(tmpfile, working_directory); | ||||
|  | ||||
| // run new version     | ||||
| execute_program("Gang Garrison 2.exe", "", false); | ||||
|  | ||||
| // exit | ||||
| game_end(); | ||||
							
								
								
									
										161
									
								
								samples/Game Maker Language/Draw.gml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								samples/Game Maker Language/Draw.gml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,161 @@ | ||||
| /* | ||||
|     Originally from /Source/gg2/Objects/InGameElements/Character.events/Draw.xml in Gang Garrison 2 | ||||
|  | ||||
|     Copyright (C) 2008-2013 Faucet Software | ||||
|     http://www.ganggarrison.com | ||||
|  | ||||
|     This program is free software;  | ||||
|     you can redistribute it and/or modify it under the terms of the GNU General Public License | ||||
|     as published by the Free Software Foundation; either version 3 of the License, or (at your option) | ||||
|     any later version. | ||||
|     This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;  | ||||
|     without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  | ||||
|     See the GNU General Public License for more details. | ||||
|     You should have received a copy of the GNU General Public License along with this program; if not, | ||||
|     see <http://www.gnu.org/licenses>. | ||||
|  | ||||
|     Additional permission under GNU GPL version 3 section 7 | ||||
|     If you modify this Program, or any covered work, by linking or combining it with the Game Maker runtime library,  | ||||
|     the 39dll library/extension, Hobbel's Download Manager DLL, or modified versions of these libraries, | ||||
|     the licensors of this Program grant you additional permission to convey the resulting work. | ||||
| */ | ||||
|  | ||||
| xoffset = view_xview[0]; | ||||
| yoffset = view_yview[0]; | ||||
| xsize = view_wview[0]; | ||||
| ysize = view_hview[0]; | ||||
|  | ||||
| if (distance_to_point(xoffset+xsize/2,yoffset+ysize/2) > 800) | ||||
|     exit; | ||||
|  | ||||
| var xr, yr; | ||||
| xr = round(x); | ||||
| yr = round(y); | ||||
|      | ||||
| image_alpha = cloakAlpha; | ||||
|  | ||||
| if (global.myself.team == team and canCloak) | ||||
|     image_alpha = cloakAlpha/2 + 0.5; | ||||
|  | ||||
| if (invisible) | ||||
|     exit; | ||||
|  | ||||
| if(stabbing) | ||||
|     image_alpha -= power(currentWeapon.stab.alpha, 2); | ||||
|  | ||||
| if team == global.myself.team && (player != global.myself || global.showHealthBar == 1){ | ||||
|     draw_set_alpha(1); | ||||
|     draw_healthbar(xr-10, yr-30, xr+10, yr-25,hp*100/maxHp,c_black,c_red,c_green,0,true,true); | ||||
| }     | ||||
| if(distance_to_point(mouse_x, mouse_y)<25) { | ||||
|     if cloak && team!=global.myself.team exit; | ||||
|     draw_set_alpha(1); | ||||
|     draw_set_halign(fa_center); | ||||
|     draw_set_valign(fa_bottom); | ||||
|     if(team==TEAM_RED) { | ||||
|         draw_set_color(c_red); | ||||
|     } else { | ||||
|         draw_set_color(c_blue); | ||||
|     } | ||||
|     draw_text(xr, yr-35, player.name); | ||||
|      | ||||
|     if(team == global.myself.team && global.showTeammateStats) | ||||
|     { | ||||
|         if(weapons[0] == Medigun) | ||||
|             draw_text(xr,yr+50, "Superburst: " + string(currentWeapon.uberCharge/20) + "%"); | ||||
|         else if(weapons[0] == Shotgun) | ||||
|             draw_text(xr,yr+50, "Nuts 'N' Bolts: " + string(nutsNBolts)); | ||||
|         else if(weapons[0] == Minegun) | ||||
|             draw_text(xr,yr+50, "Lobbed Mines: " + string(currentWeapon.lobbed)); | ||||
|     } | ||||
| }   | ||||
|  | ||||
| draw_set_alpha(1); | ||||
| if team == TEAM_RED ubercolour = c_red; | ||||
| if team == TEAM_BLUE ubercolour = c_blue; | ||||
|  | ||||
| var sprite, overlaySprite; | ||||
| if zoomed | ||||
| { | ||||
|     if (team == TEAM_RED) | ||||
|         sprite = SniperCrouchRedS; | ||||
|     else | ||||
|         sprite = SniperCrouchBlueS; | ||||
|     overlaySprite = sniperCrouchOverlay; | ||||
| } | ||||
| else | ||||
| { | ||||
|     sprite = sprite_index; | ||||
|     overlaySprite = overlay; | ||||
| } | ||||
|      | ||||
| if (omnomnomnom) | ||||
| { | ||||
|     draw_sprite_ext_overlay(omnomnomnomSprite,omnomnomnomOverlay,omnomnomnomindex,xr,yr,image_xscale,image_yscale,image_angle,c_white,1); | ||||
|     if (ubered) | ||||
|         draw_sprite_ext_overlay(omnomnomnomSprite,omnomnomnomOverlay,omnomnomnomindex,xr,yr,image_xscale,image_yscale,image_angle,ubercolour,0.7); | ||||
| } | ||||
| else if (taunting) | ||||
| { | ||||
|     draw_sprite_ext_overlay(tauntsprite,tauntOverlay,tauntindex,xr,yr,image_xscale,image_yscale,image_angle,c_white,1); | ||||
|     if (ubered) | ||||
|         draw_sprite_ext_overlay(tauntsprite,tauntOverlay,tauntindex,xr,yr,image_xscale,image_yscale,image_angle,ubercolour,0.7); | ||||
| } | ||||
| else if (player.humiliated) | ||||
|     draw_sprite_ext(humiliationPoses,floor(animationImage)+humiliationOffset,xr,yr,image_xscale,image_yscale,image_angle,c_white,image_alpha); | ||||
| else if (!taunting) | ||||
| { | ||||
|     if (cloak) | ||||
|     { | ||||
|         if (!ubered) | ||||
|             draw_sprite_ext(sprite,floor(animationImage+animationOffset),xr,yr,image_xscale,image_yscale,image_angle,c_white,image_alpha); | ||||
|         else if (ubered) | ||||
|         { | ||||
|             draw_sprite_ext(sprite,floor(animationImage+animationOffset),xr,yr,image_xscale,image_yscale,image_angle,c_white,1); | ||||
|             draw_sprite_ext(sprite,floor(animationImage+animationOffset),xr,yr,image_xscale,image_yscale,image_angle,ubercolour,0.7); | ||||
|         } | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         if (!ubered) | ||||
|             draw_sprite_ext_overlay(sprite,overlaySprite,floor(animationImage+animationOffset),xr,yr,image_xscale,image_yscale,image_angle,c_white,image_alpha); | ||||
|         else if (ubered) | ||||
|         { | ||||
|             draw_sprite_ext_overlay(sprite,overlaySprite,floor(animationImage+animationOffset),xr,yr,image_xscale,image_yscale,image_angle,c_white,1); | ||||
|             draw_sprite_ext_overlay(sprite,overlaySprite,floor(animationImage+animationOffset),xr,yr,image_xscale,image_yscale,image_angle,ubercolour,0.7); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| if (burnDuration > 0 or burnIntensity > 0) { | ||||
|     for(i = 0; i < numFlames * burnIntensity / maxIntensity; i += 1) | ||||
|     { | ||||
|         draw_sprite_ext(FlameS, alarm[5] + i + random(2), x + flameArray_x[i], y + flameArray_y[i], 1, 1, 0, c_white, burnDuration / maxDuration * 0.71 + 0.35); | ||||
|     }   | ||||
| } | ||||
|  | ||||
| // Copied from Lorgan's itemserver "angels" with slight modifications | ||||
| // All credit be upon him | ||||
| if (demon != -1) | ||||
| { | ||||
|     demonX = median(x-40,demonX,x+40); | ||||
|     demonY = median(y-40,demonY,y); | ||||
|     demonOffset += demonDir; | ||||
|     if (abs(demonOffset) > 15) | ||||
|         demonDir *= -1; | ||||
|  | ||||
|     var dir; | ||||
|     if (demonX > x) | ||||
|         dir = -1; | ||||
|     else | ||||
|         dir = 1; | ||||
|  | ||||
|     if (demonFrame > sprite_get_number(demon)) | ||||
|         demonFrame = 0; | ||||
|  | ||||
|     if (stabbing || ubered) | ||||
|         draw_sprite_ext(demon,demonFrame+floor(animationImage)+7*player.team,demonX,demonY+demonOffset,dir*1,1,0,c_white,1); | ||||
|     else | ||||
|         draw_sprite_ext(demon,demonFrame+floor(animationImage)+7*player.team,demonX,demonY+demonOffset,dir*1,1,0,c_white,image_alpha); | ||||
|  | ||||
|     demonFrame += 1; | ||||
| } | ||||
							
								
								
									
										80
									
								
								samples/Game Maker Language/characterDrawEvent.gml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								samples/Game Maker Language/characterDrawEvent.gml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | ||||
| // Originally from /spelunky/Scripts/Platform Engine/characterDrawEvent.gml in the Spelunky Community Update Project | ||||
|  | ||||
| /********************************************************************************** | ||||
|     Copyright (c) 2008, 2009 Derek Yu and Mossmouth, LLC | ||||
|      | ||||
|     This file is part of Spelunky. | ||||
|  | ||||
|     You can redistribute and/or modify Spelunky, including its source code, under | ||||
|     the terms of the Spelunky User License. | ||||
|  | ||||
|     Spelunky is distributed in the hope that it will be entertaining and useful, | ||||
|     but WITHOUT WARRANTY. Please see the Spelunky User License for more details. | ||||
|  | ||||
|     The Spelunky User License should be available in "Game Information", which | ||||
|     can be found in the Resource Explorer, or as an external file called COPYING. | ||||
|     If not, please obtain a new copy of Spelunky from <http://spelunkyworld.com/> | ||||
|      | ||||
| ***********************************************************************************/ | ||||
|  | ||||
| /* | ||||
| This event should be placed in the draw event of the platform character. | ||||
| */ | ||||
| //draws the sprite | ||||
| draw = true; | ||||
| if (facing == RIGHT) image_xscale = -1; | ||||
| else image_xscale = 1; | ||||
|  | ||||
| if (blinkToggle != 1) | ||||
| { | ||||
|     if ((state == CLIMBING or (sprite_index == sPExit or sprite_index == sDamselExit or sprite_index == sTunnelExit)) and global.hasJetpack and not whipping) | ||||
|     { | ||||
|         draw_sprite_ext(sprite_index, -1, x, y, image_xscale, image_yscale, image_angle, image_blend, image_alpha); | ||||
|         //draw_sprite(sprite_index,-1,x,y); | ||||
|         draw_sprite(sJetpackBack,-1,x,y); | ||||
|         draw = false; | ||||
|     } | ||||
|     else if (global.hasJetpack and facing == RIGHT) draw_sprite(sJetpackRight,-1,x-4,y-1); | ||||
|     else if (global.hasJetpack) draw_sprite(sJetpackLeft,-1,x+4,y-1); | ||||
|     if (draw) | ||||
|     { | ||||
|         if (redColor > 0) draw_sprite_ext(sprite_index, -1, x, y, image_xscale, image_yscale, image_angle, make_color_rgb(200 + redColor,0,0), image_alpha); | ||||
|         else draw_sprite_ext(sprite_index, -1, x, y, image_xscale, image_yscale, image_angle, image_blend, image_alpha); | ||||
|     } | ||||
|     if (facing == RIGHT) | ||||
|     { | ||||
|         if (holdArrow == ARROW_NORM) | ||||
|         { | ||||
|             draw_sprite(sArrowRight, -1, x+4, y+1); | ||||
|         } | ||||
|         else if (holdArrow == ARROW_BOMB) | ||||
|         { | ||||
|             if (holdArrowToggle) draw_sprite(sBombArrowRight, 0, x+4, y+2); | ||||
|             else draw_sprite(sBombArrowRight, 1, x+4, y+2); | ||||
|         } | ||||
|     } | ||||
|     else if (facing == LEFT) | ||||
|     { | ||||
|         if (holdArrow == ARROW_NORM) | ||||
|         { | ||||
|             draw_sprite(sArrowLeft, -1, x-4, y+1); | ||||
|         } | ||||
|         else if (holdArrow == ARROW_BOMB) | ||||
|         { | ||||
|             if (holdArrowToggle) draw_sprite(sBombArrowLeft, 0, x-4, y+2); | ||||
|             else draw_sprite(sBombArrowLeft, 1, x-4, y+2); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| /* | ||||
| if canRun | ||||
| { | ||||
|   xOffset=80 | ||||
|   if player=1 | ||||
|     yOffset=120 | ||||
|   else | ||||
|     yOffset=143 | ||||
|   //draw the "flySpeed" bar, which shows how much speed the character has acquired while holding the "run" button | ||||
|   //draw_healthbar(view_xview[0]+224+xOffset,view_yview[0]+432+yOffset,view_xview[0]+400+xOffset,view_yview[0]+450+yOffset,flySpeed,make_color_rgb(0,64,128),c_blue,c_aqua,0,1,1) | ||||
| } | ||||
| */ | ||||
							
								
								
									
										1050
									
								
								samples/Game Maker Language/characterStepEvent.gml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1050
									
								
								samples/Game Maker Language/characterStepEvent.gml
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										251
									
								
								samples/Game Maker Language/doEventPlayerDeath.gml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								samples/Game Maker Language/doEventPlayerDeath.gml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,251 @@ | ||||
| /* | ||||
|     Originally from /Source/gg2/Scripts/Events/doEventPlayerDeath.gml in Gang Garrison 2 | ||||
|  | ||||
|     Copyright (C) 2008-2013 Faucet Software | ||||
|     http://www.ganggarrison.com | ||||
|  | ||||
|     This program is free software;  | ||||
|     you can redistribute it and/or modify it under the terms of the GNU General Public License | ||||
|     as published by the Free Software Foundation; either version 3 of the License, or (at your option) | ||||
|     any later version. | ||||
|     This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;  | ||||
|     without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  | ||||
|     See the GNU General Public License for more details. | ||||
|     You should have received a copy of the GNU General Public License along with this program; if not, | ||||
|     see <http://www.gnu.org/licenses>. | ||||
|  | ||||
|     Additional permission under GNU GPL version 3 section 7 | ||||
|     If you modify this Program, or any covered work, by linking or combining it with the Game Maker runtime library,  | ||||
|     the 39dll library/extension, Hobbel's Download Manager DLL, or modified versions of these libraries, | ||||
|     the licensors of this Program grant you additional permission to convey the resulting work. | ||||
| */ | ||||
|  | ||||
| /** | ||||
|  * Perform the "player death" event, i.e. change the appropriate scores, | ||||
|  * destroy the character object to much splattering and so on. | ||||
|  * | ||||
|  * argument0: The player whose character died | ||||
|  * argument1: The player who inflicted the fatal damage (or noone for unknown) | ||||
|  * argument2: The player who assisted the kill (or noone for no assist) | ||||
|  * argument3: The source of the fatal damage | ||||
|  */ | ||||
| var victim, killer, assistant, damageSource; | ||||
| victim = argument0; | ||||
| killer = argument1; | ||||
| assistant = argument2; | ||||
| damageSource = argument3; | ||||
|  | ||||
| if(!instance_exists(killer)) | ||||
|     killer = noone; | ||||
|  | ||||
| if(!instance_exists(assistant)) | ||||
|     assistant = noone; | ||||
|  | ||||
| //************************************* | ||||
| //*      Scoring and Kill log | ||||
| //************************************* | ||||
|   | ||||
|  | ||||
| recordKillInLog(victim, killer, assistant, damageSource); | ||||
|  | ||||
| victim.stats[DEATHS] += 1; | ||||
| if(killer) | ||||
| { | ||||
|     if(damageSource == WEAPON_KNIFE || damageSource == WEAPON_BACKSTAB) | ||||
|     { | ||||
|         killer.stats[STABS] += 1; | ||||
|         killer.roundStats[STABS] += 1; | ||||
|         killer.stats[POINTS] += 1; | ||||
|         killer.roundStats[POINTS] +=1; | ||||
|     } | ||||
|      | ||||
|     if (victim.object.currentWeapon.object_index == Medigun) | ||||
|     { | ||||
|         if (victim.object.currentWeapon.uberReady) | ||||
|         { | ||||
|             killer.stats[BONUS] += 1; | ||||
|             killer.roundStats[BONUS] += 1; | ||||
|             killer.stats[POINTS] += 1; | ||||
|             killer.roundStats[POINTS] += 1; | ||||
|         } | ||||
|     } | ||||
|          | ||||
|     if (killer != victim) | ||||
|     { | ||||
|         killer.stats[KILLS] += 1; | ||||
|         killer.roundStats[KILLS] += 1; | ||||
|         killer.stats[POINTS] += 1; | ||||
|         killer.roundStats[POINTS] += 1; | ||||
|         if(victim.object.intel) | ||||
|         { | ||||
|             killer.stats[DEFENSES] += 1; | ||||
|             killer.roundStats[DEFENSES] += 1; | ||||
|             killer.stats[POINTS] += 1; | ||||
|             killer.roundStats[POINTS] += 1; | ||||
|             recordEventInLog(4, killer.team, killer.name, global.myself == killer); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| if (assistant) | ||||
| { | ||||
|     assistant.stats[ASSISTS] += 1; | ||||
|     assistant.roundStats[ASSISTS] += 1; | ||||
|     assistant.stats[POINTS] += .5; | ||||
|     assistant.roundStats[POINTS] += .5; | ||||
| } | ||||
|  | ||||
| //SPEC | ||||
| if (victim == global.myself) | ||||
|     instance_create(victim.object.x, victim.object.y, Spectator); | ||||
|  | ||||
| //************************************* | ||||
| //*         Gibbing | ||||
| //************************************* | ||||
| var xoffset, yoffset, xsize, ysize; | ||||
|  | ||||
| xoffset = view_xview[0]; | ||||
| yoffset = view_yview[0]; | ||||
| xsize = view_wview[0]; | ||||
| ysize = view_hview[0]; | ||||
|  | ||||
| randomize(); | ||||
| with(victim.object) { | ||||
|     if((damageSource == WEAPON_ROCKETLAUNCHER  | ||||
|     or damageSource == WEAPON_MINEGUN or damageSource == FRAG_BOX  | ||||
|     or damageSource == WEAPON_REFLECTED_STICKY or damageSource == WEAPON_REFLECTED_ROCKET  | ||||
|     or damageSource == FINISHED_OFF_GIB or damageSource == GENERATOR_EXPLOSION)  | ||||
|     and (player.class != CLASS_QUOTE) and (global.gibLevel>1)  | ||||
|     and distance_to_point(xoffset+xsize/2,yoffset+ysize/2) < 900) { | ||||
|         if (hasReward(victim, 'PumpkinGibs')) | ||||
|         { | ||||
|             repeat(global.gibLevel * 2) { | ||||
|                 createGib(x,y,PumpkinGib,hspeed,vspeed,random(145)-72, choose(0,1,1,2,2,3), false, true) | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             repeat(global.gibLevel) { | ||||
|                 createGib(x,y,Gib,hspeed,vspeed,random(145)-72, 0, false) | ||||
|             } | ||||
|             switch(player.team) | ||||
|             { | ||||
|             case TEAM_BLUE : | ||||
|                 repeat(global.gibLevel - 1) { | ||||
|                     createGib(x,y,BlueClump,hspeed,vspeed,random(145)-72, 0, false) | ||||
|                 } | ||||
|                 break; | ||||
|             case TEAM_RED : | ||||
|                 repeat(global.gibLevel - 1) { | ||||
|                     createGib(x,y,RedClump,hspeed,vspeed,random(145)-72, 0, false) | ||||
|                 } | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         repeat(global.gibLevel * 14) { | ||||
|             var blood; | ||||
|             blood = instance_create(x+random(23)-11,y+random(23)-11,BloodDrop); | ||||
|             blood.hspeed=(random(21)-10); | ||||
|             blood.vspeed=(random(21)-13); | ||||
|             if (hasReward(victim, 'PumpkinGibs')) | ||||
|             { | ||||
|                 blood.sprite_index = PumpkinJuiceS; | ||||
|             } | ||||
|         } | ||||
|         if (!hasReward(victim, 'PumpkinGibs')) | ||||
|         { | ||||
|             //All Classes gib head, hands, and feet | ||||
|             if(global.gibLevel > 2 || choose(0,1) == 1) | ||||
|                 createGib(x,y,Headgib,0,0,random(105)-52, player.class, false); | ||||
|             repeat(global.gibLevel -1){ | ||||
|                 //Medic has specially colored hands | ||||
|                 if (player.class == CLASS_MEDIC){ | ||||
|                     if (player.team == TEAM_RED) | ||||
|                         createGib(x,y,Hand, hspeed, vspeed, random(105)-52 , 9, false); | ||||
|                     else | ||||
|                         createGib(x,y,Hand, hspeed, vspeed, random(105)-52 , 10, false); | ||||
|                 }else{ | ||||
|                     createGib(x,y,Hand, hspeed, vspeed, random(105)-52 , player.class, false); | ||||
|                 } | ||||
|                 createGib(x,y,Feet,random(5)-2,random(3),random(13)-6 , player.class, true); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         //Class specific gibs | ||||
|         switch(player.class) { | ||||
|         case CLASS_PYRO : | ||||
|             if(global.gibLevel > 2 || choose(0,1) == 1) | ||||
|                 createGib(x,y,Accesory,hspeed,vspeed,random(105)-52, 4, false) | ||||
|             break; | ||||
|         case CLASS_SOLDIER : | ||||
|             if(global.gibLevel > 2 || choose(0,1) == 1){ | ||||
|                 switch(player.team) { | ||||
|                     case TEAM_BLUE : | ||||
|                         createGib(x,y,Accesory,hspeed,vspeed,random(105)-52, 2, false); | ||||
|                         break; | ||||
|                     case TEAM_RED : | ||||
|                         createGib(x,y,Accesory,hspeed,vspeed,random(105)-52, 1, false); | ||||
|                         break; | ||||
|                     } | ||||
|             } | ||||
|             break; | ||||
|         case CLASS_ENGINEER : | ||||
|             if(global.gibLevel > 2 || choose(0,1) == 1) | ||||
|                 createGib(x,y,Accesory,hspeed,vspeed,random(105)-52, 3, false) | ||||
|             break; | ||||
|         case CLASS_SNIPER : | ||||
|             if(global.gibLevel > 2 || choose(0,1) == 1) | ||||
|                 createGib(x,y,Accesory,hspeed,vspeed,random(105)-52, 0, false) | ||||
|             break; | ||||
|         } | ||||
|         playsound(x,y,Gibbing); | ||||
|     } else { | ||||
|         var deadbody; | ||||
|         if player.class != CLASS_QUOTE playsound(x,y,choose(DeathSnd1, DeathSnd2)); | ||||
|         deadbody = instance_create(x,y-30,DeadGuy); | ||||
|         // 'GS' reward - *G*olden *S*tatue | ||||
|         if(hasReward(player, 'GS')) | ||||
|         { | ||||
|             deadbody.sprite_index = haxxyStatue; | ||||
|             deadbody.image_index = 0; | ||||
|         } | ||||
|         else | ||||
|         {  | ||||
|             deadbody.sprite_index = sprite_index; | ||||
|             deadbody.image_index = CHARACTER_ANIMATION_DEAD; | ||||
|         } | ||||
|         deadbody.hspeed=hspeed; | ||||
|         deadbody.vspeed=vspeed; | ||||
|         if(hspeed>0) { | ||||
|             deadbody.image_xscale = -1;   | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| if (global.gg_birthday){ | ||||
|     myHat = instance_create(victim.object.x,victim.object.y,PartyHat); | ||||
|     myHat.image_index = victim.team; | ||||
| } | ||||
| if (global.xmas){ | ||||
|     myHat = instance_create(victim.object.x,victim.object.y,XmasHat); | ||||
|     myHat.image_index = victim.team; | ||||
| } | ||||
|  | ||||
|  | ||||
| with(victim.object) {        | ||||
|     instance_destroy(); | ||||
| } | ||||
|  | ||||
| //************************************* | ||||
| //*         Deathcam | ||||
| //************************************* | ||||
| if( global.killCam and victim == global.myself and killer and killer != victim and !(damageSource == KILL_BOX || damageSource == FRAG_BOX || damageSource == FINISHED_OFF || damageSource == FINISHED_OFF_GIB || damageSource == GENERATOR_EXPLOSION)) { | ||||
|     instance_create(0,0,DeathCam); | ||||
|     DeathCam.killedby=killer; | ||||
|     DeathCam.name=killer.name; | ||||
|     DeathCam.oldxview=view_xview[0]; | ||||
|     DeathCam.oldyview=view_yview[0]; | ||||
|     DeathCam.lastDamageSource=damageSource; | ||||
|     DeathCam.team = global.myself.team; | ||||
| } | ||||
							
								
								
									
										1469
									
								
								samples/Game Maker Language/faucet-http.gml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1469
									
								
								samples/Game Maker Language/faucet-http.gml
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										484
									
								
								samples/Game Maker Language/game_init.gml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										484
									
								
								samples/Game Maker Language/game_init.gml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,484 @@ | ||||
| /* | ||||
|     Originally from /Source/gg2/Scripts/game_init.gml in Gang Garrison 2 | ||||
|  | ||||
|     Copyright (C) 2008-2013 Faucet Software | ||||
|     http://www.ganggarrison.com | ||||
|  | ||||
|     This program is free software;  | ||||
|     you can redistribute it and/or modify it under the terms of the GNU General Public License | ||||
|     as published by the Free Software Foundation; either version 3 of the License, or (at your option) | ||||
|     any later version. | ||||
|     This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;  | ||||
|     without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  | ||||
|     See the GNU General Public License for more details. | ||||
|     You should have received a copy of the GNU General Public License along with this program; if not, | ||||
|     see <http://www.gnu.org/licenses>. | ||||
|  | ||||
|     Additional permission under GNU GPL version 3 section 7 | ||||
|     If you modify this Program, or any covered work, by linking or combining it with the Game Maker runtime library,  | ||||
|     the 39dll library/extension, Hobbel's Download Manager DLL, or modified versions of these libraries, | ||||
|     the licensors of this Program grant you additional permission to convey the resulting work. | ||||
| */ | ||||
|  | ||||
| // Returns true if the game is successfully initialized, false if there was an error and we should quit. | ||||
| { | ||||
|     instance_create(0,0,RoomChangeObserver); | ||||
|     set_little_endian_global(true); | ||||
|     if file_exists("game_errors.log") file_delete("game_errors.log"); | ||||
|     if file_exists("last_plugin.log") file_delete("last_plugin.log"); | ||||
|      | ||||
|     // Delete old left-over files created by the updater | ||||
|     var backupFilename; | ||||
|     backupFilename = file_find_first("gg2-old.delete.me.*", 0); | ||||
|     while(backupFilename != "") | ||||
|     { | ||||
|         file_delete(backupFilename); | ||||
|         backupFilename = file_find_next(); | ||||
|     } | ||||
|     file_find_close(); | ||||
|      | ||||
|     var customMapRotationFile, restart; | ||||
|     restart = false; | ||||
|  | ||||
|     //import wav files for music | ||||
|     global.MenuMusic=sound_add(choose("Music/menumusic1.wav","Music/menumusic2.wav","Music/menumusic3.wav","Music/menumusic4.wav","Music/menumusic5.wav","Music/menumusic6.wav"), 1, true); | ||||
|     global.IngameMusic=sound_add("Music/ingamemusic.wav", 1, true); | ||||
|     global.FaucetMusic=sound_add("Music/faucetmusic.wav", 1, true); | ||||
|     if(global.MenuMusic != -1) | ||||
|         sound_volume(global.MenuMusic, 0.8); | ||||
|     if(global.IngameMusic != -1) | ||||
|         sound_volume(global.IngameMusic, 0.8); | ||||
|     if(global.FaucetMusic != -1) | ||||
|         sound_volume(global.FaucetMusic, 0.8); | ||||
|          | ||||
|     global.sendBuffer = buffer_create(); | ||||
|     global.tempBuffer = buffer_create(); | ||||
|     global.HudCheck = false; | ||||
|     global.map_rotation = ds_list_create(); | ||||
|      | ||||
|     global.CustomMapCollisionSprite = -1; | ||||
|      | ||||
|     window_set_region_scale(-1, false); | ||||
|      | ||||
|     ini_open("gg2.ini"); | ||||
|     global.playerName = ini_read_string("Settings", "PlayerName", "Player"); | ||||
|     if string_count("#",global.playerName) > 0 global.playerName = "Player"; | ||||
|     global.playerName = string_copy(global.playerName, 0, min(string_length(global.playerName), MAX_PLAYERNAME_LENGTH)); | ||||
|     global.fullscreen = ini_read_real("Settings", "Fullscreen", 0); | ||||
|     global.useLobbyServer = ini_read_real("Settings", "UseLobby", 1); | ||||
|     global.hostingPort = ini_read_real("Settings", "HostingPort", 8190); | ||||
|     global.music = ini_read_real("Settings", "Music", ini_read_real("Settings", "IngameMusic", MUSIC_BOTH)); | ||||
|     global.playerLimit = ini_read_real("Settings", "PlayerLimit", 10); | ||||
|     //thy playerlimit shalt not exceed 48! | ||||
|     if (global.playerLimit > 48) | ||||
|     { | ||||
|         if (global.dedicatedMode != 1) | ||||
|             show_message("Warning: Player Limit cannot exceed 48. It has been set to 48"); | ||||
|         global.playerLimit = 48; | ||||
|         ini_write_real("Settings", "PlayerLimit", 48); | ||||
|     } | ||||
|     global.multiClientLimit = ini_read_real("Settings", "MultiClientLimit", 3); | ||||
|     global.particles =  ini_read_real("Settings", "Particles", PARTICLES_NORMAL); | ||||
|     global.gibLevel = ini_read_real("Settings", "Gib Level", 3); | ||||
|     global.killCam = ini_read_real("Settings", "Kill Cam", 1); | ||||
|     global.monitorSync = ini_read_real("Settings", "Monitor Sync", 0); | ||||
|     if global.monitorSync == 1 set_synchronization(true); | ||||
|     else set_synchronization(false); | ||||
|     global.medicRadar = ini_read_real("Settings", "Healer Radar", 1); | ||||
|     global.showHealer = ini_read_real("Settings", "Show Healer", 1); | ||||
|     global.showHealing = ini_read_real("Settings", "Show Healing", 1); | ||||
|     global.showHealthBar = ini_read_real("Settings", "Show Healthbar", 0); | ||||
|     global.showTeammateStats = ini_read_real("Settings", "Show Extra Teammate Stats", 0); | ||||
|     global.serverPluginsPrompt = ini_read_real("Settings", "ServerPluginsPrompt", 1); | ||||
|     global.restartPrompt = ini_read_real("Settings", "RestartPrompt", 1); | ||||
|     //user HUD settings | ||||
|     global.timerPos=ini_read_real("Settings","Timer Position", 0) | ||||
|     global.killLogPos=ini_read_real("Settings","Kill Log Position", 0) | ||||
|     global.kothHudPos=ini_read_real("Settings","KoTH HUD Position", 0) | ||||
|     global.clientPassword = ""; | ||||
|     // for admin menu | ||||
|     customMapRotationFile = ini_read_string("Server", "MapRotation", ""); | ||||
|     global.shuffleRotation = ini_read_real("Server", "ShuffleRotation", 1); | ||||
|     global.timeLimitMins = max(1, min(255, ini_read_real("Server", "Time Limit", 15))); | ||||
|     global.serverPassword = ini_read_string("Server", "Password", ""); | ||||
|     global.mapRotationFile = customMapRotationFile; | ||||
|     global.dedicatedMode = ini_read_real("Server", "Dedicated", 0); | ||||
|     global.serverName = ini_read_string("Server", "ServerName", "My Server"); | ||||
|     global.welcomeMessage = ini_read_string("Server", "WelcomeMessage", ""); | ||||
|     global.caplimit = max(1, min(255, ini_read_real("Server", "CapLimit", 5))); | ||||
|     global.caplimitBkup = global.caplimit; | ||||
|     global.autobalance = ini_read_real("Server", "AutoBalance",1); | ||||
|     global.Server_RespawntimeSec = ini_read_real("Server", "Respawn Time", 5); | ||||
|     global.rewardKey = unhex(ini_read_string("Haxxy", "RewardKey", "")); | ||||
|     global.rewardId = ini_read_string("Haxxy", "RewardId", ""); | ||||
|     global.mapdownloadLimitBps = ini_read_real("Server", "Total bandwidth limit for map downloads in bytes per second", 50000); | ||||
|     global.updaterBetaChannel = ini_read_real("General", "UpdaterBetaChannel", isBetaVersion()); | ||||
|     global.attemptPortForward = ini_read_real("Server", "Attempt UPnP Forwarding", 0);  | ||||
|     global.serverPluginList = ini_read_string("Server", "ServerPluginList", ""); | ||||
|     global.serverPluginsRequired = ini_read_real("Server", "ServerPluginsRequired", 0); | ||||
|     if (string_length(global.serverPluginList) > 254) { | ||||
|         show_message("Error: Server plugin list cannot exceed 254 characters"); | ||||
|         return false; | ||||
|     } | ||||
|     var CrosshairFilename, CrosshairRemoveBG; | ||||
|     CrosshairFilename = ini_read_string("Settings", "CrosshairFilename", ""); | ||||
|     CrosshairRemoveBG = ini_read_real("Settings", "CrosshairRemoveBG", 1); | ||||
|     global.queueJumping = ini_read_real("Settings", "Queued Jumping", 0); | ||||
|  | ||||
|     global.backgroundHash = ini_read_string("Background", "BackgroundHash", "default"); | ||||
|     global.backgroundTitle = ini_read_string("Background", "BackgroundTitle", ""); | ||||
|     global.backgroundURL = ini_read_string("Background", "BackgroundURL", ""); | ||||
|     global.backgroundShowVersion = ini_read_real("Background", "BackgroundShowVersion", true); | ||||
|      | ||||
|     readClasslimitsFromIni(); | ||||
|  | ||||
|     global.currentMapArea=1; | ||||
|     global.totalMapAreas=1; | ||||
|     global.setupTimer=1800; | ||||
|     global.joinedServerName=""; | ||||
|     global.serverPluginsInUse=false; | ||||
|     // Create plugin packet maps | ||||
|     global.pluginPacketBuffers = ds_map_create(); | ||||
|     global.pluginPacketPlayers = ds_map_create(); | ||||
|          | ||||
|     ini_write_string("Settings", "PlayerName", global.playerName); | ||||
|     ini_write_real("Settings", "Fullscreen", global.fullscreen); | ||||
|     ini_write_real("Settings", "UseLobby", global.useLobbyServer); | ||||
|     ini_write_real("Settings", "HostingPort", global.hostingPort); | ||||
|     ini_key_delete("Settings", "IngameMusic"); | ||||
|     ini_write_real("Settings", "Music", global.music); | ||||
|     ini_write_real("Settings", "PlayerLimit", global.playerLimit); | ||||
|     ini_write_real("Settings", "MultiClientLimit", global.multiClientLimit); | ||||
|     ini_write_real("Settings", "Particles", global.particles); | ||||
|     ini_write_real("Settings", "Gib Level", global.gibLevel); | ||||
|     ini_write_real("Settings", "Kill Cam", global.killCam); | ||||
|     ini_write_real("Settings", "Monitor Sync", global.monitorSync); | ||||
|     ini_write_real("Settings", "Healer Radar", global.medicRadar); | ||||
|     ini_write_real("Settings", "Show Healer", global.showHealer); | ||||
|     ini_write_real("Settings", "Show Healing", global.showHealing); | ||||
|     ini_write_real("Settings", "Show Healthbar", global.showHealthBar); | ||||
|     ini_write_real("Settings", "Show Extra Teammate Stats", global.showTeammateStats); | ||||
|     ini_write_real("Settings", "Timer Position", global.timerPos); | ||||
|     ini_write_real("Settings", "Kill Log Position", global.killLogPos); | ||||
|     ini_write_real("Settings", "KoTH HUD Position", global.kothHudPos); | ||||
|     ini_write_real("Settings", "ServerPluginsPrompt", global.serverPluginsPrompt); | ||||
|     ini_write_real("Settings", "RestartPrompt", global.restartPrompt); | ||||
|     ini_write_string("Server", "MapRotation", customMapRotationFile); | ||||
|     ini_write_real("Server", "ShuffleRotation", global.shuffleRotation); | ||||
|     ini_write_real("Server", "Dedicated", global.dedicatedMode); | ||||
|     ini_write_string("Server", "ServerName", global.serverName); | ||||
|     ini_write_string("Server", "WelcomeMessage", global.welcomeMessage); | ||||
|     ini_write_real("Server", "CapLimit", global.caplimit); | ||||
|     ini_write_real("Server", "AutoBalance", global.autobalance); | ||||
|     ini_write_real("Server", "Respawn Time", global.Server_RespawntimeSec); | ||||
|     ini_write_real("Server", "Total bandwidth limit for map downloads in bytes per second", global.mapdownloadLimitBps); | ||||
|     ini_write_real("Server", "Time Limit", global.timeLimitMins); | ||||
|     ini_write_string("Server", "Password", global.serverPassword); | ||||
|     ini_write_real("General", "UpdaterBetaChannel", global.updaterBetaChannel); | ||||
|     ini_write_real("Server", "Attempt UPnP Forwarding", global.attemptPortForward);  | ||||
|     ini_write_string("Server", "ServerPluginList", global.serverPluginList);  | ||||
|     ini_write_real("Server", "ServerPluginsRequired", global.serverPluginsRequired);  | ||||
|     ini_write_string("Settings", "CrosshairFilename", CrosshairFilename); | ||||
|     ini_write_real("Settings", "CrosshairRemoveBG", CrosshairRemoveBG); | ||||
|     ini_write_real("Settings", "Queued Jumping", global.queueJumping); | ||||
|  | ||||
|     ini_write_string("Background", "BackgroundHash", global.backgroundHash); | ||||
|     ini_write_string("Background", "BackgroundTitle", global.backgroundTitle); | ||||
|     ini_write_string("Background", "BackgroundURL", global.backgroundURL); | ||||
|     ini_write_real("Background", "BackgroundShowVersion", global.backgroundShowVersion); | ||||
|      | ||||
|     ini_write_real("Classlimits", "Scout", global.classlimits[CLASS_SCOUT]) | ||||
|     ini_write_real("Classlimits", "Pyro", global.classlimits[CLASS_PYRO]) | ||||
|     ini_write_real("Classlimits", "Soldier", global.classlimits[CLASS_SOLDIER]) | ||||
|     ini_write_real("Classlimits", "Heavy", global.classlimits[CLASS_HEAVY]) | ||||
|     ini_write_real("Classlimits", "Demoman", global.classlimits[CLASS_DEMOMAN]) | ||||
|     ini_write_real("Classlimits", "Medic", global.classlimits[CLASS_MEDIC]) | ||||
|     ini_write_real("Classlimits", "Engineer", global.classlimits[CLASS_ENGINEER]) | ||||
|     ini_write_real("Classlimits", "Spy", global.classlimits[CLASS_SPY]) | ||||
|     ini_write_real("Classlimits", "Sniper", global.classlimits[CLASS_SNIPER]) | ||||
|     ini_write_real("Classlimits", "Quote", global.classlimits[CLASS_QUOTE]) | ||||
|  | ||||
|     //screw the 0 index we will start with 1 | ||||
|     //map_truefort  | ||||
|     maps[1] = ini_read_real("Maps", "ctf_truefort", 1); | ||||
|     //map_2dfort  | ||||
|     maps[2] = ini_read_real("Maps", "ctf_2dfort", 2); | ||||
|     //map_conflict  | ||||
|     maps[3] = ini_read_real("Maps", "ctf_conflict", 3); | ||||
|     //map_classicwell  | ||||
|     maps[4] = ini_read_real("Maps", "ctf_classicwell", 4); | ||||
|     //map_waterway  | ||||
|     maps[5] = ini_read_real("Maps", "ctf_waterway", 5); | ||||
|     //map_orange  | ||||
|     maps[6] = ini_read_real("Maps", "ctf_orange", 6); | ||||
|     //map_dirtbowl | ||||
|     maps[7] = ini_read_real("Maps", "cp_dirtbowl", 7); | ||||
|     //map_egypt | ||||
|     maps[8] = ini_read_real("Maps", "cp_egypt", 8); | ||||
|     //arena_montane | ||||
|     maps[9] = ini_read_real("Maps", "arena_montane", 9); | ||||
|     //arena_lumberyard | ||||
|     maps[10] = ini_read_real("Maps", "arena_lumberyard", 10); | ||||
|     //gen_destroy | ||||
|     maps[11] = ini_read_real("Maps", "gen_destroy", 11); | ||||
|     //koth_valley | ||||
|     maps[12] = ini_read_real("Maps", "koth_valley", 12); | ||||
|     //koth_corinth | ||||
|     maps[13] = ini_read_real("Maps", "koth_corinth", 13); | ||||
|     //koth_harvest | ||||
|     maps[14] = ini_read_real("Maps", "koth_harvest", 14); | ||||
|     //dkoth_atalia | ||||
|     maps[15] = ini_read_real("Maps", "dkoth_atalia", 15); | ||||
|     //dkoth_sixties | ||||
|     maps[16] = ini_read_real("Maps", "dkoth_sixties", 16); | ||||
|      | ||||
|     //Server respawn time calculator. Converts each second to a frame. (read: multiply by 30 :hehe:) | ||||
|     if (global.Server_RespawntimeSec == 0) | ||||
|     { | ||||
|         global.Server_Respawntime = 1; | ||||
|     }     | ||||
|     else | ||||
|     { | ||||
|         global.Server_Respawntime = global.Server_RespawntimeSec * 30;     | ||||
|     }     | ||||
|      | ||||
|     // I have to include this, or the client'll complain about an unknown variable. | ||||
|     global.mapchanging = false; | ||||
|      | ||||
|     ini_write_real("Maps", "ctf_truefort", maps[1]); | ||||
|     ini_write_real("Maps", "ctf_2dfort", maps[2]); | ||||
|     ini_write_real("Maps", "ctf_conflict", maps[3]); | ||||
|     ini_write_real("Maps", "ctf_classicwell", maps[4]); | ||||
|     ini_write_real("Maps", "ctf_waterway", maps[5]); | ||||
|     ini_write_real("Maps", "ctf_orange", maps[6]); | ||||
|     ini_write_real("Maps", "cp_dirtbowl", maps[7]); | ||||
|     ini_write_real("Maps", "cp_egypt", maps[8]); | ||||
|     ini_write_real("Maps", "arena_montane", maps[9]); | ||||
|     ini_write_real("Maps", "arena_lumberyard", maps[10]); | ||||
|     ini_write_real("Maps", "gen_destroy", maps[11]); | ||||
|     ini_write_real("Maps", "koth_valley", maps[12]); | ||||
|     ini_write_real("Maps", "koth_corinth", maps[13]); | ||||
|     ini_write_real("Maps", "koth_harvest", maps[14]); | ||||
|     ini_write_real("Maps", "dkoth_atalia", maps[15]); | ||||
|     ini_write_real("Maps", "dkoth_sixties", maps[16]); | ||||
|  | ||||
|     ini_close(); | ||||
|      | ||||
|     // parse the protocol version UUID for later use | ||||
|     global.protocolUuid = buffer_create(); | ||||
|     parseUuid(PROTOCOL_UUID, global.protocolUuid); | ||||
|  | ||||
|     global.gg2lobbyId = buffer_create(); | ||||
|     parseUuid(GG2_LOBBY_UUID, global.gg2lobbyId); | ||||
|  | ||||
|     // Create abbreviations array for rewards use | ||||
|     initRewards() | ||||
|      | ||||
| var a, IPRaw, portRaw; | ||||
| doubleCheck=0; | ||||
| global.launchMap = ""; | ||||
|  | ||||
|     for(a = 1; a <= parameter_count(); a += 1)  | ||||
|     { | ||||
|         if (parameter_string(a) == "-dedicated") | ||||
|         { | ||||
|             global.dedicatedMode = 1; | ||||
|         } | ||||
|         else if (parameter_string(a) == "-restart") | ||||
|         { | ||||
|             restart = true; | ||||
|         } | ||||
|         else if (parameter_string(a) == "-server") | ||||
|         { | ||||
|             IPRaw = parameter_string(a+1); | ||||
|             if (doubleCheck == 1) | ||||
|             { | ||||
|                 doubleCheck = 2; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 doubleCheck = 1; | ||||
|             } | ||||
|         } | ||||
|         else if (parameter_string(a) == "-port") | ||||
|         { | ||||
|             portRaw = parameter_string(a+1); | ||||
|             if (doubleCheck == 1) | ||||
|             { | ||||
|                 doubleCheck = 2; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 doubleCheck = 1; | ||||
|             } | ||||
|         } | ||||
|         else if (parameter_string(a) == "-map") | ||||
|         { | ||||
|             global.launchMap = parameter_string(a+1); | ||||
|             global.dedicatedMode = 1; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     if (doubleCheck == 2) | ||||
|     { | ||||
|         global.serverPort = real(portRaw); | ||||
|         global.serverIP = IPRaw; | ||||
|         global.isHost = false; | ||||
|         instance_create(0,0,Client); | ||||
|     }    | ||||
|      | ||||
|     global.customMapdesginated = 0;     | ||||
|      | ||||
|     // if the user defined a valid map rotation file, then load from there | ||||
|  | ||||
|     if(customMapRotationFile != "" && file_exists(customMapRotationFile) && global.launchMap == "") { | ||||
|         global.customMapdesginated = 1; | ||||
|         var fileHandle, i, mapname; | ||||
|         fileHandle = file_text_open_read(customMapRotationFile); | ||||
|         for(i = 1; !file_text_eof(fileHandle); i += 1) { | ||||
|             mapname = file_text_read_string(fileHandle); | ||||
|             // remove leading whitespace from the string | ||||
|             while(string_char_at(mapname, 0) == " " || string_char_at(mapname, 0) == chr(9)) { // while it starts with a space or tab | ||||
|               mapname = string_delete(mapname, 0, 1); // delete that space or tab | ||||
|             } | ||||
|             if(mapname != "" && string_char_at(mapname, 0) != "#") { // if it's not blank and it's not a comment (starting with #) | ||||
|                 ds_list_add(global.map_rotation, mapname); | ||||
|             } | ||||
|             file_text_readln(fileHandle); | ||||
|         } | ||||
|         file_text_close(fileHandle); | ||||
|     } | ||||
|      | ||||
|      else if (global.launchMap != "") && (global.dedicatedMode == 1) | ||||
|         {   | ||||
|         ds_list_add(global.map_rotation, global.launchMap); | ||||
|         } | ||||
|      | ||||
|      else { // else load from the ini file Maps section | ||||
|         //Set up the map rotation stuff | ||||
|         var i, sort_list; | ||||
|         sort_list = ds_list_create(); | ||||
|         for(i=1; i <= 16; i += 1) { | ||||
|             if(maps[i] != 0) ds_list_add(sort_list, ((100*maps[i])+i)); | ||||
|         } | ||||
|         ds_list_sort(sort_list, 1); | ||||
|          | ||||
|         // translate the numbers back into the names they represent | ||||
|         for(i=0; i < ds_list_size(sort_list); i += 1) { | ||||
|             switch(ds_list_find_value(sort_list, i) mod 100) { | ||||
|                 case 1: | ||||
|                     ds_list_add(global.map_rotation, "ctf_truefort"); | ||||
|                 break; | ||||
|                 case 2: | ||||
|                     ds_list_add(global.map_rotation, "ctf_2dfort"); | ||||
|                 break; | ||||
|                 case 3: | ||||
|                     ds_list_add(global.map_rotation, "ctf_conflict"); | ||||
|                 break; | ||||
|                 case 4: | ||||
|                     ds_list_add(global.map_rotation, "ctf_classicwell"); | ||||
|                 break; | ||||
|                 case 5: | ||||
|                     ds_list_add(global.map_rotation, "ctf_waterway"); | ||||
|                 break; | ||||
|                 case 6: | ||||
|                     ds_list_add(global.map_rotation, "ctf_orange"); | ||||
|                 break; | ||||
|                 case 7: | ||||
|                     ds_list_add(global.map_rotation, "cp_dirtbowl"); | ||||
|                 break; | ||||
|                 case 8: | ||||
|                     ds_list_add(global.map_rotation, "cp_egypt"); | ||||
|                 break; | ||||
|                 case 9: | ||||
|                     ds_list_add(global.map_rotation, "arena_montane"); | ||||
|                 break; | ||||
|                 case 10: | ||||
|                     ds_list_add(global.map_rotation, "arena_lumberyard"); | ||||
|                 break; | ||||
|                 case 11: | ||||
|                     ds_list_add(global.map_rotation, "gen_destroy"); | ||||
|                 break; | ||||
|                 case 12: | ||||
|                     ds_list_add(global.map_rotation, "koth_valley"); | ||||
|                 break; | ||||
|                 case 13: | ||||
|                     ds_list_add(global.map_rotation, "koth_corinth"); | ||||
|                 break; | ||||
|                 case 14: | ||||
|                     ds_list_add(global.map_rotation, "koth_harvest"); | ||||
|                 break; | ||||
|                 case 15: | ||||
|                     ds_list_add(global.map_rotation, "dkoth_atalia"); | ||||
|                 break; | ||||
|                 case 16: | ||||
|                     ds_list_add(global.map_rotation, "dkoth_sixties"); | ||||
|                 break; | ||||
|                      | ||||
|             } | ||||
|         } | ||||
|         ds_list_destroy(sort_list); | ||||
|     } | ||||
|      | ||||
|     window_set_fullscreen(global.fullscreen); | ||||
|      | ||||
|     global.gg2Font = font_add_sprite(gg2FontS,ord("!"),false,0); | ||||
|     global.countFont = font_add_sprite(countFontS, ord("0"),false,2); | ||||
|     draw_set_font(global.gg2Font); | ||||
|     cursor_sprite = CrosshairS; | ||||
|      | ||||
|     if(!directory_exists(working_directory + "\Maps")) directory_create(working_directory + "\Maps"); | ||||
|      | ||||
|     instance_create(0, 0, AudioControl); | ||||
|     instance_create(0, 0, SSControl); | ||||
|      | ||||
|     // custom dialog box graphics | ||||
|     message_background(popupBackgroundB); | ||||
|     message_button(popupButtonS); | ||||
|     message_text_font("Century",9,c_white,1); | ||||
|     message_button_font("Century",9,c_white,1); | ||||
|     message_input_font("Century",9,c_white,0); | ||||
|      | ||||
|     //Key Mapping | ||||
|     ini_open("controls.gg2"); | ||||
|     global.jump = ini_read_real("Controls", "jump", ord("W")); | ||||
|     global.down = ini_read_real("Controls", "down", ord("S")); | ||||
|     global.left = ini_read_real("Controls", "left", ord("A")); | ||||
|     global.right = ini_read_real("Controls", "right", ord("D")); | ||||
|     global.attack = ini_read_real("Controls", "attack", MOUSE_LEFT); | ||||
|     global.special = ini_read_real("Controls", "special", MOUSE_RIGHT); | ||||
|     global.taunt = ini_read_real("Controls", "taunt", ord("F")); | ||||
|     global.chat1 = ini_read_real("Controls", "chat1", ord("Z")); | ||||
|     global.chat2 = ini_read_real("Controls", "chat2", ord("X")); | ||||
|     global.chat3 = ini_read_real("Controls", "chat3", ord("C")); | ||||
|     global.medic = ini_read_real("Controls", "medic", ord("E")); | ||||
|     global.drop = ini_read_real("Controls", "drop", ord("B")); | ||||
|     global.changeTeam = ini_read_real("Controls", "changeTeam", ord("N")); | ||||
|     global.changeClass = ini_read_real("Controls", "changeClass", ord("M")); | ||||
|     global.showScores = ini_read_real("Controls", "showScores", vk_shift); | ||||
|     ini_close(); | ||||
|      | ||||
|     calculateMonthAndDay(); | ||||
|  | ||||
|     if(!directory_exists(working_directory + "\Plugins")) directory_create(working_directory + "\Plugins"); | ||||
|     loadplugins(); | ||||
|      | ||||
|     /* Windows 8 is known to crash GM when more than three (?) sounds play at once | ||||
|      * We'll store the kernel version (Win8 is 6.2, Win7 is 6.1) and check it there. | ||||
|      ***/ | ||||
|     registry_set_root(1); // HKLM | ||||
|     global.NTKernelVersion = real(registry_read_string_ext("\SOFTWARE\Microsoft\Windows NT\CurrentVersion\", "CurrentVersion")); // SIC | ||||
|  | ||||
|     if (file_exists(CrosshairFilename)) | ||||
|     { | ||||
|         sprite_replace(CrosshairS,CrosshairFilename,1,CrosshairRemoveBG,false,0,0); | ||||
|         sprite_set_offset(CrosshairS,sprite_get_width(CrosshairS)/2,sprite_get_height(CrosshairS)/2); | ||||
|     } | ||||
|     if(global.dedicatedMode == 1) { | ||||
|         AudioControlToggleMute(); | ||||
|         room_goto_fix(Menu); | ||||
|     } else if(restart) { | ||||
|         room_goto_fix(Menu); | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
							
								
								
									
										1861
									
								
								samples/Game Maker Language/jsonion.gml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1861
									
								
								samples/Game Maker Language/jsonion.gml
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1169
									
								
								samples/Game Maker Language/jsonion_test.gml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1169
									
								
								samples/Game Maker Language/jsonion_test.gml
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										252
									
								
								samples/Game Maker Language/loadserverplugins.gml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										252
									
								
								samples/Game Maker Language/loadserverplugins.gml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,252 @@ | ||||
| /* | ||||
|     Originally from /Source/gg2/Scripts/Plugins/loadserverplugins.gml in Gang Garrison 2 | ||||
|  | ||||
|     Copyright (C) 2008-2013 Faucet Software | ||||
|     http://www.ganggarrison.com | ||||
|  | ||||
|     This program is free software;  | ||||
|     you can redistribute it and/or modify it under the terms of the GNU General Public License | ||||
|     as published by the Free Software Foundation; either version 3 of the License, or (at your option) | ||||
|     any later version. | ||||
|     This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;  | ||||
|     without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  | ||||
|     See the GNU General Public License for more details. | ||||
|     You should have received a copy of the GNU General Public License along with this program; if not, | ||||
|     see <http://www.gnu.org/licenses>. | ||||
|  | ||||
|     Additional permission under GNU GPL version 3 section 7 | ||||
|     If you modify this Program, or any covered work, by linking or combining it with the Game Maker runtime library,  | ||||
|     the 39dll library/extension, Hobbel's Download Manager DLL, or modified versions of these libraries, | ||||
|     the licensors of this Program grant you additional permission to convey the resulting work. | ||||
| */ | ||||
|  | ||||
| // loads plugins from ganggarrison.com asked for by server | ||||
| // argument0 - comma separated plugin list (pluginname@md5hash) | ||||
| // returns true on success, false on failure | ||||
| var list, hashList, text, i, pluginname, pluginhash, realhash, url, handle, filesize, progress, tempfile, tempdir, failed, lastContact, isCached; | ||||
|  | ||||
| failed = false; | ||||
| list = ds_list_create(); | ||||
| lastContact = 0; | ||||
| isCached = false; | ||||
| isDebug = false; | ||||
| hashList = ds_list_create(); | ||||
|  | ||||
| // split plugin list string | ||||
| list = split(argument0, ','); | ||||
|  | ||||
| // Split hashes from plugin names | ||||
| for (i = 0; i < ds_list_size(list); i += 1) | ||||
| { | ||||
|     text = ds_list_find_value(list, i); | ||||
|     pluginname = string_copy(text, 0, string_pos("@", text) - 1); | ||||
|     pluginhash = string_copy(text, string_pos("@", text) + 1, string_length(text) - string_pos("@", text)); | ||||
|     ds_list_replace(list, i, pluginname); | ||||
|     ds_list_add(hashList, pluginhash); | ||||
| } | ||||
|  | ||||
| // Check plugin names and check for duplicates | ||||
| for (i = 0; i < ds_list_size(list); i += 1) | ||||
| { | ||||
|     pluginname = ds_list_find_value(list, i); | ||||
|      | ||||
|     // invalid plugin name | ||||
|     if (!checkpluginname(pluginname)) | ||||
|     { | ||||
|         show_message('Error loading server-sent plugins - invalid plugin name:#"' + pluginname + '"'); | ||||
|         return false; | ||||
|     } | ||||
|     // is duplicate | ||||
|     else if (ds_list_find_index(list, pluginname) != i) | ||||
|     { | ||||
|         show_message('Error loading server-sent plugins - duplicate plugin:#"' + pluginname + '"'); | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Download plugins | ||||
| for (i = 0; i < ds_list_size(list); i += 1) | ||||
| { | ||||
|     pluginname = ds_list_find_value(list, i); | ||||
|     pluginhash = ds_list_find_value(hashList, i); | ||||
|     isDebug = file_exists(working_directory + "\ServerPluginsDebug\" + pluginname + ".zip"); | ||||
|     isCached = file_exists(working_directory + "\ServerPluginsCache\" + pluginname + "@" + pluginhash); | ||||
|     tempfile = temp_directory + "\" + pluginname + ".zip.tmp"; | ||||
|     tempdir = temp_directory + "\" + pluginname + ".tmp"; | ||||
|  | ||||
|     // check to see if we have a local copy for debugging | ||||
|     if (isDebug) | ||||
|     { | ||||
|         file_copy(working_directory + "\ServerPluginsDebug\" + pluginname + ".zip", tempfile); | ||||
|         // show warning | ||||
|         if (global.isHost) | ||||
|         { | ||||
|             show_message( | ||||
|                 "Warning: server-sent plugin '" | ||||
|                 + pluginname | ||||
|                 + "' is being loaded from ServerPluginsDebug. Make sure clients have the same version, else they may be unable to connect." | ||||
|             ); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             show_message( | ||||
|                 "Warning: server-sent plugin '" | ||||
|                 + pluginname | ||||
|                 + "' is being loaded from ServerPluginsDebug. Make sure the server has the same version, else you may be unable to connect." | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
|     // otherwise, check if we have it cached | ||||
|     else if (isCached) | ||||
|     { | ||||
|         file_copy(working_directory + "\ServerPluginsCache\" + pluginname + "@" + pluginhash, tempfile); | ||||
|     } | ||||
|     // otherwise, download as usual | ||||
|     else | ||||
|     { | ||||
|         // construct the URL | ||||
|         // http://www.ganggarrison.com/plugins/$PLUGINNAME$@$PLUGINHASH$.zip) | ||||
|         url = PLUGIN_SOURCE + pluginname + "@" + pluginhash + ".zip"; | ||||
|          | ||||
|         // let's make the download handle | ||||
|         handle = httpGet(url, -1); | ||||
|          | ||||
|         // download it | ||||
|         while (!httpRequestStatus(handle)) { | ||||
|             // prevent game locking up | ||||
|             io_handle(); | ||||
|  | ||||
|             httpRequestStep(handle); | ||||
|              | ||||
|             if (!global.isHost) { | ||||
|                 // send ping if we haven't contacted server in 20 seconds | ||||
|                 // we need to do this to keep the connection open | ||||
|                 if (current_time-lastContact > 20000) { | ||||
|                     write_byte(global.serverSocket, PING); | ||||
|                     socket_send(global.serverSocket); | ||||
|                     lastContact = current_time; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // draw progress bar since they may be waiting a while | ||||
|             filesize = httpRequestResponseBodySize(handle); | ||||
|             progress = httpRequestResponseBodyProgress(handle); | ||||
|             draw_background_ext(background_index[0], 0, 0, background_xscale[0], background_yscale[0], 0, c_white, 1); | ||||
|             draw_set_color(c_white); | ||||
|             draw_set_alpha(1); | ||||
|             draw_set_halign(fa_left); | ||||
|             draw_rectangle(50, 550, 300, 560, 2); | ||||
|             draw_text(50, 530, "Downloading server-sent plugin " + string(i + 1) + "/" + string(ds_list_size(list)) + ' - "' + pluginname + '"'); | ||||
|             if (filesize != -1) | ||||
|                 draw_rectangle(50, 550, 50 + progress / filesize * 250, 560, 0); | ||||
|             screen_refresh(); | ||||
|         } | ||||
|  | ||||
|         // errored | ||||
|         if (httpRequestStatus(handle) == 2) | ||||
|         { | ||||
|             show_message('Error loading server-sent plugins - download failed for "' + pluginname + '":#' + httpRequestError(handle)); | ||||
|             failed = true; | ||||
|             break; | ||||
|         } | ||||
|  | ||||
|         // request failed | ||||
|         if (httpRequestStatusCode(handle) != 200) | ||||
|         { | ||||
|             show_message('Error loading server-sent plugins - download failed for "' + pluginname + '":#' + string(httpRequestStatusCode(handle)) + ' ' + httpRequestReasonPhrase(handle)); | ||||
|             failed = true; | ||||
|             break; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             write_buffer_to_file(httpRequestResponseBody(handle), tempfile); | ||||
|             if (!file_exists(tempfile)) | ||||
|             { | ||||
|                 show_message('Error loading server-sent plugins - download failed for "' + pluginname + '":# No such file?'); | ||||
|                 failed = true; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         httpRequestDestroy(handle); | ||||
|     } | ||||
|  | ||||
|     // check file integrity | ||||
|     realhash = GG2DLL_compute_MD5(tempfile); | ||||
|     if (realhash != pluginhash) | ||||
|     { | ||||
|         show_message('Error loading server-sent plugins - integrity check failed (MD5 hash mismatch) for:#"' + pluginname + '"'); | ||||
|         failed = true; | ||||
|         break; | ||||
|     } | ||||
|      | ||||
|     // don't try to cache debug plugins | ||||
|     if (!isDebug) | ||||
|     { | ||||
|         // add to cache if we don't already have it | ||||
|         if (!file_exists(working_directory + "\ServerPluginsCache\" + pluginname + "@" + pluginhash)) | ||||
|         { | ||||
|             // make sure directory exists | ||||
|             if (!directory_exists(working_directory + "\ServerPluginsCache")) | ||||
|             { | ||||
|                 directory_create(working_directory + "\ServerPluginsCache"); | ||||
|             } | ||||
|             // store in cache | ||||
|             file_copy(tempfile, working_directory + "\ServerPluginsCache\" + pluginname + "@" + pluginhash); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // let's get 7-zip to extract the files | ||||
|     extractzip(tempfile, tempdir); | ||||
|      | ||||
|     // if the directory doesn't exist, extracting presumably failed | ||||
|     if (!directory_exists(tempdir)) | ||||
|     { | ||||
|         show_message('Error loading server-sent plugins - extracting zip failed for:#"' + pluginname + '"'); | ||||
|         failed = true; | ||||
|         break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| if (!failed) | ||||
| { | ||||
|     // Execute plugins | ||||
|     for (i = 0; i < ds_list_size(list); i += 1) | ||||
|     { | ||||
|         pluginname = ds_list_find_value(list, i); | ||||
|         tempdir = temp_directory + "\" + pluginname + ".tmp"; | ||||
|          | ||||
|         // Debugging facility, so we know *which* plugin caused compile/execute error | ||||
|         fp = file_text_open_write(working_directory + "\last_plugin.log"); | ||||
|         file_text_write_string(fp, pluginname); | ||||
|         file_text_close(fp); | ||||
|  | ||||
|         // packetID is (i), so make queues for it | ||||
|         ds_map_add(global.pluginPacketBuffers, i, ds_queue_create()); | ||||
|         ds_map_add(global.pluginPacketPlayers, i, ds_queue_create()); | ||||
|  | ||||
|         // Execute plugin | ||||
|         execute_file( | ||||
|             // the plugin's main gml file must be in the root of the zip | ||||
|             // it is called plugin.gml | ||||
|             tempdir + "\plugin.gml", | ||||
|             // the plugin needs to know where it is | ||||
|             // so the temporary directory is passed as first argument | ||||
|             tempdir, | ||||
|             // the plugin needs to know its packetID | ||||
|             // so it is passed as the second argument | ||||
|             i | ||||
|         ); | ||||
|     } | ||||
| } | ||||
|  | ||||
| // Delete last plugin log | ||||
| file_delete(working_directory + "\last_plugin.log"); | ||||
|  | ||||
| // Get rid of plugin list | ||||
| ds_list_destroy(list); | ||||
|  | ||||
| // Get rid of plugin hash list | ||||
| ds_list_destroy(hashList); | ||||
|  | ||||
| return !failed; | ||||
							
								
								
									
										384
									
								
								samples/Game Maker Language/processClientCommands.gml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										384
									
								
								samples/Game Maker Language/processClientCommands.gml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,384 @@ | ||||
| /* | ||||
|     Originally from /Source/gg2/Scripts/GameServer/processClientCommands.gml in Gang Garrison 2 | ||||
|  | ||||
|     Copyright (C) 2008-2013 Faucet Software | ||||
|     http://www.ganggarrison.com | ||||
|  | ||||
|     This program is free software;  | ||||
|     you can redistribute it and/or modify it under the terms of the GNU General Public License | ||||
|     as published by the Free Software Foundation; either version 3 of the License, or (at your option) | ||||
|     any later version. | ||||
|     This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;  | ||||
|     without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  | ||||
|     See the GNU General Public License for more details. | ||||
|     You should have received a copy of the GNU General Public License along with this program; if not, | ||||
|     see <http://www.gnu.org/licenses>. | ||||
|  | ||||
|     Additional permission under GNU GPL version 3 section 7 | ||||
|     If you modify this Program, or any covered work, by linking or combining it with the Game Maker runtime library,  | ||||
|     the 39dll library/extension, Hobbel's Download Manager DLL, or modified versions of these libraries, | ||||
|     the licensors of this Program grant you additional permission to convey the resulting work. | ||||
| */ | ||||
|  | ||||
| var player, playerId, commandLimitRemaining; | ||||
|  | ||||
| player = argument0; | ||||
| playerId = argument1; | ||||
|  | ||||
| // To prevent players from flooding the server, limit the number of commands to process per step and player. | ||||
| commandLimitRemaining = 10; | ||||
|  | ||||
| with(player) { | ||||
|     if(!variable_local_exists("commandReceiveState")) { | ||||
|         // 0: waiting for command byte. | ||||
|         // 1: waiting for command data length (1 byte) | ||||
|         // 2: waiting for command data. | ||||
|         commandReceiveState = 0; | ||||
|         commandReceiveExpectedBytes = 1; | ||||
|         commandReceiveCommand = 0; | ||||
|     } | ||||
| } | ||||
|  | ||||
| while(commandLimitRemaining > 0) { | ||||
|     var socket; | ||||
|     socket = player.socket; | ||||
|     if(!tcp_receive(socket, player.commandReceiveExpectedBytes)) { | ||||
|         return 0; | ||||
|     } | ||||
|      | ||||
|     switch(player.commandReceiveState) | ||||
|     { | ||||
|     case 0: | ||||
|         player.commandReceiveCommand = read_ubyte(socket); | ||||
|         switch(commandBytes[player.commandReceiveCommand]) { | ||||
|         case commandBytesInvalidCommand: | ||||
|             // Invalid byte received. Wait for another command byte. | ||||
|             break; | ||||
|              | ||||
|         case commandBytesPrefixLength1: | ||||
|             player.commandReceiveState = 1; | ||||
|             player.commandReceiveExpectedBytes = 1; | ||||
|             break; | ||||
|  | ||||
|         case commandBytesPrefixLength2: | ||||
|             player.commandReceiveState = 3; | ||||
|             player.commandReceiveExpectedBytes = 2; | ||||
|             break; | ||||
|  | ||||
|         default: | ||||
|             player.commandReceiveState = 2; | ||||
|             player.commandReceiveExpectedBytes = commandBytes[player.commandReceiveCommand]; | ||||
|             break; | ||||
|         } | ||||
|         break; | ||||
|          | ||||
|     case 1: | ||||
|         player.commandReceiveState = 2; | ||||
|         player.commandReceiveExpectedBytes = read_ubyte(socket); | ||||
|         break; | ||||
|  | ||||
|     case 3: | ||||
|         player.commandReceiveState = 2; | ||||
|         player.commandReceiveExpectedBytes = read_ushort(socket); | ||||
|         break; | ||||
|          | ||||
|     case 2: | ||||
|         player.commandReceiveState = 0; | ||||
|         player.commandReceiveExpectedBytes = 1; | ||||
|         commandLimitRemaining -= 1; | ||||
|          | ||||
|         switch(player.commandReceiveCommand) | ||||
|         { | ||||
|         case PLAYER_LEAVE: | ||||
|             socket_destroy(player.socket); | ||||
|             player.socket = -1; | ||||
|             break; | ||||
|              | ||||
|         case PLAYER_CHANGECLASS: | ||||
|             var class; | ||||
|             class = read_ubyte(socket); | ||||
|             if(getCharacterObject(player.team, class) != -1) | ||||
|             { | ||||
|                 if(player.object != -1) | ||||
|                 { | ||||
|                     with(player.object) | ||||
|                     { | ||||
|                         if (collision_point(x,y,SpawnRoom,0,0) < 0) | ||||
|                         { | ||||
|                             if (!instance_exists(lastDamageDealer) || lastDamageDealer == player) | ||||
|                             { | ||||
|                                 sendEventPlayerDeath(player, player, noone, BID_FAREWELL); | ||||
|                                 doEventPlayerDeath(player, player, noone, BID_FAREWELL); | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
|                                 var assistant; | ||||
|                                 assistant = secondToLastDamageDealer; | ||||
|                                 if (lastDamageDealer.object) | ||||
|                                     if (lastDamageDealer.object.healer) | ||||
|                                         assistant = lastDamageDealer.object.healer; | ||||
|                                 sendEventPlayerDeath(player, lastDamageDealer, assistant, FINISHED_OFF); | ||||
|                                 doEventPlayerDeath(player, lastDamageDealer, assistant, FINISHED_OFF); | ||||
|                             } | ||||
|                         } | ||||
|                         else  | ||||
|                         instance_destroy();  | ||||
|                          | ||||
|                     } | ||||
|                 } | ||||
|                 else if(player.alarm[5]<=0) | ||||
|                     player.alarm[5] = 1; | ||||
|                 class = checkClasslimits(player, player.team, class); | ||||
|                 player.class = class; | ||||
|                 ServerPlayerChangeclass(playerId, player.class, global.sendBuffer); | ||||
|             } | ||||
|             break; | ||||
|              | ||||
|         case PLAYER_CHANGETEAM: | ||||
|             var newTeam, balance, redSuperiority; | ||||
|             newTeam = read_ubyte(socket); | ||||
|              | ||||
|             redSuperiority = 0   //calculate which team is bigger | ||||
|             with(Player) | ||||
|             { | ||||
|                 if(team == TEAM_RED) | ||||
|                     redSuperiority += 1; | ||||
|                 else if(team == TEAM_BLUE) | ||||
|                     redSuperiority -= 1; | ||||
|             } | ||||
|             if(redSuperiority > 0) | ||||
|                 balance = TEAM_RED; | ||||
|             else if(redSuperiority < 0) | ||||
|                 balance = TEAM_BLUE; | ||||
|             else | ||||
|                 balance = -1; | ||||
|              | ||||
|             if(balance != newTeam) | ||||
|             { | ||||
|                 if(getCharacterObject(newTeam, player.class) != -1 or newTeam==TEAM_SPECTATOR) | ||||
|                 {   | ||||
|                     if(player.object != -1) | ||||
|                     { | ||||
|                         with(player.object) | ||||
|                         { | ||||
|                             if (!instance_exists(lastDamageDealer) || lastDamageDealer == player) | ||||
|                             { | ||||
|                                 sendEventPlayerDeath(player, player, noone, BID_FAREWELL); | ||||
|                                 doEventPlayerDeath(player, player, noone, BID_FAREWELL); | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
|                                 var assistant; | ||||
|                                 assistant = secondToLastDamageDealer; | ||||
|                                 if (lastDamageDealer.object) | ||||
|                                     if (lastDamageDealer.object.healer) | ||||
|                                         assistant = lastDamageDealer.object.healer; | ||||
|                                 sendEventPlayerDeath(player, lastDamageDealer, assistant, FINISHED_OFF); | ||||
|                                 doEventPlayerDeath(player, lastDamageDealer, assistant, FINISHED_OFF); | ||||
|                             } | ||||
|                         } | ||||
|                         player.alarm[5] = global.Server_Respawntime; | ||||
|                     } | ||||
|                     else if(player.alarm[5]<=0) | ||||
|                         player.alarm[5] = 1;                     | ||||
|                     var newClass; | ||||
|                     newClass = checkClasslimits(player, newTeam, player.class); | ||||
|                     if newClass != player.class | ||||
|                     { | ||||
|                         player.class = newClass; | ||||
|                         ServerPlayerChangeclass(playerId, player.class, global.sendBuffer); | ||||
|                     } | ||||
|                     player.team = newTeam; | ||||
|                     ServerPlayerChangeteam(playerId, player.team, global.sendBuffer); | ||||
|                     ServerBalanceTeams(); | ||||
|                 } | ||||
|             } | ||||
|             break;                    | ||||
|              | ||||
|         case CHAT_BUBBLE: | ||||
|             var bubbleImage; | ||||
|             bubbleImage = read_ubyte(socket); | ||||
|             if(global.aFirst) { | ||||
|                 bubbleImage = 0; | ||||
|             } | ||||
|             write_ubyte(global.sendBuffer, CHAT_BUBBLE); | ||||
|             write_ubyte(global.sendBuffer, playerId); | ||||
|             write_ubyte(global.sendBuffer, bubbleImage); | ||||
|              | ||||
|             setChatBubble(player, bubbleImage); | ||||
|             break; | ||||
|              | ||||
|         case BUILD_SENTRY: | ||||
|             if(player.object != -1) | ||||
|             { | ||||
|                 if(player.class == CLASS_ENGINEER | ||||
|                         and collision_circle(player.object.x, player.object.y, 50, Sentry, false, true) < 0 | ||||
|                         and player.object.nutsNBolts == 100 | ||||
|                         and (collision_point(player.object.x,player.object.y,SpawnRoom,0,0) < 0) | ||||
|                         and !player.sentry | ||||
|                         and !player.object.onCabinet) | ||||
|                 { | ||||
|                     write_ubyte(global.sendBuffer, BUILD_SENTRY); | ||||
|                     write_ubyte(global.sendBuffer, playerId); | ||||
|                     write_ushort(global.serializeBuffer, round(player.object.x*5)); | ||||
|                     write_ushort(global.serializeBuffer, round(player.object.y*5)); | ||||
|                     write_byte(global.serializeBuffer, player.object.image_xscale); | ||||
|                     buildSentry(player, player.object.x, player.object.y, player.object.image_xscale); | ||||
|                 } | ||||
|             } | ||||
|             break;                                        | ||||
|  | ||||
|         case DESTROY_SENTRY: | ||||
|             with(player.sentry) | ||||
|                 instance_destroy(); | ||||
|             break;                      | ||||
|          | ||||
|         case DROP_INTEL: | ||||
|             if (player.object != -1) | ||||
|             { | ||||
|                 if (player.object.intel) | ||||
|                 { | ||||
|                     sendEventDropIntel(player); | ||||
|                     doEventDropIntel(player); | ||||
|                 } | ||||
|             } | ||||
|             break;      | ||||
|                | ||||
|         case OMNOMNOMNOM: | ||||
|             if(player.object != -1) { | ||||
|                 if(!player.humiliated | ||||
|                     and !player.object.taunting | ||||
|                     and !player.object.omnomnomnom | ||||
|                     and player.object.canEat | ||||
|                     and player.class==CLASS_HEAVY) | ||||
|                 {                             | ||||
|                     write_ubyte(global.sendBuffer, OMNOMNOMNOM); | ||||
|                     write_ubyte(global.sendBuffer, playerId); | ||||
|                     with(player.object) | ||||
|                     { | ||||
|                         omnomnomnom = true; | ||||
|                         if player.team == TEAM_RED { | ||||
|                             omnomnomnomindex=0; | ||||
|                             omnomnomnomend=31; | ||||
|                         } else if player.team==TEAM_BLUE { | ||||
|                             omnomnomnomindex=32; | ||||
|                             omnomnomnomend=63; | ||||
|                         }  | ||||
|                         xscale=image_xscale; | ||||
|                     }              | ||||
|                 } | ||||
|             } | ||||
|             break; | ||||
|               | ||||
|         case TOGGLE_ZOOM: | ||||
|             if player.object != -1 { | ||||
|                 if player.class == CLASS_SNIPER { | ||||
|                     write_ubyte(global.sendBuffer, TOGGLE_ZOOM); | ||||
|                     write_ubyte(global.sendBuffer, playerId); | ||||
|                     toggleZoom(player.object); | ||||
|                 } | ||||
|             } | ||||
|             break; | ||||
|                                                        | ||||
|         case PLAYER_CHANGENAME: | ||||
|             var nameLength; | ||||
|             nameLength = socket_receivebuffer_size(socket); | ||||
|             if(nameLength > MAX_PLAYERNAME_LENGTH) | ||||
|             { | ||||
|                 write_ubyte(player.socket, KICK); | ||||
|                 write_ubyte(player.socket, KICK_NAME); | ||||
|                 socket_destroy(player.socket); | ||||
|                 player.socket = -1; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 with(player) | ||||
|                 { | ||||
|                     if(variable_local_exists("lastNamechange"))  | ||||
|                         if(current_time - lastNamechange < 1000) | ||||
|                             break; | ||||
|                     lastNamechange = current_time; | ||||
|                     name = read_string(socket, nameLength); | ||||
|                     if(string_count("#",name) > 0) | ||||
|                     { | ||||
|                         name = "I <3 Bacon"; | ||||
|                     } | ||||
|                     write_ubyte(global.sendBuffer, PLAYER_CHANGENAME); | ||||
|                     write_ubyte(global.sendBuffer, playerId); | ||||
|                     write_ubyte(global.sendBuffer, string_length(name)); | ||||
|                     write_string(global.sendBuffer, name); | ||||
|                 } | ||||
|             } | ||||
|             break; | ||||
|              | ||||
|         case INPUTSTATE: | ||||
|             if(player.object != -1) | ||||
|             { | ||||
|                 with(player.object) | ||||
|                 { | ||||
|                     keyState = read_ubyte(socket); | ||||
|                     netAimDirection = read_ushort(socket); | ||||
|                     aimDirection = netAimDirection*360/65536; | ||||
|                     event_user(1); | ||||
|                 } | ||||
|             } | ||||
|             break; | ||||
|          | ||||
|         case REWARD_REQUEST: | ||||
|             player.rewardId = read_string(socket, socket_receivebuffer_size(socket)); | ||||
|             player.challenge = rewardCreateChallenge(); | ||||
|              | ||||
|             write_ubyte(socket, REWARD_CHALLENGE_CODE); | ||||
|             write_binstring(socket, player.challenge); | ||||
|             break; | ||||
|              | ||||
|         case REWARD_CHALLENGE_RESPONSE: | ||||
|             var answer, i, authbuffer; | ||||
|             answer = read_binstring(socket, 16); | ||||
|              | ||||
|             with(player) | ||||
|                 if(variable_local_exists("challenge") and variable_local_exists("rewardId")) | ||||
|                     rewardAuthStart(player, answer, challenge, true, rewardId); | ||||
|             | ||||
|             break; | ||||
|  | ||||
|         case PLUGIN_PACKET: | ||||
|             var packetID, buf, success; | ||||
|  | ||||
|             packetID = read_ubyte(socket); | ||||
|              | ||||
|             // get packet data | ||||
|             buf = buffer_create(); | ||||
|             write_buffer_part(buf, socket, socket_receivebuffer_size(socket)); | ||||
|  | ||||
|             // try to enqueue | ||||
|             success = _PluginPacketPush(packetID, buf, player); | ||||
|              | ||||
|             // if it returned false, packetID was invalid | ||||
|             if (!success) | ||||
|             { | ||||
|                 // clear up buffer | ||||
|                 buffer_destroy(buf); | ||||
|  | ||||
|                 // kick player | ||||
|                 write_ubyte(player.socket, KICK); | ||||
|                 write_ubyte(player.socket, KICK_BAD_PLUGIN_PACKET); | ||||
|                 socket_destroy(player.socket); | ||||
|                 player.socket = -1; | ||||
|             } | ||||
|             break; | ||||
|              | ||||
|         case CLIENT_SETTINGS: | ||||
|             var mirror; | ||||
|             mirror = read_ubyte(player.socket); | ||||
|             player.queueJump = mirror; | ||||
|              | ||||
|             write_ubyte(global.sendBuffer, CLIENT_SETTINGS); | ||||
|             write_ubyte(global.sendBuffer, playerId); | ||||
|             write_ubyte(global.sendBuffer, mirror); | ||||
|             break; | ||||
|          | ||||
|         } | ||||
|         break; | ||||
|     }  | ||||
| } | ||||
							
								
								
									
										298
									
								
								samples/Game Maker Language/scrInitLevel.gml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										298
									
								
								samples/Game Maker Language/scrInitLevel.gml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,298 @@ | ||||
| // Originally from /spelunky/Scripts/Level Generation/scrInitLevel.gml in the Spelunky Community Update Project | ||||
|  | ||||
| // | ||||
| // scrInitLevel() | ||||
| // | ||||
| // Calls scrLevelGen(), scrRoomGen*(), and scrEntityGen() to build level. | ||||
| // | ||||
|  | ||||
| /********************************************************************************** | ||||
|     Copyright (c) 2008, 2009 Derek Yu and Mossmouth, LLC | ||||
|      | ||||
|     This file is part of Spelunky. | ||||
|  | ||||
|     You can redistribute and/or modify Spelunky, including its source code, under | ||||
|     the terms of the Spelunky User License. | ||||
|  | ||||
|     Spelunky is distributed in the hope that it will be entertaining and useful, | ||||
|     but WITHOUT WARRANTY.  Please see the Spelunky User License for more details. | ||||
|  | ||||
|     The Spelunky User License should be available in "Game Information", which | ||||
|     can be found in the Resource Explorer, or as an external file called COPYING. | ||||
|     If not, please obtain a new copy of Spelunky from <http://spelunkyworld.com/> | ||||
|      | ||||
| ***********************************************************************************/ | ||||
|  | ||||
| global.levelType = 0; | ||||
| //global.currLevel = 16; | ||||
| if (global.currLevel > 4 and global.currLevel < 9) global.levelType = 1; | ||||
| if (global.currLevel > 8 and global.currLevel < 13) global.levelType = 2; | ||||
| if (global.currLevel > 12 and global.currLevel < 16) global.levelType = 3; | ||||
| if (global.currLevel == 16) global.levelType = 4; | ||||
|  | ||||
| if (global.currLevel <= 1 or | ||||
|     global.currLevel == 5 or | ||||
|     global.currLevel == 9 or | ||||
|     global.currLevel == 13) | ||||
| { | ||||
|     global.hadDarkLevel = false; | ||||
| } | ||||
|  | ||||
| // global.levelType = 3; // debug | ||||
|  | ||||
| // DEBUG MODE // | ||||
| /* | ||||
| if (global.currLevel == 2) global.levelType = 4; | ||||
| if (global.currLevel == 3) global.levelType = 2; | ||||
| if (global.currLevel == 4) global.levelType = 3; | ||||
| if (global.currLevel == 5) global.levelType = 4; | ||||
| */ | ||||
|  | ||||
| // global.levelType = 0; | ||||
|  | ||||
| global.startRoomX = 0; | ||||
| global.startRoomY = 0; | ||||
| global.endRoomX = 0; | ||||
| global.endRoomY = 0; | ||||
| oGame.levelGen = false; | ||||
|  | ||||
| // this is used to determine the path to the exit (generally no bombs required) | ||||
| for (i = 0; i < 4; i += 1) | ||||
| { | ||||
|     for (j = 0; j < 4; j += 1) | ||||
|     { | ||||
|         global.roomPath[i,j] = 0; | ||||
|     } | ||||
| } | ||||
|  | ||||
| // side walls | ||||
| if (global.levelType == 4) | ||||
|     k = 54; | ||||
| else if (global.levelType == 2) | ||||
|     k = 38; | ||||
| else if (global.lake) | ||||
|     k = 41; | ||||
| else | ||||
|     k = 33; | ||||
| for (i = 0; i <= 42; i += 1) | ||||
| { | ||||
|     for (j = 0; j <= k; j += 1) | ||||
|     { | ||||
|         if (not isLevel()) | ||||
|         { | ||||
|             i = 999; | ||||
|             j = 999; | ||||
|         } | ||||
|         else if (global.levelType == 2) | ||||
|         { | ||||
|             if (i*16 == 0 or | ||||
|                 i*16 == 656 or | ||||
|                 j*16 == 0) | ||||
|             { | ||||
|                 obj = instance_create(i*16, j*16, oDark); | ||||
|                 obj.invincible = true; | ||||
|                 obj.sprite_index = sDark; | ||||
|             } | ||||
|         } | ||||
|         else if (global.levelType == 4) | ||||
|         { | ||||
|             if (i*16 == 0 or | ||||
|                 i*16 == 656 or | ||||
|                 j*16 == 0) | ||||
|             { | ||||
|                 obj = instance_create(i*16, j*16, oTemple); | ||||
|                 obj.invincible = true; | ||||
|                 if (not global.cityOfGold) obj.sprite_index = sTemple; | ||||
|             } | ||||
|         } | ||||
|         else if (global.lake) | ||||
|         { | ||||
|             if (i*16 == 0 or | ||||
|                 i*16 == 656 or | ||||
|                 j*16 == 0 or | ||||
|                 j*16 >= 656) | ||||
|             { | ||||
|                 obj = instance_create(i*16, j*16, oLush); obj.sprite_index = sLush; | ||||
|                 obj.invincible = true; | ||||
|             } | ||||
|         } | ||||
|         else if (i*16 == 0 or | ||||
|             i*16 == 656 or | ||||
|             j*16 == 0 or | ||||
|             j*16 >= 528) | ||||
|         { | ||||
|             if (global.levelType == 0) { obj = instance_create(i*16, j*16, oBrick); obj.sprite_index = sBrick; } | ||||
|             else if (global.levelType == 1) { obj = instance_create(i*16, j*16, oLush); obj.sprite_index = sLush; } | ||||
|             else { obj = instance_create(i*16, j*16, oTemple); if (not global.cityOfGold) obj.sprite_index = sTemple; } | ||||
|             obj.invincible = true; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| if (global.levelType == 2) | ||||
| { | ||||
|     for (i = 0; i <= 42; i += 1) | ||||
|     { | ||||
|         instance_create(i*16, 40*16, oDark); | ||||
|         //instance_create(i*16, 35*16, oSpikes); | ||||
|     } | ||||
| } | ||||
|  | ||||
| if (global.levelType == 3) | ||||
| { | ||||
|     background_index = bgTemple; | ||||
| } | ||||
|  | ||||
| global.temp1 = global.gameStart; | ||||
| scrLevelGen(); | ||||
|  | ||||
| global.cemetary = false; | ||||
| if (global.levelType == 1 and rand(1,global.probCemetary) == 1) global.cemetary = true; | ||||
|  | ||||
| with oRoom | ||||
| { | ||||
|     if (global.levelType == 0) scrRoomGen(); | ||||
|     else if (global.levelType == 1) | ||||
|     { | ||||
|         if (global.blackMarket) scrRoomGenMarket(); | ||||
|         else scrRoomGen2(); | ||||
|     } | ||||
|     else if (global.levelType == 2) | ||||
|     { | ||||
|         if (global.yetiLair) scrRoomGenYeti(); | ||||
|         else scrRoomGen3(); | ||||
|     } | ||||
|     else if (global.levelType == 3) scrRoomGen4(); | ||||
|     else scrRoomGen5(); | ||||
| } | ||||
|  | ||||
| global.darkLevel = false; | ||||
| //if (not global.hadDarkLevel and global.currLevel != 0 and global.levelType != 2 and global.currLevel != 16 and rand(1,1) == 1) | ||||
| if (not global.hadDarkLevel and not global.noDarkLevel and global.currLevel != 0 and global.currLevel != 1 and global.levelType != 2 and global.currLevel != 16 and rand(1,global.probDarkLevel) == 1) | ||||
| { | ||||
|     global.darkLevel = true; | ||||
|     global.hadDarkLevel = true; | ||||
|     //instance_create(oPlayer1.x, oPlayer1.y, oFlare); | ||||
| } | ||||
|  | ||||
| if (global.blackMarket) global.darkLevel = false; | ||||
|  | ||||
| global.genUdjatEye = false; | ||||
| if (not global.madeUdjatEye) | ||||
| { | ||||
|     if (global.currLevel == 2 and rand(1,3) == 1) global.genUdjatEye = true; | ||||
|     else if (global.currLevel == 3 and rand(1,2) == 1) global.genUdjatEye = true; | ||||
|     else if (global.currLevel == 4) global.genUdjatEye = true; | ||||
| } | ||||
|  | ||||
| global.genMarketEntrance = false; | ||||
| if (not global.madeMarketEntrance) | ||||
| { | ||||
|     if (global.currLevel == 5 and rand(1,3) == 1) global.genMarketEntrance = true; | ||||
|     else if (global.currLevel == 6 and rand(1,2) == 1) global.genMarketEntrance = true; | ||||
|     else if (global.currLevel == 7) global.genMarketEntrance = true; | ||||
| } | ||||
|  | ||||
| //////////////////////////// | ||||
| // ENTITY / TREASURES | ||||
| //////////////////////////// | ||||
| global.temp2 = global.gameStart; | ||||
| if (not isRoom("rTutorial") and not isRoom("rLoadLevel")) scrEntityGen(); | ||||
|  | ||||
| if (instance_exists(oEntrance) and not global.customLevel) | ||||
| { | ||||
|     oPlayer1.x = oEntrance.x+8; | ||||
|     oPlayer1.y = oEntrance.y+8; | ||||
| } | ||||
|  | ||||
| if (global.darkLevel or | ||||
|     global.blackMarket or | ||||
|     global.snakePit or | ||||
|     global.cemetary or | ||||
|     global.lake or | ||||
|     global.yetiLair or | ||||
|     global.alienCraft or | ||||
|     global.sacrificePit or | ||||
|     global.cityOfGold) | ||||
| { | ||||
|     if (not isRoom("rLoadLevel")) | ||||
|     { | ||||
|         with oPlayer1 { alarm[0] = 10; } | ||||
|     } | ||||
| } | ||||
|  | ||||
| if (global.levelType == 4) scrSetupWalls(864); | ||||
| else if (global.lake) scrSetupWalls(656); | ||||
| else scrSetupWalls(528); | ||||
|  | ||||
| // add background details | ||||
| if (global.graphicsHigh) | ||||
| { | ||||
|     repeat(20) | ||||
|     { | ||||
|         // bg = instance_create(16*rand(1,42), 16*rand(1,33), oCaveBG); | ||||
|         if (global.levelType == 1 and rand(1,3) < 3) | ||||
|             tile_add(bgExtrasLush, 32*rand(0,1), 0, 32, 32, 16*rand(1,42), 16*rand(1,33), 10002); | ||||
|         else if (global.levelType == 2 and rand(1,3) < 3) | ||||
|             tile_add(bgExtrasIce, 32*rand(0,1), 0, 32, 32, 16*rand(1,42), 16*rand(1,33), 10002); | ||||
|         else if (global.levelType == 3 and rand(1,3) < 3) | ||||
|             tile_add(bgExtrasTemple, 32*rand(0,1), 0, 32, 32, 16*rand(1,42), 16*rand(1,33), 10002); | ||||
|         else | ||||
|             tile_add(bgExtras, 32*rand(0,1), 0, 32, 32, 16*rand(1,42), 16*rand(1,33), 10002); | ||||
|     } | ||||
| } | ||||
|  | ||||
| oGame.levelGen = true; | ||||
|  | ||||
| // generate angry shopkeeper at exit if murderer or thief | ||||
| if ((global.murderer or global.thiefLevel > 0) and isRealLevel()) | ||||
| { | ||||
|     with oExit | ||||
|     { | ||||
|         if (type == "Exit") | ||||
|         { | ||||
|             obj = instance_create(x, y, oShopkeeper); | ||||
|             obj.status = 4; | ||||
|         } | ||||
|     } | ||||
|     // global.thiefLevel -= 1; | ||||
| } | ||||
|  | ||||
| with oTreasure | ||||
| { | ||||
|     if (collision_point(x, y, oSolid, 0, 0)) | ||||
|     { | ||||
|         obj = instance_place(x, y, oSolid); | ||||
|         if (obj.invincible) instance_destroy(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| with oWater | ||||
| { | ||||
|     if (sprite_index == sWaterTop or sprite_index == sLavaTop) | ||||
|     { | ||||
|         scrCheckWaterTop(); | ||||
|     } | ||||
|     /* | ||||
|         obj = instance_place(x-16, y, oWater); | ||||
|         if (instance_exists(obj)) | ||||
|         { | ||||
|             if (obj.sprite_index == sWaterTop or obj.sprite_index == sLavaTop) | ||||
|             { | ||||
|                 if (type == "Lava") sprite_index = sLavaTop; | ||||
|                 else sprite_index = sWaterTop; | ||||
|             } | ||||
|         } | ||||
|         obj = instance_place(x+16, y, oWater); | ||||
|         if (instance_exists(obj)) | ||||
|         { | ||||
|             if (obj.sprite_index == sWaterTop or obj.sprite_index == sLavaTop) | ||||
|             { | ||||
|                 if (type == "Lava") sprite_index = sLavaTop; | ||||
|                 else sprite_index = sWaterTop; | ||||
|             } | ||||
|         } | ||||
|     */ | ||||
| } | ||||
|  | ||||
| global.temp3 = global.gameStart; | ||||
							
								
								
									
										22
									
								
								samples/Gnuplot/dashcolor.1.gnu
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								samples/Gnuplot/dashcolor.1.gnu
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| # set terminal pngcairo  background "#ffffff" fontscale 1.0 dashed size 640, 480  | ||||
| # set output 'dashcolor.1.png' | ||||
| set label 1 "set style line 1 lt 2 lc rgb \"red\" lw 3" at -0.4, -0.25, 0 left norotate back textcolor rgb "red"  nopoint offset character 0, 0, 0 | ||||
| set label 2 "set style line 2 lt 2 lc rgb \"orange\" lw 2" at -0.4, -0.35, 0 left norotate back textcolor rgb "orange"  nopoint offset character 0, 0, 0 | ||||
| set label 3 "set style line 3 lt 2 lc rgb \"yellow\" lw 3" at -0.4, -0.45, 0 left norotate back textcolor rgb "yellow"  nopoint offset character 0, 0, 0 | ||||
| set label 4 "set style line 4 lt 2 lc rgb \"green\" lw 2" at -0.4, -0.55, 0 left norotate back textcolor rgb "green"  nopoint offset character 0, 0, 0 | ||||
| set label 5 "plot ... lt 1 lc 3 " at -0.4, -0.65, 0 left norotate back textcolor lt 3 nopoint offset character 0, 0, 0 | ||||
| set label 6 "plot ... lt 3 lc 3 " at -0.4, -0.75, 0 left norotate back textcolor lt 3 nopoint offset character 0, 0, 0 | ||||
| set label 7 "plot ... lt 5 lc 3 " at -0.4, -0.85, 0 left norotate back textcolor lt 3 nopoint offset character 0, 0, 0 | ||||
| set style line 1  linetype 2 linecolor rgb "red"  linewidth 3.000 pointtype 2 pointsize default pointinterval 0 | ||||
| set style line 2  linetype 2 linecolor rgb "orange"  linewidth 2.000 pointtype 2 pointsize default pointinterval 0 | ||||
| set style line 3  linetype 2 linecolor rgb "yellow"  linewidth 3.000 pointtype 2 pointsize default pointinterval 0 | ||||
| set style line 4  linetype 2 linecolor rgb "green"  linewidth 2.000 pointtype 2 pointsize default pointinterval 0 | ||||
| set noxtics | ||||
| set noytics | ||||
| set title "Independent colors and dot/dash styles"  | ||||
| set xlabel "You will only see dashed lines if your current terminal setting permits it"  | ||||
| set xrange [ -0.500000 : 3.50000 ] noreverse nowriteback | ||||
| set yrange [ -1.00000 : 1.40000 ] noreverse nowriteback | ||||
| set bmargin  7 | ||||
| unset colorbox | ||||
| plot cos(x)     ls 1 title 'ls 1',        cos(x-.2)  ls 2 title 'ls 2',     cos(x-.4)  ls 3 title 'ls 3',     cos(x-.6)  ls 4 title 'ls 4',      cos(x-.8)  lt 1 lc 3 title 'lt 1 lc 3',       cos(x-1.)  lt 3 lc 3 title 'lt 3 lc 3',       cos(x-1.2) lt 5 lc 3 title 'lt 5 lc 3' | ||||
							
								
								
									
										15
									
								
								samples/Gnuplot/histograms.2.gnu
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								samples/Gnuplot/histograms.2.gnu
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| # set terminal pngcairo  transparent enhanced font "arial,10" fontscale 1.0 size 500, 350  | ||||
| # set output 'histograms.2.png' | ||||
| set boxwidth 0.9 absolute | ||||
| set style fill   solid 1.00 border lt -1 | ||||
| set key inside right top vertical Right noreverse noenhanced autotitles nobox | ||||
| set style histogram clustered gap 1 title  offset character 0, 0, 0 | ||||
| set datafile missing '-' | ||||
| set style data histograms | ||||
| set xtics border in scale 0,0 nomirror rotate by -45  offset character 0, 0, 0 autojustify | ||||
| set xtics  norangelimit font ",8" | ||||
| set xtics   () | ||||
| set title "US immigration from Northern Europe\nPlot selected data columns as histogram of clustered boxes"  | ||||
| set yrange [ 0.00000 : 300000. ] noreverse nowriteback | ||||
| i = 22 | ||||
| plot 'immigration.dat' using 6:xtic(1) ti col, '' u 12 ti col, '' u 13 ti col, '' u 14 ti col | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user