diff --git a/.gitignore b/.gitignore
--- a/.gitignore
+++ b/.gitignore
@@ -20,7 +20,16 @@
#ignore public assets???
/public/assets
+/public
+
+/data
#ignore .orig and .swp
*.orig
*.swp
+
+#ignore rvm setting file
+.ruby-gemset
+.ruby-version
+
+/config/secrets.yml
diff --git a/Gemfile b/Gemfile
--- a/Gemfile
+++ b/Gemfile
@@ -1,25 +1,34 @@
source 'https://rubygems.org'
-gem 'rails', '3.2.21'
+#rails
+gem 'rails', '~>4.2.0'
+gem 'activerecord-session_store'
+
# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'
+#---------------- database ---------------------
+#the database
gem 'mysql2'
+#for testing
+gem 'sqlite3'
+#for dumping database into yaml
+gem 'yaml_db'
# Gems used only for assets and not required
# in production environments by default.
-group :assets do
- gem 'sass-rails', '~> 3.2.6'
- gem 'coffee-rails', '~> 3.2.2'
+gem 'sass-rails'
+gem 'coffee-rails'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', :platforms => :ruby
- gem 'uglifier'
-end
+gem 'uglifier'
-gem 'prototype-rails'
+gem 'haml'
+gem 'haml-rails'
+# gem 'prototype-rails'
# To use ActiveModel has_secure_password
# gem 'bcrypt-ruby', '~> 3.0.0'
@@ -42,22 +51,41 @@
# jquery addition
gem 'jquery-rails'
-gem 'jquery-ui-sass-rails'
+gem 'jquery-ui-rails'
gem 'jquery-timepicker-addon-rails'
gem 'jquery-tablesorter'
+gem 'jquery-countdown-rails'
#syntax highlighter
gem 'rouge'
-gem 'haml'
+#add bootstrap
+gem 'bootstrap-sass', '~> 3.2.0'
+gem 'bootstrap-switch-rails'
+gem 'bootstrap-toggle-rails'
+gem 'autoprefixer-rails'
+
+#bootstrap sortable
+gem 'momentjs-rails'
+gem 'rails_bootstrap_sortable'
+
+#----------- user interface -----------------
+#select 2
+gem 'select2-rails'
+#ace editor
+gem 'ace-rails-ap'
+#paginator
+gem 'will_paginate', '~> 3.0.7'
+
gem 'mail'
gem 'rdiscount'
-gem 'test-unit'
-gem 'will_paginate', '~> 3.0.7'
gem 'dynamic_form'
gem 'in_place_editing'
gem 'verification', :git => 'https://github.com/sikachu/verification.git'
-group :test, :development do
- gem 'rspec-rails', '~> 2.99.0'
-end
+
+#---------------- testiing -----------------------
+gem 'minitest-reporters'
+
+#---------------- for console --------------------
+gem 'fuzzy-string-match'
diff --git a/Gemfile.lock b/Gemfile.lock
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,175 +1,235 @@
GIT
remote: https://github.com/sikachu/verification.git
- revision: 76eaf51b13276ecae54bd9cd115832595d2ff56d
+ revision: ff31697b940d7b0e2ec65f08764215c96104e76d
specs:
verification (1.0.3)
- actionpack (>= 3.0.0, < 5.0)
- activesupport (>= 3.0.0, < 5.0)
+ actionpack (>= 3.0.0, < 5.1)
+ activesupport (>= 3.0.0, < 5.1)
GEM
remote: https://rubygems.org/
specs:
- actionmailer (3.2.21)
- actionpack (= 3.2.21)
- mail (~> 2.5.4)
- actionpack (3.2.21)
- activemodel (= 3.2.21)
- activesupport (= 3.2.21)
- builder (~> 3.0.0)
+ RubyInline (3.12.4)
+ ZenTest (~> 4.3)
+ ZenTest (4.11.1)
+ ace-rails-ap (4.1.1)
+ actionmailer (4.2.7.1)
+ actionpack (= 4.2.7.1)
+ actionview (= 4.2.7.1)
+ activejob (= 4.2.7.1)
+ mail (~> 2.5, >= 2.5.4)
+ rails-dom-testing (~> 1.0, >= 1.0.5)
+ actionpack (4.2.7.1)
+ actionview (= 4.2.7.1)
+ activesupport (= 4.2.7.1)
+ rack (~> 1.6)
+ rack-test (~> 0.6.2)
+ rails-dom-testing (~> 1.0, >= 1.0.5)
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
+ actionview (4.2.7.1)
+ activesupport (= 4.2.7.1)
+ builder (~> 3.1)
erubis (~> 2.7.0)
- journey (~> 1.0.4)
- rack (~> 1.4.5)
- rack-cache (~> 1.2)
- rack-test (~> 0.6.1)
- sprockets (~> 2.2.1)
- activemodel (3.2.21)
- activesupport (= 3.2.21)
- builder (~> 3.0.0)
- activerecord (3.2.21)
- activemodel (= 3.2.21)
- activesupport (= 3.2.21)
- arel (~> 3.0.2)
- tzinfo (~> 0.3.29)
- activeresource (3.2.21)
- activemodel (= 3.2.21)
- activesupport (= 3.2.21)
- activesupport (3.2.21)
- i18n (~> 0.6, >= 0.6.4)
- multi_json (~> 1.0)
- arel (3.0.3)
+ rails-dom-testing (~> 1.0, >= 1.0.5)
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
+ activejob (4.2.7.1)
+ activesupport (= 4.2.7.1)
+ globalid (>= 0.3.0)
+ activemodel (4.2.7.1)
+ activesupport (= 4.2.7.1)
+ builder (~> 3.1)
+ activerecord (4.2.7.1)
+ activemodel (= 4.2.7.1)
+ activesupport (= 4.2.7.1)
+ arel (~> 6.0)
+ activerecord-session_store (1.0.0)
+ actionpack (>= 4.0, < 5.1)
+ activerecord (>= 4.0, < 5.1)
+ multi_json (~> 1.11, >= 1.11.2)
+ rack (>= 1.5.2, < 3)
+ railties (>= 4.0, < 5.1)
+ activesupport (4.2.7.1)
+ i18n (~> 0.7)
+ json (~> 1.7, >= 1.7.7)
+ minitest (~> 5.1)
+ thread_safe (~> 0.3, >= 0.3.4)
+ tzinfo (~> 1.1)
+ ansi (1.5.0)
+ arel (6.0.4)
+ autoprefixer-rails (6.6.0)
+ execjs
best_in_place (3.0.3)
actionpack (>= 3.2)
railties (>= 3.2)
- builder (3.0.4)
- coffee-rails (3.2.2)
+ bootstrap-sass (3.2.0.2)
+ sass (~> 3.2)
+ bootstrap-switch-rails (3.3.3)
+ bootstrap-toggle-rails (2.2.1.0)
+ builder (3.2.2)
+ coffee-rails (4.2.1)
coffee-script (>= 2.2.0)
- railties (~> 3.2.0)
- coffee-script (2.3.0)
+ railties (>= 4.0.0, < 5.2.x)
+ coffee-script (2.4.1)
coffee-script-source
execjs
- coffee-script-source (1.9.0)
- diff-lcs (1.2.5)
+ coffee-script-source (1.12.2)
+ concurrent-ruby (1.0.4)
dynamic_form (1.1.4)
erubis (2.7.0)
- execjs (2.3.0)
- haml (4.0.6)
+ execjs (2.7.0)
+ fuzzy-string-match (1.0.0)
+ RubyInline (>= 3.8.6)
+ globalid (0.3.7)
+ activesupport (>= 4.1.0)
+ haml (4.0.7)
tilt
- hike (1.2.3)
+ haml-rails (0.9.0)
+ actionpack (>= 4.0.1)
+ activesupport (>= 4.0.1)
+ haml (>= 4.0.6, < 5.0)
+ html2haml (>= 1.0.1)
+ railties (>= 4.0.1)
+ html2haml (2.0.0)
+ erubis (~> 2.7.0)
+ haml (~> 4.0.0)
+ nokogiri (~> 1.6.0)
+ ruby_parser (~> 3.5)
i18n (0.7.0)
in_place_editing (1.2.0)
- journey (1.0.4)
- jquery-rails (3.1.2)
- railties (>= 3.0, < 5.0)
+ jquery-countdown-rails (2.0.2)
+ jquery-rails (4.2.1)
+ rails-dom-testing (>= 1, < 3)
+ railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
- jquery-tablesorter (1.13.4)
- railties (>= 3.1, < 5)
+ jquery-tablesorter (1.23.3)
+ railties (>= 3.2, < 6)
jquery-timepicker-addon-rails (1.4.1)
railties (>= 3.1)
- jquery-ui-rails (4.0.3)
- jquery-rails
- railties (>= 3.1.0)
- jquery-ui-sass-rails (4.0.3.0)
- jquery-rails
- jquery-ui-rails (= 4.0.3)
- railties (>= 3.1.0)
- json (1.8.2)
- mail (2.5.4)
- mime-types (~> 1.16)
- treetop (~> 1.4.8)
- mime-types (1.25.1)
- multi_json (1.10.1)
- mysql2 (0.3.17)
- polyglot (0.3.5)
- power_assert (0.2.2)
- prototype-rails (3.2.1)
- rails (~> 3.2)
- rack (1.4.5)
- rack-cache (1.2)
- rack (>= 0.4)
- rack-ssl (1.3.4)
- rack
+ jquery-ui-rails (6.0.1)
+ railties (>= 3.2.16)
+ json (1.8.3)
+ loofah (2.0.3)
+ nokogiri (>= 1.5.9)
+ mail (2.6.4)
+ mime-types (>= 1.16, < 4)
+ mime-types (3.1)
+ mime-types-data (~> 3.2015)
+ mime-types-data (3.2016.0521)
+ mini_portile2 (2.1.0)
+ minitest (5.10.1)
+ minitest-reporters (1.1.13)
+ ansi
+ builder
+ minitest (>= 5.0)
+ ruby-progressbar
+ momentjs-rails (2.15.1)
+ railties (>= 3.1)
+ multi_json (1.12.1)
+ mysql2 (0.4.5)
+ nokogiri (1.6.8.1)
+ mini_portile2 (~> 2.1.0)
+ rack (1.6.5)
rack-test (0.6.3)
rack (>= 1.0)
- rails (3.2.21)
- actionmailer (= 3.2.21)
- actionpack (= 3.2.21)
- activerecord (= 3.2.21)
- activeresource (= 3.2.21)
- activesupport (= 3.2.21)
- bundler (~> 1.0)
- railties (= 3.2.21)
- railties (3.2.21)
- actionpack (= 3.2.21)
- activesupport (= 3.2.21)
- rack-ssl (~> 1.3.2)
+ rails (4.2.7.1)
+ actionmailer (= 4.2.7.1)
+ actionpack (= 4.2.7.1)
+ actionview (= 4.2.7.1)
+ activejob (= 4.2.7.1)
+ activemodel (= 4.2.7.1)
+ activerecord (= 4.2.7.1)
+ activesupport (= 4.2.7.1)
+ bundler (>= 1.3.0, < 2.0)
+ railties (= 4.2.7.1)
+ sprockets-rails
+ rails-deprecated_sanitizer (1.0.3)
+ activesupport (>= 4.2.0.alpha)
+ rails-dom-testing (1.0.8)
+ activesupport (>= 4.2.0.beta, < 5.0)
+ nokogiri (~> 1.6)
+ rails-deprecated_sanitizer (>= 1.0.1)
+ rails-html-sanitizer (1.0.3)
+ loofah (~> 2.0)
+ rails_bootstrap_sortable (2.0.1)
+ momentjs-rails (>= 2.8.3)
+ railties (4.2.7.1)
+ actionpack (= 4.2.7.1)
+ activesupport (= 4.2.7.1)
rake (>= 0.8.7)
- rdoc (~> 3.4)
- thor (>= 0.14.6, < 2.0)
- rake (10.4.2)
- rdiscount (2.1.8)
- rdoc (3.12.2)
- json (~> 1.4)
- rouge (1.8.0)
- rspec-collection_matchers (1.1.2)
- rspec-expectations (>= 2.99.0.beta1)
- rspec-core (2.99.2)
- rspec-expectations (2.99.2)
- diff-lcs (>= 1.1.3, < 2.0)
- rspec-mocks (2.99.3)
- rspec-rails (2.99.0)
- actionpack (>= 3.0)
- activemodel (>= 3.0)
- activesupport (>= 3.0)
- railties (>= 3.0)
- rspec-collection_matchers
- rspec-core (~> 2.99.0)
- rspec-expectations (~> 2.99.0)
- rspec-mocks (~> 2.99.0)
- sass (3.4.11)
- sass-rails (3.2.6)
- railties (~> 3.2.0)
- sass (>= 3.1.10)
- tilt (~> 1.3)
- sprockets (2.2.3)
- hike (~> 1.2)
- multi_json (~> 1.0)
- rack (~> 1.0)
- tilt (~> 1.1, != 1.3.0)
- test-unit (3.0.9)
- power_assert
- thor (0.19.1)
- tilt (1.4.1)
- treetop (1.4.15)
- polyglot
- polyglot (>= 0.3.1)
- tzinfo (0.3.43)
- uglifier (2.7.0)
- execjs (>= 0.3.0)
- json (>= 1.8.0)
- will_paginate (3.0.7)
+ thor (>= 0.18.1, < 2.0)
+ rake (12.0.0)
+ rdiscount (2.2.0.1)
+ rouge (2.0.7)
+ ruby-progressbar (1.8.1)
+ ruby_parser (3.8.3)
+ sexp_processor (~> 4.1)
+ sass (3.4.23)
+ sass-rails (5.0.6)
+ railties (>= 4.0.0, < 6)
+ sass (~> 3.1)
+ sprockets (>= 2.8, < 4.0)
+ sprockets-rails (>= 2.0, < 4.0)
+ tilt (>= 1.1, < 3)
+ select2-rails (4.0.3)
+ thor (~> 0.14)
+ sexp_processor (4.7.0)
+ sprockets (3.7.1)
+ concurrent-ruby (~> 1.0)
+ rack (> 1, < 3)
+ sprockets-rails (3.2.0)
+ actionpack (>= 4.0)
+ activesupport (>= 4.0)
+ sprockets (>= 3.0.0)
+ sqlite3 (1.3.12)
+ thor (0.19.4)
+ thread_safe (0.3.5)
+ tilt (2.0.5)
+ tzinfo (1.2.2)
+ thread_safe (~> 0.1)
+ uglifier (3.0.4)
+ execjs (>= 0.3.0, < 3)
+ will_paginate (3.0.12)
+ yaml_db (0.4.2)
+ rails (>= 3.0, < 5.1)
+ rake (>= 0.8.7)
PLATFORMS
ruby
DEPENDENCIES
+ ace-rails-ap
+ activerecord-session_store
+ autoprefixer-rails
best_in_place (~> 3.0.1)
- coffee-rails (~> 3.2.2)
+ bootstrap-sass (~> 3.2.0)
+ bootstrap-switch-rails
+ bootstrap-toggle-rails
+ coffee-rails
dynamic_form
+ fuzzy-string-match
haml
+ haml-rails
in_place_editing
+ jquery-countdown-rails
jquery-rails
jquery-tablesorter
jquery-timepicker-addon-rails
- jquery-ui-sass-rails
+ jquery-ui-rails
mail
+ minitest-reporters
+ momentjs-rails
mysql2
- prototype-rails
- rails (= 3.2.21)
+ rails (~> 4.2.0)
+ rails_bootstrap_sortable
rdiscount
rouge
- rspec-rails (~> 2.99.0)
- sass-rails (~> 3.2.6)
- test-unit
+ sass-rails
+ select2-rails
+ sqlite3
uglifier
verification!
will_paginate (~> 3.0.7)
+ yaml_db
+
+BUNDLED WITH
+ 1.13.6
diff --git a/app/assets/javascripts/announcements.js.coffee b/app/assets/javascripts/announcements.js.coffee
new file mode 100644
--- /dev/null
+++ b/app/assets/javascripts/announcements.js.coffee
@@ -0,0 +1,6 @@
+#js for announcement
+$ ->
+ $(document).ajaxError (event, jqxhr, settings, exception) ->
+ if jqxhr.status
+ alert 'We\'re sorry, but something went wrong (' + jqxhr.status + ')'
+ return
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -10,8 +10,32 @@
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW.
//
-//= require prototype
-//= require prototype_ujs
-//= require effects
-//= require dragdrop
-//= require controls
+//= require jquery
+//= require jquery_ujs
+//= require jquery-ui
+//= require bootstrap-sprockets
+//= require moment
+//= require bootstrap-sortable
+//= require select2
+//= require ace-rails-ap
+//= require ace/mode-c_cpp
+//= require ace/mode-python
+//= require ace/mode-ruby
+//= require ace/mode-pascal
+//= require ace/mode-javascript
+//= require ace/mode-java
+//= require ace/theme-merbivore
+//= require custom
+//= require jquery.countdown
+//-------------- addition from local_jquery -----------
+//= require jquery-tablesorter
+//= require best_in_place
+//= require best_in_place.jquery-ui
+//= require brython
+
+// since this is after blank line, it is not downloaded
+//x= require prototype
+//x= require prototype_ujs
+//x= require effects
+//x= require dragdrop
+//x= require controls
diff --git a/app/assets/javascripts/brython.js b/app/assets/javascripts/brython.js
new file mode 100644
--- /dev/null
+++ b/app/assets/javascripts/brython.js
@@ -0,0 +1,10848 @@
+// brython.js brython.info
+// version [3, 3, 0, 'alpha', 0]
+// implementation [3, 2, 7, 'final', 0]
+// version compiled from commented, indented source files at github.com/brython-dev/brython
+var __BRYTHON__=__BRYTHON__ ||{}
+;(function($B){
+var scripts=document.getElementsByTagName('script')
+var this_url=scripts[scripts.length-1].src
+var elts=this_url.split('/')
+elts.pop()
+var $path=$B.brython_path=elts.join('/')+'/'
+var $href=$B.script_path=window.location.href
+var $href_elts=$href.split('/')
+$href_elts.pop()
+var $script_dir=$B.script_dir=$href_elts.join('/')
+$B.$py_module_path={}
+$B.$py_src={}
+$B.path=[$path+'Lib',$path+'libs',$script_dir,$path+'Lib/site-packages']
+$B.bound={}
+$B.type={}
+$B.async_enabled=false
+if($B.async_enabled)$B.block={}
+$B.modules={}
+$B.imported={}
+$B.vars={}
+$B._globals={}
+$B.frames_stack=[]
+$B.builtins={__repr__:function(){return "
- Name
- <%= f.text_field :name %>
-
- Password
- <%= f.text_field :password %>
-
- Started
- <%= f.check_box :started %>
-
- Start time
- <%= f.datetime_select :start_time %>
-
- <%= f.submit "Update" %> -
-<% end %> - -<%= link_to 'Show', @site %> | -<%= link_to 'Back', sites_path %> diff --git a/app/views/sites/edit.html.haml b/app/views/sites/edit.html.haml new file mode 100644 --- /dev/null +++ b/app/views/sites/edit.html.haml @@ -0,0 +1,24 @@ +%h1 Editing site += error_messages_for :site += form_for(@site) do |f| + %p + %b Name + %br/ + = f.text_field :name + %p + %b Password + %br/ + = f.text_field :password + %p + %b Started + %br/ + = f.check_box :started + %p + %b Start time + %br/ + = f.datetime_select :start_time, :include_blank => true + %p + = f.submit "Update" += link_to 'Show', @site +| += link_to 'Back', sites_path diff --git a/app/views/sites/index.html.erb b/app/views/sites/index.html.erb deleted file mode 100644 --- a/app/views/sites/index.html.erb +++ /dev/null @@ -1,29 +0,0 @@ -Name | -Password | -Started | -Start time | -|||
---|---|---|---|---|---|---|
<%=h site.name %> | -<%=h site.password %> | -<%=h site.started %> | -<%=h site.start_time %> | -<%= link_to 'Show', site %> | -<%= link_to 'Edit', edit_site_path(site) %> | -<%= link_to 'Destroy', site, :confirm => 'Are you sure?', :method => :delete %> | -
- Name
- <%= f.text_field :name %>
-
- Password
- <%= f.text_field :password %>
-
- Started
- <%= f.check_box :started %>
-
- Start time
- <%= f.datetime_select :start_time %>
-
- <%= f.submit "Create" %> -
-<% end %> - -<%= link_to 'Back', sites_path %> diff --git a/app/views/sites/new.html.haml b/app/views/sites/new.html.haml new file mode 100644 --- /dev/null +++ b/app/views/sites/new.html.haml @@ -0,0 +1,22 @@ +%h1 New site += error_messages_for :site += form_for(@site) do |f| + %p + %b Name + %br/ + = f.text_field :name + %p + %b Password + %br/ + = f.text_field :password + %p + %b Started + %br/ + = f.check_box :started + %p + %b Start time + %br/ + = f.datetime_select :start_time + %p + = f.submit "Create" += link_to 'Back', sites_path diff --git a/app/views/sites/show.html.erb b/app/views/sites/show.html.erb deleted file mode 100644 --- a/app/views/sites/show.html.erb +++ /dev/null @@ -1,23 +0,0 @@ -- Name: - <%=h @site.name %> -
- -- Password: - <%=h @site.password %> -
- -- Started: - <%=h @site.started %> -
- -- Start time: - <%=h @site.start_time %> -
- - -<%= link_to 'Edit', edit_site_path(@site) %> | -<%= link_to 'Back', sites_path %> diff --git a/app/views/sites/show.html.haml b/app/views/sites/show.html.haml new file mode 100644 --- /dev/null +++ b/app/views/sites/show.html.haml @@ -0,0 +1,15 @@ +%p + %b Name: + = h @site.name +%p + %b Password: + = h @site.password +%p + %b Started: + = h @site.started +%p + %b Start time: + = h @site.start_time += link_to 'Edit', edit_site_path(@site) +| += link_to 'Back', sites_path diff --git a/app/views/submissions/_form.html.haml b/app/views/submissions/_form.html.haml new file mode 100644 --- /dev/null +++ b/app/views/submissions/_form.html.haml @@ -0,0 +1,10 @@ += form_for @submission do |f| + - if @submission.errors.any? + #error_explanation + %h2= "#{pluralize(@submission.errors.count, "error")} prohibited this submission from being saved:" + %ul + - @submission.errors.full_messages.each do |msg| + %li= msg + + .actions + = f.submit 'Save' diff --git a/app/views/submissions/compiler_msg.js.haml b/app/views/submissions/compiler_msg.js.haml new file mode 100644 --- /dev/null +++ b/app/views/submissions/compiler_msg.js.haml @@ -0,0 +1,4 @@ +:plain + $("#compiler_msg").html("#{j @submission.compiler_message}"); + $("#compiler").modal(); + diff --git a/app/views/submissions/edit.html.haml b/app/views/submissions/edit.html.haml new file mode 100644 --- /dev/null +++ b/app/views/submissions/edit.html.haml @@ -0,0 +1,269 @@ +%h2 Live submit +%br + +%textarea#text_sourcecode{style: "display:none"}~ @source +.container + .row + .col-md-12 + .alert.alert-info + Write your code in the following box, choose language, and click submit button when finished + .row + .col-md-8 + %div#editor{style: 'height: 500px; border-radius: 7px; font-size: 14px;'} + .col-md-4 + = form_tag({controller: :main, :action => 'submit'}, :multipart => true, class: 'form') do + + = hidden_field_tag 'editor_text', @source + = hidden_field_tag 'submission[problem_id]', @problem.id + .form-group + = label_tag "Task:" + = text_field_tag 'asdf', "#{@problem.long_name}", class: 'form-control', disabled: true + + .form-group + = label_tag 'Language' + = select_tag 'language_id', options_from_collection_for_select(Language.all, 'id', 'pretty_name', @lang_id || Language.find_by_pretty_name("Python").id || Language.first.id), class: 'form-control select', style: "width: 100px" + .form-group + = submit_tag 'Submit', class: 'btn btn-success', id: 'live_submit', + data: {confirm: "Submitting this source code for task #{@problem.long_name}?"} + .panel.panel-info + .panel-heading + Latest Submission Status + = link_to "Refresh",get_latest_submission_status_submissions_path(@submission.user,@problem), class: "btn btn-default btn-sm", remote: true if @submission + .panel-body + - if @submission + = render :partial => 'submission_short', + :locals => {submission: @submission, problem_name: @problem.name, problem_id: @problem.id } + .row + .col-md-12 + %h2 Console + %textarea#console{style: 'height: 100%; width: 100%;background-color:#000;color:#fff;font-family: consolas, monaco, "Droid Sans Mono";',rows: 20} + +:javascript + $(document).ready(function() { + e = ace.edit("editor") + e.setValue($("#text_sourcecode").val()); + e.gotoLine(1); + $("#language_id").trigger('change'); + brython(); + }); + + +%script#__main__{type:'text/python3'} + :plain + import sys + import traceback + + from browser import document as doc + from browser import window, alert, console + + _credits = """ Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands + for supporting Python development. See www.python.org for more information.""" + + _copyright = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com + All Rights Reserved. + + Copyright (c) 2001-2013 Python Software Foundation. + All Rights Reserved. + + Copyright (c) 2000 BeOpen.com. + All Rights Reserved. + + Copyright (c) 1995-2001 Corporation for National Research Initiatives. + All Rights Reserved. + + Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. + All Rights Reserved.""" + + _license = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. Redistributions in binary + form must reproduce the above copyright notice, this list of conditions and + the following disclaimer in the documentation and/or other materials provided + with the distribution. + Neither the name of the- | - | - | - | - | |
<%= text_field 'user', 'login', :size => 10 %> | -<%= text_field 'user', 'full_name', :size => 30 %> | -<%= password_field 'user', 'password', :size => 10 %> | -<%= password_field 'user', 'password_confirmation', :size => 10 %> | -<%= email_field 'user', 'email', :size => 15 %> | -<%= submit_tag "Create" %> | -
<%= column.human_name %> | - <% end %> - <% end %> -- | - | - | |
---|---|---|---|---|
<%= link_to user.login, controller: :users, :action => 'profile', :id => user %> | - <% for column in User.content_columns %> - <% if !@hidden_columns.index(column.name) and column.name != 'login' %> -<%=h user.send(column.name) %> | - <% end %> - <% end %> -<%= link_to 'Show', :action => 'show', :id => user %> | -<%= link_to 'Edit', :action => 'edit', :id => user %> | -<%= link_to 'Destroy', { :action => 'destroy', :id => user }, :confirm => 'Are you sure?', :method => :post %> | -
+ #self._log(ctx, "LITERAL", ctx.peek_code(1))
+ self.general_op_literal(ctx, operator.eq)
+ return True
+
+ def op_not_literal(self, ctx):
+ # match anything that is not the given literal character
+ #
+ #self._log(ctx, "NOT_LITERAL", ctx.peek_code(1))
+ self.general_op_literal(ctx, operator.ne)
+ return True
+
+ def op_literal_ignore(self, ctx):
+ # match literal regardless of case
+ #
+ #self._log(ctx, "LITERAL_IGNORE", ctx.peek_code(1))
+ self.general_op_literal(ctx, operator.eq, ctx.state.lower)
+ return True
+
+ def op_not_literal_ignore(self, ctx):
+ # match literal regardless of case
+ #
+ #self._log(ctx, "LITERAL_IGNORE", ctx.peek_code(1))
+ self.general_op_literal(ctx, operator.ne, ctx.state.lower)
+ return True
+
+ def op_at(self, ctx):
+ # match at given position
+ #
+ #self._log(ctx, "AT", ctx.peek_code(1))
+ if not self.at_dispatcher.dispatch(ctx.peek_code(1), ctx):
+ ctx.has_matched = False
+ #print('_sre.py:line693, update context.has_matched variable')
+ return True
+ ctx.skip_code(2)
+ return True
+
+ def op_category(self, ctx):
+ # match at given category
+ #
+ #self._log(ctx, "CATEGORY", ctx.peek_code(1))
+ if ctx.at_end() or not self.ch_dispatcher.dispatch(ctx.peek_code(1), ctx):
+ ctx.has_matched = False
+ #print('_sre.py:line703, update context.has_matched variable')
+ return True
+ ctx.skip_code(2)
+ ctx.skip_char(1)
+ return True
+
+ def op_any(self, ctx):
+ # match anything (except a newline)
+ #
+ #self._log(ctx, "ANY")
+ if ctx.at_end() or ctx.at_linebreak():
+ ctx.has_matched = False
+ #print('_sre.py:line714, update context.has_matched variable')
+ return True
+ ctx.skip_code(1)
+ ctx.skip_char(1)
+ return True
+
+ def op_any_all(self, ctx):
+ # match anything
+ #
+ #self._log(ctx, "ANY_ALL")
+ if ctx.at_end():
+ ctx.has_matched = False
+ #print('_sre.py:line725, update context.has_matched variable')
+ return True
+ ctx.skip_code(1)
+ ctx.skip_char(1)
+ return True
+
+ def general_op_in(self, ctx, decorate=lambda x: x):
+ #self._log(ctx, "OP_IN")
+ #print('general_op_in')
+ if ctx.at_end():
+ ctx.has_matched = False
+ #print('_sre.py:line734, update context.has_matched variable')
+ return
+ skip = ctx.peek_code(1)
+ ctx.skip_code(2) # set op pointer to the set code
+ #print(ctx.peek_char(), ord(ctx.peek_char()),
+ # decorate(ord(ctx.peek_char())))
+ if not self.check_charset(ctx, decorate(ord(ctx.peek_char()))):
+ #print('_sre.py:line738, update context.has_matched variable')
+ ctx.has_matched = False
+ return
+ ctx.skip_code(skip - 1)
+ ctx.skip_char(1)
+ #print('end:general_op_in')
+
+ def op_in(self, ctx):
+ # match set member (or non_member)
+ #
+ #self._log(ctx, "OP_IN")
+ self.general_op_in(ctx)
+ return True
+
+ def op_in_ignore(self, ctx):
+ # match set member (or non_member), disregarding case of current char
+ #
+ #self._log(ctx, "OP_IN_IGNORE")
+ self.general_op_in(ctx, ctx.state.lower)
+ return True
+
+ def op_jump(self, ctx):
+ # jump forward
+ #
+ #self._log(ctx, "JUMP", ctx.peek_code(1))
+ ctx.skip_code(ctx.peek_code(1) + 1)
+ return True
+
+ # skip info
+ #
+ op_info = op_jump
+
+ def op_mark(self, ctx):
+ # set mark
+ #
+ #self._log(ctx, "OP_MARK", ctx.peek_code(1))
+ ctx.state.set_mark(ctx.peek_code(1), ctx.string_position)
+ ctx.skip_code(2)
+ return True
+
+ def op_branch(self, ctx):
+ # alternation
+ # <0=skip> code ...
+ #self._log(ctx, "BRANCH")
+ ctx.state.marks_push()
+ ctx.skip_code(1)
+ current_branch_length = ctx.peek_code(0)
+ while current_branch_length:
+ # The following tries to shortcut branches starting with a
+ # (unmatched) literal. _sre.c also shortcuts charsets here.
+ if not (ctx.peek_code(1) == OPCODES["literal"] and \
+ (ctx.at_end() or ctx.peek_code(2) != ord(ctx.peek_char()))):
+ ctx.state.string_position = ctx.string_position
+ child_context = ctx.push_new_context(1)
+ #print("_sre.py:803:op_branch")
+ yield False
+ if child_context.has_matched:
+ ctx.has_matched = True
+ yield True
+ ctx.state.marks_pop_keep()
+ ctx.skip_code(current_branch_length)
+ current_branch_length = ctx.peek_code(0)
+ ctx.state.marks_pop_discard()
+ ctx.has_matched = False
+ #print('_sre.py:line805, update context.has_matched variable')
+ yield True
+
+ def op_repeat_one(self, ctx):
+ # match repeated sequence (maximizing).
+ # this operator only works if the repeated item is exactly one character
+ # wide, and we're not already collecting backtracking points.
+ # <1=min> <2=max> item tail
+ mincount = ctx.peek_code(2)
+ maxcount = ctx.peek_code(3)
+ #print("repeat one", mincount, maxcount)
+ #self._log(ctx, "REPEAT_ONE", mincount, maxcount)
+
+ if ctx.remaining_chars() < mincount:
+ ctx.has_matched = False
+ yield True
+ ctx.state.string_position = ctx.string_position
+ count = self.count_repetitions(ctx, maxcount)
+ ctx.skip_char(count)
+ if count < mincount:
+ ctx.has_matched = False
+ yield True
+ if ctx.peek_code(ctx.peek_code(1) + 1) == OPCODES["success"]:
+ # tail is empty. we're finished
+ ctx.state.string_position = ctx.string_position
+ ctx.has_matched = True
+ yield True
+
+ ctx.state.marks_push()
+ if ctx.peek_code(ctx.peek_code(1) + 1) == OPCODES["literal"]:
+ # Special case: Tail starts with a literal. Skip positions where
+ # the rest of the pattern cannot possibly match.
+ char = ctx.peek_code(ctx.peek_code(1) + 2)
+ while True:
+ while count >= mincount and \
+ (ctx.at_end() or ord(ctx.peek_char()) != char):
+ ctx.skip_char(-1)
+ count -= 1
+ if count < mincount:
+ break
+ ctx.state.string_position = ctx.string_position
+ child_context = ctx.push_new_context(ctx.peek_code(1) + 1)
+ #print("_sre.py:856:push_new_context")
+ yield False
+ if child_context.has_matched:
+ ctx.has_matched = True
+ yield True
+ ctx.skip_char(-1)
+ count -= 1
+ ctx.state.marks_pop_keep()
+
+ else:
+ # General case: backtracking
+ while count >= mincount:
+ ctx.state.string_position = ctx.string_position
+ child_context = ctx.push_new_context(ctx.peek_code(1) + 1)
+ yield False
+ if child_context.has_matched:
+ ctx.has_matched = True
+ yield True
+ ctx.skip_char(-1)
+ count -= 1
+ ctx.state.marks_pop_keep()
+
+ ctx.state.marks_pop_discard()
+ ctx.has_matched = False
+ #ctx.has_matched = True # <== this should be True (so match object gets returned to program)
+ yield True
+
+ def op_min_repeat_one(self, ctx):
+ # match repeated sequence (minimizing)
+ # <1=min> <2=max> item tail
+ mincount = ctx.peek_code(2)
+ maxcount = ctx.peek_code(3)
+ #self._log(ctx, "MIN_REPEAT_ONE", mincount, maxcount)
+
+ if ctx.remaining_chars() < mincount:
+ ctx.has_matched = False
+ yield True
+ ctx.state.string_position = ctx.string_position
+ if mincount == 0:
+ count = 0
+ else:
+ count = self.count_repetitions(ctx, mincount)
+ if count < mincount:
+ ctx.has_matched = False
+ #print('_sre.py:line891, update context.has_matched variable')
+ yield True
+ ctx.skip_char(count)
+ if ctx.peek_code(ctx.peek_code(1) + 1) == OPCODES["success"]:
+ # tail is empty. we're finished
+ ctx.state.string_position = ctx.string_position
+ ctx.has_matched = True
+ yield True
+
+ ctx.state.marks_push()
+ while maxcount == MAXREPEAT or count <= maxcount:
+ ctx.state.string_position = ctx.string_position
+ child_context = ctx.push_new_context(ctx.peek_code(1) + 1)
+ #print('_sre.py:916:push new context')
+ yield False
+ if child_context.has_matched:
+ ctx.has_matched = True
+ yield True
+ ctx.state.string_position = ctx.string_position
+ if self.count_repetitions(ctx, 1) == 0:
+ break
+ ctx.skip_char(1)
+ count += 1
+ ctx.state.marks_pop_keep()
+
+ ctx.state.marks_pop_discard()
+ ctx.has_matched = False
+ yield True
+
+ def op_repeat(self, ctx):
+ # create repeat context. all the hard work is done by the UNTIL
+ # operator (MAX_UNTIL, MIN_UNTIL)
+ # <1=min> <2=max> item tail
+ #self._log(ctx, "REPEAT", ctx.peek_code(2), ctx.peek_code(3))
+
+ #if ctx.state.repeat is None:
+ # print("951:ctx.state.repeat is None")
+ # #ctx.state.repeat=_RepeatContext(ctx)
+
+ repeat = _RepeatContext(ctx)
+ ctx.state.repeat = repeat
+ ctx.state.string_position = ctx.string_position
+ child_context = ctx.push_new_context(ctx.peek_code(1) + 1)
+ #print("_sre.py:941:push new context", id(child_context))
+ #print(child_context.state.repeat)
+ #print(ctx.state.repeat)
+ # are these two yields causing the issue?
+ yield False
+ ctx.state.repeat = repeat.previous
+ ctx.has_matched = child_context.has_matched
+ yield True
+
+ def op_max_until(self, ctx):
+ # maximizing repeat
+ # <1=min> <2=max> item tail
+ repeat = ctx.state.repeat
+ #print("op_max_until") #, id(ctx.state.repeat))
+ if repeat is None:
+ #print(id(ctx), id(ctx.state))
+ raise RuntimeError("Internal re error: MAX_UNTIL without REPEAT.")
+ mincount = repeat.peek_code(2)
+ maxcount = repeat.peek_code(3)
+ ctx.state.string_position = ctx.string_position
+ count = repeat.count + 1
+ #self._log(ctx, "MAX_UNTIL", count)
+
+ if count < mincount:
+ # not enough matches
+ repeat.count = count
+ child_context = repeat.push_new_context(4)
+ yield False
+ ctx.has_matched = child_context.has_matched
+ if not ctx.has_matched:
+ repeat.count = count - 1
+ ctx.state.string_position = ctx.string_position
+ yield True
+
+ if (count < maxcount or maxcount == MAXREPEAT) \
+ and ctx.state.string_position != repeat.last_position:
+ # we may have enough matches, if we can match another item, do so
+ repeat.count = count
+ ctx.state.marks_push()
+ save_last_position = repeat.last_position # zero-width match protection
+ repeat.last_position = ctx.state.string_position
+ child_context = repeat.push_new_context(4)
+ yield False
+ repeat.last_position = save_last_position
+ if child_context.has_matched:
+ ctx.state.marks_pop_discard()
+ ctx.has_matched = True
+ yield True
+ ctx.state.marks_pop()
+ repeat.count = count - 1
+ ctx.state.string_position = ctx.string_position
+
+ # cannot match more repeated items here. make sure the tail matches
+ ctx.state.repeat = repeat.previous
+ child_context = ctx.push_new_context(1)
+ #print("_sre.py:987:op_max_until")
+ yield False
+ ctx.has_matched = child_context.has_matched
+ if not ctx.has_matched:
+ ctx.state.repeat = repeat
+ ctx.state.string_position = ctx.string_position
+ yield True
+
+ def op_min_until(self, ctx):
+ # minimizing repeat
+ # <1=min> <2=max> item tail
+ repeat = ctx.state.repeat
+ if repeat is None:
+ raise RuntimeError("Internal re error: MIN_UNTIL without REPEAT.")
+ mincount = repeat.peek_code(2)
+ maxcount = repeat.peek_code(3)
+ ctx.state.string_position = ctx.string_position
+ count = repeat.count + 1
+ #self._log(ctx, "MIN_UNTIL", count)
+
+ if count < mincount:
+ # not enough matches
+ repeat.count = count
+ child_context = repeat.push_new_context(4)
+ yield False
+ ctx.has_matched = child_context.has_matched
+ if not ctx.has_matched:
+ repeat.count = count - 1
+ ctx.state.string_position = ctx.string_position
+ yield True
+
+ # see if the tail matches
+ ctx.state.marks_push()
+ ctx.state.repeat = repeat.previous
+ child_context = ctx.push_new_context(1)
+ #print('_sre.py:1022:push new context')
+ yield False
+ if child_context.has_matched:
+ ctx.has_matched = True
+ yield True
+ ctx.state.repeat = repeat
+ ctx.state.string_position = ctx.string_position
+ ctx.state.marks_pop()
+
+ # match more until tail matches
+ if count >= maxcount and maxcount != MAXREPEAT:
+ ctx.has_matched = False
+ #print('_sre.py:line1022, update context.has_matched variable')
+ yield True
+ repeat.count = count
+ child_context = repeat.push_new_context(4)
+ yield False
+ ctx.has_matched = child_context.has_matched
+ if not ctx.has_matched:
+ repeat.count = count - 1
+ ctx.state.string_position = ctx.string_position
+ yield True
+
+ def general_op_groupref(self, ctx, decorate=lambda x: x):
+ group_start, group_end = ctx.state.get_marks(ctx.peek_code(1))
+ if group_start is None or group_end is None or group_end < group_start:
+ ctx.has_matched = False
+ return True
+ while group_start < group_end:
+ if ctx.at_end() or decorate(ord(ctx.peek_char())) \
+ != decorate(ord(ctx.state.string[group_start])):
+ ctx.has_matched = False
+ #print('_sre.py:line1042, update context.has_matched variable')
+ return True
+ group_start += 1
+ ctx.skip_char(1)
+ ctx.skip_code(2)
+ return True
+
+ def op_groupref(self, ctx):
+ # match backreference
+ #
+ #self._log(ctx, "GROUPREF", ctx.peek_code(1))
+ return self.general_op_groupref(ctx)
+
+ def op_groupref_ignore(self, ctx):
+ # match backreference case-insensitive
+ #
+ #self._log(ctx, "GROUPREF_IGNORE", ctx.peek_code(1))
+ return self.general_op_groupref(ctx, ctx.state.lower)
+
+ def op_groupref_exists(self, ctx):
+ # codeyes codeno ...
+ #self._log(ctx, "GROUPREF_EXISTS", ctx.peek_code(1))
+ group_start, group_end = ctx.state.get_marks(ctx.peek_code(1))
+ if group_start is None or group_end is None or group_end < group_start:
+ ctx.skip_code(ctx.peek_code(2) + 1)
+ else:
+ ctx.skip_code(3)
+ return True
+
+ def op_assert(self, ctx):
+ # assert subpattern
+ #
+ #self._log(ctx, "ASSERT", ctx.peek_code(2))
+ ctx.state.string_position = ctx.string_position - ctx.peek_code(2)
+ if ctx.state.string_position < 0:
+ ctx.has_matched = False
+ yield True
+ child_context = ctx.push_new_context(3)
+ yield False
+ if child_context.has_matched:
+ ctx.skip_code(ctx.peek_code(1) + 1)
+ else:
+ ctx.has_matched = False
+ yield True
+
+ def op_assert_not(self, ctx):
+ # assert not subpattern
+ #
+ #self._log(ctx, "ASSERT_NOT", ctx.peek_code(2))
+ ctx.state.string_position = ctx.string_position - ctx.peek_code(2)
+ if ctx.state.string_position >= 0:
+ child_context = ctx.push_new_context(3)
+ yield False
+ if child_context.has_matched:
+ ctx.has_matched = False
+ yield True
+ ctx.skip_code(ctx.peek_code(1) + 1)
+ yield True
+
+ def unknown(self, ctx):
+ #self._log(ctx, "UNKNOWN", ctx.peek_code())
+ raise RuntimeError("Internal re error. Unknown opcode: %s" % ctx.peek_code())
+
+ def check_charset(self, ctx, char):
+ """Checks whether a character matches set of arbitrary length. Assumes
+ the code pointer is at the first member of the set."""
+ self.set_dispatcher.reset(char)
+ save_position = ctx.code_position
+ result = None
+ while result is None:
+ result = self.set_dispatcher.dispatch(ctx.peek_code(), ctx)
+ ctx.code_position = save_position
+ #print("_sre.py:1123:check_charset", result)
+ return result
+
+ def count_repetitions(self, ctx, maxcount):
+ """Returns the number of repetitions of a single item, starting from the
+ current string position. The code pointer is expected to point to a
+ REPEAT_ONE operation (with the repeated 4 ahead)."""
+ count = 0
+ real_maxcount = ctx.state.end - ctx.string_position
+ if maxcount < real_maxcount and maxcount != MAXREPEAT:
+ real_maxcount = maxcount
+ # XXX could special case every single character pattern here, as in C.
+ # This is a general solution, a bit hackisch, but works and should be
+ # efficient.
+ code_position = ctx.code_position
+ string_position = ctx.string_position
+ ctx.skip_code(4)
+ reset_position = ctx.code_position
+ while count < real_maxcount:
+ # this works because the single character pattern is followed by
+ # a success opcode
+ ctx.code_position = reset_position
+ self.dispatch(ctx.peek_code(), ctx)
+ #print("count_repetitions", ctx.has_matched, count)
+ if ctx.has_matched is False: # could be None as well
+ break
+ count += 1
+ ctx.has_matched = None
+ ctx.code_position = code_position
+ ctx.string_position = string_position
+ return count
+
+ def _log(self, context, opname, *args):
+ arg_string = ("%s " * len(args)) % args
+ _log("|%s|%s|%s %s" % (context.pattern_codes,
+ context.string_position, opname, arg_string))
+
+_OpcodeDispatcher.build_dispatch_table(OPCODES, "op_")
+
+
+class _CharsetDispatcher(_Dispatcher):
+
+ def __init__(self):
+ self.ch_dispatcher = _ChcodeDispatcher()
+
+ def reset(self, char):
+ self.char = char
+ self.ok = True
+
+ def set_failure(self, ctx):
+ return not self.ok
+ def set_literal(self, ctx):
+ #
+ if ctx.peek_code(1) == self.char:
+ return self.ok
+ else:
+ ctx.skip_code(2)
+ def set_category(self, ctx):
+ #
+ if self.ch_dispatcher.dispatch(ctx.peek_code(1), ctx):
+ return self.ok
+ else:
+ ctx.skip_code(2)
+ def set_charset(self, ctx):
+ # (16 bits per code word)
+ char_code = self.char
+ ctx.skip_code(1) # point to beginning of bitmap
+ if CODESIZE == 2:
+ if char_code < 256 and ctx.peek_code(char_code >> 4) \
+ & (1 << (char_code & 15)):
+ return self.ok
+ ctx.skip_code(16) # skip bitmap
+ else:
+ if char_code < 256 and ctx.peek_code(char_code >> 5) \
+ & (1 << (char_code & 31)):
+ return self.ok
+ ctx.skip_code(8) # skip bitmap
+ def set_range(self, ctx):
+ #
+ if ctx.peek_code(1) <= self.char <= ctx.peek_code(2):
+ return self.ok
+ ctx.skip_code(3)
+ def set_negate(self, ctx):
+ self.ok = not self.ok
+ ctx.skip_code(1)
+
+ #fixme brython. array module doesn't exist
+ def set_bigcharset(self, ctx):
+ raise NotImplementationError("_sre.py: set_bigcharset, array not implemented")
+ # <256 blockindices>
+ char_code = self.char
+ count = ctx.peek_code(1)
+ ctx.skip_code(2)
+ if char_code < 65536:
+ block_index = char_code >> 8
+ # NB: there are CODESIZE block indices per bytecode
+ a = array.array("B")
+ a.fromstring(array.array(CODESIZE == 2 and "H" or "I",
+ [ctx.peek_code(block_index // CODESIZE)]).tostring())
+ block = a[block_index % CODESIZE]
+ ctx.skip_code(256 // CODESIZE) # skip block indices
+ block_value = ctx.peek_code(block * (32 // CODESIZE)
+ + ((char_code & 255) >> (CODESIZE == 2 and 4 or 5)))
+ if block_value & (1 << (char_code & ((8 * CODESIZE) - 1))):
+ return self.ok
+ else:
+ ctx.skip_code(256 // CODESIZE) # skip block indices
+ ctx.skip_code(count * (32 // CODESIZE)) # skip blocks
+
+ def unknown(self, ctx):
+ return False
+
+_CharsetDispatcher.build_dispatch_table(OPCODES, "set_")
+
+
+class _AtcodeDispatcher(_Dispatcher):
+
+ def at_beginning(self, ctx):
+ return ctx.at_beginning()
+ at_beginning_string = at_beginning
+ def at_beginning_line(self, ctx):
+ return ctx.at_beginning() or _is_linebreak(ctx.peek_char(-1))
+ def at_end(self, ctx):
+ return (ctx.remaining_chars() == 1 and ctx.at_linebreak()) or ctx.at_end()
+ def at_end_line(self, ctx):
+ return ctx.at_linebreak() or ctx.at_end()
+ def at_end_string(self, ctx):
+ return ctx.at_end()
+ def at_boundary(self, ctx):
+ return ctx.at_boundary(_is_word)
+ def at_non_boundary(self, ctx):
+ return not ctx.at_boundary(_is_word)
+ def at_loc_boundary(self, ctx):
+ return ctx.at_boundary(_is_loc_word)
+ def at_loc_non_boundary(self, ctx):
+ return not ctx.at_boundary(_is_loc_word)
+ def at_uni_boundary(self, ctx):
+ return ctx.at_boundary(_is_uni_word)
+ def at_uni_non_boundary(self, ctx):
+ return not ctx.at_boundary(_is_uni_word)
+ def unknown(self, ctx):
+ return False
+
+_AtcodeDispatcher.build_dispatch_table(ATCODES, "")
+
+
+class _ChcodeDispatcher(_Dispatcher):
+
+ def category_digit(self, ctx):
+ return _is_digit(ctx.peek_char())
+ def category_not_digit(self, ctx):
+ return not _is_digit(ctx.peek_char())
+ def category_space(self, ctx):
+ return _is_space(ctx.peek_char())
+ def category_not_space(self, ctx):
+ return not _is_space(ctx.peek_char())
+ def category_word(self, ctx):
+ return _is_word(ctx.peek_char())
+ def category_not_word(self, ctx):
+ return not _is_word(ctx.peek_char())
+ def category_linebreak(self, ctx):
+ return _is_linebreak(ctx.peek_char())
+ def category_not_linebreak(self, ctx):
+ return not _is_linebreak(ctx.peek_char())
+ def category_loc_word(self, ctx):
+ return _is_loc_word(ctx.peek_char())
+ def category_loc_not_word(self, ctx):
+ return not _is_loc_word(ctx.peek_char())
+ def category_uni_digit(self, ctx):
+ return ctx.peek_char().isdigit()
+ def category_uni_not_digit(self, ctx):
+ return not ctx.peek_char().isdigit()
+ def category_uni_space(self, ctx):
+ return ctx.peek_char().isspace()
+ def category_uni_not_space(self, ctx):
+ return not ctx.peek_char().isspace()
+ def category_uni_word(self, ctx):
+ return _is_uni_word(ctx.peek_char())
+ def category_uni_not_word(self, ctx):
+ return not _is_uni_word(ctx.peek_char())
+ def category_uni_linebreak(self, ctx):
+ return ord(ctx.peek_char()) in _uni_linebreaks
+ def category_uni_not_linebreak(self, ctx):
+ return ord(ctx.peek_char()) not in _uni_linebreaks
+ def unknown(self, ctx):
+ return False
+
+_ChcodeDispatcher.build_dispatch_table(CHCODES, "")
+
+
+_ascii_char_info = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 6, 2,
+2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0,
+0, 0, 16, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0, 0 ]
+
+def _is_digit(char):
+ code = ord(char)
+ return code < 128 and _ascii_char_info[code] & 1
+
+def _is_space(char):
+ code = ord(char)
+ return code < 128 and _ascii_char_info[code] & 2
+
+def _is_word(char):
+ # NB: non-ASCII chars aren't words according to _sre.c
+ code = ord(char)
+ return code < 128 and _ascii_char_info[code] & 16
+
+def _is_loc_word(char):
+ return (not (ord(char) & ~255) and char.isalnum()) or char == '_'
+
+def _is_uni_word(char):
+ # not valid in python 3
+ #return unichr(ord(char)).isalnum() or char == '_'
+ return chr(ord(char)).isalnum() or char == '_'
+
+def _is_linebreak(char):
+ return char == "\n"
+
+# Static list of all unicode codepoints reported by Py_UNICODE_ISLINEBREAK.
+_uni_linebreaks = [10, 13, 28, 29, 30, 133, 8232, 8233]
+
+def _log(message):
+ if 0:
+ print(message)
diff --git a/lib/assets/Lib/_string.py b/lib/assets/Lib/_string.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/_string.py
@@ -0,0 +1,42 @@
+"""string helper module"""
+
+import re
+
+class __loader__(object):
+ pass
+
+def formatter_field_name_split(fieldname):
+ """split the argument as a field name"""
+ _list=[]
+ for _name in fieldname:
+ _parts = _name.split('.')
+ for _item in _parts:
+ is_attr=False #fix me
+ if re.match('\d+', _item):
+ _list.append((int(_item), is_attr))
+ else:
+ _list.append((_item, is_attr))
+
+ return _list[0][0], iter(_list[1:])
+
+def formatter_parser(*args,**kw):
+ """parse the argument as a format string"""
+
+ assert len(args)==1
+ assert isinstance(args[0], str)
+
+ _result=[]
+ for _match in re.finditer("([^{]*)?(\{[^}]*\})?", args[0]):
+ _pre, _fmt = _match.groups()
+ if _fmt is None:
+ _result.append((_pre, None, None, None))
+ elif _fmt == '{}':
+ _result.append((_pre, '', '', None))
+ else:
+ _m=re.match("\{([^!]*)!?(.*)?\}", _fmt)
+ _name=_m.groups(0)
+ _flags=_m.groups(1)
+
+ _result.append((_pre, _name, _flags, None))
+
+ return _result
diff --git a/lib/assets/Lib/_strptime.py b/lib/assets/Lib/_strptime.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/_strptime.py
@@ -0,0 +1,510 @@
+"""Strptime-related classes and functions.
+
+CLASSES:
+ LocaleTime -- Discovers and stores locale-specific time information
+ TimeRE -- Creates regexes for pattern matching a string of text containing
+ time information
+
+FUNCTIONS:
+ _getlang -- Figure out what language is being used for the locale
+ strptime -- Calculates the time struct represented by the passed-in string
+
+"""
+import time
+import locale
+import calendar
+from re import compile as re_compile
+from re import IGNORECASE
+from re import escape as re_escape
+from datetime import (date as datetime_date,
+ timedelta as datetime_timedelta,
+ timezone as datetime_timezone)
+try:
+ from _thread import allocate_lock as _thread_allocate_lock
+except ImportError:
+ from _dummy_thread import allocate_lock as _thread_allocate_lock
+
+__all__ = []
+
+def _getlang():
+ # Figure out what the current language is set to.
+ return locale.getlocale(locale.LC_TIME)
+
+class LocaleTime(object):
+ """Stores and handles locale-specific information related to time.
+
+ ATTRIBUTES:
+ f_weekday -- full weekday names (7-item list)
+ a_weekday -- abbreviated weekday names (7-item list)
+ f_month -- full month names (13-item list; dummy value in [0], which
+ is added by code)
+ a_month -- abbreviated month names (13-item list, dummy value in
+ [0], which is added by code)
+ am_pm -- AM/PM representation (2-item list)
+ LC_date_time -- format string for date/time representation (string)
+ LC_date -- format string for date representation (string)
+ LC_time -- format string for time representation (string)
+ timezone -- daylight- and non-daylight-savings timezone representation
+ (2-item list of sets)
+ lang -- Language used by instance (2-item tuple)
+ """
+
+ def __init__(self):
+ """Set all attributes.
+
+ Order of methods called matters for dependency reasons.
+
+ The locale language is set at the offset and then checked again before
+ exiting. This is to make sure that the attributes were not set with a
+ mix of information from more than one locale. This would most likely
+ happen when using threads where one thread calls a locale-dependent
+ function while another thread changes the locale while the function in
+ the other thread is still running. Proper coding would call for
+ locks to prevent changing the locale while locale-dependent code is
+ running. The check here is done in case someone does not think about
+ doing this.
+
+ Only other possible issue is if someone changed the timezone and did
+ not call tz.tzset . That is an issue for the programmer, though,
+ since changing the timezone is worthless without that call.
+
+ """
+ self.lang = _getlang()
+ self.__calc_weekday()
+ self.__calc_month()
+ self.__calc_am_pm()
+ self.__calc_timezone()
+ self.__calc_date_time()
+ if _getlang() != self.lang:
+ raise ValueError("locale changed during initialization")
+
+ def __pad(self, seq, front):
+ # Add '' to seq to either the front (is True), else the back.
+ seq = list(seq)
+ if front:
+ seq.insert(0, '')
+ else:
+ seq.append('')
+ return seq
+
+ def __calc_weekday(self):
+ # Set self.a_weekday and self.f_weekday using the calendar
+ # module.
+ a_weekday = [calendar.day_abbr[i].lower() for i in range(7)]
+ f_weekday = [calendar.day_name[i].lower() for i in range(7)]
+ self.a_weekday = a_weekday
+ self.f_weekday = f_weekday
+
+ def __calc_month(self):
+ # Set self.f_month and self.a_month using the calendar module.
+ a_month = [calendar.month_abbr[i].lower() for i in range(13)]
+ f_month = [calendar.month_name[i].lower() for i in range(13)]
+ self.a_month = a_month
+ self.f_month = f_month
+
+ def __calc_am_pm(self):
+ # Set self.am_pm by using time.strftime().
+
+ # The magic date (1999,3,17,hour,44,55,2,76,0) is not really that
+ # magical; just happened to have used it everywhere else where a
+ # static date was needed.
+ am_pm = []
+ for hour in (1, 22):
+ time_tuple = time.struct_time((1999,3,17,hour,44,55,2,76,0))
+ am_pm.append(time.strftime("%p", time_tuple).lower())
+ self.am_pm = am_pm
+
+ def __calc_date_time(self):
+ # Set self.date_time, self.date, & self.time by using
+ # time.strftime().
+
+ # Use (1999,3,17,22,44,55,2,76,0) for magic date because the amount of
+ # overloaded numbers is minimized. The order in which searches for
+ # values within the format string is very important; it eliminates
+ # possible ambiguity for what something represents.
+ time_tuple = time.struct_time((1999,3,17,22,44,55,2,76,0))
+ date_time = [None, None, None]
+ date_time[0] = time.strftime("%c", time_tuple).lower()
+ date_time[1] = time.strftime("%x", time_tuple).lower()
+ date_time[2] = time.strftime("%X", time_tuple).lower()
+ replacement_pairs = [('%', '%%'), (self.f_weekday[2], '%A'),
+ (self.f_month[3], '%B'), (self.a_weekday[2], '%a'),
+ (self.a_month[3], '%b'), (self.am_pm[1], '%p'),
+ ('1999', '%Y'), ('99', '%y'), ('22', '%H'),
+ ('44', '%M'), ('55', '%S'), ('76', '%j'),
+ ('17', '%d'), ('03', '%m'), ('3', '%m'),
+ # '3' needed for when no leading zero.
+ ('2', '%w'), ('10', '%I')]
+ replacement_pairs.extend([(tz, "%Z") for tz_values in self.timezone
+ for tz in tz_values])
+ for offset,directive in ((0,'%c'), (1,'%x'), (2,'%X')):
+ current_format = date_time[offset]
+ for old, new in replacement_pairs:
+ # Must deal with possible lack of locale info
+ # manifesting itself as the empty string (e.g., Swedish's
+ # lack of AM/PM info) or a platform returning a tuple of empty
+ # strings (e.g., MacOS 9 having timezone as ('','')).
+ if old:
+ current_format = current_format.replace(old, new)
+ # If %W is used, then Sunday, 2005-01-03 will fall on week 0 since
+ # 2005-01-03 occurs before the first Monday of the year. Otherwise
+ # %U is used.
+ time_tuple = time.struct_time((1999,1,3,1,1,1,6,3,0))
+ if '00' in time.strftime(directive, time_tuple):
+ U_W = '%W'
+ else:
+ U_W = '%U'
+ date_time[offset] = current_format.replace('11', U_W)
+ self.LC_date_time = date_time[0]
+ self.LC_date = date_time[1]
+ self.LC_time = date_time[2]
+
+ def __calc_timezone(self):
+ # Set self.timezone by using time.tzname.
+ # Do not worry about possibility of time.tzname[0] == timetzname[1]
+ # and time.daylight; handle that in strptime .
+ #try:
+ #time.tzset()
+ #except AttributeError:
+ #pass
+ no_saving = frozenset(["utc", "gmt", time.tzname[0].lower()])
+ if time.daylight:
+ has_saving = frozenset([time.tzname[1].lower()])
+ else:
+ has_saving = frozenset()
+ self.timezone = (no_saving, has_saving)
+
+
+class TimeRE(dict):
+ """Handle conversion from format directives to regexes."""
+
+ def __init__(self, locale_time=None):
+ """Create keys/values.
+
+ Order of execution is important for dependency reasons.
+
+ """
+ if locale_time:
+ self.locale_time = locale_time
+ else:
+ self.locale_time = LocaleTime()
+ base = super()
+ base.__init__({
+ # The " \d" part of the regex is to make %c from ANSI C work
+ 'd': r"(?P3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])",
+ 'f': r"(?P[0-9]{1,6})",
+ 'H': r"(?P2[0-3]|[0-1]\d|\d)",
+ 'I': r"(?P1[0-2]|0[1-9]|[1-9])",
+ 'j': r"(?P36[0-6]|3[0-5]\d|[1-2]\d\d|0[1-9]\d|00[1-9]|[1-9]\d|0[1-9]|[1-9])",
+ 'm': r"(?P1[0-2]|0[1-9]|[1-9])",
+ 'M': r"(?P[0-5]\d|\d)",
+ 'S': r"(?P6[0-1]|[0-5]\d|\d)",
+ 'U': r"(?P5[0-3]|[0-4]\d|\d)",
+ 'w': r"(?P[0-6])",
+ # W is set below by using 'U'
+ 'y': r"(?P\d\d)",
+ #XXX: Does 'Y' need to worry about having less or more than
+ # 4 digits?
+ 'Y': r"(?P\d\d\d\d)",
+ 'z': r"(?P[+-]\d\d[0-5]\d)",
+ 'A': self.__seqToRE(self.locale_time.f_weekday, 'A'),
+ 'a': self.__seqToRE(self.locale_time.a_weekday, 'a'),
+ 'B': self.__seqToRE(self.locale_time.f_month[1:], 'B'),
+ 'b': self.__seqToRE(self.locale_time.a_month[1:], 'b'),
+ 'p': self.__seqToRE(self.locale_time.am_pm, 'p'),
+ 'Z': self.__seqToRE((tz for tz_names in self.locale_time.timezone
+ for tz in tz_names),
+ 'Z'),
+ '%': '%'})
+ base.__setitem__('W', base.__getitem__('U').replace('U', 'W'))
+ base.__setitem__('c', self.pattern(self.locale_time.LC_date_time))
+ base.__setitem__('x', self.pattern(self.locale_time.LC_date))
+ base.__setitem__('X', self.pattern(self.locale_time.LC_time))
+
+ def __seqToRE(self, to_convert, directive):
+ """Convert a list to a regex string for matching a directive.
+
+ Want possible matching values to be from longest to shortest. This
+ prevents the possibility of a match occurring for a value that also
+ a substring of a larger value that should have matched (e.g., 'abc'
+ matching when 'abcdef' should have been the match).
+
+ """
+ to_convert = sorted(to_convert, key=len, reverse=True)
+ for value in to_convert:
+ if value != '':
+ break
+ else:
+ return ''
+ regex = '|'.join(re_escape(stuff) for stuff in to_convert)
+ regex = '(?P<%s>%s' % (directive, regex)
+ return '%s)' % regex
+
+ def pattern(self, format):
+ """Return regex pattern for the format string.
+
+ Need to make sure that any characters that might be interpreted as
+ regex syntax are escaped.
+
+ """
+ processed_format = ''
+ # The sub() call escapes all characters that might be misconstrued
+ # as regex syntax. Cannot use re.escape since we have to deal with
+ # format directives (%m, etc.).
+ regex_chars = re_compile(r"([\\.^$*+?\(\){}\[\]|])")
+ format = regex_chars.sub(r"\\\1", format)
+ whitespace_replacement = re_compile('\s+')
+ format = whitespace_replacement.sub('\s+', format)
+ while '%' in format:
+ directive_index = format.index('%')+1
+ processed_format = "%s%s%s" % (processed_format,
+ format[:directive_index-1],
+ self[format[directive_index]])
+ format = format[directive_index+1:]
+ return "%s%s" % (processed_format, format)
+
+ def compile(self, format):
+ """Return a compiled re object for the format string."""
+ return re_compile(self.pattern(format), IGNORECASE)
+
+_cache_lock = _thread_allocate_lock()
+# DO NOT modify _TimeRE_cache or _regex_cache without acquiring the cache lock
+# first!
+_TimeRE_cache = TimeRE()
+_CACHE_MAX_SIZE = 5 # Max number of regexes stored in _regex_cache
+_regex_cache = {}
+
+def _calc_julian_from_U_or_W(year, week_of_year, day_of_week, week_starts_Mon):
+ """Calculate the Julian day based on the year, week of the year, and day of
+ the week, with week_start_day representing whether the week of the year
+ assumes the week starts on Sunday or Monday (6 or 0)."""
+ first_weekday = datetime_date(year, 1, 1).weekday()
+ # If we are dealing with the %U directive (week starts on Sunday), it's
+ # easier to just shift the view to Sunday being the first day of the
+ # week.
+ if not week_starts_Mon:
+ first_weekday = (first_weekday + 1) % 7
+ day_of_week = (day_of_week + 1) % 7
+ # Need to watch out for a week 0 (when the first day of the year is not
+ # the same as that specified by %U or %W).
+ week_0_length = (7 - first_weekday) % 7
+ if week_of_year == 0:
+ return 1 + day_of_week - first_weekday
+ else:
+ days_to_week = week_0_length + (7 * (week_of_year - 1))
+ return 1 + days_to_week + day_of_week
+
+
+def _strptime(data_string, format="%a %b %d %H:%M:%S %Y"):
+ """Return a 2-tuple consisting of a time struct and an int containing
+ the number of microseconds based on the input string and the
+ format string."""
+
+ for index, arg in enumerate([data_string, format]):
+ if not isinstance(arg, str):
+ msg = "strptime() argument {} must be str, not {}"
+ raise TypeError(msg.format(index, type(arg)))
+
+ global _TimeRE_cache, _regex_cache
+ with _cache_lock:
+
+ if _getlang() != _TimeRE_cache.locale_time.lang:
+ _TimeRE_cache = TimeRE()
+ _regex_cache.clear()
+ if len(_regex_cache) > _CACHE_MAX_SIZE:
+ _regex_cache.clear()
+ locale_time = _TimeRE_cache.locale_time
+ format_regex = _regex_cache.get(format)
+ if not format_regex:
+ try:
+ format_regex = _TimeRE_cache.compile(format)
+ # KeyError raised when a bad format is found; can be specified as
+ # \\, in which case it was a stray % but with a space after it
+ except KeyError as err:
+ bad_directive = err.args[0]
+ if bad_directive == "\\":
+ bad_directive = "%"
+ del err
+ raise ValueError("'%s' is a bad directive in format '%s'" %
+ (bad_directive, format)) from None
+ # IndexError only occurs when the format string is "%"
+ except IndexError:
+ raise ValueError("stray %% in format '%s'" % format) from None
+ _regex_cache[format] = format_regex
+ found = format_regex.match(data_string)
+ if not found:
+ raise ValueError("time data %r does not match format %r" %
+ (data_string, format))
+ if len(data_string) != found.end():
+ raise ValueError("unconverted data remains: %s" %
+ data_string[found.end():])
+
+ year = None
+ month = day = 1
+ hour = minute = second = fraction = 0
+ tz = -1
+ tzoffset = None
+ # Default to -1 to signify that values not known; not critical to have,
+ # though
+ week_of_year = -1
+ week_of_year_start = -1
+ # weekday and julian defaulted to -1 so as to signal need to calculate
+ # values
+ weekday = julian = -1
+ found_dict = found.groupdict()
+ for group_key in found_dict.keys():
+ # Directives not explicitly handled below:
+ # c, x, X
+ # handled by making out of other directives
+ # U, W
+ # worthless without day of the week
+ if group_key == 'y':
+ year = int(found_dict['y'])
+ # Open Group specification for strptime() states that a %y
+ #value in the range of [00, 68] is in the century 2000, while
+ #[69,99] is in the century 1900
+ if year <= 68:
+ year += 2000
+ else:
+ year += 1900
+ elif group_key == 'Y':
+ year = int(found_dict['Y'])
+ elif group_key == 'm':
+ month = int(found_dict['m'])
+ elif group_key == 'B':
+ month = locale_time.f_month.index(found_dict['B'].lower())
+ elif group_key == 'b':
+ month = locale_time.a_month.index(found_dict['b'].lower())
+ elif group_key == 'd':
+ day = int(found_dict['d'])
+ elif group_key == 'H':
+ hour = int(found_dict['H'])
+ elif group_key == 'I':
+ hour = int(found_dict['I'])
+ ampm = found_dict.get('p', '').lower()
+ # If there was no AM/PM indicator, we'll treat this like AM
+ if ampm in ('', locale_time.am_pm[0]):
+ # We're in AM so the hour is correct unless we're
+ # looking at 12 midnight.
+ # 12 midnight == 12 AM == hour 0
+ if hour == 12:
+ hour = 0
+ elif ampm == locale_time.am_pm[1]:
+ # We're in PM so we need to add 12 to the hour unless
+ # we're looking at 12 noon.
+ # 12 noon == 12 PM == hour 12
+ if hour != 12:
+ hour += 12
+ elif group_key == 'M':
+ minute = int(found_dict['M'])
+ elif group_key == 'S':
+ second = int(found_dict['S'])
+ elif group_key == 'f':
+ s = found_dict['f']
+ # Pad to always return microseconds.
+ s += "0" * (6 - len(s))
+ fraction = int(s)
+ elif group_key == 'A':
+ weekday = locale_time.f_weekday.index(found_dict['A'].lower())
+ elif group_key == 'a':
+ weekday = locale_time.a_weekday.index(found_dict['a'].lower())
+ elif group_key == 'w':
+ weekday = int(found_dict['w'])
+ if weekday == 0:
+ weekday = 6
+ else:
+ weekday -= 1
+ elif group_key == 'j':
+ julian = int(found_dict['j'])
+ elif group_key in ('U', 'W'):
+ week_of_year = int(found_dict[group_key])
+ if group_key == 'U':
+ # U starts week on Sunday.
+ week_of_year_start = 6
+ else:
+ # W starts week on Monday.
+ week_of_year_start = 0
+ elif group_key == 'z':
+ z = found_dict['z']
+ tzoffset = int(z[1:3]) * 60 + int(z[3:5])
+ if z.startswith("-"):
+ tzoffset = -tzoffset
+ elif group_key == 'Z':
+ # Since -1 is default value only need to worry about setting tz if
+ # it can be something other than -1.
+ found_zone = found_dict['Z'].lower()
+ for value, tz_values in enumerate(locale_time.timezone):
+ if found_zone in tz_values:
+ # Deal with bad locale setup where timezone names are the
+ # same and yet time.daylight is true; too ambiguous to
+ # be able to tell what timezone has daylight savings
+ if (time.tzname[0] == time.tzname[1] and
+ time.daylight and found_zone not in ("utc", "gmt")):
+ break
+ else:
+ tz = value
+ break
+ leap_year_fix = False
+ if year is None and month == 2 and day == 29:
+ year = 1904 # 1904 is first leap year of 20th century
+ leap_year_fix = True
+ elif year is None:
+ year = 1900
+ # If we know the week of the year and what day of that week, we can figure
+ # out the Julian day of the year.
+ if julian == -1 and week_of_year != -1 and weekday != -1:
+ week_starts_Mon = True if week_of_year_start == 0 else False
+ julian = _calc_julian_from_U_or_W(year, week_of_year, weekday,
+ week_starts_Mon)
+ # Cannot pre-calculate datetime_date() since can change in Julian
+ # calculation and thus could have different value for the day of the week
+ # calculation.
+ if julian == -1:
+ # Need to add 1 to result since first day of the year is 1, not 0.
+ julian = datetime_date(year, month, day).toordinal() - \
+ datetime_date(year, 1, 1).toordinal() + 1
+ else: # Assume that if they bothered to include Julian day it will
+ # be accurate.
+ datetime_result = datetime_date.fromordinal((julian - 1) + datetime_date(year, 1, 1).toordinal())
+ year = datetime_result.year
+ month = datetime_result.month
+ day = datetime_result.day
+ if weekday == -1:
+ weekday = datetime_date(year, month, day).weekday()
+ # Add timezone info
+ tzname = found_dict.get("Z")
+ if tzoffset is not None:
+ gmtoff = tzoffset * 60
+ else:
+ gmtoff = None
+
+ if leap_year_fix:
+ # the caller didn't supply a year but asked for Feb 29th. We couldn't
+ # use the default of 1900 for computations. We set it back to ensure
+ # that February 29th is smaller than March 1st.
+ year = 1900
+
+ return (year, month, day,
+ hour, minute, second,
+ weekday, julian, tz, tzname, gmtoff), fraction
+
+def _strptime_time(data_string, format="%a %b %d %H:%M:%S %Y"):
+ """Return a time struct based on the input string and the
+ format string."""
+ tt = _strptime(data_string, format)[0]
+ return time.struct_time(tt[:time._STRUCT_TM_ITEMS])
+
+def _strptime_datetime(cls, data_string, format="%a %b %d %H:%M:%S %Y"):
+ """Return a class cls instance based on the input string and the
+ format string."""
+ tt, fraction = _strptime(data_string, format)
+ tzname, gmtoff = tt[-2:]
+ args = tt[:6] + (fraction,)
+ if gmtoff is not None:
+ tzdelta = datetime_timedelta(seconds=gmtoff)
+ if tzname:
+ tz = datetime_timezone(tzdelta, tzname)
+ else:
+ tz = datetime_timezone(tzdelta)
+ args += (tz,)
+ return cls(*args)
diff --git a/lib/assets/Lib/_struct.py b/lib/assets/Lib/_struct.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/_struct.py
@@ -0,0 +1,448 @@
+#
+# This module is a pure Python version of pypy.module.struct.
+# It is only imported if the vastly faster pypy.module.struct is not
+# compiled in. For now we keep this version for reference and
+# because pypy.module.struct is not ootype-backend-friendly yet.
+#
+
+# this module 'borrowed' from
+# https://bitbucket.org/pypy/pypy/src/18626459a9b2/lib_pypy/_struct.py?at=py3k-listview_str
+# with many bug fixes
+
+"""Functions to convert between Python values and C structs.
+Python strings are used to hold the data representing the C struct
+and also as format strings to describe the layout of data in the C struct.
+
+The optional first format char indicates byte order, size and alignment:
+ @: native order, size & alignment (default)
+ =: native order, std. size & alignment
+ <: little-endian, std. size & alignment
+ >: big-endian, std. size & alignment
+ !: same as >
+
+The remaining chars indicate types of args and must match exactly;
+these can be preceded by a decimal repeat count:
+ x: pad byte (no data);
+ c:char;
+ b:signed byte;
+ B:unsigned byte;
+ h:short;
+ H:unsigned short;
+ i:int;
+ I:unsigned int;
+ l:long;
+ L:unsigned long;
+ f:float;
+ d:double.
+Special cases (preceding decimal count indicates length):
+ s:string (array of char); p: pascal string (with count byte).
+Special case (only available in native format):
+ P:an integer type that is wide enough to hold a pointer.
+Special case (not in native mode unless 'long long' in platform C):
+ q:long long;
+ Q:unsigned long long
+Whitespace between formats is ignored.
+
+The variable struct.error is an exception raised on errors."""
+
+import math, sys
+
+# TODO: XXX Find a way to get information on native sizes and alignments
+class StructError(Exception):
+ pass
+error = StructError
+def unpack_int(data,index,size,le):
+ bytes = [b for b in data[index:index+size]]
+ if le == 'little':
+ bytes.reverse()
+ number = 0
+ for b in bytes:
+ number = number << 8 | b
+ return int(number)
+
+def unpack_signed_int(data,index,size,le):
+ number = unpack_int(data,index,size,le)
+ max = 2**(size*8)
+ if number > 2**(size*8 - 1) - 1:
+ number = int(-1*(max - number))
+ return number
+
+INFINITY = 1e200 * 1e200
+NAN = INFINITY / INFINITY
+
+def unpack_char(data,index,size,le):
+ return data[index:index+size]
+
+def pack_int(number,size,le):
+ x=number
+ res=[]
+ for i in range(size):
+ res.append(x&0xff)
+ x >>= 8
+ if le == 'big':
+ res.reverse()
+ return bytes(res)
+
+def pack_signed_int(number,size,le):
+ if not isinstance(number, int):
+ raise StructError("argument for i,I,l,L,q,Q,h,H must be integer")
+ if number > 2**(8*size-1)-1 or number < -1*2**(8*size-1):
+ raise OverflowError("Number:%i too large to convert" % number)
+ return pack_int(number,size,le)
+
+def pack_unsigned_int(number,size,le):
+ if not isinstance(number, int):
+ raise StructError("argument for i,I,l,L,q,Q,h,H must be integer")
+ if number < 0:
+ raise TypeError("can't convert negative long to unsigned")
+ if number > 2**(8*size)-1:
+ raise OverflowError("Number:%i too large to convert" % number)
+ return pack_int(number,size,le)
+
+def pack_char(char,size,le):
+ return bytes(char)
+
+def isinf(x):
+ return x != 0.0 and x / 2 == x
+def isnan(v):
+ return v != v*1.0 or (v == 1.0 and v == 2.0)
+
+def pack_float(x, size, le):
+ unsigned = float_pack(x, size)
+ result = []
+ for i in range(size):
+ result.append((unsigned >> (i * 8)) & 0xFF)
+ if le == "big":
+ result.reverse()
+ return bytes(result)
+
+def unpack_float(data, index, size, le):
+ binary = [data[i] for i in range(index, index + size)]
+ if le == "big":
+ binary.reverse()
+ unsigned = 0
+ for i in range(size):
+ unsigned |= binary[i] << (i * 8)
+ return float_unpack(unsigned, size, le)
+
+def round_to_nearest(x):
+ """Python 3 style round: round a float x to the nearest int, but
+ unlike the builtin Python 2.x round function:
+
+ - return an int, not a float
+ - do round-half-to-even, not round-half-away-from-zero.
+
+ We assume that x is finite and nonnegative; except wrong results
+ if you use this for negative x.
+
+ """
+ int_part = int(x)
+ frac_part = x - int_part
+ if frac_part > 0.5 or frac_part == 0.5 and int_part & 1 == 1:
+ int_part += 1
+ return int_part
+
+def float_unpack(Q, size, le):
+ """Convert a 32-bit or 64-bit integer created
+ by float_pack into a Python float."""
+
+ if size == 8:
+ MIN_EXP = -1021 # = sys.float_info.min_exp
+ MAX_EXP = 1024 # = sys.float_info.max_exp
+ MANT_DIG = 53 # = sys.float_info.mant_dig
+ BITS = 64
+ elif size == 4:
+ MIN_EXP = -125 # C's FLT_MIN_EXP
+ MAX_EXP = 128 # FLT_MAX_EXP
+ MANT_DIG = 24 # FLT_MANT_DIG
+ BITS = 32
+ else:
+ raise ValueError("invalid size value")
+
+ if Q >> BITS:
+ raise ValueError("input out of range")
+
+ # extract pieces
+ sign = Q >> BITS - 1
+ exp = (Q & ((1 << BITS - 1) - (1 << MANT_DIG - 1))) >> MANT_DIG - 1
+ mant = Q & ((1 << MANT_DIG - 1) - 1)
+
+ if exp == MAX_EXP - MIN_EXP + 2:
+ # nan or infinity
+ result = float('nan') if mant else float('inf')
+ elif exp == 0:
+ # subnormal or zero
+ result = math.ldexp(float(mant), MIN_EXP - MANT_DIG)
+ else:
+ # normal
+ mant += 1 << MANT_DIG - 1
+ result = math.ldexp(float(mant), exp + MIN_EXP - MANT_DIG - 1)
+ return -result if sign else result
+
+
+def float_pack(x, size):
+ """Convert a Python float x into a 64-bit unsigned integer
+ with the same byte representation."""
+
+ if size == 8:
+ MIN_EXP = -1021 # = sys.float_info.min_exp
+ MAX_EXP = 1024 # = sys.float_info.max_exp
+ MANT_DIG = 53 # = sys.float_info.mant_dig
+ BITS = 64
+ elif size == 4:
+ MIN_EXP = -125 # C's FLT_MIN_EXP
+ MAX_EXP = 128 # FLT_MAX_EXP
+ MANT_DIG = 24 # FLT_MANT_DIG
+ BITS = 32
+ else:
+ raise ValueError("invalid size value")
+
+ sign = math.copysign(1.0, x) < 0.0
+ if math.isinf(x):
+ mant = 0
+ exp = MAX_EXP - MIN_EXP + 2
+ elif math.isnan(x):
+ mant = 1 << (MANT_DIG-2) # other values possible
+ exp = MAX_EXP - MIN_EXP + 2
+ elif x == 0.0:
+ mant = 0
+ exp = 0
+ else:
+ m, e = math.frexp(abs(x)) # abs(x) == m * 2**e
+ exp = e - (MIN_EXP - 1)
+ if exp > 0:
+ # Normal case.
+ mant = round_to_nearest(m * (1 << MANT_DIG))
+ mant -= 1 << MANT_DIG - 1
+ else:
+ # Subnormal case.
+ if exp + MANT_DIG - 1 >= 0:
+ mant = round_to_nearest(m * (1 << exp + MANT_DIG - 1))
+ else:
+ mant = 0
+ exp = 0
+
+ # Special case: rounding produced a MANT_DIG-bit mantissa.
+ assert 0 <= mant <= 1 << MANT_DIG - 1
+ if mant == 1 << MANT_DIG - 1:
+ mant = 0
+ exp += 1
+
+ # Raise on overflow (in some circumstances, may want to return
+ # infinity instead).
+ if exp >= MAX_EXP - MIN_EXP + 2:
+ raise OverflowError("float too large to pack in this format")
+
+ # check constraints
+ assert 0 <= mant < 1 << MANT_DIG - 1
+ assert 0 <= exp <= MAX_EXP - MIN_EXP + 2
+ assert 0 <= sign <= 1
+ return ((sign << BITS - 1) | (exp << MANT_DIG - 1)) | mant
+
+
+big_endian_format = {
+ 'x':{ 'size' : 1, 'alignment' : 0, 'pack' : None, 'unpack' : None},
+ 'b':{ 'size' : 1, 'alignment' : 0, 'pack' : pack_signed_int, 'unpack' : unpack_signed_int},
+ 'B':{ 'size' : 1, 'alignment' : 0, 'pack' : pack_unsigned_int, 'unpack' : unpack_int},
+ 'c':{ 'size' : 1, 'alignment' : 0, 'pack' : pack_char, 'unpack' : unpack_char},
+ 's':{ 'size' : 1, 'alignment' : 0, 'pack' : None, 'unpack' : None},
+ 'p':{ 'size' : 1, 'alignment' : 0, 'pack' : None, 'unpack' : None},
+ 'h':{ 'size' : 2, 'alignment' : 0, 'pack' : pack_signed_int, 'unpack' : unpack_signed_int},
+ 'H':{ 'size' : 2, 'alignment' : 0, 'pack' : pack_unsigned_int, 'unpack' : unpack_int},
+ 'i':{ 'size' : 4, 'alignment' : 0, 'pack' : pack_signed_int, 'unpack' : unpack_signed_int},
+ 'I':{ 'size' : 4, 'alignment' : 0, 'pack' : pack_unsigned_int, 'unpack' : unpack_int},
+ 'l':{ 'size' : 4, 'alignment' : 0, 'pack' : pack_signed_int, 'unpack' : unpack_signed_int},
+ 'L':{ 'size' : 4, 'alignment' : 0, 'pack' : pack_unsigned_int, 'unpack' : unpack_int},
+ 'q':{ 'size' : 8, 'alignment' : 0, 'pack' : pack_signed_int, 'unpack' : unpack_signed_int},
+ 'Q':{ 'size' : 8, 'alignment' : 0, 'pack' : pack_unsigned_int, 'unpack' : unpack_int},
+ 'f':{ 'size' : 4, 'alignment' : 0, 'pack' : pack_float, 'unpack' : unpack_float},
+ 'd':{ 'size' : 8, 'alignment' : 0, 'pack' : pack_float, 'unpack' : unpack_float},
+ }
+default = big_endian_format
+formatmode={ '<' : (default, 'little'),
+ '>' : (default, 'big'),
+ '!' : (default, 'big'),
+ '=' : (default, sys.byteorder),
+ '@' : (default, sys.byteorder)
+ }
+
+def getmode(fmt):
+ try:
+ formatdef,endianness = formatmode[fmt[0]]
+ alignment = fmt[0] not in formatmode or fmt[0]=='@'
+ index = 1
+ except (IndexError, KeyError):
+ formatdef,endianness = formatmode['@']
+ alignment = True
+ index = 0
+ return formatdef,endianness,index,alignment
+
+def getNum(fmt,i):
+ num=None
+ cur = fmt[i]
+ while ('0'<= cur ) and ( cur <= '9'):
+ if num == None:
+ num = int(cur)
+ else:
+ num = 10*num + int(cur)
+ i += 1
+ cur = fmt[i]
+ return num,i
+
+def calcsize(fmt):
+ """calcsize(fmt) -> int
+ Return size of C struct described by format string fmt.
+ See struct.__doc__ for more on format strings."""
+
+ formatdef,endianness,i,alignment = getmode(fmt)
+ num = 0
+ result = 0
+ while i string
+ Return string containing values v1, v2, ... packed according to fmt.
+ See struct.__doc__ for more on format strings."""
+ formatdef,endianness,i,alignment = getmode(fmt)
+ args = list(args)
+ n_args = len(args)
+ result = []
+ while i 0:
+ result += [bytes([len(args[0])]) + args[0][:num-1] + b'\0'*padding]
+ else:
+ if num<255:
+ result += [bytes([num-1]) + args[0][:num-1]]
+ else:
+ result += [bytes([255]) + args[0][:num-1]]
+ args.pop(0)
+ else:
+ raise StructError("arg for string format not a string")
+
+ else:
+ if len(args) < num:
+ raise StructError("insufficient arguments to pack")
+ for var in args[:num]:
+ # pad with 0 until position is a multiple of size
+ if len(result) and alignment:
+ padding = format['size'] - len(result) % format['size']
+ result += [bytes([0])]*padding
+ result += [format['pack'](var,format['size'],endianness)]
+ args=args[num:]
+ num = None
+ i += 1
+ if len(args) != 0:
+ raise StructError("too many arguments for pack format")
+ return b''.join(result)
+
+def unpack(fmt,data):
+ """unpack(fmt, string) -> (v1, v2, ...)
+ Unpack the string, containing packed C structure data, according
+ to fmt. Requires len(string)==calcsize(fmt).
+ See struct.__doc__ for more on format strings."""
+ formatdef,endianness,i,alignment = getmode(fmt)
+ j = 0
+ num = 0
+ result = []
+ length= calcsize(fmt)
+ if length != len (data):
+ raise StructError("unpack str size does not match format")
+ while i= num:
+ n = num-1
+ result.append(data[j+1:j+n+1])
+ j += num
+ else:
+ # skip padding bytes until we get at a multiple of size
+ if j>0 and alignment:
+ padding = format['size'] - j % format['size']
+ j += padding
+ for n in range(num):
+ result += [format['unpack'](data,j,format['size'],endianness)]
+ j += format['size']
+
+ return tuple(result)
+
+def pack_into(fmt, buf, offset, *args):
+ data = pack(fmt, *args)
+ buf[offset:offset+len(data)] = data
+
+def unpack_from(fmt, buf, offset=0):
+ size = calcsize(fmt)
+ data = buf[offset:offset+size]
+ if len(data) != size:
+ raise error("unpack_from requires a buffer of at least %d bytes"
+ % (size,))
+ return unpack(fmt, data)
+
+def _clearcache():
+ "Clear the internal cache."
+ # No cache in this implementation
+
+if __name__=='__main__':
+ t = pack('Bf',1,2)
+ print(t, len(t))
+ print(unpack('Bf', t))
+ print(calcsize('Bf'))
+
+
\ No newline at end of file
diff --git a/lib/assets/Lib/_sysconfigdata.py b/lib/assets/Lib/_sysconfigdata.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/_sysconfigdata.py
@@ -0,0 +1,2 @@
+build_time_vars={'HAVE_SYS_WAIT_H': 1, 'HAVE_UTIL_H': 0, 'HAVE_SYMLINKAT': 1, 'HAVE_LIBSENDFILE': 0, 'SRCDIRS': 'Parser Grammar Objects Python Modules Mac', 'SIZEOF_OFF_T': 8, 'BASECFLAGS': '-Wno-unused-result', 'HAVE_UTIME_H': 1, 'EXTRAMACHDEPPATH': '', 'HAVE_SYS_TIME_H': 1, 'CFLAGSFORSHARED': '-fPIC', 'HAVE_HYPOT': 1, 'PGSRCS': '\\', 'HAVE_LIBUTIL_H': 0, 'HAVE_COMPUTED_GOTOS': 1, 'HAVE_LUTIMES': 1, 'HAVE_MAKEDEV': 1, 'HAVE_REALPATH': 1, 'HAVE_LINUX_TIPC_H': 1, 'MULTIARCH': 'i386-linux-gnu', 'HAVE_GETWD': 1, 'HAVE_GCC_ASM_FOR_X64': 0, 'HAVE_INET_PTON': 1, 'HAVE_GETHOSTBYNAME_R_6_ARG': 1, 'SIZEOF__BOOL': 1, 'HAVE_ZLIB_COPY': 1, 'ASDLGEN': 'python3.3 ../Parser/asdl_c.py', 'GRAMMAR_INPUT': '../Grammar/Grammar', 'HOST_GNU_TYPE': 'i686-pc-linux-gnu', 'HAVE_SCHED_RR_GET_INTERVAL': 1, 'HAVE_BLUETOOTH_H': 0, 'HAVE_MKFIFO': 1, 'TIMEMODULE_LIB': 0, 'LIBM': '-lm', 'PGENOBJS': '\\ \\', 'PYTHONFRAMEWORK': '', 'GETPGRP_HAVE_ARG': 0, 'HAVE_MMAP': 1, 'SHLIB_SUFFIX': '.so', 'SIZEOF_FLOAT': 4, 'HAVE_RENAMEAT': 1, 'HAVE_LANGINFO_H': 1, 'HAVE_STDLIB_H': 1, 'PY_CORE_CFLAGS': '-Wno-unused-result -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -I. -IInclude -I../Include -D_FORTIFY_SOURCE=2 -fPIC -DPy_BUILD_CORE', 'HAVE_BROKEN_PIPE_BUF': 0, 'HAVE_CONFSTR': 1, 'HAVE_SIGTIMEDWAIT': 1, 'HAVE_FTELLO': 1, 'READELF': 'readelf', 'HAVE_SIGALTSTACK': 1, 'TESTTIMEOUT': 3600, 'PYTHONPATH': ':plat-i386-linux-gnu', 'SIZEOF_WCHAR_T': 4, 'LIBOBJS': '', 'HAVE_SYSCONF': 1, 'MAKESETUP': '../Modules/makesetup', 'HAVE_UTIMENSAT': 1, 'HAVE_FCHOWNAT': 1, 'HAVE_WORKING_TZSET': 1, 'HAVE_FINITE': 1, 'HAVE_ASINH': 1, 'HAVE_SETEUID': 1, 'CONFIGFILES': 'configure configure.ac acconfig.h pyconfig.h.in Makefile.pre.in', 'HAVE_SETGROUPS': 1, 'PARSER_OBJS': '\\ Parser/myreadline.o Parser/parsetok.o Parser/tokenizer.o', 'HAVE_MBRTOWC': 1, 'SIZEOF_INT': 4, 'HAVE_STDARG_PROTOTYPES': 1, 'TM_IN_SYS_TIME': 0, 'HAVE_SYS_TIMES_H': 1, 'HAVE_LCHOWN': 1, 'HAVE_SSIZE_T': 1, 'HAVE_PAUSE': 1, 'SYSLIBS': '-lm', 'POSIX_SEMAPHORES_NOT_ENABLED': 0, 'HAVE_DEVICE_MACROS': 1, 'BLDSHARED': 'i686-linux-gnu-gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro -Wno-unused-result -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security ', 'LIBSUBDIRS': 'tkinter tkinter/test tkinter/test/test_tkinter \\', 'HAVE_SYS_UN_H': 1, 'HAVE_SYS_STAT_H': 1, 'VPATH': '..', 'INCLDIRSTOMAKE': '/usr/include /usr/include /usr/include/python3.3m /usr/include/python3.3m', 'HAVE_BROKEN_SEM_GETVALUE': 0, 'HAVE_TIMEGM': 1, 'PACKAGE_VERSION': 0, 'MAJOR_IN_SYSMACROS': 0, 'HAVE_ATANH': 1, 'HAVE_GAI_STRERROR': 1, 'HAVE_SYS_POLL_H': 1, 'SIZEOF_PTHREAD_T': 4, 'SIZEOF_FPOS_T': 16, 'HAVE_CTERMID': 1, 'HAVE_TMPFILE': 1, 'HAVE_SETUID': 1, 'CXX': 'i686-linux-gnu-g++ -pthread', 'srcdir': '..', 'HAVE_UINT32_T': 1, 'HAVE_ADDRINFO': 1, 'HAVE_GETSPENT': 1, 'SIZEOF_DOUBLE': 8, 'HAVE_INT32_T': 1, 'LIBRARY_OBJS_OMIT_FROZEN': '\\', 'HAVE_FUTIMES': 1, 'CONFINCLUDEPY': '/usr/include/python3.3m', 'HAVE_RL_COMPLETION_APPEND_CHARACTER': 1, 'LIBFFI_INCLUDEDIR': '', 'HAVE_SETGID': 1, 'HAVE_UINT64_T': 1, 'EXEMODE': 755, 'UNIVERSALSDK': '', 'HAVE_LIBDL': 1, 'HAVE_GETNAMEINFO': 1, 'HAVE_STDINT_H': 1, 'COREPYTHONPATH': ':plat-i386-linux-gnu', 'HAVE_SOCKADDR_STORAGE': 1, 'HAVE_WAITID': 1, 'EXTRAPLATDIR': '@EXTRAPLATDIR@', 'HAVE_ACCEPT4': 1, 'RUNSHARED': 'LD_LIBRARY_PATH=/build/buildd/python3.3-3.3.1/build-shared:', 'EXE': '', 'HAVE_SIGACTION': 1, 'HAVE_CHOWN': 1, 'HAVE_GETLOGIN': 1, 'HAVE_TZNAME': 0, 'PACKAGE_NAME': 0, 'HAVE_GETPGID': 1, 'HAVE_GLIBC_MEMMOVE_BUG': 0, 'BUILD_GNU_TYPE': 'i686-pc-linux-gnu', 'HAVE_LINUX_CAN_H': 1, 'DYNLOADFILE': 'dynload_shlib.o', 'HAVE_PWRITE': 1, 'BUILDEXE': '', 'HAVE_OPENPTY': 1, 'HAVE_LOCKF': 1, 'HAVE_COPYSIGN': 1, 'HAVE_PREAD': 1, 'HAVE_DLOPEN': 1, 'HAVE_SYS_KERN_CONTROL_H': 0, 'PY_FORMAT_LONG_LONG': '"ll"', 'HAVE_TCSETPGRP': 1, 'HAVE_SETSID': 1, 'HAVE_STRUCT_STAT_ST_BIRTHTIME': 0, 'HAVE_STRING_H': 1, 'LDLIBRARY': 'libpython3.3m.so', 'INSTALL_SCRIPT': '/usr/bin/install -c', 'HAVE_SYS_XATTR_H': 1, 'HAVE_CURSES_IS_TERM_RESIZED': 1, 'HAVE_TMPNAM_R': 1, 'STRICT_SYSV_CURSES': "/* Don't use ncurses extensions */", 'WANT_SIGFPE_HANDLER': 1, 'HAVE_INT64_T': 1, 'HAVE_STAT_TV_NSEC': 1, 'HAVE_SYS_MKDEV_H': 0, 'HAVE_BROKEN_POLL': 0, 'HAVE_IF_NAMEINDEX': 1, 'HAVE_GETPWENT': 1, 'PSRCS': '\\', 'RANLIB': 'ranlib', 'HAVE_WCSCOLL': 1, 'WITH_NEXT_FRAMEWORK': 0, 'ASDLGEN_FILES': '../Parser/asdl.py ../Parser/asdl_c.py', 'HAVE_RL_PRE_INPUT_HOOK': 1, 'PACKAGE_URL': 0, 'SHLIB_EXT': 0, 'HAVE_SYS_LOADAVG_H': 0, 'HAVE_LIBIEEE': 0, 'HAVE_SEM_OPEN': 1, 'HAVE_TERM_H': 1, 'IO_OBJS': '\\', 'IO_H': 'Modules/_io/_iomodule.h', 'HAVE_STATVFS': 1, 'VERSION': '3.3', 'HAVE_GETC_UNLOCKED': 1, 'MACHDEPS': 'plat-i386-linux-gnu @EXTRAPLATDIR@', 'SUBDIRSTOO': 'Include Lib Misc', 'HAVE_SETREUID': 1, 'HAVE_ERFC': 1, 'HAVE_SETRESUID': 1, 'LINKFORSHARED': '-Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions', 'HAVE_SYS_TYPES_H': 1, 'HAVE_GETPAGESIZE': 1, 'HAVE_SETEGID': 1, 'HAVE_PTY_H': 1, 'HAVE_STRUCT_STAT_ST_FLAGS': 0, 'HAVE_WCHAR_H': 1, 'HAVE_FSEEKO': 1, 'Py_ENABLE_SHARED': 1, 'HAVE_SIGRELSE': 1, 'HAVE_PTHREAD_INIT': 0, 'FILEMODE': 644, 'HAVE_SYS_RESOURCE_H': 1, 'HAVE_READLINKAT': 1, 'PYLONG_BITS_IN_DIGIT': 0, 'LINKCC': 'i686-linux-gnu-gcc -pthread', 'HAVE_SETLOCALE': 1, 'HAVE_CHROOT': 1, 'HAVE_OPENAT': 1, 'HAVE_FEXECVE': 1, 'LDCXXSHARED': 'i686-linux-gnu-g++ -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions', 'DIST': 'README ChangeLog configure configure.ac acconfig.h pyconfig.h.in Makefile.pre.in Include Lib Misc Ext-dummy', 'HAVE_MKNOD': 1, 'PY_LDFLAGS': '-Wl,-Bsymbolic-functions -Wl,-z,relro', 'HAVE_BROKEN_MBSTOWCS': 0, 'LIBRARY_OBJS': '\\', 'HAVE_LOG1P': 1, 'SIZEOF_VOID_P': 4, 'HAVE_FCHOWN': 1, 'PYTHONFRAMEWORKPREFIX': '', 'HAVE_LIBDLD': 0, 'HAVE_TGAMMA': 1, 'HAVE_ERRNO_H': 1, 'HAVE_IO_H': 0, 'OTHER_LIBTOOL_OPT': '', 'HAVE_POLL_H': 1, 'PY_CPPFLAGS': '-I. -IInclude -I../Include -D_FORTIFY_SOURCE=2', 'XMLLIBSUBDIRS': 'xml xml/dom xml/etree xml/parsers xml/sax', 'GRAMMAR_H': 'Include/graminit.h', 'TANH_PRESERVES_ZERO_SIGN': 1, 'HAVE_GETLOADAVG': 1, 'UNICODE_DEPS': '\\ \\', 'HAVE_GETCWD': 1, 'MANDIR': '/usr/share/man', 'MACHDESTLIB': '/usr/lib/python3.3', 'GRAMMAR_C': 'Python/graminit.c', 'PGOBJS': '\\', 'HAVE_DEV_PTMX': 1, 'HAVE_UINTPTR_T': 1, 'HAVE_SCHED_SETAFFINITY': 1, 'PURIFY': '', 'HAVE_DECL_ISINF': 1, 'HAVE_RL_CALLBACK': 1, 'HAVE_WRITEV': 1, 'HAVE_GETHOSTBYNAME_R_5_ARG': 0, 'HAVE_SYS_AUDIOIO_H': 0, 'EXT_SUFFIX': '.cpython-33m.so', 'SIZEOF_LONG_LONG': 8, 'DLINCLDIR': '.', 'HAVE_PATHCONF': 1, 'HAVE_UNLINKAT': 1, 'MKDIR_P': '/bin/mkdir -p', 'HAVE_ALTZONE': 0, 'SCRIPTDIR': '/usr/lib', 'OPCODETARGETGEN_FILES': '\\', 'HAVE_GETSPNAM': 1, 'HAVE_SYS_TERMIO_H': 0, 'HAVE_ATTRIBUTE_FORMAT_PARSETUPLE': 0, 'HAVE_PTHREAD_H': 1, 'Py_DEBUG': 0, 'HAVE_STRUCT_STAT_ST_BLOCKS': 1, 'X87_DOUBLE_ROUNDING': 1, 'SIZEOF_TIME_T': 4, 'HAVE_DYNAMIC_LOADING': 1, 'HAVE_DIRECT_H': 0, 'SRC_GDB_HOOKS': '../Tools/gdb/libpython.py', 'HAVE_GETADDRINFO': 1, 'HAVE_BROKEN_NICE': 0, 'HAVE_DIRENT_H': 1, 'HAVE_WCSXFRM': 1, 'HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK': 1, 'HAVE_FSTATVFS': 1, 'PYTHON': 'python', 'HAVE_OSX105_SDK': 0, 'BINDIR': '/usr/bin', 'TESTPYTHON': 'LD_LIBRARY_PATH=/build/buildd/python3.3-3.3.1/build-shared: ./python', 'ARFLAGS': 'rc', 'PLATDIR': 'plat-i386-linux-gnu', 'HAVE_ASM_TYPES_H': 1, 'PY3LIBRARY': 'libpython3.so', 'HAVE_PLOCK': 0, 'FLOCK_NEEDS_LIBBSD': 0, 'WITH_TSC': 0, 'HAVE_LIBREADLINE': 1, 'MACHDEP': 'linux', 'HAVE_SELECT': 1, 'LDFLAGS': '-Wl,-Bsymbolic-functions -Wl,-z,relro', 'HAVE_HSTRERROR': 1, 'SOABI': 'cpython-33m', 'HAVE_GETTIMEOFDAY': 1, 'HAVE_LIBRESOLV': 0, 'HAVE_UNSETENV': 1, 'HAVE_TM_ZONE': 1, 'HAVE_GETPGRP': 1, 'HAVE_FLOCK': 1, 'HAVE_SYS_BSDTTY_H': 0, 'SUBDIRS': '', 'PYTHONFRAMEWORKINSTALLDIR': '', 'PACKAGE_BUGREPORT': 0, 'HAVE_CLOCK': 1, 'HAVE_GETPEERNAME': 1, 'SIZEOF_PID_T': 4, 'HAVE_CONIO_H': 0, 'HAVE_FSTATAT': 1, 'HAVE_NETPACKET_PACKET_H': 1, 'HAVE_WAIT3': 1, 'DESTPATH': '', 'HAVE_STAT_TV_NSEC2': 0, 'HAVE_GETRESGID': 1, 'HAVE_UCS4_TCL': 0, 'SIGNED_RIGHT_SHIFT_ZERO_FILLS': 0, 'HAVE_TIMES': 1, 'HAVE_UNAME': 1, 'HAVE_ERF': 1, 'SIZEOF_SHORT': 2, 'HAVE_NCURSES_H': 1, 'HAVE_SYS_SENDFILE_H': 1, 'HAVE_CTERMID_R': 0, 'HAVE_TMPNAM': 1, 'prefix': '/usr', 'HAVE_NICE': 1, 'WITH_THREAD': 1, 'LN': 'ln', 'TESTRUNNER': 'LD_LIBRARY_PATH=/build/buildd/python3.3-3.3.1/build-shared: ./python ../Tools/scripts/run_tests.py', 'HAVE_SIGINTERRUPT': 1, 'HAVE_SETPGID': 1, 'RETSIGTYPE': 'void', 'HAVE_SCHED_GET_PRIORITY_MAX': 1, 'HAVE_SYS_SYS_DOMAIN_H': 0, 'HAVE_SYS_DIR_H': 0, 'HAVE__GETPTY': 0, 'HAVE_BLUETOOTH_BLUETOOTH_H': 1, 'HAVE_BIND_TEXTDOMAIN_CODESET': 1, 'HAVE_POLL': 1, 'PYTHON_OBJS': '\\', 'HAVE_WAITPID': 1, 'USE_INLINE': 1, 'HAVE_FUTIMENS': 1, 'USE_COMPUTED_GOTOS': 1, 'MAINCC': 'i686-linux-gnu-gcc -pthread', 'HAVE_SOCKETPAIR': 1, 'HAVE_PROCESS_H': 0, 'HAVE_SETVBUF': 1, 'HAVE_FDOPENDIR': 1, 'CONFINCLUDEDIR': '/usr/include', 'BINLIBDEST': '/usr/lib/python3.3', 'HAVE_SYS_IOCTL_H': 1, 'HAVE_SYSEXITS_H': 1, 'LDLAST': '', 'HAVE_SYS_FILE_H': 1, 'HAVE_RL_COMPLETION_SUPPRESS_APPEND': 1, 'HAVE_RL_COMPLETION_MATCHES': 1, 'HAVE_TCGETPGRP': 1, 'SIZEOF_SIZE_T': 4, 'HAVE_EPOLL_CREATE1': 1, 'HAVE_SYS_SELECT_H': 1, 'HAVE_CLOCK_GETTIME': 1, 'CFLAGS': '-Wno-unused-result -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security ', 'HAVE_SNPRINTF': 1, 'BLDLIBRARY': '-lpython3.3m', 'PARSER_HEADERS': '\\', 'SO': '.so', 'LIBRARY': 'libpython3.3m.a', 'HAVE_FPATHCONF': 1, 'HAVE_TERMIOS_H': 1, 'HAVE_BROKEN_PTHREAD_SIGMASK': 0, 'AST_H': 'Include/Python-ast.h', 'HAVE_GCC_UINT128_T': 0, 'HAVE_ACOSH': 1, 'MODOBJS': 'Modules/_threadmodule.o Modules/signalmodule.o Modules/arraymodule.o Modules/mathmodule.o Modules/_math.o Modules/_struct.o Modules/timemodule.o Modules/_randommodule.o Modules/atexitmodule.o Modules/_elementtree.o Modules/_pickle.o Modules/_datetimemodule.o Modules/_bisectmodule.o Modules/_heapqmodule.o Modules/unicodedata.o Modules/fcntlmodule.o Modules/spwdmodule.o Modules/grpmodule.o Modules/selectmodule.o Modules/socketmodule.o Modules/_posixsubprocess.o Modules/md5module.o Modules/sha1module.o Modules/sha256module.o Modules/sha512module.o Modules/syslogmodule.o Modules/binascii.o Modules/zlibmodule.o Modules/pyexpat.o Modules/posixmodule.o Modules/errnomodule.o Modules/pwdmodule.o Modules/_sre.o Modules/_codecsmodule.o Modules/_weakref.o Modules/_functoolsmodule.o Modules/operator.o Modules/_collectionsmodule.o Modules/itertoolsmodule.o Modules/_localemodule.o Modules/_iomodule.o Modules/iobase.o Modules/fileio.o Modules/bytesio.o Modules/bufferedio.o Modules/textio.o Modules/stringio.o Modules/zipimport.o Modules/faulthandler.o Modules/symtablemodule.o Modules/xxsubtype.o', 'AST_C': 'Python/Python-ast.c', 'HAVE_SYS_NDIR_H': 0, 'DESTDIRS': '/usr /usr/lib /usr/lib/python3.3 /usr/lib/python3.3/lib-dynload', 'HAVE_SIGNAL_H': 1, 'PACKAGE_TARNAME': 0, 'HAVE_GETPRIORITY': 1, 'INCLUDEDIR': '/usr/include', 'HAVE_INTTYPES_H': 1, 'SIGNAL_OBJS': '', 'HAVE_READV': 1, 'HAVE_SETHOSTNAME': 1, 'MODLIBS': '-lrt -lexpat -L/usr/lib -lz -lexpat', 'CC': 'i686-linux-gnu-gcc -pthread', 'HAVE_LCHMOD': 0, 'SIZEOF_UINTPTR_T': 4, 'LIBPC': '/usr/lib/i386-linux-gnu/pkgconfig', 'BYTESTR_DEPS': '\\', 'HAVE_MKDIRAT': 1, 'LIBPL': '/usr/lib/python3.3/config-3.3m-i386-linux-gnu', 'HAVE_SHADOW_H': 1, 'HAVE_SYS_EVENT_H': 0, 'INSTALL': '/usr/bin/install -c', 'HAVE_GCC_ASM_FOR_X87': 1, 'HAVE_BROKEN_UNSETENV': 0, 'BASECPPFLAGS': '', 'DOUBLE_IS_BIG_ENDIAN_IEEE754': 0, 'HAVE_STRUCT_STAT_ST_RDEV': 1, 'HAVE_SEM_UNLINK': 1, 'BUILDPYTHON': 'python', 'HAVE_RL_CATCH_SIGNAL': 1, 'HAVE_DECL_TZNAME': 0, 'RESSRCDIR': 'Mac/Resources/framework', 'HAVE_PTHREAD_SIGMASK': 1, 'HAVE_UTIMES': 1, 'DISTDIRS': 'Include Lib Misc Ext-dummy', 'HAVE_FDATASYNC': 1, 'HAVE_USABLE_WCHAR_T': 0, 'PY_FORMAT_SIZE_T': '"z"', 'HAVE_SCHED_SETSCHEDULER': 1, 'VA_LIST_IS_ARRAY': 0, 'HAVE_LINUX_NETLINK_H': 1, 'HAVE_SETREGID': 1, 'HAVE_STROPTS_H': 1, 'LDVERSION': '3.3m', 'abs_builddir': '/build/buildd/python3.3-3.3.1/build-shared', 'SITEPATH': '', 'HAVE_GETHOSTBYNAME': 0, 'HAVE_SIGPENDING': 1, 'HAVE_KQUEUE': 0, 'HAVE_SYNC': 1, 'HAVE_GETSID': 1, 'HAVE_ROUND': 1, 'HAVE_STRFTIME': 1, 'AST_H_DIR': 'Include', 'HAVE_PIPE2': 1, 'AST_C_DIR': 'Python', 'TESTPYTHONOPTS': '', 'HAVE_DEV_PTC': 0, 'GETTIMEOFDAY_NO_TZ': 0, 'HAVE_NET_IF_H': 1, 'HAVE_SENDFILE': 1, 'HAVE_SETPGRP': 1, 'HAVE_SEM_GETVALUE': 1, 'CONFIGURE_LDFLAGS': '-Wl,-Bsymbolic-functions -Wl,-z,relro', 'DLLLIBRARY': '', 'PYTHON_FOR_BUILD': './python -E', 'SETPGRP_HAVE_ARG': 0, 'HAVE_INET_ATON': 1, 'INSTALL_SHARED': '/usr/bin/install -c -m 555', 'WITH_DOC_STRINGS': 1, 'OPCODETARGETS_H': '\\', 'HAVE_INITGROUPS': 1, 'HAVE_LINKAT': 1, 'BASEMODLIBS': '', 'SGI_ABI': '', 'HAVE_SCHED_SETPARAM': 1, 'OPT': '-DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes', 'HAVE_POSIX_FADVISE': 1, 'datarootdir': '/usr/share', 'HAVE_MEMRCHR': 1, 'HGTAG': '', 'HAVE_MEMMOVE': 1, 'HAVE_GETRESUID': 1, 'DOUBLE_IS_ARM_MIXED_ENDIAN_IEEE754': 0, 'HAVE_LSTAT': 1, 'AR': 'ar', 'HAVE_WAIT4': 1, 'HAVE_SYS_MODEM_H': 0, 'INSTSONAME': 'libpython3.3m.so.1.0', 'HAVE_SYS_STATVFS_H': 1, 'HAVE_LGAMMA': 1, 'HAVE_PROTOTYPES': 1, 'HAVE_SYS_UIO_H': 1, 'MAJOR_IN_MKDEV': 0, 'QUICKTESTOPTS': '-x test_subprocess test_io test_lib2to3 \\', 'HAVE_SYS_DEVPOLL_H': 0, 'HAVE_CHFLAGS': 0, 'HAVE_FSYNC': 1, 'HAVE_FCHMOD': 1, 'INCLUDEPY': '/usr/include/python3.3m', 'HAVE_SEM_TIMEDWAIT': 1, 'LDLIBRARYDIR': '', 'HAVE_STRUCT_TM_TM_ZONE': 1, 'HAVE_CURSES_H': 1, 'TIME_WITH_SYS_TIME': 1, 'HAVE_DUP2': 1, 'ENABLE_IPV6': 1, 'WITH_VALGRIND': 0, 'HAVE_SETITIMER': 1, 'THREADOBJ': 'Python/thread.o', 'LOCALMODLIBS': '-lrt -lexpat -L/usr/lib -lz -lexpat', 'HAVE_MEMORY_H': 1, 'HAVE_GETITIMER': 1, 'HAVE_C99_BOOL': 1, 'INSTALL_DATA': '/usr/bin/install -c -m 644', 'PGEN': 'Parser/pgen', 'HAVE_GRP_H': 1, 'HAVE_WCSFTIME': 1, 'AIX_GENUINE_CPLUSPLUS': 0, 'HAVE_LIBINTL_H': 1, 'SHELL': '/bin/sh', 'HAVE_UNISTD_H': 1, 'EXTRATESTOPTS': '', 'HAVE_EXECV': 1, 'HAVE_FSEEK64': 0, 'MVWDELCH_IS_EXPRESSION': 1, 'DESTSHARED': '/usr/lib/python3.3/lib-dynload', 'OPCODETARGETGEN': '\\', 'LIBDEST': '/usr/lib/python3.3', 'CCSHARED': '-fPIC', 'HAVE_EXPM1': 1, 'HAVE_DLFCN_H': 1, 'exec_prefix': '/usr', 'HAVE_READLINK': 1, 'WINDOW_HAS_FLAGS': 1, 'HAVE_FTELL64': 0, 'HAVE_STRLCPY': 0, 'MACOSX_DEPLOYMENT_TARGET': '', 'HAVE_SYS_SYSCALL_H': 1, 'DESTLIB': '/usr/lib/python3.3', 'LDSHARED': 'i686-linux-gnu-gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro -Wno-unused-result -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security ', 'HGVERSION': '', 'PYTHON_HEADERS': '\\', 'HAVE_STRINGS_H': 1, 'DOUBLE_IS_LITTLE_ENDIAN_IEEE754': 1, 'HAVE_POSIX_FALLOCATE': 1, 'HAVE_DIRFD': 1, 'HAVE_LOG2': 1, 'HAVE_GETPID': 1, 'HAVE_ALARM': 1, 'MACHDEP_OBJS': '', 'HAVE_SPAWN_H': 1, 'HAVE_FORK': 1, 'HAVE_SETRESGID': 1, 'HAVE_FCHMODAT': 1, 'HAVE_CLOCK_GETRES': 1, 'MACHDEPPATH': ':plat-i386-linux-gnu', 'STDC_HEADERS': 1, 'HAVE_SETPRIORITY': 1, 'LIBC': '', 'HAVE_SYS_EPOLL_H': 1, 'HAVE_SYS_UTSNAME_H': 1, 'HAVE_PUTENV': 1, 'HAVE_CURSES_RESIZE_TERM': 1, 'HAVE_FUTIMESAT': 1, 'WITH_DYLD': 0, 'INSTALL_PROGRAM': '/usr/bin/install -c', 'LIBS': '-lpthread -ldl -lutil', 'HAVE_TRUNCATE': 1, 'TESTOPTS': '', 'PROFILE_TASK': '../Tools/pybench/pybench.py -n 2 --with-gc --with-syscheck', 'HAVE_CURSES_RESIZETERM': 1, 'ABIFLAGS': 'm', 'HAVE_GETGROUPLIST': 1, 'OBJECT_OBJS': '\\', 'HAVE_MKNODAT': 1, 'HAVE_ST_BLOCKS': 1, 'HAVE_STRUCT_STAT_ST_GEN': 0, 'SYS_SELECT_WITH_SYS_TIME': 1, 'SHLIBS': '-lpthread -ldl -lutil', 'HAVE_GETGROUPS': 1, 'MODULE_OBJS': '\\', 'PYTHONFRAMEWORKDIR': 'no-framework', 'HAVE_FCNTL_H': 1, 'HAVE_LINK': 1, 'HAVE_SIGWAIT': 1, 'HAVE_GAMMA': 1, 'HAVE_SYS_LOCK_H': 0, 'HAVE_FORKPTY': 1, 'HAVE_SOCKADDR_SA_LEN': 0, 'HAVE_TEMPNAM': 1, 'HAVE_STRUCT_STAT_ST_BLKSIZE': 1, 'HAVE_MKFIFOAT': 1, 'HAVE_SIGWAITINFO': 1, 'HAVE_FTIME': 1, 'HAVE_EPOLL': 1, 'HAVE_SYS_SOCKET_H': 1, 'HAVE_LARGEFILE_SUPPORT': 1, 'CONFIGURE_CFLAGS': '-g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security', 'HAVE_PTHREAD_DESTRUCTOR': 0, 'CONFIGURE_CPPFLAGS': '-D_FORTIFY_SOURCE=2', 'HAVE_SYMLINK': 1, 'HAVE_LONG_LONG': 1, 'HAVE_IEEEFP_H': 0, 'LIBDIR': '/usr/lib', 'HAVE_PTHREAD_KILL': 1, 'TESTPATH': '', 'HAVE_STRDUP': 1, 'POBJS': '\\', 'NO_AS_NEEDED': '-Wl,--no-as-needed', 'HAVE_LONG_DOUBLE': 1, 'HGBRANCH': '', 'DISTFILES': 'README ChangeLog configure configure.ac acconfig.h pyconfig.h.in Makefile.pre.in', 'PTHREAD_SYSTEM_SCHED_SUPPORTED': 1, 'HAVE_FACCESSAT': 1, 'AST_ASDL': '../Parser/Python.asdl', 'CPPFLAGS': '-I. -IInclude -I../Include -D_FORTIFY_SOURCE=2', 'HAVE_MKTIME': 1, 'HAVE_NDIR_H': 0, 'PY_CFLAGS': '-Wno-unused-result -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security ', 'LIBOBJDIR': 'Python/', 'HAVE_LINUX_CAN_RAW_H': 1, 'HAVE_GETHOSTBYNAME_R_3_ARG': 0, 'PACKAGE_STRING': 0, 'GNULD': 'yes', 'LOG1P_DROPS_ZERO_SIGN': 0, 'HAVE_FTRUNCATE': 1, 'WITH_LIBINTL': 0, 'HAVE_MREMAP': 1, 'HAVE_DECL_ISNAN': 1, 'HAVE_KILLPG': 1, 'SIZEOF_LONG': 4, 'HAVE_DECL_ISFINITE': 1, 'HAVE_IPA_PURE_CONST_BUG': 0, 'WITH_PYMALLOC': 1, 'abs_srcdir': '/build/buildd/python3.3-3.3.1/build-shared/..', 'HAVE_FCHDIR': 1, 'HAVE_BROKEN_POSIX_SEMAPHORES': 0, 'AC_APPLE_UNIVERSAL_BUILD': 0, 'PGENSRCS': '\\ \\', 'DIRMODE': 755, 'HAVE_GETHOSTBYNAME_R': 1, 'HAVE_LCHFLAGS': 0, 'HAVE_SYS_PARAM_H': 1, 'SIZEOF_LONG_DOUBLE': 12, 'CONFIG_ARGS': "'--enable-shared' '--prefix=/usr' '--enable-ipv6' '--enable-loadable-sqlite-extensions' '--with-dbmliborder=bdb:gdbm' '--with-computed-gotos' '--with-system-expat' '--with-system-ffi' '--with-fpectl' 'CC=i686-linux-gnu-gcc' 'CFLAGS=-g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security ' 'LDFLAGS=-Wl,-Bsymbolic-functions -Wl,-z,relro' 'CPPFLAGS=-D_FORTIFY_SOURCE=2'", 'HAVE_SCHED_H': 1, 'HAVE_KILL': 1}
+
diff --git a/lib/assets/Lib/_testcapi.py b/lib/assets/Lib/_testcapi.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/_testcapi.py
@@ -0,0 +1,290 @@
+
+CHAR_MAX = 127
+
+CHAR_MIN = -128
+
+DBL_MAX = 1.7976931348623157e+308
+
+DBL_MIN = 2.2250738585072014e-308
+
+FLT_MAX = 3.4028234663852886e+38
+
+FLT_MIN = 1.1754943508222875e-38
+
+INT_MAX = 2147483647
+
+INT_MIN = -2147483648
+
+LLONG_MAX = 9223372036854775807
+
+LLONG_MIN = -9223372036854775808
+
+LONG_MAX = 2147483647
+
+LONG_MIN = -2147483648
+
+PY_SSIZE_T_MAX = 2147483647
+
+PY_SSIZE_T_MIN = -2147483648
+
+SHRT_MAX = 32767
+
+SHRT_MIN = -32768
+
+SIZEOF_PYGC_HEAD = 16
+
+UCHAR_MAX = 255
+
+UINT_MAX = 4294967295
+
+ULLONG_MAX = 18446744073709551615
+
+ULONG_MAX = 4294967295
+
+USHRT_MAX = 65535
+
+__loader__ = "<_frozen_importlib.ExtensionFileLoader object at 0x00C98DD0>"
+
+def _pending_threadfunc(*args,**kw):
+ pass
+
+class _test_structmembersType(object):
+ pass
+
+def _test_thread_state(*args,**kw):
+ pass
+
+def argparsing(*args,**kw):
+ pass
+
+def code_newempty(*args,**kw):
+ pass
+
+def codec_incrementaldecoder(*args,**kw):
+ pass
+
+def codec_incrementalencoder(*args,**kw):
+ pass
+
+def crash_no_current_thread(*args,**kw):
+ pass
+
+class error(Exception):
+ pass
+
+def exception_print(*args,**kw):
+ pass
+
+def getargs_B(*args,**kw):
+ pass
+
+def getargs_H(*args,**kw):
+ pass
+
+def getargs_I(*args,**kw):
+ pass
+
+def getargs_K(*args,**kw):
+ pass
+
+def getargs_L(*args,**kw):
+ pass
+
+def getargs_Z(*args,**kw):
+ pass
+
+def getargs_Z_hash(*args,**kw):
+ pass
+
+def getargs_b(*args,**kw):
+ pass
+
+def getargs_c(*args,**kw):
+ pass
+
+def getargs_h(*args,**kw):
+ pass
+
+def getargs_i(*args,**kw):
+ pass
+
+def getargs_k(*args,**kw):
+ pass
+
+def getargs_keyword_only(*args,**kw):
+ pass
+
+def getargs_keywords(*args,**kw):
+ pass
+
+def getargs_l(*args,**kw):
+ pass
+
+def getargs_n(*args,**kw):
+ pass
+
+def getargs_p(*args,**kw):
+ pass
+
+def getargs_s(*args,**kw):
+ pass
+
+def getargs_s_hash(*args,**kw):
+ pass
+
+def getargs_s_star(*args,**kw):
+ pass
+
+def getargs_tuple(*args,**kw):
+ pass
+
+def getargs_u(*args,**kw):
+ pass
+
+def getargs_u_hash(*args,**kw):
+ pass
+
+def getargs_w_star(*args,**kw):
+ pass
+
+def getargs_y(*args,**kw):
+ pass
+
+def getargs_y_hash(*args,**kw):
+ pass
+
+def getargs_y_star(*args,**kw):
+ pass
+
+def getargs_z(*args,**kw):
+ pass
+
+def getargs_z_hash(*args,**kw):
+ pass
+
+def getargs_z_star(*args,**kw):
+ pass
+
+class instancemethod(object):
+ pass
+
+def make_exception_with_doc(*args,**kw):
+ pass
+
+def make_memoryview_from_NULL_pointer(*args,**kw):
+ pass
+
+def parse_tuple_and_keywords(*args,**kw):
+ pass
+
+def pytime_object_to_time_t(*args,**kw):
+ pass
+
+def pytime_object_to_timespec(*args,**kw):
+ pass
+
+def pytime_object_to_timeval(*args,**kw):
+ pass
+
+def raise_exception(*args,**kw):
+ pass
+
+def raise_memoryerror(*args,**kw):
+ pass
+
+def run_in_subinterp(*args,**kw):
+ pass
+
+def set_exc_info(*args,**kw):
+ pass
+
+def test_L_code(*args,**kw):
+ pass
+
+def test_Z_code(*args,**kw):
+ pass
+
+def test_capsule(*args,**kw):
+ pass
+
+def test_config(*args,**kw):
+ pass
+
+def test_datetime_capi(*args,**kw):
+ pass
+
+def test_dict_iteration(*args,**kw):
+ pass
+
+def test_empty_argparse(*args,**kw):
+ pass
+
+def test_k_code(*args,**kw):
+ pass
+
+def test_lazy_hash_inheritance(*args,**kw):
+ pass
+
+def test_list_api(*args,**kw):
+ pass
+
+def test_long_and_overflow(*args,**kw):
+ pass
+
+def test_long_api(*args,**kw):
+ pass
+
+def test_long_as_double(*args,**kw):
+ pass
+
+def test_long_as_size_t(*args,**kw):
+ pass
+
+def test_long_long_and_overflow(*args,**kw):
+ pass
+
+def test_long_numbits(*args,**kw):
+ pass
+
+def test_longlong_api(*args,**kw):
+ pass
+
+def test_null_strings(*args,**kw):
+ pass
+
+def test_s_code(*args,**kw):
+ pass
+
+def test_string_from_format(*args,**kw):
+ pass
+
+def test_string_to_double(*args,**kw):
+ pass
+
+def test_u_code(*args,**kw):
+ pass
+
+def test_unicode_compare_with_ascii(*args,**kw):
+ pass
+
+def test_widechar(*args,**kw):
+ pass
+
+def test_with_docstring(*args,**kw):
+ """This is a pretty normal docstring."""
+ pass
+
+def traceback_print(*args,**kw):
+ pass
+
+def unicode_aswidechar(*args,**kw):
+ pass
+
+def unicode_aswidecharstring(*args,**kw):
+ pass
+
+def unicode_encodedecimal(*args,**kw):
+ pass
+
+def unicode_transformdecimaltoascii(*args,**kw):
+ pass
diff --git a/lib/assets/Lib/_thread.py b/lib/assets/Lib/_thread.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/_thread.py
@@ -0,0 +1,155 @@
+"""Drop-in replacement for the thread module.
+
+Meant to be used as a brain-dead substitute so that threaded code does
+not need to be rewritten for when the thread module is not present.
+
+Suggested usage is::
+
+ try:
+ import _thread
+ except ImportError:
+ import _dummy_thread as _thread
+
+"""
+# Exports only things specified by thread documentation;
+# skipping obsolete synonyms allocate(), start_new(), exit_thread().
+__all__ = ['error', 'start_new_thread', 'exit', 'get_ident', 'allocate_lock',
+ 'interrupt_main', 'LockType']
+
+# A dummy value
+TIMEOUT_MAX = 2**31
+
+# NOTE: this module can be imported early in the extension building process,
+# and so top level imports of other modules should be avoided. Instead, all
+# imports are done when needed on a function-by-function basis. Since threads
+# are disabled, the import lock should not be an issue anyway (??).
+
+error = RuntimeError
+
+def start_new_thread(function, args, kwargs={}):
+ """Dummy implementation of _thread.start_new_thread().
+
+ Compatibility is maintained by making sure that ``args`` is a
+ tuple and ``kwargs`` is a dictionary. If an exception is raised
+ and it is SystemExit (which can be done by _thread.exit()) it is
+ caught and nothing is done; all other exceptions are printed out
+ by using traceback.print_exc().
+
+ If the executed function calls interrupt_main the KeyboardInterrupt will be
+ raised when the function returns.
+
+ """
+ if type(args) != type(tuple()):
+ raise TypeError("2nd arg must be a tuple")
+ if type(kwargs) != type(dict()):
+ raise TypeError("3rd arg must be a dict")
+ global _main
+ _main = False
+ try:
+ function(*args, **kwargs)
+ except SystemExit:
+ pass
+ except:
+ import traceback
+ traceback.print_exc()
+ _main = True
+ global _interrupt
+ if _interrupt:
+ _interrupt = False
+ raise KeyboardInterrupt
+
+def exit():
+ """Dummy implementation of _thread.exit()."""
+ raise SystemExit
+
+def get_ident():
+ """Dummy implementation of _thread.get_ident().
+
+ Since this module should only be used when _threadmodule is not
+ available, it is safe to assume that the current process is the
+ only thread. Thus a constant can be safely returned.
+ """
+ return -1
+
+def allocate_lock():
+ """Dummy implementation of _thread.allocate_lock()."""
+ return LockType()
+
+def stack_size(size=None):
+ """Dummy implementation of _thread.stack_size()."""
+ if size is not None:
+ raise error("setting thread stack size not supported")
+ return 0
+
+class LockType(object):
+ """Class implementing dummy implementation of _thread.LockType.
+
+ Compatibility is maintained by maintaining self.locked_status
+ which is a boolean that stores the state of the lock. Pickling of
+ the lock, though, should not be done since if the _thread module is
+ then used with an unpickled ``lock()`` from here problems could
+ occur from this class not having atomic methods.
+
+ """
+
+ def __init__(self):
+ self.locked_status = False
+
+ def acquire(self, waitflag=None, timeout=-1):
+ """Dummy implementation of acquire().
+
+ For blocking calls, self.locked_status is automatically set to
+ True and returned appropriately based on value of
+ ``waitflag``. If it is non-blocking, then the value is
+ actually checked and not set if it is already acquired. This
+ is all done so that threading.Condition's assert statements
+ aren't triggered and throw a little fit.
+
+ """
+ if waitflag is None or waitflag:
+ self.locked_status = True
+ return True
+ else:
+ if not self.locked_status:
+ self.locked_status = True
+ return True
+ else:
+ if timeout > 0:
+ import time
+ time.sleep(timeout)
+ return False
+
+ __enter__ = acquire
+
+ def __exit__(self, typ, val, tb):
+ self.release()
+
+ def release(self):
+ """Release the dummy lock."""
+ # XXX Perhaps shouldn't actually bother to test? Could lead
+ # to problems for complex, threaded code.
+ if not self.locked_status:
+ raise error
+ self.locked_status = False
+ return True
+
+ def locked(self):
+ return self.locked_status
+
+# Used to signal that interrupt_main was called in a "thread"
+_interrupt = False
+# True when not executing in a "thread"
+_main = True
+
+def interrupt_main():
+ """Set _interrupt flag to True to have start_new_thread raise
+ KeyboardInterrupt upon exiting."""
+ if _main:
+ raise KeyboardInterrupt
+ else:
+ global _interrupt
+ _interrupt = True
+
+# Brython-specific to avoid circular references between threading and _threading_local
+class _local:
+ pass
\ No newline at end of file
diff --git a/lib/assets/Lib/_threading_local.py b/lib/assets/Lib/_threading_local.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/_threading_local.py
@@ -0,0 +1,246 @@
+"""Thread-local objects.
+
+(Note that this module provides a Python version of the threading.local
+ class. Depending on the version of Python you're using, there may be a
+ faster one available. You should always import the `local` class from
+ `threading`.)
+
+Thread-local objects support the management of thread-local data.
+If you have data that you want to be local to a thread, simply create
+a thread-local object and use its attributes:
+
+ >>> mydata = local()
+ >>> mydata.number = 42
+ >>> mydata.number
+ 42
+
+You can also access the local-object's dictionary:
+
+ >>> mydata.__dict__
+ {'number': 42}
+ >>> mydata.__dict__.setdefault('widgets', [])
+ []
+ >>> mydata.widgets
+ []
+
+What's important about thread-local objects is that their data are
+local to a thread. If we access the data in a different thread:
+
+ >>> log = []
+ >>> def f():
+ ... items = sorted(mydata.__dict__.items())
+ ... log.append(items)
+ ... mydata.number = 11
+ ... log.append(mydata.number)
+
+ >>> import threading
+ >>> thread = threading.Thread(target=f)
+ >>> thread.start()
+ >>> thread.join()
+ >>> log
+ [[], 11]
+
+we get different data. Furthermore, changes made in the other thread
+don't affect data seen in this thread:
+
+ >>> mydata.number
+ 42
+
+Of course, values you get from a local object, including a __dict__
+attribute, are for whatever thread was current at the time the
+attribute was read. For that reason, you generally don't want to save
+these values across threads, as they apply only to the thread they
+came from.
+
+You can create custom local objects by subclassing the local class:
+
+ >>> class MyLocal(local):
+ ... number = 2
+ ... initialized = False
+ ... def __init__(self, **kw):
+ ... if self.initialized:
+ ... raise SystemError('__init__ called too many times')
+ ... self.initialized = True
+ ... self.__dict__.update(kw)
+ ... def squared(self):
+ ... return self.number ** 2
+
+This can be useful to support default values, methods and
+initialization. Note that if you define an __init__ method, it will be
+called each time the local object is used in a separate thread. This
+is necessary to initialize each thread's dictionary.
+
+Now if we create a local object:
+
+ >>> mydata = MyLocal(color='red')
+
+Now we have a default number:
+
+ >>> mydata.number
+ 2
+
+an initial color:
+
+ >>> mydata.color
+ 'red'
+ >>> del mydata.color
+
+And a method that operates on the data:
+
+ >>> mydata.squared()
+ 4
+
+As before, we can access the data in a separate thread:
+
+ >>> log = []
+ >>> thread = threading.Thread(target=f)
+ >>> thread.start()
+ >>> thread.join()
+ >>> log
+ [[('color', 'red'), ('initialized', True)], 11]
+
+without affecting this thread's data:
+
+ >>> mydata.number
+ 2
+ >>> mydata.color
+ Traceback (most recent call last):
+ ...
+ AttributeError: 'MyLocal' object has no attribute 'color'
+
+Note that subclasses can define slots, but they are not thread
+local. They are shared across threads:
+
+ >>> class MyLocal(local):
+ ... __slots__ = 'number'
+
+ >>> mydata = MyLocal()
+ >>> mydata.number = 42
+ >>> mydata.color = 'red'
+
+So, the separate thread:
+
+ >>> thread = threading.Thread(target=f)
+ >>> thread.start()
+ >>> thread.join()
+
+affects what we see:
+
+ >>> mydata.number
+ 11
+
+>>> del mydata
+"""
+
+from weakref import ref
+from contextlib import contextmanager
+
+__all__ = ["local"]
+
+# We need to use objects from the threading module, but the threading
+# module may also want to use our `local` class, if support for locals
+# isn't compiled in to the `thread` module. This creates potential problems
+# with circular imports. For that reason, we don't import `threading`
+# until the bottom of this file (a hack sufficient to worm around the
+# potential problems). Note that all platforms on CPython do have support
+# for locals in the `thread` module, and there is no circular import problem
+# then, so problems introduced by fiddling the order of imports here won't
+# manifest.
+
+class _localimpl:
+ """A class managing thread-local dicts"""
+ __slots__ = 'key', 'dicts', 'localargs', 'locallock', '__weakref__'
+
+ def __init__(self):
+ # The key used in the Thread objects' attribute dicts.
+ # We keep it a string for speed but make it unlikely to clash with
+ # a "real" attribute.
+ self.key = '_threading_local._localimpl.' + str(id(self))
+ # { id(Thread) -> (ref(Thread), thread-local dict) }
+ self.dicts = {}
+
+ def get_dict(self):
+ """Return the dict for the current thread. Raises KeyError if none
+ defined."""
+ thread = current_thread()
+ return self.dicts[id(thread)][1]
+
+ def create_dict(self):
+ """Create a new dict for the current thread, and return it."""
+ localdict = {}
+ key = self.key
+ thread = current_thread()
+ idt = id(thread)
+ def local_deleted(_, key=key):
+ # When the localimpl is deleted, remove the thread attribute.
+ thread = wrthread()
+ if thread is not None:
+ del thread.__dict__[key]
+ def thread_deleted(_, idt=idt):
+ # When the thread is deleted, remove the local dict.
+ # Note that this is suboptimal if the thread object gets
+ # caught in a reference loop. We would like to be called
+ # as soon as the OS-level thread ends instead.
+ local = wrlocal()
+ if local is not None:
+ dct = local.dicts.pop(idt)
+ wrlocal = ref(self, local_deleted)
+ wrthread = ref(thread, thread_deleted)
+ thread.__dict__[key] = wrlocal
+ self.dicts[idt] = wrthread, localdict
+ return localdict
+
+
+@contextmanager
+def _patch(self):
+ impl = object.__getattribute__(self, '_local__impl')
+ try:
+ dct = impl.get_dict()
+ except KeyError:
+ dct = impl.create_dict()
+ args, kw = impl.localargs
+ self.__init__(*args, **kw)
+ with impl.locallock:
+ object.__setattr__(self, '__dict__', dct)
+ yield
+
+
+class local:
+ __slots__ = '_local__impl', '__dict__'
+
+ def __new__(cls, *args, **kw):
+ if (args or kw) and (cls.__init__ is object.__init__):
+ raise TypeError("Initialization arguments are not supported")
+ self = object.__new__(cls)
+ impl = _localimpl()
+ impl.localargs = (args, kw)
+ impl.locallock = RLock()
+ object.__setattr__(self, '_local__impl', impl)
+ # We need to create the thread dict in anticipation of
+ # __init__ being called, to make sure we don't call it
+ # again ourselves.
+ impl.create_dict()
+ return self
+
+ def __getattribute__(self, name):
+ with _patch(self):
+ return object.__getattribute__(self, name)
+
+ def __setattr__(self, name, value):
+ if name == '__dict__':
+ raise AttributeError(
+ "%r object attribute '__dict__' is read-only"
+ % self.__class__.__name__)
+ with _patch(self):
+ return object.__setattr__(self, name, value)
+
+ def __delattr__(self, name):
+ if name == '__dict__':
+ raise AttributeError(
+ "%r object attribute '__dict__' is read-only"
+ % self.__class__.__name__)
+ with _patch(self):
+ return object.__delattr__(self, name)
+
+
+from threading import current_thread, RLock
diff --git a/lib/assets/Lib/_warnings.py b/lib/assets/Lib/_warnings.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/_warnings.py
@@ -0,0 +1,20 @@
+"""_warnings provides basic warning filtering support.
+It is a helper module to speed up interpreter start-up."""
+
+
+default_action = """default"""
+
+filters = [('ignore', None, DeprecationWarning, None, 0),
+ ('ignore', None, PendingDeprecationWarning, None, 0),
+ ('ignore', None, ImportWarning, None, 0),
+ ('ignore', None, BytesWarning, None, 0)]
+
+once_registry = {}
+
+def warn(*args,**kw):
+ """Issue a warning, or maybe ignore it or raise an exception."""
+ pass
+
+def warn_explicit(*args,**kw):
+ """Low-level inferface to warnings functionality."""
+ pass
diff --git a/lib/assets/Lib/_weakref.py b/lib/assets/Lib/_weakref.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/_weakref.py
@@ -0,0 +1,33 @@
+class ProxyType:
+
+ def __init__(self,obj):
+ self.obj = obj
+
+CallableProxyType = ProxyType
+ProxyTypes = [ProxyType,CallableProxyType]
+
+class ReferenceType:
+
+ def __init__(self,obj,callback):
+ self.obj = obj
+ self.callback = callback
+
+class ref:
+
+ def __init__(self,obj,callback=None):
+ self.obj = ReferenceType(obj,callback)
+ self.callback=callback
+
+ def __call__(self):
+ return self.obj.obj
+
+def getweakrefcount(obj):
+ return 1
+
+def getweakrefs(obj):
+ return obj
+
+
+def proxy(obj,callback=None):
+ return ProxyType(obj)
+
diff --git a/lib/assets/Lib/_weakrefset.py b/lib/assets/Lib/_weakrefset.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/_weakrefset.py
@@ -0,0 +1,194 @@
+# Access WeakSet through the weakref module.
+# This code is separated-out because it is needed
+# by abc.py to load everything else at startup.
+
+from _weakref import ref
+
+__all__ = ['WeakSet']
+
+
+class _IterationGuard:
+ # This context manager registers itself in the current iterators of the
+ # weak container, such as to delay all removals until the context manager
+ # exits.
+ # This technique should be relatively thread-safe (since sets are).
+
+ def __init__(self, weakcontainer):
+ # Don't create cycles
+ self.weakcontainer = ref(weakcontainer)
+
+ def __enter__(self):
+ w = self.weakcontainer()
+ if w is not None:
+ w._iterating.add(self)
+ return self
+
+ def __exit__(self, e, t, b):
+ w = self.weakcontainer()
+ if w is not None:
+ s = w._iterating
+ s.remove(self)
+ if not s:
+ w._commit_removals()
+
+
+class WeakSet:
+ def __init__(self, data=None):
+ self.data = set()
+ def _remove(item, selfref=ref(self)):
+ self = selfref()
+ if self is not None:
+ if self._iterating:
+ self._pending_removals.append(item)
+ else:
+ self.data.discard(item)
+ self._remove = _remove
+ # A list of keys to be removed
+ self._pending_removals = []
+ self._iterating = set()
+ if data is not None:
+ self.update(data)
+
+ def _commit_removals(self):
+ l = self._pending_removals
+ discard = self.data.discard
+ while l:
+ discard(l.pop())
+
+ def __iter__(self):
+ with _IterationGuard(self):
+ for itemref in self.data:
+ item = itemref()
+ if item is not None:
+ yield item
+
+ def __len__(self):
+ return len(self.data) - len(self._pending_removals)
+
+ def __contains__(self, item):
+ try:
+ wr = ref(item)
+ except TypeError:
+ return False
+ return wr in self.data
+
+ def __reduce__(self):
+ return (self.__class__, (list(self),),
+ getattr(self, '__dict__', None))
+
+ def add(self, item):
+ if self._pending_removals:
+ self._commit_removals()
+ self.data.add(ref(item, self._remove))
+
+ def clear(self):
+ if self._pending_removals:
+ self._commit_removals()
+ self.data.clear()
+
+ def copy(self):
+ return self.__class__(self)
+
+ def pop(self):
+ if self._pending_removals:
+ self._commit_removals()
+ while True:
+ try:
+ itemref = self.data.pop()
+ except KeyError:
+ raise KeyError('pop from empty WeakSet')
+ item = itemref()
+ if item is not None:
+ return item
+
+ def remove(self, item):
+ if self._pending_removals:
+ self._commit_removals()
+ self.data.remove(ref(item))
+
+ def discard(self, item):
+ if self._pending_removals:
+ self._commit_removals()
+ self.data.discard(ref(item))
+
+ def update(self, other):
+ if self._pending_removals:
+ self._commit_removals()
+ for element in other:
+ self.add(element)
+
+ def __ior__(self, other):
+ self.update(other)
+ return self
+
+ def difference(self, other):
+ newset = self.copy()
+ newset.difference_update(other)
+ return newset
+ __sub__ = difference
+
+ def difference_update(self, other):
+ self.__isub__(other)
+ def __isub__(self, other):
+ if self._pending_removals:
+ self._commit_removals()
+ if self is other:
+ self.data.clear()
+ else:
+ self.data.difference_update(ref(item) for item in other)
+ return self
+
+ def intersection(self, other):
+ return self.__class__(item for item in other if item in self)
+ __and__ = intersection
+
+ def intersection_update(self, other):
+ self.__iand__(other)
+ def __iand__(self, other):
+ if self._pending_removals:
+ self._commit_removals()
+ self.data.intersection_update(ref(item) for item in other)
+ return self
+
+ def issubset(self, other):
+ return self.data.issubset(ref(item) for item in other)
+ __le__ = issubset
+
+ def __lt__(self, other):
+ return self.data < set(ref(item) for item in other)
+
+ def issuperset(self, other):
+ return self.data.issuperset(ref(item) for item in other)
+ __ge__ = issuperset
+
+ def __gt__(self, other):
+ return self.data > set(ref(item) for item in other)
+
+ def __eq__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return self.data == set(ref(item) for item in other)
+
+ def symmetric_difference(self, other):
+ newset = self.copy()
+ newset.symmetric_difference_update(other)
+ return newset
+ __xor__ = symmetric_difference
+
+ def symmetric_difference_update(self, other):
+ self.__ixor__(other)
+ def __ixor__(self, other):
+ if self._pending_removals:
+ self._commit_removals()
+ if self is other:
+ self.data.clear()
+ else:
+ self.data.symmetric_difference_update(ref(item, self._remove) for item in other)
+ return self
+
+ def union(self, other):
+ return self.__class__(e for s in (self, other) for e in s)
+ __or__ = union
+
+ def isdisjoint(self, other):
+ return len(self.intersection(other)) == 0
diff --git a/lib/assets/Lib/abc.py b/lib/assets/Lib/abc.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/abc.py
@@ -0,0 +1,228 @@
+# Copyright 2007 Google, Inc. All Rights Reserved.
+# Licensed to PSF under a Contributor Agreement.
+
+"""Abstract Base Classes (ABCs) according to PEP 3119."""
+
+from _weakrefset import WeakSet
+
+def abstractmethod(funcobj):
+ """A decorator indicating abstract methods.
+
+ Requires that the metaclass is ABCMeta or derived from it. A
+ class that has a metaclass derived from ABCMeta cannot be
+ instantiated unless all of its abstract methods are overridden.
+ The abstract methods can be called using any of the normal
+ 'super' call mechanisms.
+
+ Usage:
+
+ class C(metaclass=ABCMeta):
+ @abstractmethod
+ def my_abstract_method(self, ...):
+ ...
+ """
+ funcobj.__isabstractmethod__ = True
+ return funcobj
+
+
+class abstractclassmethod(classmethod):
+ """
+ A decorator indicating abstract classmethods.
+
+ Similar to abstractmethod.
+
+ Usage:
+
+ class C(metaclass=ABCMeta):
+ @abstractclassmethod
+ def my_abstract_classmethod(cls, ...):
+ ...
+
+ 'abstractclassmethod' is deprecated. Use 'classmethod' with
+ 'abstractmethod' instead.
+ """
+
+ __isabstractmethod__ = True
+
+ def __init__(self, callable):
+ callable.__isabstractmethod__ = True
+ super().__init__(callable)
+
+
+class abstractstaticmethod(staticmethod):
+ """
+ A decorator indicating abstract staticmethods.
+
+ Similar to abstractmethod.
+
+ Usage:
+
+ class C(metaclass=ABCMeta):
+ @abstractstaticmethod
+ def my_abstract_staticmethod(...):
+ ...
+
+ 'abstractstaticmethod' is deprecated. Use 'staticmethod' with
+ 'abstractmethod' instead.
+ """
+
+ __isabstractmethod__ = True
+
+ def __init__(self, callable):
+ callable.__isabstractmethod__ = True
+ super().__init__(callable)
+
+
+class abstractproperty(property):
+ """
+ A decorator indicating abstract properties.
+
+ Requires that the metaclass is ABCMeta or derived from it. A
+ class that has a metaclass derived from ABCMeta cannot be
+ instantiated unless all of its abstract properties are overridden.
+ The abstract properties can be called using any of the normal
+ 'super' call mechanisms.
+
+ Usage:
+
+ class C(metaclass=ABCMeta):
+ @abstractproperty
+ def my_abstract_property(self):
+ ...
+
+ This defines a read-only property; you can also define a read-write
+ abstract property using the 'long' form of property declaration:
+
+ class C(metaclass=ABCMeta):
+ def getx(self): ...
+ def setx(self, value): ...
+ x = abstractproperty(getx, setx)
+
+ 'abstractproperty' is deprecated. Use 'property' with 'abstractmethod'
+ instead.
+ """
+
+ __isabstractmethod__ = True
+
+
+class ABCMeta(type):
+
+ """Metaclass for defining Abstract Base Classes (ABCs).
+
+ Use this metaclass to create an ABC. An ABC can be subclassed
+ directly, and then acts as a mix-in class. You can also register
+ unrelated concrete classes (even built-in classes) and unrelated
+ ABCs as 'virtual subclasses' -- these and their descendants will
+ be considered subclasses of the registering ABC by the built-in
+ issubclass() function, but the registering ABC won't show up in
+ their MRO (Method Resolution Order) nor will method
+ implementations defined by the registering ABC be callable (not
+ even via super()).
+
+ """
+
+ # A global counter that is incremented each time a class is
+ # registered as a virtual subclass of anything. It forces the
+ # negative cache to be cleared before its next use.
+ _abc_invalidation_counter = 0
+
+ def __new__(mcls, name, bases, namespace):
+ cls = super().__new__(mcls, name, bases, namespace)
+ # Compute set of abstract method names
+ abstracts = {name
+ for name, value in namespace.items()
+ if getattr(value, "__isabstractmethod__", False)}
+ for base in bases:
+ for name in getattr(base, "__abstractmethods__", set()):
+ value = getattr(cls, name, None)
+ if getattr(value, "__isabstractmethod__", False):
+ abstracts.add(name)
+ cls.__abstractmethods__ = frozenset(abstracts)
+ # Set up inheritance registry
+ cls._abc_registry = WeakSet()
+ cls._abc_cache = WeakSet()
+ cls._abc_negative_cache = WeakSet()
+ cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
+ return cls
+
+ def register(cls, subclass):
+ """Register a virtual subclass of an ABC.
+
+ Returns the subclass, to allow usage as a class decorator.
+ """
+ if not isinstance(subclass, type):
+ raise TypeError("Can only register classes")
+ if issubclass(subclass, cls):
+ return subclass # Already a subclass
+ # Subtle: test for cycles *after* testing for "already a subclass";
+ # this means we allow X.register(X) and interpret it as a no-op.
+ if issubclass(cls, subclass):
+ # This would create a cycle, which is bad for the algorithm below
+ raise RuntimeError("Refusing to create an inheritance cycle")
+ cls._abc_registry.add(subclass)
+ ABCMeta._abc_invalidation_counter += 1 # Invalidate negative cache
+ return subclass
+
+ def _dump_registry(cls, file=None):
+ """Debug helper to print the ABC registry."""
+ print("Class: %s.%s" % (cls.__module__, cls.__name__), file=file)
+ print("Inv.counter: %s" % ABCMeta._abc_invalidation_counter, file=file)
+ for name in sorted(cls.__dict__.keys()):
+ if name.startswith("_abc_"):
+ value = getattr(cls, name)
+ print("%s: %r" % (name, value), file=file)
+
+ def __instancecheck__(cls, instance):
+ """Override for isinstance(instance, cls)."""
+ # Inline the cache checking
+ subclass = instance.__class__
+ if subclass in cls._abc_cache:
+ return True
+ subtype = type(instance)
+ if subtype is subclass:
+ if (cls._abc_negative_cache_version ==
+ ABCMeta._abc_invalidation_counter and
+ subclass in cls._abc_negative_cache):
+ return False
+ # Fall back to the subclass check.
+ return cls.__subclasscheck__(subclass)
+ return any(cls.__subclasscheck__(c) for c in {subclass, subtype})
+
+ def __subclasscheck__(cls, subclass):
+ """Override for issubclass(subclass, cls)."""
+ # Check cache
+ if subclass in cls._abc_cache:
+ return True
+ # Check negative cache; may have to invalidate
+ if cls._abc_negative_cache_version < ABCMeta._abc_invalidation_counter:
+ # Invalidate the negative cache
+ cls._abc_negative_cache = WeakSet()
+ cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
+ elif subclass in cls._abc_negative_cache:
+ return False
+ # Check the subclass hook
+ ok = cls.__subclasshook__(subclass)
+ if ok is not NotImplemented:
+ assert isinstance(ok, bool)
+ if ok:
+ cls._abc_cache.add(subclass)
+ else:
+ cls._abc_negative_cache.add(subclass)
+ return ok
+ # Check if it's a direct subclass
+ if cls in getattr(subclass, '__mro__', ()):
+ cls._abc_cache.add(subclass)
+ return True
+ # Check if it's a subclass of a registered class (recursive)
+ for rcls in cls._abc_registry:
+ if issubclass(subclass, rcls):
+ cls._abc_cache.add(subclass)
+ return True
+ # Check if it's a subclass of a subclass (recursive)
+ for scls in cls.__subclasses__():
+ if issubclass(subclass, scls):
+ cls._abc_cache.add(subclass)
+ return True
+ # No dice; update negative cache
+ cls._abc_negative_cache.add(subclass)
+ return False
diff --git a/lib/assets/Lib/antigravity.py b/lib/assets/Lib/antigravity.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/antigravity.py
@@ -0,0 +1,17 @@
+
+import webbrowser
+import hashlib
+
+webbrowser.open("http://xkcd.com/353/")
+
+def geohash(latitude, longitude, datedow):
+ '''Compute geohash() using the Munroe algorithm.
+
+ >>> geohash(37.421542, -122.085589, b'2005-05-26-10458.68')
+ 37.857713 -122.544543
+
+ '''
+ # http://xkcd.com/426/
+ h = hashlib.md5(datedow).hexdigest()
+ p, q = [('%f' % float.fromhex('0.' + x)) for x in (h[:16], h[16:32])]
+ print('%d%s %d%s' % (latitude, p[1:], longitude, q[1:]))
diff --git a/lib/assets/Lib/argparse.py b/lib/assets/Lib/argparse.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/argparse.py
@@ -0,0 +1,2386 @@
+# Author: Steven J. Bethard .
+
+"""Command-line parsing library
+
+This module is an optparse-inspired command-line parsing library that:
+
+ - handles both optional and positional arguments
+ - produces highly informative usage messages
+ - supports parsers that dispatch to sub-parsers
+
+The following is a simple usage example that sums integers from the
+command-line and writes the result to a file::
+
+ parser = argparse.ArgumentParser(
+ description='sum the integers at the command line')
+ parser.add_argument(
+ 'integers', metavar='int', nargs='+', type=int,
+ help='an integer to be summed')
+ parser.add_argument(
+ '--log', default=sys.stdout, type=argparse.FileType('w'),
+ help='the file where the sum should be written')
+ args = parser.parse_args()
+ args.log.write('%s' % sum(args.integers))
+ args.log.close()
+
+The module contains the following public classes:
+
+ - ArgumentParser -- The main entry point for command-line parsing. As the
+ example above shows, the add_argument() method is used to populate
+ the parser with actions for optional and positional arguments. Then
+ the parse_args() method is invoked to convert the args at the
+ command-line into an object with attributes.
+
+ - ArgumentError -- The exception raised by ArgumentParser objects when
+ there are errors with the parser's actions. Errors raised while
+ parsing the command-line are caught by ArgumentParser and emitted
+ as command-line messages.
+
+ - FileType -- A factory for defining types of files to be created. As the
+ example above shows, instances of FileType are typically passed as
+ the type= argument of add_argument() calls.
+
+ - Action -- The base class for parser actions. Typically actions are
+ selected by passing strings like 'store_true' or 'append_const' to
+ the action= argument of add_argument(). However, for greater
+ customization of ArgumentParser actions, subclasses of Action may
+ be defined and passed as the action= argument.
+
+ - HelpFormatter, RawDescriptionHelpFormatter, RawTextHelpFormatter,
+ ArgumentDefaultsHelpFormatter -- Formatter classes which
+ may be passed as the formatter_class= argument to the
+ ArgumentParser constructor. HelpFormatter is the default,
+ RawDescriptionHelpFormatter and RawTextHelpFormatter tell the parser
+ not to change the formatting for help text, and
+ ArgumentDefaultsHelpFormatter adds information about argument defaults
+ to the help.
+
+All other classes in this module are considered implementation details.
+(Also note that HelpFormatter and RawDescriptionHelpFormatter are only
+considered public as object names -- the API of the formatter objects is
+still considered an implementation detail.)
+"""
+
+__version__ = '1.1'
+__all__ = [
+ 'ArgumentParser',
+ 'ArgumentError',
+ 'ArgumentTypeError',
+ 'FileType',
+ 'HelpFormatter',
+ 'ArgumentDefaultsHelpFormatter',
+ 'RawDescriptionHelpFormatter',
+ 'RawTextHelpFormatter',
+ 'MetavarTypeHelpFormatter',
+ 'Namespace',
+ 'Action',
+ 'ONE_OR_MORE',
+ 'OPTIONAL',
+ 'PARSER',
+ 'REMAINDER',
+ 'SUPPRESS',
+ 'ZERO_OR_MORE',
+]
+
+
+import collections as _collections
+import copy as _copy
+import os as _os
+import re as _re
+import sys as _sys
+import textwrap as _textwrap
+
+from gettext import gettext as _, ngettext
+
+
+SUPPRESS = '==SUPPRESS=='
+
+OPTIONAL = '?'
+ZERO_OR_MORE = '*'
+ONE_OR_MORE = '+'
+PARSER = 'A...'
+REMAINDER = '...'
+_UNRECOGNIZED_ARGS_ATTR = '_unrecognized_args'
+
+# =============================
+# Utility functions and classes
+# =============================
+
+class _AttributeHolder(object):
+ """Abstract base class that provides __repr__.
+
+ The __repr__ method returns a string in the format::
+ ClassName(attr=name, attr=name, ...)
+ The attributes are determined either by a class-level attribute,
+ '_kwarg_names', or by inspecting the instance __dict__.
+ """
+
+ def __repr__(self):
+ type_name = type(self).__name__
+ arg_strings = []
+ for arg in self._get_args():
+ arg_strings.append(repr(arg))
+ for name, value in self._get_kwargs():
+ arg_strings.append('%s=%r' % (name, value))
+ return '%s(%s)' % (type_name, ', '.join(arg_strings))
+
+ def _get_kwargs(self):
+ return sorted(self.__dict__.items())
+
+ def _get_args(self):
+ return []
+
+
+def _ensure_value(namespace, name, value):
+ if getattr(namespace, name, None) is None:
+ setattr(namespace, name, value)
+ return getattr(namespace, name)
+
+
+# ===============
+# Formatting Help
+# ===============
+
+class HelpFormatter(object):
+ """Formatter for generating usage messages and argument help strings.
+
+ Only the name of this class is considered a public API. All the methods
+ provided by the class are considered an implementation detail.
+ """
+
+ def __init__(self,
+ prog,
+ indent_increment=2,
+ max_help_position=24,
+ width=None):
+
+ # default setting for width
+ if width is None:
+ try:
+ width = int(_os.environ['COLUMNS'])
+ except (KeyError, ValueError):
+ width = 80
+ width -= 2
+
+ self._prog = prog
+ self._indent_increment = indent_increment
+ self._max_help_position = max_help_position
+ self._max_help_position = min(max_help_position,
+ max(width - 20, indent_increment * 2))
+ self._width = width
+
+ self._current_indent = 0
+ self._level = 0
+ self._action_max_length = 0
+
+ self._root_section = self._Section(self, None)
+ self._current_section = self._root_section
+
+ self._whitespace_matcher = _re.compile(r'\s+')
+ self._long_break_matcher = _re.compile(r'\n\n\n+')
+
+ # ===============================
+ # Section and indentation methods
+ # ===============================
+ def _indent(self):
+ self._current_indent += self._indent_increment
+ self._level += 1
+
+ def _dedent(self):
+ self._current_indent -= self._indent_increment
+ assert self._current_indent >= 0, 'Indent decreased below 0.'
+ self._level -= 1
+
+ class _Section(object):
+
+ def __init__(self, formatter, parent, heading=None):
+ self.formatter = formatter
+ self.parent = parent
+ self.heading = heading
+ self.items = []
+
+ def format_help(self):
+ # format the indented section
+ if self.parent is not None:
+ self.formatter._indent()
+ join = self.formatter._join_parts
+ for func, args in self.items:
+ func(*args)
+ item_help = join([func(*args) for func, args in self.items])
+ if self.parent is not None:
+ self.formatter._dedent()
+
+ # return nothing if the section was empty
+ if not item_help:
+ return ''
+
+ # add the heading if the section was non-empty
+ if self.heading is not SUPPRESS and self.heading is not None:
+ current_indent = self.formatter._current_indent
+ heading = '%*s%s:\n' % (current_indent, '', self.heading)
+ else:
+ heading = ''
+
+ # join the section-initial newline, the heading and the help
+ return join(['\n', heading, item_help, '\n'])
+
+ def _add_item(self, func, args):
+ self._current_section.items.append((func, args))
+
+ # ========================
+ # Message building methods
+ # ========================
+ def start_section(self, heading):
+ self._indent()
+ section = self._Section(self, self._current_section, heading)
+ self._add_item(section.format_help, [])
+ self._current_section = section
+
+ def end_section(self):
+ self._current_section = self._current_section.parent
+ self._dedent()
+
+ def add_text(self, text):
+ if text is not SUPPRESS and text is not None:
+ self._add_item(self._format_text, [text])
+
+ def add_usage(self, usage, actions, groups, prefix=None):
+ if usage is not SUPPRESS:
+ args = usage, actions, groups, prefix
+ self._add_item(self._format_usage, args)
+
+ def add_argument(self, action):
+ if action.help is not SUPPRESS:
+
+ # find all invocations
+ get_invocation = self._format_action_invocation
+ invocations = [get_invocation(action)]
+ for subaction in self._iter_indented_subactions(action):
+ invocations.append(get_invocation(subaction))
+
+ # update the maximum item length
+ invocation_length = max([len(s) for s in invocations])
+ action_length = invocation_length + self._current_indent
+ self._action_max_length = max(self._action_max_length,
+ action_length)
+
+ # add the item to the list
+ self._add_item(self._format_action, [action])
+
+ def add_arguments(self, actions):
+ for action in actions:
+ self.add_argument(action)
+
+ # =======================
+ # Help-formatting methods
+ # =======================
+ def format_help(self):
+ help = self._root_section.format_help()
+ if help:
+ help = self._long_break_matcher.sub('\n\n', help)
+ help = help.strip('\n') + '\n'
+ return help
+
+ def _join_parts(self, part_strings):
+ return ''.join([part
+ for part in part_strings
+ if part and part is not SUPPRESS])
+
+ def _format_usage(self, usage, actions, groups, prefix):
+ if prefix is None:
+ prefix = _('usage: ')
+
+ # if usage is specified, use that
+ if usage is not None:
+ usage = usage % dict(prog=self._prog)
+
+ # if no optionals or positionals are available, usage is just prog
+ elif usage is None and not actions:
+ usage = '%(prog)s' % dict(prog=self._prog)
+
+ # if optionals and positionals are available, calculate usage
+ elif usage is None:
+ prog = '%(prog)s' % dict(prog=self._prog)
+
+ # split optionals from positionals
+ optionals = []
+ positionals = []
+ for action in actions:
+ if action.option_strings:
+ optionals.append(action)
+ else:
+ positionals.append(action)
+
+ # build full usage string
+ format = self._format_actions_usage
+ action_usage = format(optionals + positionals, groups)
+ usage = ' '.join([s for s in [prog, action_usage] if s])
+
+ # wrap the usage parts if it's too long
+ text_width = self._width - self._current_indent
+ if len(prefix) + len(usage) > text_width:
+
+ # break usage into wrappable parts
+ part_regexp = r'\(.*?\)+|\[.*?\]+|\S+'
+ opt_usage = format(optionals, groups)
+ pos_usage = format(positionals, groups)
+ opt_parts = _re.findall(part_regexp, opt_usage)
+ pos_parts = _re.findall(part_regexp, pos_usage)
+ assert ' '.join(opt_parts) == opt_usage
+ assert ' '.join(pos_parts) == pos_usage
+
+ # helper for wrapping lines
+ def get_lines(parts, indent, prefix=None):
+ lines = []
+ line = []
+ if prefix is not None:
+ line_len = len(prefix) - 1
+ else:
+ line_len = len(indent) - 1
+ for part in parts:
+ if line_len + 1 + len(part) > text_width and line:
+ lines.append(indent + ' '.join(line))
+ line = []
+ line_len = len(indent) - 1
+ line.append(part)
+ line_len += len(part) + 1
+ if line:
+ lines.append(indent + ' '.join(line))
+ if prefix is not None:
+ lines[0] = lines[0][len(indent):]
+ return lines
+
+ # if prog is short, follow it with optionals or positionals
+ if len(prefix) + len(prog) <= 0.75 * text_width:
+ indent = ' ' * (len(prefix) + len(prog) + 1)
+ if opt_parts:
+ lines = get_lines([prog] + opt_parts, indent, prefix)
+ lines.extend(get_lines(pos_parts, indent))
+ elif pos_parts:
+ lines = get_lines([prog] + pos_parts, indent, prefix)
+ else:
+ lines = [prog]
+
+ # if prog is long, put it on its own line
+ else:
+ indent = ' ' * len(prefix)
+ parts = opt_parts + pos_parts
+ lines = get_lines(parts, indent)
+ if len(lines) > 1:
+ lines = []
+ lines.extend(get_lines(opt_parts, indent))
+ lines.extend(get_lines(pos_parts, indent))
+ lines = [prog] + lines
+
+ # join lines into usage
+ usage = '\n'.join(lines)
+
+ # prefix with 'usage:'
+ return '%s%s\n\n' % (prefix, usage)
+
+ def _format_actions_usage(self, actions, groups):
+ # find group indices and identify actions in groups
+ group_actions = set()
+ inserts = {}
+ for group in groups:
+ try:
+ start = actions.index(group._group_actions[0])
+ except ValueError:
+ continue
+ else:
+ end = start + len(group._group_actions)
+ if actions[start:end] == group._group_actions:
+ for action in group._group_actions:
+ group_actions.add(action)
+ if not group.required:
+ if start in inserts:
+ inserts[start] += ' ['
+ else:
+ inserts[start] = '['
+ inserts[end] = ']'
+ else:
+ if start in inserts:
+ inserts[start] += ' ('
+ else:
+ inserts[start] = '('
+ inserts[end] = ')'
+ for i in range(start + 1, end):
+ inserts[i] = '|'
+
+ # collect all actions format strings
+ parts = []
+ for i, action in enumerate(actions):
+
+ # suppressed arguments are marked with None
+ # remove | separators for suppressed arguments
+ if action.help is SUPPRESS:
+ parts.append(None)
+ if inserts.get(i) == '|':
+ inserts.pop(i)
+ elif inserts.get(i + 1) == '|':
+ inserts.pop(i + 1)
+
+ # produce all arg strings
+ elif not action.option_strings:
+ default = self._get_default_metavar_for_positional(action)
+ part = self._format_args(action, default)
+
+ # if it's in a group, strip the outer []
+ if action in group_actions:
+ if part[0] == '[' and part[-1] == ']':
+ part = part[1:-1]
+
+ # add the action string to the list
+ parts.append(part)
+
+ # produce the first way to invoke the option in brackets
+ else:
+ option_string = action.option_strings[0]
+
+ # if the Optional doesn't take a value, format is:
+ # -s or --long
+ if action.nargs == 0:
+ part = '%s' % option_string
+
+ # if the Optional takes a value, format is:
+ # -s ARGS or --long ARGS
+ else:
+ default = self._get_default_metavar_for_optional(action)
+ args_string = self._format_args(action, default)
+ part = '%s %s' % (option_string, args_string)
+
+ # make it look optional if it's not required or in a group
+ if not action.required and action not in group_actions:
+ part = '[%s]' % part
+
+ # add the action string to the list
+ parts.append(part)
+
+ # insert things at the necessary indices
+ for i in sorted(inserts, reverse=True):
+ parts[i:i] = [inserts[i]]
+
+ # join all the action items with spaces
+ text = ' '.join([item for item in parts if item is not None])
+
+ # clean up separators for mutually exclusive groups
+ open = r'[\[(]'
+ close = r'[\])]'
+ text = _re.sub(r'(%s) ' % open, r'\1', text)
+ text = _re.sub(r' (%s)' % close, r'\1', text)
+ text = _re.sub(r'%s *%s' % (open, close), r'', text)
+ text = _re.sub(r'\(([^|]*)\)', r'\1', text)
+ text = text.strip()
+
+ # return the text
+ return text
+
+ def _format_text(self, text):
+ if '%(prog)' in text:
+ text = text % dict(prog=self._prog)
+ text_width = max(self._width - self._current_indent, 11)
+ indent = ' ' * self._current_indent
+ return self._fill_text(text, text_width, indent) + '\n\n'
+
+ def _format_action(self, action):
+ # determine the required width and the entry label
+ help_position = min(self._action_max_length + 2,
+ self._max_help_position)
+ help_width = max(self._width - help_position, 11)
+ action_width = help_position - self._current_indent - 2
+ action_header = self._format_action_invocation(action)
+
+ # no help; start on same line and add a final newline
+ if not action.help:
+ tup = self._current_indent, '', action_header
+ action_header = '%*s%s\n' % tup
+
+ # short action name; start on the same line and pad two spaces
+ elif len(action_header) <= action_width:
+ tup = self._current_indent, '', action_width, action_header
+ action_header = '%*s%-*s ' % tup
+ indent_first = 0
+
+ # long action name; start on the next line
+ else:
+ tup = self._current_indent, '', action_header
+ action_header = '%*s%s\n' % tup
+ indent_first = help_position
+
+ # collect the pieces of the action help
+ parts = [action_header]
+
+ # if there was help for the action, add lines of help text
+ if action.help:
+ help_text = self._expand_help(action)
+ help_lines = self._split_lines(help_text, help_width)
+ parts.append('%*s%s\n' % (indent_first, '', help_lines[0]))
+ for line in help_lines[1:]:
+ parts.append('%*s%s\n' % (help_position, '', line))
+
+ # or add a newline if the description doesn't end with one
+ elif not action_header.endswith('\n'):
+ parts.append('\n')
+
+ # if there are any sub-actions, add their help as well
+ for subaction in self._iter_indented_subactions(action):
+ parts.append(self._format_action(subaction))
+
+ # return a single string
+ return self._join_parts(parts)
+
+ def _format_action_invocation(self, action):
+ if not action.option_strings:
+ default = self._get_default_metavar_for_positional(action)
+ metavar, = self._metavar_formatter(action, default)(1)
+ return metavar
+
+ else:
+ parts = []
+
+ # if the Optional doesn't take a value, format is:
+ # -s, --long
+ if action.nargs == 0:
+ parts.extend(action.option_strings)
+
+ # if the Optional takes a value, format is:
+ # -s ARGS, --long ARGS
+ else:
+ default = self._get_default_metavar_for_optional(action)
+ args_string = self._format_args(action, default)
+ for option_string in action.option_strings:
+ parts.append('%s %s' % (option_string, args_string))
+
+ return ', '.join(parts)
+
+ def _metavar_formatter(self, action, default_metavar):
+ if action.metavar is not None:
+ result = action.metavar
+ elif action.choices is not None:
+ choice_strs = [str(choice) for choice in action.choices]
+ result = '{%s}' % ','.join(choice_strs)
+ else:
+ result = default_metavar
+
+ def format(tuple_size):
+ if isinstance(result, tuple):
+ return result
+ else:
+ return (result, ) * tuple_size
+ return format
+
+ def _format_args(self, action, default_metavar):
+ get_metavar = self._metavar_formatter(action, default_metavar)
+ if action.nargs is None:
+ result = '%s' % get_metavar(1)
+ elif action.nargs == OPTIONAL:
+ result = '[%s]' % get_metavar(1)
+ elif action.nargs == ZERO_OR_MORE:
+ result = '[%s [%s ...]]' % get_metavar(2)
+ elif action.nargs == ONE_OR_MORE:
+ result = '%s [%s ...]' % get_metavar(2)
+ elif action.nargs == REMAINDER:
+ result = '...'
+ elif action.nargs == PARSER:
+ result = '%s ...' % get_metavar(1)
+ else:
+ formats = ['%s' for _ in range(action.nargs)]
+ result = ' '.join(formats) % get_metavar(action.nargs)
+ return result
+
+ def _expand_help(self, action):
+ params = dict(vars(action), prog=self._prog)
+ for name in list(params):
+ if params[name] is SUPPRESS:
+ del params[name]
+ for name in list(params):
+ if hasattr(params[name], '__name__'):
+ params[name] = params[name].__name__
+ if params.get('choices') is not None:
+ choices_str = ', '.join([str(c) for c in params['choices']])
+ params['choices'] = choices_str
+ return self._get_help_string(action) % params
+
+ def _iter_indented_subactions(self, action):
+ try:
+ get_subactions = action._get_subactions
+ except AttributeError:
+ pass
+ else:
+ self._indent()
+ yield from get_subactions()
+ self._dedent()
+
+ def _split_lines(self, text, width):
+ text = self._whitespace_matcher.sub(' ', text).strip()
+ return _textwrap.wrap(text, width)
+
+ def _fill_text(self, text, width, indent):
+ text = self._whitespace_matcher.sub(' ', text).strip()
+ return _textwrap.fill(text, width, initial_indent=indent,
+ subsequent_indent=indent)
+
+ def _get_help_string(self, action):
+ return action.help
+
+ def _get_default_metavar_for_optional(self, action):
+ return action.dest.upper()
+
+ def _get_default_metavar_for_positional(self, action):
+ return action.dest
+
+
+class RawDescriptionHelpFormatter(HelpFormatter):
+ """Help message formatter which retains any formatting in descriptions.
+
+ Only the name of this class is considered a public API. All the methods
+ provided by the class are considered an implementation detail.
+ """
+
+ def _fill_text(self, text, width, indent):
+ return ''.join(indent + line for line in text.splitlines(keepends=True))
+
+
+class RawTextHelpFormatter(RawDescriptionHelpFormatter):
+ """Help message formatter which retains formatting of all help text.
+
+ Only the name of this class is considered a public API. All the methods
+ provided by the class are considered an implementation detail.
+ """
+
+ def _split_lines(self, text, width):
+ return text.splitlines()
+
+
+class ArgumentDefaultsHelpFormatter(HelpFormatter):
+ """Help message formatter which adds default values to argument help.
+
+ Only the name of this class is considered a public API. All the methods
+ provided by the class are considered an implementation detail.
+ """
+
+ def _get_help_string(self, action):
+ help = action.help
+ if '%(default)' not in action.help:
+ if action.default is not SUPPRESS:
+ defaulting_nargs = [OPTIONAL, ZERO_OR_MORE]
+ if action.option_strings or action.nargs in defaulting_nargs:
+ help += ' (default: %(default)s)'
+ return help
+
+
+class MetavarTypeHelpFormatter(HelpFormatter):
+ """Help message formatter which uses the argument 'type' as the default
+ metavar value (instead of the argument 'dest')
+
+ Only the name of this class is considered a public API. All the methods
+ provided by the class are considered an implementation detail.
+ """
+
+ def _get_default_metavar_for_optional(self, action):
+ return action.type.__name__
+
+ def _get_default_metavar_for_positional(self, action):
+ return action.type.__name__
+
+
+
+# =====================
+# Options and Arguments
+# =====================
+
+def _get_action_name(argument):
+ if argument is None:
+ return None
+ elif argument.option_strings:
+ return '/'.join(argument.option_strings)
+ elif argument.metavar not in (None, SUPPRESS):
+ return argument.metavar
+ elif argument.dest not in (None, SUPPRESS):
+ return argument.dest
+ else:
+ return None
+
+
+class ArgumentError(Exception):
+ """An error from creating or using an argument (optional or positional).
+
+ The string value of this exception is the message, augmented with
+ information about the argument that caused it.
+ """
+
+ def __init__(self, argument, message):
+ self.argument_name = _get_action_name(argument)
+ self.message = message
+
+ def __str__(self):
+ if self.argument_name is None:
+ format = '%(message)s'
+ else:
+ format = 'argument %(argument_name)s: %(message)s'
+ return format % dict(message=self.message,
+ argument_name=self.argument_name)
+
+
+class ArgumentTypeError(Exception):
+ """An error from trying to convert a command line string to a type."""
+ pass
+
+
+# ==============
+# Action classes
+# ==============
+
+class Action(_AttributeHolder):
+ """Information about how to convert command line strings to Python objects.
+
+ Action objects are used by an ArgumentParser to represent the information
+ needed to parse a single argument from one or more strings from the
+ command line. The keyword arguments to the Action constructor are also
+ all attributes of Action instances.
+
+ Keyword Arguments:
+
+ - option_strings -- A list of command-line option strings which
+ should be associated with this action.
+
+ - dest -- The name of the attribute to hold the created object(s)
+
+ - nargs -- The number of command-line arguments that should be
+ consumed. By default, one argument will be consumed and a single
+ value will be produced. Other values include:
+ - N (an integer) consumes N arguments (and produces a list)
+ - '?' consumes zero or one arguments
+ - '*' consumes zero or more arguments (and produces a list)
+ - '+' consumes one or more arguments (and produces a list)
+ Note that the difference between the default and nargs=1 is that
+ with the default, a single value will be produced, while with
+ nargs=1, a list containing a single value will be produced.
+
+ - const -- The value to be produced if the option is specified and the
+ option uses an action that takes no values.
+
+ - default -- The value to be produced if the option is not specified.
+
+ - type -- A callable that accepts a single string argument, and
+ returns the converted value. The standard Python types str, int,
+ float, and complex are useful examples of such callables. If None,
+ str is used.
+
+ - choices -- A container of values that should be allowed. If not None,
+ after a command-line argument has been converted to the appropriate
+ type, an exception will be raised if it is not a member of this
+ collection.
+
+ - required -- True if the action must always be specified at the
+ command line. This is only meaningful for optional command-line
+ arguments.
+
+ - help -- The help string describing the argument.
+
+ - metavar -- The name to be used for the option's argument with the
+ help string. If None, the 'dest' value will be used as the name.
+ """
+
+ def __init__(self,
+ option_strings,
+ dest,
+ nargs=None,
+ const=None,
+ default=None,
+ type=None,
+ choices=None,
+ required=False,
+ help=None,
+ metavar=None):
+ self.option_strings = option_strings
+ self.dest = dest
+ self.nargs = nargs
+ self.const = const
+ self.default = default
+ self.type = type
+ self.choices = choices
+ self.required = required
+ self.help = help
+ self.metavar = metavar
+
+ def _get_kwargs(self):
+ names = [
+ 'option_strings',
+ 'dest',
+ 'nargs',
+ 'const',
+ 'default',
+ 'type',
+ 'choices',
+ 'help',
+ 'metavar',
+ ]
+ return [(name, getattr(self, name)) for name in names]
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ raise NotImplementedError(_('.__call__() not defined'))
+
+
+class _StoreAction(Action):
+
+ def __init__(self,
+ option_strings,
+ dest,
+ nargs=None,
+ const=None,
+ default=None,
+ type=None,
+ choices=None,
+ required=False,
+ help=None,
+ metavar=None):
+ if nargs == 0:
+ raise ValueError('nargs for store actions must be > 0; if you '
+ 'have nothing to store, actions such as store '
+ 'true or store const may be more appropriate')
+ if const is not None and nargs != OPTIONAL:
+ raise ValueError('nargs must be %r to supply const' % OPTIONAL)
+ super(_StoreAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ nargs=nargs,
+ const=const,
+ default=default,
+ type=type,
+ choices=choices,
+ required=required,
+ help=help,
+ metavar=metavar)
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ setattr(namespace, self.dest, values)
+
+
+class _StoreConstAction(Action):
+
+ def __init__(self,
+ option_strings,
+ dest,
+ const,
+ default=None,
+ required=False,
+ help=None,
+ metavar=None):
+ super(_StoreConstAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ nargs=0,
+ const=const,
+ default=default,
+ required=required,
+ help=help)
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ setattr(namespace, self.dest, self.const)
+
+
+class _StoreTrueAction(_StoreConstAction):
+
+ def __init__(self,
+ option_strings,
+ dest,
+ default=False,
+ required=False,
+ help=None):
+ super(_StoreTrueAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ const=True,
+ default=default,
+ required=required,
+ help=help)
+
+
+class _StoreFalseAction(_StoreConstAction):
+
+ def __init__(self,
+ option_strings,
+ dest,
+ default=True,
+ required=False,
+ help=None):
+ super(_StoreFalseAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ const=False,
+ default=default,
+ required=required,
+ help=help)
+
+
+class _AppendAction(Action):
+
+ def __init__(self,
+ option_strings,
+ dest,
+ nargs=None,
+ const=None,
+ default=None,
+ type=None,
+ choices=None,
+ required=False,
+ help=None,
+ metavar=None):
+ if nargs == 0:
+ raise ValueError('nargs for append actions must be > 0; if arg '
+ 'strings are not supplying the value to append, '
+ 'the append const action may be more appropriate')
+ if const is not None and nargs != OPTIONAL:
+ raise ValueError('nargs must be %r to supply const' % OPTIONAL)
+ super(_AppendAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ nargs=nargs,
+ const=const,
+ default=default,
+ type=type,
+ choices=choices,
+ required=required,
+ help=help,
+ metavar=metavar)
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ items = _copy.copy(_ensure_value(namespace, self.dest, []))
+ items.append(values)
+ setattr(namespace, self.dest, items)
+
+
+class _AppendConstAction(Action):
+
+ def __init__(self,
+ option_strings,
+ dest,
+ const,
+ default=None,
+ required=False,
+ help=None,
+ metavar=None):
+ super(_AppendConstAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ nargs=0,
+ const=const,
+ default=default,
+ required=required,
+ help=help,
+ metavar=metavar)
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ items = _copy.copy(_ensure_value(namespace, self.dest, []))
+ items.append(self.const)
+ setattr(namespace, self.dest, items)
+
+
+class _CountAction(Action):
+
+ def __init__(self,
+ option_strings,
+ dest,
+ default=None,
+ required=False,
+ help=None):
+ super(_CountAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ nargs=0,
+ default=default,
+ required=required,
+ help=help)
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ new_count = _ensure_value(namespace, self.dest, 0) + 1
+ setattr(namespace, self.dest, new_count)
+
+
+class _HelpAction(Action):
+
+ def __init__(self,
+ option_strings,
+ dest=SUPPRESS,
+ default=SUPPRESS,
+ help=None):
+ super(_HelpAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ default=default,
+ nargs=0,
+ help=help)
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ parser.print_help()
+ parser.exit()
+
+
+class _VersionAction(Action):
+
+ def __init__(self,
+ option_strings,
+ version=None,
+ dest=SUPPRESS,
+ default=SUPPRESS,
+ help="show program's version number and exit"):
+ super(_VersionAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ default=default,
+ nargs=0,
+ help=help)
+ self.version = version
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ version = self.version
+ if version is None:
+ version = parser.version
+ formatter = parser._get_formatter()
+ formatter.add_text(version)
+ parser._print_message(formatter.format_help(), _sys.stdout)
+ parser.exit()
+
+
+class _SubParsersAction(Action):
+
+ class _ChoicesPseudoAction(Action):
+
+ def __init__(self, name, aliases, help):
+ metavar = dest = name
+ if aliases:
+ metavar += ' (%s)' % ', '.join(aliases)
+ sup = super(_SubParsersAction._ChoicesPseudoAction, self)
+ sup.__init__(option_strings=[], dest=dest, help=help,
+ metavar=metavar)
+
+ def __init__(self,
+ option_strings,
+ prog,
+ parser_class,
+ dest=SUPPRESS,
+ help=None,
+ metavar=None):
+
+ self._prog_prefix = prog
+ self._parser_class = parser_class
+ self._name_parser_map = _collections.OrderedDict()
+ self._choices_actions = []
+
+ super(_SubParsersAction, self).__init__(
+ option_strings=option_strings,
+ dest=dest,
+ nargs=PARSER,
+ choices=self._name_parser_map,
+ help=help,
+ metavar=metavar)
+
+ def add_parser(self, name, **kwargs):
+ # set prog from the existing prefix
+ if kwargs.get('prog') is None:
+ kwargs['prog'] = '%s %s' % (self._prog_prefix, name)
+
+ aliases = kwargs.pop('aliases', ())
+
+ # create a pseudo-action to hold the choice help
+ if 'help' in kwargs:
+ help = kwargs.pop('help')
+ choice_action = self._ChoicesPseudoAction(name, aliases, help)
+ self._choices_actions.append(choice_action)
+
+ # create the parser and add it to the map
+ parser = self._parser_class(**kwargs)
+ self._name_parser_map[name] = parser
+
+ # make parser available under aliases also
+ for alias in aliases:
+ self._name_parser_map[alias] = parser
+
+ return parser
+
+ def _get_subactions(self):
+ return self._choices_actions
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ parser_name = values[0]
+ arg_strings = values[1:]
+
+ # set the parser name if requested
+ if self.dest is not SUPPRESS:
+ setattr(namespace, self.dest, parser_name)
+
+ # select the parser
+ try:
+ parser = self._name_parser_map[parser_name]
+ except KeyError:
+ args = {'parser_name': parser_name,
+ 'choices': ', '.join(self._name_parser_map)}
+ msg = _('unknown parser %(parser_name)r (choices: %(choices)s)') % args
+ raise ArgumentError(self, msg)
+
+ # parse all the remaining options into the namespace
+ # store any unrecognized options on the object, so that the top
+ # level parser can decide what to do with them
+
+ # In case this subparser defines new defaults, we parse them
+ # in a new namespace object and then update the original
+ # namespace for the relevant parts.
+ subnamespace, arg_strings = parser.parse_known_args(arg_strings, None)
+ for key, value in vars(subnamespace).items():
+ setattr(namespace, key, value)
+
+ if arg_strings:
+ vars(namespace).setdefault(_UNRECOGNIZED_ARGS_ATTR, [])
+ getattr(namespace, _UNRECOGNIZED_ARGS_ATTR).extend(arg_strings)
+
+
+# ==============
+# Type classes
+# ==============
+
+class FileType(object):
+ """Factory for creating file object types
+
+ Instances of FileType are typically passed as type= arguments to the
+ ArgumentParser add_argument() method.
+
+ Keyword Arguments:
+ - mode -- A string indicating how the file is to be opened. Accepts the
+ same values as the builtin open() function.
+ - bufsize -- The file's desired buffer size. Accepts the same values as
+ the builtin open() function.
+ - encoding -- The file's encoding. Accepts the same values as the
+ builtin open() function.
+ - errors -- A string indicating how encoding and decoding errors are to
+ be handled. Accepts the same value as the builtin open() function.
+ """
+
+ def __init__(self, mode='r', bufsize=-1, encoding=None, errors=None):
+ self._mode = mode
+ self._bufsize = bufsize
+ self._encoding = encoding
+ self._errors = errors
+
+ def __call__(self, string):
+ # the special argument "-" means sys.std{in,out}
+ if string == '-':
+ if 'r' in self._mode:
+ return _sys.stdin
+ elif 'w' in self._mode:
+ return _sys.stdout
+ else:
+ msg = _('argument "-" with mode %r') % self._mode
+ raise ValueError(msg)
+
+ # all other arguments are used as file names
+ try:
+ return open(string, self._mode, self._bufsize, self._encoding,
+ self._errors)
+ except OSError as e:
+ message = _("can't open '%s': %s")
+ raise ArgumentTypeError(message % (string, e))
+
+ def __repr__(self):
+ args = self._mode, self._bufsize
+ kwargs = [('encoding', self._encoding), ('errors', self._errors)]
+ args_str = ', '.join([repr(arg) for arg in args if arg != -1] +
+ ['%s=%r' % (kw, arg) for kw, arg in kwargs
+ if arg is not None])
+ return '%s(%s)' % (type(self).__name__, args_str)
+
+# ===========================
+# Optional and Positional Parsing
+# ===========================
+
+class Namespace(_AttributeHolder):
+ """Simple object for storing attributes.
+
+ Implements equality by attribute names and values, and provides a simple
+ string representation.
+ """
+
+ def __init__(self, **kwargs):
+ for name in kwargs:
+ setattr(self, name, kwargs[name])
+
+ def __eq__(self, other):
+ if not isinstance(other, Namespace):
+ return NotImplemented
+ return vars(self) == vars(other)
+
+ def __ne__(self, other):
+ if not isinstance(other, Namespace):
+ return NotImplemented
+ return not (self == other)
+
+ def __contains__(self, key):
+ return key in self.__dict__
+
+
+class _ActionsContainer(object):
+
+ def __init__(self,
+ description,
+ prefix_chars,
+ argument_default,
+ conflict_handler):
+ super(_ActionsContainer, self).__init__()
+
+ self.description = description
+ self.argument_default = argument_default
+ self.prefix_chars = prefix_chars
+ self.conflict_handler = conflict_handler
+
+ # set up registries
+ self._registries = {}
+
+ # register actions
+ self.register('action', None, _StoreAction)
+ self.register('action', 'store', _StoreAction)
+ self.register('action', 'store_const', _StoreConstAction)
+ self.register('action', 'store_true', _StoreTrueAction)
+ self.register('action', 'store_false', _StoreFalseAction)
+ self.register('action', 'append', _AppendAction)
+ self.register('action', 'append_const', _AppendConstAction)
+ self.register('action', 'count', _CountAction)
+ self.register('action', 'help', _HelpAction)
+ self.register('action', 'version', _VersionAction)
+ self.register('action', 'parsers', _SubParsersAction)
+
+ # raise an exception if the conflict handler is invalid
+ self._get_handler()
+
+ # action storage
+ self._actions = []
+ self._option_string_actions = {}
+
+ # groups
+ self._action_groups = []
+ self._mutually_exclusive_groups = []
+
+ # defaults storage
+ self._defaults = {}
+
+ # determines whether an "option" looks like a negative number
+ self._negative_number_matcher = _re.compile(r'^-\d+$|^-\d*\.\d+$')
+
+ # whether or not there are any optionals that look like negative
+ # numbers -- uses a list so it can be shared and edited
+ self._has_negative_number_optionals = []
+
+ # ====================
+ # Registration methods
+ # ====================
+ def register(self, registry_name, value, object):
+ registry = self._registries.setdefault(registry_name, {})
+ registry[value] = object
+
+ def _registry_get(self, registry_name, value, default=None):
+ return self._registries[registry_name].get(value, default)
+
+ # ==================================
+ # Namespace default accessor methods
+ # ==================================
+ def set_defaults(self, **kwargs):
+ self._defaults.update(kwargs)
+
+ # if these defaults match any existing arguments, replace
+ # the previous default on the object with the new one
+ for action in self._actions:
+ if action.dest in kwargs:
+ action.default = kwargs[action.dest]
+
+ def get_default(self, dest):
+ for action in self._actions:
+ if action.dest == dest and action.default is not None:
+ return action.default
+ return self._defaults.get(dest, None)
+
+
+ # =======================
+ # Adding argument actions
+ # =======================
+ def add_argument(self, *args, **kwargs):
+ """
+ add_argument(dest, ..., name=value, ...)
+ add_argument(option_string, option_string, ..., name=value, ...)
+ """
+
+ # if no positional args are supplied or only one is supplied and
+ # it doesn't look like an option string, parse a positional
+ # argument
+ chars = self.prefix_chars
+ if not args or len(args) == 1 and args[0][0] not in chars:
+ if args and 'dest' in kwargs:
+ raise ValueError('dest supplied twice for positional argument')
+ kwargs = self._get_positional_kwargs(*args, **kwargs)
+
+ # otherwise, we're adding an optional argument
+ else:
+ kwargs = self._get_optional_kwargs(*args, **kwargs)
+
+ # if no default was supplied, use the parser-level default
+ if 'default' not in kwargs:
+ dest = kwargs['dest']
+ if dest in self._defaults:
+ kwargs['default'] = self._defaults[dest]
+ elif self.argument_default is not None:
+ kwargs['default'] = self.argument_default
+
+ # create the action object, and add it to the parser
+ action_class = self._pop_action_class(kwargs)
+ if not callable(action_class):
+ raise ValueError('unknown action "%s"' % (action_class,))
+ action = action_class(**kwargs)
+
+ # raise an error if the action type is not callable
+ type_func = self._registry_get('type', action.type, action.type)
+ if not callable(type_func):
+ raise ValueError('%r is not callable' % (type_func,))
+
+ # raise an error if the metavar does not match the type
+ if hasattr(self, "_get_formatter"):
+ try:
+ self._get_formatter()._format_args(action, None)
+ except TypeError:
+ raise ValueError("length of metavar tuple does not match nargs")
+
+ return self._add_action(action)
+
+ def add_argument_group(self, *args, **kwargs):
+ group = _ArgumentGroup(self, *args, **kwargs)
+ self._action_groups.append(group)
+ return group
+
+ def add_mutually_exclusive_group(self, **kwargs):
+ group = _MutuallyExclusiveGroup(self, **kwargs)
+ self._mutually_exclusive_groups.append(group)
+ return group
+
+ def _add_action(self, action):
+ # resolve any conflicts
+ self._check_conflict(action)
+
+ # add to actions list
+ self._actions.append(action)
+ action.container = self
+
+ # index the action by any option strings it has
+ for option_string in action.option_strings:
+ self._option_string_actions[option_string] = action
+
+ # set the flag if any option strings look like negative numbers
+ for option_string in action.option_strings:
+ if self._negative_number_matcher.match(option_string):
+ if not self._has_negative_number_optionals:
+ self._has_negative_number_optionals.append(True)
+
+ # return the created action
+ return action
+
+ def _remove_action(self, action):
+ self._actions.remove(action)
+
+ def _add_container_actions(self, container):
+ # collect groups by titles
+ title_group_map = {}
+ for group in self._action_groups:
+ if group.title in title_group_map:
+ msg = _('cannot merge actions - two groups are named %r')
+ raise ValueError(msg % (group.title))
+ title_group_map[group.title] = group
+
+ # map each action to its group
+ group_map = {}
+ for group in container._action_groups:
+
+ # if a group with the title exists, use that, otherwise
+ # create a new group matching the container's group
+ if group.title not in title_group_map:
+ title_group_map[group.title] = self.add_argument_group(
+ title=group.title,
+ description=group.description,
+ conflict_handler=group.conflict_handler)
+
+ # map the actions to their new group
+ for action in group._group_actions:
+ group_map[action] = title_group_map[group.title]
+
+ # add container's mutually exclusive groups
+ # NOTE: if add_mutually_exclusive_group ever gains title= and
+ # description= then this code will need to be expanded as above
+ for group in container._mutually_exclusive_groups:
+ mutex_group = self.add_mutually_exclusive_group(
+ required=group.required)
+
+ # map the actions to their new mutex group
+ for action in group._group_actions:
+ group_map[action] = mutex_group
+
+ # add all actions to this container or their group
+ for action in container._actions:
+ group_map.get(action, self)._add_action(action)
+
+ def _get_positional_kwargs(self, dest, **kwargs):
+ # make sure required is not specified
+ if 'required' in kwargs:
+ msg = _("'required' is an invalid argument for positionals")
+ raise TypeError(msg)
+
+ # mark positional arguments as required if at least one is
+ # always required
+ if kwargs.get('nargs') not in [OPTIONAL, ZERO_OR_MORE]:
+ kwargs['required'] = True
+ if kwargs.get('nargs') == ZERO_OR_MORE and 'default' not in kwargs:
+ kwargs['required'] = True
+
+ # return the keyword arguments with no option strings
+ return dict(kwargs, dest=dest, option_strings=[])
+
+ def _get_optional_kwargs(self, *args, **kwargs):
+ # determine short and long option strings
+ option_strings = []
+ long_option_strings = []
+ for option_string in args:
+ # error on strings that don't start with an appropriate prefix
+ if not option_string[0] in self.prefix_chars:
+ args = {'option': option_string,
+ 'prefix_chars': self.prefix_chars}
+ msg = _('invalid option string %(option)r: '
+ 'must start with a character %(prefix_chars)r')
+ raise ValueError(msg % args)
+
+ # strings starting with two prefix characters are long options
+ option_strings.append(option_string)
+ if option_string[0] in self.prefix_chars:
+ if len(option_string) > 1:
+ if option_string[1] in self.prefix_chars:
+ long_option_strings.append(option_string)
+
+ # infer destination, '--foo-bar' -> 'foo_bar' and '-x' -> 'x'
+ dest = kwargs.pop('dest', None)
+ if dest is None:
+ if long_option_strings:
+ dest_option_string = long_option_strings[0]
+ else:
+ dest_option_string = option_strings[0]
+ dest = dest_option_string.lstrip(self.prefix_chars)
+ if not dest:
+ msg = _('dest= is required for options like %r')
+ raise ValueError(msg % option_string)
+ dest = dest.replace('-', '_')
+
+ # return the updated keyword arguments
+ return dict(kwargs, dest=dest, option_strings=option_strings)
+
+ def _pop_action_class(self, kwargs, default=None):
+ action = kwargs.pop('action', default)
+ return self._registry_get('action', action, action)
+
+ def _get_handler(self):
+ # determine function from conflict handler string
+ handler_func_name = '_handle_conflict_%s' % self.conflict_handler
+ try:
+ return getattr(self, handler_func_name)
+ except AttributeError:
+ msg = _('invalid conflict_resolution value: %r')
+ raise ValueError(msg % self.conflict_handler)
+
+ def _check_conflict(self, action):
+
+ # find all options that conflict with this option
+ confl_optionals = []
+ for option_string in action.option_strings:
+ if option_string in self._option_string_actions:
+ confl_optional = self._option_string_actions[option_string]
+ confl_optionals.append((option_string, confl_optional))
+
+ # resolve any conflicts
+ if confl_optionals:
+ conflict_handler = self._get_handler()
+ conflict_handler(action, confl_optionals)
+
+ def _handle_conflict_error(self, action, conflicting_actions):
+ message = ngettext('conflicting option string: %s',
+ 'conflicting option strings: %s',
+ len(conflicting_actions))
+ conflict_string = ', '.join([option_string
+ for option_string, action
+ in conflicting_actions])
+ raise ArgumentError(action, message % conflict_string)
+
+ def _handle_conflict_resolve(self, action, conflicting_actions):
+
+ # remove all conflicting options
+ for option_string, action in conflicting_actions:
+
+ # remove the conflicting option
+ action.option_strings.remove(option_string)
+ self._option_string_actions.pop(option_string, None)
+
+ # if the option now has no option string, remove it from the
+ # container holding it
+ if not action.option_strings:
+ action.container._remove_action(action)
+
+
+class _ArgumentGroup(_ActionsContainer):
+
+ def __init__(self, container, title=None, description=None, **kwargs):
+ # add any missing keyword arguments by checking the container
+ update = kwargs.setdefault
+ update('conflict_handler', container.conflict_handler)
+ update('prefix_chars', container.prefix_chars)
+ update('argument_default', container.argument_default)
+ super_init = super(_ArgumentGroup, self).__init__
+ super_init(description=description, **kwargs)
+
+ # group attributes
+ self.title = title
+ self._group_actions = []
+
+ # share most attributes with the container
+ self._registries = container._registries
+ self._actions = container._actions
+ self._option_string_actions = container._option_string_actions
+ self._defaults = container._defaults
+ self._has_negative_number_optionals = \
+ container._has_negative_number_optionals
+ self._mutually_exclusive_groups = container._mutually_exclusive_groups
+
+ def _add_action(self, action):
+ action = super(_ArgumentGroup, self)._add_action(action)
+ self._group_actions.append(action)
+ return action
+
+ def _remove_action(self, action):
+ super(_ArgumentGroup, self)._remove_action(action)
+ self._group_actions.remove(action)
+
+
+class _MutuallyExclusiveGroup(_ArgumentGroup):
+
+ def __init__(self, container, required=False):
+ super(_MutuallyExclusiveGroup, self).__init__(container)
+ self.required = required
+ self._container = container
+
+ def _add_action(self, action):
+ if action.required:
+ msg = _('mutually exclusive arguments must be optional')
+ raise ValueError(msg)
+ action = self._container._add_action(action)
+ self._group_actions.append(action)
+ return action
+
+ def _remove_action(self, action):
+ self._container._remove_action(action)
+ self._group_actions.remove(action)
+
+
+class ArgumentParser(_AttributeHolder, _ActionsContainer):
+ """Object for parsing command line strings into Python objects.
+
+ Keyword Arguments:
+ - prog -- The name of the program (default: sys.argv[0])
+ - usage -- A usage message (default: auto-generated from arguments)
+ - description -- A description of what the program does
+ - epilog -- Text following the argument descriptions
+ - parents -- Parsers whose arguments should be copied into this one
+ - formatter_class -- HelpFormatter class for printing help messages
+ - prefix_chars -- Characters that prefix optional arguments
+ - fromfile_prefix_chars -- Characters that prefix files containing
+ additional arguments
+ - argument_default -- The default value for all arguments
+ - conflict_handler -- String indicating how to handle conflicts
+ - add_help -- Add a -h/-help option
+ """
+
+ def __init__(self,
+ prog=None,
+ usage=None,
+ description=None,
+ epilog=None,
+ parents=[],
+ formatter_class=HelpFormatter,
+ prefix_chars='-',
+ fromfile_prefix_chars=None,
+ argument_default=None,
+ conflict_handler='error',
+ add_help=True):
+
+ superinit = super(ArgumentParser, self).__init__
+ superinit(description=description,
+ prefix_chars=prefix_chars,
+ argument_default=argument_default,
+ conflict_handler=conflict_handler)
+
+ # default setting for prog
+ if prog is None:
+ prog = _os.path.basename(_sys.argv[0])
+
+ self.prog = prog
+ self.usage = usage
+ self.epilog = epilog
+ self.formatter_class = formatter_class
+ self.fromfile_prefix_chars = fromfile_prefix_chars
+ self.add_help = add_help
+
+ add_group = self.add_argument_group
+ self._positionals = add_group(_('positional arguments'))
+ self._optionals = add_group(_('optional arguments'))
+ self._subparsers = None
+
+ # register types
+ def identity(string):
+ return string
+ self.register('type', None, identity)
+
+ # add help argument if necessary
+ # (using explicit default to override global argument_default)
+ default_prefix = '-' if '-' in prefix_chars else prefix_chars[0]
+ if self.add_help:
+ self.add_argument(
+ default_prefix+'h', default_prefix*2+'help',
+ action='help', default=SUPPRESS,
+ help=_('show this help message and exit'))
+
+ # add parent arguments and defaults
+ for parent in parents:
+ self._add_container_actions(parent)
+ try:
+ defaults = parent._defaults
+ except AttributeError:
+ pass
+ else:
+ self._defaults.update(defaults)
+
+ # =======================
+ # Pretty __repr__ methods
+ # =======================
+ def _get_kwargs(self):
+ names = [
+ 'prog',
+ 'usage',
+ 'description',
+ 'formatter_class',
+ 'conflict_handler',
+ 'add_help',
+ ]
+ return [(name, getattr(self, name)) for name in names]
+
+ # ==================================
+ # Optional/Positional adding methods
+ # ==================================
+ def add_subparsers(self, **kwargs):
+ if self._subparsers is not None:
+ self.error(_('cannot have multiple subparser arguments'))
+
+ # add the parser class to the arguments if it's not present
+ kwargs.setdefault('parser_class', type(self))
+
+ if 'title' in kwargs or 'description' in kwargs:
+ title = _(kwargs.pop('title', 'subcommands'))
+ description = _(kwargs.pop('description', None))
+ self._subparsers = self.add_argument_group(title, description)
+ else:
+ self._subparsers = self._positionals
+
+ # prog defaults to the usage message of this parser, skipping
+ # optional arguments and with no "usage:" prefix
+ if kwargs.get('prog') is None:
+ formatter = self._get_formatter()
+ positionals = self._get_positional_actions()
+ groups = self._mutually_exclusive_groups
+ formatter.add_usage(self.usage, positionals, groups, '')
+ kwargs['prog'] = formatter.format_help().strip()
+
+ # create the parsers action and add it to the positionals list
+ parsers_class = self._pop_action_class(kwargs, 'parsers')
+ action = parsers_class(option_strings=[], **kwargs)
+ self._subparsers._add_action(action)
+
+ # return the created parsers action
+ return action
+
+ def _add_action(self, action):
+ if action.option_strings:
+ self._optionals._add_action(action)
+ else:
+ self._positionals._add_action(action)
+ return action
+
+ def _get_optional_actions(self):
+ return [action
+ for action in self._actions
+ if action.option_strings]
+
+ def _get_positional_actions(self):
+ return [action
+ for action in self._actions
+ if not action.option_strings]
+
+ # =====================================
+ # Command line argument parsing methods
+ # =====================================
+ def parse_args(self, args=None, namespace=None):
+ args, argv = self.parse_known_args(args, namespace)
+ if argv:
+ msg = _('unrecognized arguments: %s')
+ self.error(msg % ' '.join(argv))
+ return args
+
+ def parse_known_args(self, args=None, namespace=None):
+ if args is None:
+ # args default to the system args
+ args = _sys.argv[1:]
+ else:
+ # make sure that args are mutable
+ args = list(args)
+
+ # default Namespace built from parser defaults
+ if namespace is None:
+ namespace = Namespace()
+
+ # add any action defaults that aren't present
+ for action in self._actions:
+ if action.dest is not SUPPRESS:
+ if not hasattr(namespace, action.dest):
+ if action.default is not SUPPRESS:
+ setattr(namespace, action.dest, action.default)
+
+ # add any parser defaults that aren't present
+ for dest in self._defaults:
+ if not hasattr(namespace, dest):
+ setattr(namespace, dest, self._defaults[dest])
+
+ # parse the arguments and exit if there are any errors
+ try:
+ namespace, args = self._parse_known_args(args, namespace)
+ if hasattr(namespace, _UNRECOGNIZED_ARGS_ATTR):
+ args.extend(getattr(namespace, _UNRECOGNIZED_ARGS_ATTR))
+ delattr(namespace, _UNRECOGNIZED_ARGS_ATTR)
+ return namespace, args
+ except ArgumentError:
+ err = _sys.exc_info()[1]
+ self.error(str(err))
+
+ def _parse_known_args(self, arg_strings, namespace):
+ # replace arg strings that are file references
+ if self.fromfile_prefix_chars is not None:
+ arg_strings = self._read_args_from_files(arg_strings)
+
+ # map all mutually exclusive arguments to the other arguments
+ # they can't occur with
+ action_conflicts = {}
+ for mutex_group in self._mutually_exclusive_groups:
+ group_actions = mutex_group._group_actions
+ for i, mutex_action in enumerate(mutex_group._group_actions):
+ conflicts = action_conflicts.setdefault(mutex_action, [])
+ conflicts.extend(group_actions[:i])
+ conflicts.extend(group_actions[i + 1:])
+
+ # find all option indices, and determine the arg_string_pattern
+ # which has an 'O' if there is an option at an index,
+ # an 'A' if there is an argument, or a '-' if there is a '--'
+ option_string_indices = {}
+ arg_string_pattern_parts = []
+ arg_strings_iter = iter(arg_strings)
+ for i, arg_string in enumerate(arg_strings_iter):
+
+ # all args after -- are non-options
+ if arg_string == '--':
+ arg_string_pattern_parts.append('-')
+ for arg_string in arg_strings_iter:
+ arg_string_pattern_parts.append('A')
+
+ # otherwise, add the arg to the arg strings
+ # and note the index if it was an option
+ else:
+ option_tuple = self._parse_optional(arg_string)
+ if option_tuple is None:
+ pattern = 'A'
+ else:
+ option_string_indices[i] = option_tuple
+ pattern = 'O'
+ arg_string_pattern_parts.append(pattern)
+
+ # join the pieces together to form the pattern
+ arg_strings_pattern = ''.join(arg_string_pattern_parts)
+
+ # converts arg strings to the appropriate and then takes the action
+ seen_actions = set()
+ seen_non_default_actions = set()
+
+ def take_action(action, argument_strings, option_string=None):
+ seen_actions.add(action)
+ argument_values = self._get_values(action, argument_strings)
+
+ # error if this argument is not allowed with other previously
+ # seen arguments, assuming that actions that use the default
+ # value don't really count as "present"
+ if argument_values is not action.default:
+ seen_non_default_actions.add(action)
+ for conflict_action in action_conflicts.get(action, []):
+ if conflict_action in seen_non_default_actions:
+ msg = _('not allowed with argument %s')
+ action_name = _get_action_name(conflict_action)
+ raise ArgumentError(action, msg % action_name)
+
+ # take the action if we didn't receive a SUPPRESS value
+ # (e.g. from a default)
+ if argument_values is not SUPPRESS:
+ action(self, namespace, argument_values, option_string)
+
+ # function to convert arg_strings into an optional action
+ def consume_optional(start_index):
+
+ # get the optional identified at this index
+ option_tuple = option_string_indices[start_index]
+ action, option_string, explicit_arg = option_tuple
+
+ # identify additional optionals in the same arg string
+ # (e.g. -xyz is the same as -x -y -z if no args are required)
+ match_argument = self._match_argument
+ action_tuples = []
+ while True:
+
+ # if we found no optional action, skip it
+ if action is None:
+ extras.append(arg_strings[start_index])
+ return start_index + 1
+
+ # if there is an explicit argument, try to match the
+ # optional's string arguments to only this
+ if explicit_arg is not None:
+ arg_count = match_argument(action, 'A')
+
+ # if the action is a single-dash option and takes no
+ # arguments, try to parse more single-dash options out
+ # of the tail of the option string
+ chars = self.prefix_chars
+ if arg_count == 0 and option_string[1] not in chars:
+ action_tuples.append((action, [], option_string))
+ char = option_string[0]
+ option_string = char + explicit_arg[0]
+ new_explicit_arg = explicit_arg[1:] or None
+ optionals_map = self._option_string_actions
+ if option_string in optionals_map:
+ action = optionals_map[option_string]
+ explicit_arg = new_explicit_arg
+ else:
+ msg = _('ignored explicit argument %r')
+ raise ArgumentError(action, msg % explicit_arg)
+
+ # if the action expect exactly one argument, we've
+ # successfully matched the option; exit the loop
+ elif arg_count == 1:
+ stop = start_index + 1
+ args = [explicit_arg]
+ action_tuples.append((action, args, option_string))
+ break
+
+ # error if a double-dash option did not use the
+ # explicit argument
+ else:
+ msg = _('ignored explicit argument %r')
+ raise ArgumentError(action, msg % explicit_arg)
+
+ # if there is no explicit argument, try to match the
+ # optional's string arguments with the following strings
+ # if successful, exit the loop
+ else:
+ start = start_index + 1
+ selected_patterns = arg_strings_pattern[start:]
+ arg_count = match_argument(action, selected_patterns)
+ stop = start + arg_count
+ args = arg_strings[start:stop]
+ action_tuples.append((action, args, option_string))
+ break
+
+ # add the Optional to the list and return the index at which
+ # the Optional's string args stopped
+ assert action_tuples
+ for action, args, option_string in action_tuples:
+ take_action(action, args, option_string)
+ return stop
+
+ # the list of Positionals left to be parsed; this is modified
+ # by consume_positionals()
+ positionals = self._get_positional_actions()
+
+ # function to convert arg_strings into positional actions
+ def consume_positionals(start_index):
+ # match as many Positionals as possible
+ match_partial = self._match_arguments_partial
+ selected_pattern = arg_strings_pattern[start_index:]
+ arg_counts = match_partial(positionals, selected_pattern)
+
+ # slice off the appropriate arg strings for each Positional
+ # and add the Positional and its args to the list
+ for action, arg_count in zip(positionals, arg_counts):
+ args = arg_strings[start_index: start_index + arg_count]
+ start_index += arg_count
+ take_action(action, args)
+
+ # slice off the Positionals that we just parsed and return the
+ # index at which the Positionals' string args stopped
+ positionals[:] = positionals[len(arg_counts):]
+ return start_index
+
+ # consume Positionals and Optionals alternately, until we have
+ # passed the last option string
+ extras = []
+ start_index = 0
+ if option_string_indices:
+ max_option_string_index = max(option_string_indices)
+ else:
+ max_option_string_index = -1
+ while start_index <= max_option_string_index:
+
+ # consume any Positionals preceding the next option
+ next_option_string_index = min([
+ index
+ for index in option_string_indices
+ if index >= start_index])
+ if start_index != next_option_string_index:
+ positionals_end_index = consume_positionals(start_index)
+
+ # only try to parse the next optional if we didn't consume
+ # the option string during the positionals parsing
+ if positionals_end_index > start_index:
+ start_index = positionals_end_index
+ continue
+ else:
+ start_index = positionals_end_index
+
+ # if we consumed all the positionals we could and we're not
+ # at the index of an option string, there were extra arguments
+ if start_index not in option_string_indices:
+ strings = arg_strings[start_index:next_option_string_index]
+ extras.extend(strings)
+ start_index = next_option_string_index
+
+ # consume the next optional and any arguments for it
+ start_index = consume_optional(start_index)
+
+ # consume any positionals following the last Optional
+ stop_index = consume_positionals(start_index)
+
+ # if we didn't consume all the argument strings, there were extras
+ extras.extend(arg_strings[stop_index:])
+
+ # make sure all required actions were present and also convert
+ # action defaults which were not given as arguments
+ required_actions = []
+ for action in self._actions:
+ if action not in seen_actions:
+ if action.required:
+ required_actions.append(_get_action_name(action))
+ else:
+ # Convert action default now instead of doing it before
+ # parsing arguments to avoid calling convert functions
+ # twice (which may fail) if the argument was given, but
+ # only if it was defined already in the namespace
+ if (action.default is not None and
+ isinstance(action.default, str) and
+ hasattr(namespace, action.dest) and
+ action.default is getattr(namespace, action.dest)):
+ setattr(namespace, action.dest,
+ self._get_value(action, action.default))
+
+ if required_actions:
+ self.error(_('the following arguments are required: %s') %
+ ', '.join(required_actions))
+
+ # make sure all required groups had one option present
+ for group in self._mutually_exclusive_groups:
+ if group.required:
+ for action in group._group_actions:
+ if action in seen_non_default_actions:
+ break
+
+ # if no actions were used, report the error
+ else:
+ names = [_get_action_name(action)
+ for action in group._group_actions
+ if action.help is not SUPPRESS]
+ msg = _('one of the arguments %s is required')
+ self.error(msg % ' '.join(names))
+
+ # return the updated namespace and the extra arguments
+ return namespace, extras
+
+ def _read_args_from_files(self, arg_strings):
+ # expand arguments referencing files
+ new_arg_strings = []
+ for arg_string in arg_strings:
+
+ # for regular arguments, just add them back into the list
+ if not arg_string or arg_string[0] not in self.fromfile_prefix_chars:
+ new_arg_strings.append(arg_string)
+
+ # replace arguments referencing files with the file content
+ else:
+ try:
+ with open(arg_string[1:]) as args_file:
+ arg_strings = []
+ for arg_line in args_file.read().splitlines():
+ for arg in self.convert_arg_line_to_args(arg_line):
+ arg_strings.append(arg)
+ arg_strings = self._read_args_from_files(arg_strings)
+ new_arg_strings.extend(arg_strings)
+ except OSError:
+ err = _sys.exc_info()[1]
+ self.error(str(err))
+
+ # return the modified argument list
+ return new_arg_strings
+
+ def convert_arg_line_to_args(self, arg_line):
+ return [arg_line]
+
+ def _match_argument(self, action, arg_strings_pattern):
+ # match the pattern for this action to the arg strings
+ nargs_pattern = self._get_nargs_pattern(action)
+ match = _re.match(nargs_pattern, arg_strings_pattern)
+
+ # raise an exception if we weren't able to find a match
+ if match is None:
+ nargs_errors = {
+ None: _('expected one argument'),
+ OPTIONAL: _('expected at most one argument'),
+ ONE_OR_MORE: _('expected at least one argument'),
+ }
+ default = ngettext('expected %s argument',
+ 'expected %s arguments',
+ action.nargs) % action.nargs
+ msg = nargs_errors.get(action.nargs, default)
+ raise ArgumentError(action, msg)
+
+ # return the number of arguments matched
+ return len(match.group(1))
+
+ def _match_arguments_partial(self, actions, arg_strings_pattern):
+ # progressively shorten the actions list by slicing off the
+ # final actions until we find a match
+ result = []
+ for i in range(len(actions), 0, -1):
+ actions_slice = actions[:i]
+ pattern = ''.join([self._get_nargs_pattern(action)
+ for action in actions_slice])
+ match = _re.match(pattern, arg_strings_pattern)
+ if match is not None:
+ result.extend([len(string) for string in match.groups()])
+ break
+
+ # return the list of arg string counts
+ return result
+
+ def _parse_optional(self, arg_string):
+ # if it's an empty string, it was meant to be a positional
+ if not arg_string:
+ return None
+
+ # if it doesn't start with a prefix, it was meant to be positional
+ if not arg_string[0] in self.prefix_chars:
+ return None
+
+ # if the option string is present in the parser, return the action
+ if arg_string in self._option_string_actions:
+ action = self._option_string_actions[arg_string]
+ return action, arg_string, None
+
+ # if it's just a single character, it was meant to be positional
+ if len(arg_string) == 1:
+ return None
+
+ # if the option string before the "=" is present, return the action
+ if '=' in arg_string:
+ option_string, explicit_arg = arg_string.split('=', 1)
+ if option_string in self._option_string_actions:
+ action = self._option_string_actions[option_string]
+ return action, option_string, explicit_arg
+
+ # search through all possible prefixes of the option string
+ # and all actions in the parser for possible interpretations
+ option_tuples = self._get_option_tuples(arg_string)
+
+ # if multiple actions match, the option string was ambiguous
+ if len(option_tuples) > 1:
+ options = ', '.join([option_string
+ for action, option_string, explicit_arg in option_tuples])
+ args = {'option': arg_string, 'matches': options}
+ msg = _('ambiguous option: %(option)s could match %(matches)s')
+ self.error(msg % args)
+
+ # if exactly one action matched, this segmentation is good,
+ # so return the parsed action
+ elif len(option_tuples) == 1:
+ option_tuple, = option_tuples
+ return option_tuple
+
+ # if it was not found as an option, but it looks like a negative
+ # number, it was meant to be positional
+ # unless there are negative-number-like options
+ if self._negative_number_matcher.match(arg_string):
+ if not self._has_negative_number_optionals:
+ return None
+
+ # if it contains a space, it was meant to be a positional
+ if ' ' in arg_string:
+ return None
+
+ # it was meant to be an optional but there is no such option
+ # in this parser (though it might be a valid option in a subparser)
+ return None, arg_string, None
+
+ def _get_option_tuples(self, option_string):
+ result = []
+
+ # option strings starting with two prefix characters are only
+ # split at the '='
+ chars = self.prefix_chars
+ if option_string[0] in chars and option_string[1] in chars:
+ if '=' in option_string:
+ option_prefix, explicit_arg = option_string.split('=', 1)
+ else:
+ option_prefix = option_string
+ explicit_arg = None
+ for option_string in self._option_string_actions:
+ if option_string.startswith(option_prefix):
+ action = self._option_string_actions[option_string]
+ tup = action, option_string, explicit_arg
+ result.append(tup)
+
+ # single character options can be concatenated with their arguments
+ # but multiple character options always have to have their argument
+ # separate
+ elif option_string[0] in chars and option_string[1] not in chars:
+ option_prefix = option_string
+ explicit_arg = None
+ short_option_prefix = option_string[:2]
+ short_explicit_arg = option_string[2:]
+
+ for option_string in self._option_string_actions:
+ if option_string == short_option_prefix:
+ action = self._option_string_actions[option_string]
+ tup = action, option_string, short_explicit_arg
+ result.append(tup)
+ elif option_string.startswith(option_prefix):
+ action = self._option_string_actions[option_string]
+ tup = action, option_string, explicit_arg
+ result.append(tup)
+
+ # shouldn't ever get here
+ else:
+ self.error(_('unexpected option string: %s') % option_string)
+
+ # return the collected option tuples
+ return result
+
+ def _get_nargs_pattern(self, action):
+ # in all examples below, we have to allow for '--' args
+ # which are represented as '-' in the pattern
+ nargs = action.nargs
+
+ # the default (None) is assumed to be a single argument
+ if nargs is None:
+ nargs_pattern = '(-*A-*)'
+
+ # allow zero or one arguments
+ elif nargs == OPTIONAL:
+ nargs_pattern = '(-*A?-*)'
+
+ # allow zero or more arguments
+ elif nargs == ZERO_OR_MORE:
+ nargs_pattern = '(-*[A-]*)'
+
+ # allow one or more arguments
+ elif nargs == ONE_OR_MORE:
+ nargs_pattern = '(-*A[A-]*)'
+
+ # allow any number of options or arguments
+ elif nargs == REMAINDER:
+ nargs_pattern = '([-AO]*)'
+
+ # allow one argument followed by any number of options or arguments
+ elif nargs == PARSER:
+ nargs_pattern = '(-*A[-AO]*)'
+
+ # all others should be integers
+ else:
+ nargs_pattern = '(-*%s-*)' % '-*'.join('A' * nargs)
+
+ # if this is an optional action, -- is not allowed
+ if action.option_strings:
+ nargs_pattern = nargs_pattern.replace('-*', '')
+ nargs_pattern = nargs_pattern.replace('-', '')
+
+ # return the pattern
+ return nargs_pattern
+
+ # ========================
+ # Value conversion methods
+ # ========================
+ def _get_values(self, action, arg_strings):
+ # for everything but PARSER, REMAINDER args, strip out first '--'
+ if action.nargs not in [PARSER, REMAINDER]:
+ try:
+ arg_strings.remove('--')
+ except ValueError:
+ pass
+
+ # optional argument produces a default when not present
+ if not arg_strings and action.nargs == OPTIONAL:
+ if action.option_strings:
+ value = action.const
+ else:
+ value = action.default
+ if isinstance(value, str):
+ value = self._get_value(action, value)
+ self._check_value(action, value)
+
+ # when nargs='*' on a positional, if there were no command-line
+ # args, use the default if it is anything other than None
+ elif (not arg_strings and action.nargs == ZERO_OR_MORE and
+ not action.option_strings):
+ if action.default is not None:
+ value = action.default
+ else:
+ value = arg_strings
+ self._check_value(action, value)
+
+ # single argument or optional argument produces a single value
+ elif len(arg_strings) == 1 and action.nargs in [None, OPTIONAL]:
+ arg_string, = arg_strings
+ value = self._get_value(action, arg_string)
+ self._check_value(action, value)
+
+ # REMAINDER arguments convert all values, checking none
+ elif action.nargs == REMAINDER:
+ value = [self._get_value(action, v) for v in arg_strings]
+
+ # PARSER arguments convert all values, but check only the first
+ elif action.nargs == PARSER:
+ value = [self._get_value(action, v) for v in arg_strings]
+ self._check_value(action, value[0])
+
+ # all other types of nargs produce a list
+ else:
+ value = [self._get_value(action, v) for v in arg_strings]
+ for v in value:
+ self._check_value(action, v)
+
+ # return the converted value
+ return value
+
+ def _get_value(self, action, arg_string):
+ type_func = self._registry_get('type', action.type, action.type)
+ if not callable(type_func):
+ msg = _('%r is not callable')
+ raise ArgumentError(action, msg % type_func)
+
+ # convert the value to the appropriate type
+ try:
+ result = type_func(arg_string)
+
+ # ArgumentTypeErrors indicate errors
+ except ArgumentTypeError:
+ name = getattr(action.type, '__name__', repr(action.type))
+ msg = str(_sys.exc_info()[1])
+ raise ArgumentError(action, msg)
+
+ # TypeErrors or ValueErrors also indicate errors
+ except (TypeError, ValueError):
+ name = getattr(action.type, '__name__', repr(action.type))
+ args = {'type': name, 'value': arg_string}
+ msg = _('invalid %(type)s value: %(value)r')
+ raise ArgumentError(action, msg % args)
+
+ # return the converted value
+ return result
+
+ def _check_value(self, action, value):
+ # converted value must be one of the choices (if specified)
+ if action.choices is not None and value not in action.choices:
+ args = {'value': value,
+ 'choices': ', '.join(map(repr, action.choices))}
+ msg = _('invalid choice: %(value)r (choose from %(choices)s)')
+ raise ArgumentError(action, msg % args)
+
+ # =======================
+ # Help-formatting methods
+ # =======================
+ def format_usage(self):
+ formatter = self._get_formatter()
+ formatter.add_usage(self.usage, self._actions,
+ self._mutually_exclusive_groups)
+ return formatter.format_help()
+
+ def format_help(self):
+ formatter = self._get_formatter()
+
+ # usage
+ formatter.add_usage(self.usage, self._actions,
+ self._mutually_exclusive_groups)
+
+ # description
+ formatter.add_text(self.description)
+
+ # positionals, optionals and user-defined groups
+ for action_group in self._action_groups:
+ formatter.start_section(action_group.title)
+ formatter.add_text(action_group.description)
+ formatter.add_arguments(action_group._group_actions)
+ formatter.end_section()
+
+ # epilog
+ formatter.add_text(self.epilog)
+
+ # determine help from format above
+ return formatter.format_help()
+
+ def _get_formatter(self):
+ return self.formatter_class(prog=self.prog)
+
+ # =====================
+ # Help-printing methods
+ # =====================
+ def print_usage(self, file=None):
+ if file is None:
+ file = _sys.stdout
+ self._print_message(self.format_usage(), file)
+
+ def print_help(self, file=None):
+ if file is None:
+ file = _sys.stdout
+ self._print_message(self.format_help(), file)
+
+ def _print_message(self, message, file=None):
+ if message:
+ if file is None:
+ file = _sys.stderr
+ file.write(message)
+
+ # ===============
+ # Exiting methods
+ # ===============
+ def exit(self, status=0, message=None):
+ if message:
+ self._print_message(message, _sys.stderr)
+ _sys.exit(status)
+
+ def error(self, message):
+ """error(message: string)
+
+ Prints a usage message incorporating the message to stderr and
+ exits.
+
+ If you override this in a subclass, it should not return -- it
+ should either exit or raise an exception.
+ """
+ self.print_usage(_sys.stderr)
+ args = {'prog': self.prog, 'message': message}
+ self.exit(2, _('%(prog)s: error: %(message)s\n') % args)
diff --git a/lib/assets/Lib/atexit.py b/lib/assets/Lib/atexit.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/atexit.py
@@ -0,0 +1,37 @@
+"""allow programmer to define multiple exit functions to be executedupon normal program termination.
+
+Two public functions, register and unregister, are defined.
+"""
+
+
+class __loader__(object):
+ pass
+
+def _clear(*args,**kw):
+ """_clear() -> None
+ Clear the list of previously registered exit functions."""
+ pass
+
+def _run_exitfuncs(*args,**kw):
+ """_run_exitfuncs() -> None
+ Run all registered exit functions."""
+ pass
+
+def register(*args,**kw):
+ """register(func, *args, **kwargs) -> func
+ Register a function to be executed upon normal program termination
+
+ func - function to be called at exit
+ args - optional arguments to pass to func
+ kwargs - optional keyword arguments to pass to func
+
+ func is returned to facilitate usage as a decorator."""
+ pass
+
+def unregister(*args,**kw):
+ """unregister(func) -> None
+ Unregister a exit function which was previously registered using
+ atexit.register
+
+ func - function to be unregistered"""
+ pass
diff --git a/lib/assets/Lib/base64.py b/lib/assets/Lib/base64.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/base64.py
@@ -0,0 +1,406 @@
+#! /usr/bin/env python3
+
+"""RFC 3548: Base16, Base32, Base64 Data Encodings"""
+
+# Modified 04-Oct-1995 by Jack Jansen to use binascii module
+# Modified 30-Dec-2003 by Barry Warsaw to add full RFC 3548 support
+# Modified 22-May-2007 by Guido van Rossum to use bytes everywhere
+
+#import re
+#import struct
+#import binascii
+
+import _base64 # Javascript module in libs
+
+__all__ = [
+ # Legacy interface exports traditional RFC 1521 Base64 encodings
+ 'encode', 'decode', 'encodebytes', 'decodebytes',
+ # Generalized interface for other encodings
+ 'b64encode', 'b64decode', 'b32encode', 'b32decode',
+ 'b16encode', 'b16decode',
+ # Standard Base64 encoding
+ 'standard_b64encode', 'standard_b64decode',
+ # Some common Base64 alternatives. As referenced by RFC 3458, see thread
+ # starting at:
+ #
+ # http://zgp.org/pipermail/p2p-hackers/2001-September/000316.html
+ 'urlsafe_b64encode', 'urlsafe_b64decode',
+ ]
+
+
+bytes_types = (bytes, bytearray) # Types acceptable as binary data
+
+def _bytes_from_decode_data(s):
+ if isinstance(s, str):
+ try:
+ return s.encode('ascii')
+ except UnicodeEncodeError:
+ raise ValueError('string argument should contain only ASCII characters')
+ elif isinstance(s, bytes_types):
+ return s
+ else:
+ raise TypeError("argument should be bytes or ASCII string, not %s" % s.__class__.__name__)
+
+
+
+# Base64 encoding/decoding uses binascii
+
+def b64encode(s, altchars=None):
+ """Encode a byte string using Base64.
+
+ s is the byte string to encode. Optional altchars must be a byte
+ string of length 2 which specifies an alternative alphabet for the
+ '+' and '/' characters. This allows an application to
+ e.g. generate url or filesystem safe Base64 strings.
+
+ The encoded byte string is returned.
+ """
+ if not isinstance(s, bytes_types):
+ raise TypeError("expected bytes, not %s" % s.__class__.__name__)
+ if altchars is not None:
+ if not isinstance(altchars, bytes_types):
+ print('wrong altchars')
+ raise TypeError("expected bytes, not %s"
+ % altchars.__class__.__name__)
+ assert len(altchars) >= 2, repr(altchars)
+ return _base64.Base64.encode(s, altchars)
+
+
+def b64decode(s, altchars=None, validate=False):
+ """Decode a Base64 encoded byte string.
+
+ s is the byte string to decode. Optional altchars must be a
+ string of length 2 which specifies the alternative alphabet used
+ instead of the '+' and '/' characters.
+
+ The decoded string is returned. A binascii.Error is raised if s is
+ incorrectly padded.
+
+ If validate is False (the default), non-base64-alphabet characters are
+ discarded prior to the padding check. If validate is True,
+ non-base64-alphabet characters in the input result in a binascii.Error.
+ """
+ if altchars is not None:
+ altchars = _bytes_from_decode_data(altchars)
+ assert len(altchars) == 2, repr(altchars)
+ s = s.translate(bytes.maketrans(altchars, b'+/'))
+ return _base64.Base64.decode(s, altchars, validate)
+
+
+def standard_b64encode(s):
+ """Encode a byte string using the standard Base64 alphabet.
+
+ s is the byte string to encode. The encoded byte string is returned.
+ """
+ return b64encode(s)
+
+def standard_b64decode(s):
+ """Decode a byte string encoded with the standard Base64 alphabet.
+
+ s is the byte string to decode. The decoded byte string is
+ returned. binascii.Error is raised if the input is incorrectly
+ padded or if there are non-alphabet characters present in the
+ input.
+ """
+ return b64decode(s)
+
+
+_urlsafe_encode_translation = bytes.maketrans(b'+/', b'-_')
+_urlsafe_decode_translation = bytes.maketrans(b'-_', b'+/')
+
+def urlsafe_b64encode(s):
+ """Encode a byte string using a url-safe Base64 alphabet.
+
+ s is the byte string to encode. The encoded byte string is
+ returned. The alphabet uses '-' instead of '+' and '_' instead of
+ '/'.
+ """
+ return b64encode(s).translate(_urlsafe_encode_translation)
+
+def urlsafe_b64decode(s):
+ """Decode a byte string encoded with the standard Base64 alphabet.
+
+ s is the byte string to decode. The decoded byte string is
+ returned. binascii.Error is raised if the input is incorrectly
+ padded or if there are non-alphabet characters present in the
+ input.
+
+ The alphabet uses '-' instead of '+' and '_' instead of '/'.
+ """
+ s = _bytes_from_decode_data(s)
+ s = s.translate(_urlsafe_decode_translation)
+ return b64decode(s)
+
+
+
+# Base32 encoding/decoding must be done in Python
+_b32alphabet = {
+ 0: b'A', 9: b'J', 18: b'S', 27: b'3',
+ 1: b'B', 10: b'K', 19: b'T', 28: b'4',
+ 2: b'C', 11: b'L', 20: b'U', 29: b'5',
+ 3: b'D', 12: b'M', 21: b'V', 30: b'6',
+ 4: b'E', 13: b'N', 22: b'W', 31: b'7',
+ 5: b'F', 14: b'O', 23: b'X',
+ 6: b'G', 15: b'P', 24: b'Y',
+ 7: b'H', 16: b'Q', 25: b'Z',
+ 8: b'I', 17: b'R', 26: b'2',
+ }
+
+_b32tab = [v[0] for k, v in sorted(_b32alphabet.items())]
+_b32rev = dict([(v[0], k) for k, v in _b32alphabet.items()])
+
+
+def b32encode(s):
+ """Encode a byte string using Base32.
+
+ s is the byte string to encode. The encoded byte string is returned.
+ """
+ if not isinstance(s, bytes_types):
+ raise TypeError("expected bytes, not %s" % s.__class__.__name__)
+ quanta, leftover = divmod(len(s), 5)
+ # Pad the last quantum with zero bits if necessary
+ if leftover:
+ s = s + bytes(5 - leftover) # Don't use += !
+ quanta += 1
+ encoded = bytearray()
+ for i in range(quanta):
+ # c1 and c2 are 16 bits wide, c3 is 8 bits wide. The intent of this
+ # code is to process the 40 bits in units of 5 bits. So we take the 1
+ # leftover bit of c1 and tack it onto c2. Then we take the 2 leftover
+ # bits of c2 and tack them onto c3. The shifts and masks are intended
+ # to give us values of exactly 5 bits in width.
+ c1, c2, c3 = struct.unpack('!HHB', s[i*5:(i+1)*5])
+ c2 += (c1 & 1) << 16 # 17 bits wide
+ c3 += (c2 & 3) << 8 # 10 bits wide
+ encoded += bytes([_b32tab[c1 >> 11], # bits 1 - 5
+ _b32tab[(c1 >> 6) & 0x1f], # bits 6 - 10
+ _b32tab[(c1 >> 1) & 0x1f], # bits 11 - 15
+ _b32tab[c2 >> 12], # bits 16 - 20 (1 - 5)
+ _b32tab[(c2 >> 7) & 0x1f], # bits 21 - 25 (6 - 10)
+ _b32tab[(c2 >> 2) & 0x1f], # bits 26 - 30 (11 - 15)
+ _b32tab[c3 >> 5], # bits 31 - 35 (1 - 5)
+ _b32tab[c3 & 0x1f], # bits 36 - 40 (1 - 5)
+ ])
+ # Adjust for any leftover partial quanta
+ if leftover == 1:
+ encoded[-6:] = b'======'
+ elif leftover == 2:
+ encoded[-4:] = b'===='
+ elif leftover == 3:
+ encoded[-3:] = b'==='
+ elif leftover == 4:
+ encoded[-1:] = b'='
+ return bytes(encoded)
+
+
+def b32decode(s, casefold=False, map01=None):
+ """Decode a Base32 encoded byte string.
+
+ s is the byte string to decode. Optional casefold is a flag
+ specifying whether a lowercase alphabet is acceptable as input.
+ For security purposes, the default is False.
+
+ RFC 3548 allows for optional mapping of the digit 0 (zero) to the
+ letter O (oh), and for optional mapping of the digit 1 (one) to
+ either the letter I (eye) or letter L (el). The optional argument
+ map01 when not None, specifies which letter the digit 1 should be
+ mapped to (when map01 is not None, the digit 0 is always mapped to
+ the letter O). For security purposes the default is None, so that
+ 0 and 1 are not allowed in the input.
+
+ The decoded byte string is returned. binascii.Error is raised if
+ the input is incorrectly padded or if there are non-alphabet
+ characters present in the input.
+ """
+ s = _bytes_from_decode_data(s)
+ quanta, leftover = divmod(len(s), 8)
+ if leftover:
+ raise binascii.Error('Incorrect padding')
+ # Handle section 2.4 zero and one mapping. The flag map01 will be either
+ # False, or the character to map the digit 1 (one) to. It should be
+ # either L (el) or I (eye).
+ if map01 is not None:
+ map01 = _bytes_from_decode_data(map01)
+ assert len(map01) == 1, repr(map01)
+ s = s.translate(bytes.maketrans(b'01', b'O' + map01))
+ if casefold:
+ s = s.upper()
+ # Strip off pad characters from the right. We need to count the pad
+ # characters because this will tell us how many null bytes to remove from
+ # the end of the decoded string.
+ padchars = 0
+ mo = re.search(b'(?P[=]*)$', s)
+ if mo:
+ padchars = len(mo.group('pad'))
+ if padchars > 0:
+ s = s[:-padchars]
+ # Now decode the full quanta
+ parts = []
+ acc = 0
+ shift = 35
+ for c in s:
+ val = _b32rev.get(c)
+ if val is None:
+ raise binascii.Error('Non-base32 digit found')
+ acc += _b32rev[c] << shift
+ shift -= 5
+ if shift < 0:
+ parts.append(binascii.unhexlify(bytes('%010x' % acc, "ascii")))
+ acc = 0
+ shift = 35
+ # Process the last, partial quanta
+ last = binascii.unhexlify(bytes('%010x' % acc, "ascii"))
+ if padchars == 0:
+ last = b'' # No characters
+ elif padchars == 1:
+ last = last[:-1]
+ elif padchars == 3:
+ last = last[:-2]
+ elif padchars == 4:
+ last = last[:-3]
+ elif padchars == 6:
+ last = last[:-4]
+ else:
+ raise binascii.Error('Incorrect padding')
+ parts.append(last)
+ return b''.join(parts)
+
+
+
+# RFC 3548, Base 16 Alphabet specifies uppercase, but hexlify() returns
+# lowercase. The RFC also recommends against accepting input case
+# insensitively.
+def b16encode(s):
+ """Encode a byte string using Base16.
+
+ s is the byte string to encode. The encoded byte string is returned.
+ """
+ if not isinstance(s, bytes_types):
+ raise TypeError("expected bytes, not %s" % s.__class__.__name__)
+ return binascii.hexlify(s).upper()
+
+
+def b16decode(s, casefold=False):
+ """Decode a Base16 encoded byte string.
+
+ s is the byte string to decode. Optional casefold is a flag
+ specifying whether a lowercase alphabet is acceptable as input.
+ For security purposes, the default is False.
+
+ The decoded byte string is returned. binascii.Error is raised if
+ s were incorrectly padded or if there are non-alphabet characters
+ present in the string.
+ """
+ s = _bytes_from_decode_data(s)
+ if casefold:
+ s = s.upper()
+ if re.search(b'[^0-9A-F]', s):
+ raise binascii.Error('Non-base16 digit found')
+ return binascii.unhexlify(s)
+
+
+
+# Legacy interface. This code could be cleaned up since I don't believe
+# binascii has any line length limitations. It just doesn't seem worth it
+# though. The files should be opened in binary mode.
+
+MAXLINESIZE = 76 # Excluding the CRLF
+MAXBINSIZE = (MAXLINESIZE//4)*3
+
+def encode(input, output):
+ """Encode a file; input and output are binary files."""
+ while True:
+ s = input.read(MAXBINSIZE)
+ if not s:
+ break
+ while len(s) < MAXBINSIZE:
+ ns = input.read(MAXBINSIZE-len(s))
+ if not ns:
+ break
+ s += ns
+ line = binascii.b2a_base64(s)
+ output.write(line)
+
+
+def decode(input, output):
+ """Decode a file; input and output are binary files."""
+ while True:
+ line = input.readline()
+ if not line:
+ break
+ s = binascii.a2b_base64(line)
+ output.write(s)
+
+
+def encodebytes(s):
+ """Encode a bytestring into a bytestring containing multiple lines
+ of base-64 data."""
+ if not isinstance(s, bytes_types):
+ raise TypeError("expected bytes, not %s" % s.__class__.__name__)
+ pieces = []
+ for i in range(0, len(s), MAXBINSIZE):
+ chunk = s[i : i + MAXBINSIZE]
+ pieces.append(binascii.b2a_base64(chunk))
+ return b"".join(pieces)
+
+def encodestring(s):
+ """Legacy alias of encodebytes()."""
+ import warnings
+ warnings.warn("encodestring() is a deprecated alias, use encodebytes()",
+ DeprecationWarning, 2)
+ return encodebytes(s)
+
+
+def decodebytes(s):
+ """Decode a bytestring of base-64 data into a bytestring."""
+ if not isinstance(s, bytes_types):
+ raise TypeError("expected bytes, not %s" % s.__class__.__name__)
+ return binascii.a2b_base64(s)
+
+def decodestring(s):
+ """Legacy alias of decodebytes()."""
+ import warnings
+ warnings.warn("decodestring() is a deprecated alias, use decodebytes()",
+ DeprecationWarning, 2)
+ return decodebytes(s)
+
+
+# Usable as a script...
+def main():
+ """Small main program"""
+ import sys, getopt
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], 'deut')
+ except getopt.error as msg:
+ sys.stdout = sys.stderr
+ print(msg)
+ print("""usage: %s [-d|-e|-u|-t] [file|-]
+ -d, -u: decode
+ -e: encode (default)
+ -t: encode and decode string 'Aladdin:open sesame'"""%sys.argv[0])
+ sys.exit(2)
+ func = encode
+ for o, a in opts:
+ if o == '-e': func = encode
+ if o == '-d': func = decode
+ if o == '-u': func = decode
+ if o == '-t': test(); return
+ if args and args[0] != '-':
+ with open(args[0], 'rb') as f:
+ func(f, sys.stdout.buffer)
+ else:
+ func(sys.stdin.buffer, sys.stdout.buffer)
+
+
+def test():
+ s0 = b"Aladdin:open sesame"
+ print(repr(s0))
+ s1 = encodebytes(s0)
+ print(repr(s1))
+ s2 = decodebytes(s1)
+ print(repr(s2))
+ assert s0 == s2
+
+
+if __name__ == '__main__':
+ main()
diff --git a/lib/assets/Lib/bdb.py b/lib/assets/Lib/bdb.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/bdb.py
@@ -0,0 +1,673 @@
+"""Debugger basics"""
+
+import fnmatch
+import sys
+import os
+from inspect import CO_GENERATOR
+
+__all__ = ["BdbQuit", "Bdb", "Breakpoint"]
+
+class BdbQuit(Exception):
+ """Exception to give up completely."""
+
+
+class Bdb:
+ """Generic Python debugger base class.
+
+ This class takes care of details of the trace facility;
+ a derived class should implement user interaction.
+ The standard debugger class (pdb.Pdb) is an example.
+ """
+
+ def __init__(self, skip=None):
+ self.skip = set(skip) if skip else None
+ self.breaks = {}
+ self.fncache = {}
+ self.frame_returning = None
+
+ def canonic(self, filename):
+ if filename == "<" + filename[1:-1] + ">":
+ return filename
+ canonic = self.fncache.get(filename)
+ if not canonic:
+ canonic = os.path.abspath(filename)
+ canonic = os.path.normcase(canonic)
+ self.fncache[filename] = canonic
+ return canonic
+
+ def reset(self):
+ import linecache
+ linecache.checkcache()
+ self.botframe = None
+ self._set_stopinfo(None, None)
+
+ def trace_dispatch(self, frame, event, arg):
+ if self.quitting:
+ return # None
+ if event == 'line':
+ return self.dispatch_line(frame)
+ if event == 'call':
+ return self.dispatch_call(frame, arg)
+ if event == 'return':
+ return self.dispatch_return(frame, arg)
+ if event == 'exception':
+ return self.dispatch_exception(frame, arg)
+ if event == 'c_call':
+ return self.trace_dispatch
+ if event == 'c_exception':
+ return self.trace_dispatch
+ if event == 'c_return':
+ return self.trace_dispatch
+ print('bdb.Bdb.dispatch: unknown debugging event:', repr(event))
+ return self.trace_dispatch
+
+ def dispatch_line(self, frame):
+ if self.stop_here(frame) or self.break_here(frame):
+ self.user_line(frame)
+ if self.quitting: raise BdbQuit
+ return self.trace_dispatch
+
+ def dispatch_call(self, frame, arg):
+ # XXX 'arg' is no longer used
+ if self.botframe is None:
+ # First call of dispatch since reset()
+ self.botframe = frame.f_back # (CT) Note that this may also be None!
+ return self.trace_dispatch
+ if not (self.stop_here(frame) or self.break_anywhere(frame)):
+ # No need to trace this function
+ return # None
+ # Ignore call events in generator except when stepping.
+ if self.stopframe and frame.f_code.co_flags & CO_GENERATOR:
+ return self.trace_dispatch
+ self.user_call(frame, arg)
+ if self.quitting: raise BdbQuit
+ return self.trace_dispatch
+
+ def dispatch_return(self, frame, arg):
+ if self.stop_here(frame) or frame == self.returnframe:
+ # Ignore return events in generator except when stepping.
+ if self.stopframe and frame.f_code.co_flags & CO_GENERATOR:
+ return self.trace_dispatch
+ try:
+ self.frame_returning = frame
+ self.user_return(frame, arg)
+ finally:
+ self.frame_returning = None
+ if self.quitting: raise BdbQuit
+ # The user issued a 'next' or 'until' command.
+ if self.stopframe is frame and self.stoplineno != -1:
+ self._set_stopinfo(None, None)
+ return self.trace_dispatch
+
+ def dispatch_exception(self, frame, arg):
+ if self.stop_here(frame):
+ # When stepping with next/until/return in a generator frame, skip
+ # the internal StopIteration exception (with no traceback)
+ # triggered by a subiterator run with the 'yield from' statement.
+ if not (frame.f_code.co_flags & CO_GENERATOR
+ and arg[0] is StopIteration and arg[2] is None):
+ self.user_exception(frame, arg)
+ if self.quitting: raise BdbQuit
+ # Stop at the StopIteration or GeneratorExit exception when the user
+ # has set stopframe in a generator by issuing a return command, or a
+ # next/until command at the last statement in the generator before the
+ # exception.
+ elif (self.stopframe and frame is not self.stopframe
+ and self.stopframe.f_code.co_flags & CO_GENERATOR
+ and arg[0] in (StopIteration, GeneratorExit)):
+ self.user_exception(frame, arg)
+ if self.quitting: raise BdbQuit
+
+ return self.trace_dispatch
+
+ # Normally derived classes don't override the following
+ # methods, but they may if they want to redefine the
+ # definition of stopping and breakpoints.
+
+ def is_skipped_module(self, module_name):
+ for pattern in self.skip:
+ if fnmatch.fnmatch(module_name, pattern):
+ return True
+ return False
+
+ def stop_here(self, frame):
+ # (CT) stopframe may now also be None, see dispatch_call.
+ # (CT) the former test for None is therefore removed from here.
+ if self.skip and \
+ self.is_skipped_module(frame.f_globals.get('__name__')):
+ return False
+ if frame is self.stopframe:
+ if self.stoplineno == -1:
+ return False
+ return frame.f_lineno >= self.stoplineno
+ if not self.stopframe:
+ return True
+ return False
+
+ def break_here(self, frame):
+ filename = self.canonic(frame.f_code.co_filename)
+ if filename not in self.breaks:
+ return False
+ lineno = frame.f_lineno
+ if lineno not in self.breaks[filename]:
+ # The line itself has no breakpoint, but maybe the line is the
+ # first line of a function with breakpoint set by function name.
+ lineno = frame.f_code.co_firstlineno
+ if lineno not in self.breaks[filename]:
+ return False
+
+ # flag says ok to delete temp. bp
+ (bp, flag) = effective(filename, lineno, frame)
+ if bp:
+ self.currentbp = bp.number
+ if (flag and bp.temporary):
+ self.do_clear(str(bp.number))
+ return True
+ else:
+ return False
+
+ def do_clear(self, arg):
+ raise NotImplementedError("subclass of bdb must implement do_clear()")
+
+ def break_anywhere(self, frame):
+ return self.canonic(frame.f_code.co_filename) in self.breaks
+
+ # Derived classes should override the user_* methods
+ # to gain control.
+
+ def user_call(self, frame, argument_list):
+ """This method is called when there is the remote possibility
+ that we ever need to stop in this function."""
+ pass
+
+ def user_line(self, frame):
+ """This method is called when we stop or break at this line."""
+ pass
+
+ def user_return(self, frame, return_value):
+ """This method is called when a return trap is set here."""
+ pass
+
+ def user_exception(self, frame, exc_info):
+ """This method is called if an exception occurs,
+ but only if we are to stop at or just below this level."""
+ pass
+
+ def _set_stopinfo(self, stopframe, returnframe, stoplineno=0):
+ self.stopframe = stopframe
+ self.returnframe = returnframe
+ self.quitting = False
+ # stoplineno >= 0 means: stop at line >= the stoplineno
+ # stoplineno -1 means: don't stop at all
+ self.stoplineno = stoplineno
+
+ # Derived classes and clients can call the following methods
+ # to affect the stepping state.
+
+ def set_until(self, frame, lineno=None):
+ """Stop when the line with the line no greater than the current one is
+ reached or when returning from current frame"""
+ # the name "until" is borrowed from gdb
+ if lineno is None:
+ lineno = frame.f_lineno + 1
+ self._set_stopinfo(frame, frame, lineno)
+
+ def set_step(self):
+ """Stop after one line of code."""
+ # Issue #13183: pdb skips frames after hitting a breakpoint and running
+ # step commands.
+ # Restore the trace function in the caller (that may not have been set
+ # for performance reasons) when returning from the current frame.
+ if self.frame_returning:
+ caller_frame = self.frame_returning.f_back
+ if caller_frame and not caller_frame.f_trace:
+ caller_frame.f_trace = self.trace_dispatch
+ self._set_stopinfo(None, None)
+
+ def set_next(self, frame):
+ """Stop on the next line in or below the given frame."""
+ self._set_stopinfo(frame, None)
+
+ def set_return(self, frame):
+ """Stop when returning from the given frame."""
+ if frame.f_code.co_flags & CO_GENERATOR:
+ self._set_stopinfo(frame, None, -1)
+ else:
+ self._set_stopinfo(frame.f_back, frame)
+
+ def set_trace(self, frame=None):
+ """Start debugging from `frame`.
+
+ If frame is not specified, debugging starts from caller's frame.
+ """
+ if frame is None:
+ frame = sys._getframe().f_back
+ self.reset()
+ while frame:
+ frame.f_trace = self.trace_dispatch
+ self.botframe = frame
+ frame = frame.f_back
+ self.set_step()
+ sys.settrace(self.trace_dispatch)
+
+ def set_continue(self):
+ # Don't stop except at breakpoints or when finished
+ self._set_stopinfo(self.botframe, None, -1)
+ if not self.breaks:
+ # no breakpoints; run without debugger overhead
+ sys.settrace(None)
+ frame = sys._getframe().f_back
+ while frame and frame is not self.botframe:
+ del frame.f_trace
+ frame = frame.f_back
+
+ def set_quit(self):
+ self.stopframe = self.botframe
+ self.returnframe = None
+ self.quitting = True
+ sys.settrace(None)
+
+ # Derived classes and clients can call the following methods
+ # to manipulate breakpoints. These methods return an
+ # error message is something went wrong, None if all is well.
+ # Set_break prints out the breakpoint line and file:lineno.
+ # Call self.get_*break*() to see the breakpoints or better
+ # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint().
+
+ def set_break(self, filename, lineno, temporary=False, cond=None,
+ funcname=None):
+ filename = self.canonic(filename)
+ import linecache # Import as late as possible
+ line = linecache.getline(filename, lineno)
+ if not line:
+ return 'Line %s:%d does not exist' % (filename, lineno)
+ list = self.breaks.setdefault(filename, [])
+ if lineno not in list:
+ list.append(lineno)
+ bp = Breakpoint(filename, lineno, temporary, cond, funcname)
+
+ def _prune_breaks(self, filename, lineno):
+ if (filename, lineno) not in Breakpoint.bplist:
+ self.breaks[filename].remove(lineno)
+ if not self.breaks[filename]:
+ del self.breaks[filename]
+
+ def clear_break(self, filename, lineno):
+ filename = self.canonic(filename)
+ if filename not in self.breaks:
+ return 'There are no breakpoints in %s' % filename
+ if lineno not in self.breaks[filename]:
+ return 'There is no breakpoint at %s:%d' % (filename, lineno)
+ # If there's only one bp in the list for that file,line
+ # pair, then remove the breaks entry
+ for bp in Breakpoint.bplist[filename, lineno][:]:
+ bp.deleteMe()
+ self._prune_breaks(filename, lineno)
+
+ def clear_bpbynumber(self, arg):
+ try:
+ bp = self.get_bpbynumber(arg)
+ except ValueError as err:
+ return str(err)
+ bp.deleteMe()
+ self._prune_breaks(bp.file, bp.line)
+
+ def clear_all_file_breaks(self, filename):
+ filename = self.canonic(filename)
+ if filename not in self.breaks:
+ return 'There are no breakpoints in %s' % filename
+ for line in self.breaks[filename]:
+ blist = Breakpoint.bplist[filename, line]
+ for bp in blist:
+ bp.deleteMe()
+ del self.breaks[filename]
+
+ def clear_all_breaks(self):
+ if not self.breaks:
+ return 'There are no breakpoints'
+ for bp in Breakpoint.bpbynumber:
+ if bp:
+ bp.deleteMe()
+ self.breaks = {}
+
+ def get_bpbynumber(self, arg):
+ if not arg:
+ raise ValueError('Breakpoint number expected')
+ try:
+ number = int(arg)
+ except ValueError:
+ raise ValueError('Non-numeric breakpoint number %s' % arg)
+ try:
+ bp = Breakpoint.bpbynumber[number]
+ except IndexError:
+ raise ValueError('Breakpoint number %d out of range' % number)
+ if bp is None:
+ raise ValueError('Breakpoint %d already deleted' % number)
+ return bp
+
+ def get_break(self, filename, lineno):
+ filename = self.canonic(filename)
+ return filename in self.breaks and \
+ lineno in self.breaks[filename]
+
+ def get_breaks(self, filename, lineno):
+ filename = self.canonic(filename)
+ return filename in self.breaks and \
+ lineno in self.breaks[filename] and \
+ Breakpoint.bplist[filename, lineno] or []
+
+ def get_file_breaks(self, filename):
+ filename = self.canonic(filename)
+ if filename in self.breaks:
+ return self.breaks[filename]
+ else:
+ return []
+
+ def get_all_breaks(self):
+ return self.breaks
+
+ # Derived classes and clients can call the following method
+ # to get a data structure representing a stack trace.
+
+ def get_stack(self, f, t):
+ stack = []
+ if t and t.tb_frame is f:
+ t = t.tb_next
+ while f is not None:
+ stack.append((f, f.f_lineno))
+ if f is self.botframe:
+ break
+ f = f.f_back
+ stack.reverse()
+ i = max(0, len(stack) - 1)
+ while t is not None:
+ stack.append((t.tb_frame, t.tb_lineno))
+ t = t.tb_next
+ if f is None:
+ i = max(0, len(stack) - 1)
+ return stack, i
+
+ def format_stack_entry(self, frame_lineno, lprefix=': '):
+ import linecache, reprlib
+ frame, lineno = frame_lineno
+ filename = self.canonic(frame.f_code.co_filename)
+ s = '%s(%r)' % (filename, lineno)
+ if frame.f_code.co_name:
+ s += frame.f_code.co_name
+ else:
+ s += ""
+ if '__args__' in frame.f_locals:
+ args = frame.f_locals['__args__']
+ else:
+ args = None
+ if args:
+ s += reprlib.repr(args)
+ else:
+ s += '()'
+ if '__return__' in frame.f_locals:
+ rv = frame.f_locals['__return__']
+ s += '->'
+ s += reprlib.repr(rv)
+ line = linecache.getline(filename, lineno, frame.f_globals)
+ if line:
+ s += lprefix + line.strip()
+ return s
+
+ # The following methods can be called by clients to use
+ # a debugger to debug a statement or an expression.
+ # Both can be given as a string, or a code object.
+
+ def run(self, cmd, globals=None, locals=None):
+ if globals is None:
+ import __main__
+ globals = __main__.__dict__
+ if locals is None:
+ locals = globals
+ self.reset()
+ if isinstance(cmd, str):
+ cmd = compile(cmd, "", "exec")
+ sys.settrace(self.trace_dispatch)
+ try:
+ exec(cmd, globals, locals)
+ except BdbQuit:
+ pass
+ finally:
+ self.quitting = True
+ sys.settrace(None)
+
+ def runeval(self, expr, globals=None, locals=None):
+ if globals is None:
+ import __main__
+ globals = __main__.__dict__
+ if locals is None:
+ locals = globals
+ self.reset()
+ sys.settrace(self.trace_dispatch)
+ try:
+ return eval(expr, globals, locals)
+ except BdbQuit:
+ pass
+ finally:
+ self.quitting = True
+ sys.settrace(None)
+
+ def runctx(self, cmd, globals, locals):
+ # B/W compatibility
+ self.run(cmd, globals, locals)
+
+ # This method is more useful to debug a single function call.
+
+ def runcall(self, func, *args, **kwds):
+ self.reset()
+ sys.settrace(self.trace_dispatch)
+ res = None
+ try:
+ res = func(*args, **kwds)
+ except BdbQuit:
+ pass
+ finally:
+ self.quitting = True
+ sys.settrace(None)
+ return res
+
+
+def set_trace():
+ Bdb().set_trace()
+
+
+class Breakpoint:
+ """Breakpoint class.
+
+ Implements temporary breakpoints, ignore counts, disabling and
+ (re)-enabling, and conditionals.
+
+ Breakpoints are indexed by number through bpbynumber and by
+ the file,line tuple using bplist. The former points to a
+ single instance of class Breakpoint. The latter points to a
+ list of such instances since there may be more than one
+ breakpoint per line.
+
+ """
+
+ # XXX Keeping state in the class is a mistake -- this means
+ # you cannot have more than one active Bdb instance.
+
+ next = 1 # Next bp to be assigned
+ bplist = {} # indexed by (file, lineno) tuple
+ bpbynumber = [None] # Each entry is None or an instance of Bpt
+ # index 0 is unused, except for marking an
+ # effective break .... see effective()
+
+ def __init__(self, file, line, temporary=False, cond=None, funcname=None):
+ self.funcname = funcname
+ # Needed if funcname is not None.
+ self.func_first_executable_line = None
+ self.file = file # This better be in canonical form!
+ self.line = line
+ self.temporary = temporary
+ self.cond = cond
+ self.enabled = True
+ self.ignore = 0
+ self.hits = 0
+ self.number = Breakpoint.next
+ Breakpoint.next += 1
+ # Build the two lists
+ self.bpbynumber.append(self)
+ if (file, line) in self.bplist:
+ self.bplist[file, line].append(self)
+ else:
+ self.bplist[file, line] = [self]
+
+ def deleteMe(self):
+ index = (self.file, self.line)
+ self.bpbynumber[self.number] = None # No longer in list
+ self.bplist[index].remove(self)
+ if not self.bplist[index]:
+ # No more bp for this f:l combo
+ del self.bplist[index]
+
+ def enable(self):
+ self.enabled = True
+
+ def disable(self):
+ self.enabled = False
+
+ def bpprint(self, out=None):
+ if out is None:
+ out = sys.stdout
+ print(self.bpformat(), file=out)
+
+ def bpformat(self):
+ if self.temporary:
+ disp = 'del '
+ else:
+ disp = 'keep '
+ if self.enabled:
+ disp = disp + 'yes '
+ else:
+ disp = disp + 'no '
+ ret = '%-4dbreakpoint %s at %s:%d' % (self.number, disp,
+ self.file, self.line)
+ if self.cond:
+ ret += '\n\tstop only if %s' % (self.cond,)
+ if self.ignore:
+ ret += '\n\tignore next %d hits' % (self.ignore,)
+ if self.hits:
+ if self.hits > 1:
+ ss = 's'
+ else:
+ ss = ''
+ ret += '\n\tbreakpoint already hit %d time%s' % (self.hits, ss)
+ return ret
+
+ def __str__(self):
+ return 'breakpoint %s at %s:%s' % (self.number, self.file, self.line)
+
+# -----------end of Breakpoint class----------
+
+def checkfuncname(b, frame):
+ """Check whether we should break here because of `b.funcname`."""
+ if not b.funcname:
+ # Breakpoint was set via line number.
+ if b.line != frame.f_lineno:
+ # Breakpoint was set at a line with a def statement and the function
+ # defined is called: don't break.
+ return False
+ return True
+
+ # Breakpoint set via function name.
+
+ if frame.f_code.co_name != b.funcname:
+ # It's not a function call, but rather execution of def statement.
+ return False
+
+ # We are in the right frame.
+ if not b.func_first_executable_line:
+ # The function is entered for the 1st time.
+ b.func_first_executable_line = frame.f_lineno
+
+ if b.func_first_executable_line != frame.f_lineno:
+ # But we are not at the first line number: don't break.
+ return False
+ return True
+
+# Determines if there is an effective (active) breakpoint at this
+# line of code. Returns breakpoint number or 0 if none
+def effective(file, line, frame):
+ """Determine which breakpoint for this file:line is to be acted upon.
+
+ Called only if we know there is a bpt at this
+ location. Returns breakpoint that was triggered and a flag
+ that indicates if it is ok to delete a temporary bp.
+
+ """
+ possibles = Breakpoint.bplist[file, line]
+ for b in possibles:
+ if not b.enabled:
+ continue
+ if not checkfuncname(b, frame):
+ continue
+ # Count every hit when bp is enabled
+ b.hits += 1
+ if not b.cond:
+ # If unconditional, and ignoring go on to next, else break
+ if b.ignore > 0:
+ b.ignore -= 1
+ continue
+ else:
+ # breakpoint and marker that it's ok to delete if temporary
+ return (b, True)
+ else:
+ # Conditional bp.
+ # Ignore count applies only to those bpt hits where the
+ # condition evaluates to true.
+ try:
+ val = eval(b.cond, frame.f_globals, frame.f_locals)
+ if val:
+ if b.ignore > 0:
+ b.ignore -= 1
+ # continue
+ else:
+ return (b, True)
+ # else:
+ # continue
+ except:
+ # if eval fails, most conservative thing is to stop on
+ # breakpoint regardless of ignore count. Don't delete
+ # temporary, as another hint to user.
+ return (b, False)
+ return (None, None)
+
+
+# -------------------- testing --------------------
+
+class Tdb(Bdb):
+ def user_call(self, frame, args):
+ name = frame.f_code.co_name
+ if not name: name = '???'
+ print('+++ call', name, args)
+ def user_line(self, frame):
+ import linecache
+ name = frame.f_code.co_name
+ if not name: name = '???'
+ fn = self.canonic(frame.f_code.co_filename)
+ line = linecache.getline(fn, frame.f_lineno, frame.f_globals)
+ print('+++', fn, frame.f_lineno, name, ':', line.strip())
+ def user_return(self, frame, retval):
+ print('+++ return', retval)
+ def user_exception(self, frame, exc_stuff):
+ print('+++ exception', exc_stuff)
+ self.set_continue()
+
+def foo(n):
+ print('foo(', n, ')')
+ x = bar(n*10)
+ print('bar returned', x)
+
+def bar(a):
+ print('bar(', a, ')')
+ return a/2
+
+def test():
+ t = Tdb()
+ t.run('import bdb; bdb.foo(10)')
diff --git a/lib/assets/Lib/binascii.py b/lib/assets/Lib/binascii.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/binascii.py
@@ -0,0 +1,727 @@
+"""A pure Python implementation of binascii.
+
+Rather slow and buggy in corner cases.
+PyPy provides an RPython version too.
+"""
+
+# borrowed from https://bitbucket.org/pypy/pypy/src/f2bf94943a41/lib_pypy/binascii.py
+
+class Error(Exception):
+ pass
+
+class Done(Exception):
+ pass
+
+class Incomplete(Exception):
+ pass
+
+def a2b_uu(s):
+ if not s:
+ return ''
+
+ length = (ord(s[0]) - 0x20) % 64
+
+ def quadruplets_gen(s):
+ while s:
+ try:
+ yield ord(s[0]), ord(s[1]), ord(s[2]), ord(s[3])
+ except IndexError:
+ s += ' '
+ yield ord(s[0]), ord(s[1]), ord(s[2]), ord(s[3])
+ return
+ s = s[4:]
+
+ try:
+ result = [''.join(
+ [chr((A - 0x20) << 2 | (((B - 0x20) >> 4) & 0x3)),
+ chr(((B - 0x20) & 0xf) << 4 | (((C - 0x20) >> 2) & 0xf)),
+ chr(((C - 0x20) & 0x3) << 6 | ((D - 0x20) & 0x3f))
+ ]) for A, B, C, D in quadruplets_gen(s[1:].rstrip())]
+ except ValueError:
+ raise Error('Illegal char')
+ result = ''.join(result)
+ trailingdata = result[length:]
+ if trailingdata.strip('\x00'):
+ raise Error('Trailing garbage')
+ result = result[:length]
+ if len(result) < length:
+ result += ((length - len(result)) * '\x00')
+ return bytes(result, __BRYTHON__.charset)
+
+
+def b2a_uu(s):
+ length = len(s)
+ if length > 45:
+ raise Error('At most 45 bytes at once')
+
+ def triples_gen(s):
+ while s:
+ try:
+ yield ord(s[0]), ord(s[1]), ord(s[2])
+ except IndexError:
+ s += '\0\0'
+ yield ord(s[0]), ord(s[1]), ord(s[2])
+ return
+ s = s[3:]
+
+ result = [''.join(
+ [chr(0x20 + (( A >> 2 ) & 0x3F)),
+ chr(0x20 + (((A << 4) | ((B >> 4) & 0xF)) & 0x3F)),
+ chr(0x20 + (((B << 2) | ((C >> 6) & 0x3)) & 0x3F)),
+ chr(0x20 + (( C ) & 0x3F))])
+ for A, B, C in triples_gen(s)]
+ return chr(ord(' ') + (length & 0o77)) + ''.join(result) + '\n'
+
+
+table_a2b_base64 = {
+ 'A': 0,
+ 'B': 1,
+ 'C': 2,
+ 'D': 3,
+ 'E': 4,
+ 'F': 5,
+ 'G': 6,
+ 'H': 7,
+ 'I': 8,
+ 'J': 9,
+ 'K': 10,
+ 'L': 11,
+ 'M': 12,
+ 'N': 13,
+ 'O': 14,
+ 'P': 15,
+ 'Q': 16,
+ 'R': 17,
+ 'S': 18,
+ 'T': 19,
+ 'U': 20,
+ 'V': 21,
+ 'W': 22,
+ 'X': 23,
+ 'Y': 24,
+ 'Z': 25,
+ 'a': 26,
+ 'b': 27,
+ 'c': 28,
+ 'd': 29,
+ 'e': 30,
+ 'f': 31,
+ 'g': 32,
+ 'h': 33,
+ 'i': 34,
+ 'j': 35,
+ 'k': 36,
+ 'l': 37,
+ 'm': 38,
+ 'n': 39,
+ 'o': 40,
+ 'p': 41,
+ 'q': 42,
+ 'r': 43,
+ 's': 44,
+ 't': 45,
+ 'u': 46,
+ 'v': 47,
+ 'w': 48,
+ 'x': 49,
+ 'y': 50,
+ 'z': 51,
+ '0': 52,
+ '1': 53,
+ '2': 54,
+ '3': 55,
+ '4': 56,
+ '5': 57,
+ '6': 58,
+ '7': 59,
+ '8': 60,
+ '9': 61,
+ '+': 62,
+ '/': 63,
+ '=': 0,
+}
+
+
+def a2b_base64(s):
+ if not isinstance(s, (str, bytes)):
+ raise TypeError("expected string, got %r" % (s,))
+ s = s.rstrip()
+ # clean out all invalid characters, this also strips the final '=' padding
+ # check for correct padding
+
+ def next_valid_char(s, pos):
+ for i in range(pos + 1, len(s)):
+ c = s[i]
+ if c < 0x7f:
+ try:
+ table_a2b_base64[chr(c)]
+ return chr(c)
+ except KeyError:
+ pass
+ return None
+
+ quad_pos = 0
+ leftbits = 0
+ leftchar = 0
+ res = []
+ for i, c in enumerate(s):
+ if isinstance(c, int):
+ c = chr(c)
+ if c > '\x7f' or c == '\n' or c == '\r' or c == ' ':
+ continue
+ if c == '=':
+ if quad_pos < 2 or (quad_pos == 2 and next_valid_char(s, i) != '='):
+ continue
+ else:
+ leftbits = 0
+ break
+ try:
+ next_c = table_a2b_base64[c]
+ except KeyError:
+ continue
+ quad_pos = (quad_pos + 1) & 0x03
+ leftchar = (leftchar << 6) | next_c
+ leftbits += 6
+ if leftbits >= 8:
+ leftbits -= 8
+ res.append((leftchar >> leftbits & 0xff))
+ leftchar &= ((1 << leftbits) - 1)
+ if leftbits != 0:
+ raise Error('Incorrect padding')
+
+ return bytes(''.join([chr(i) for i in res]),__BRYTHON__.charset)
+
+table_b2a_base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"\
+ "0123456789+/"
+
+def b2a_base64(s):
+ length = len(s)
+ final_length = length % 3
+
+ def triples_gen(s):
+ while s:
+ try:
+ yield s[0], s[1], s[2]
+ except IndexError:
+ s += b'\0\0'
+ yield s[0], s[1], s[2]
+ return
+ s = s[3:]
+
+ a = triples_gen(s[ :length - final_length])
+
+ result = [''.join(
+ [table_b2a_base64[( A >> 2 ) & 0x3F],
+ table_b2a_base64[((A << 4) | ((B >> 4) & 0xF)) & 0x3F],
+ table_b2a_base64[((B << 2) | ((C >> 6) & 0x3)) & 0x3F],
+ table_b2a_base64[( C ) & 0x3F]])
+ for A, B, C in a]
+
+ final = s[length - final_length:]
+ if final_length == 0:
+ snippet = ''
+ elif final_length == 1:
+ a = final[0]
+ snippet = table_b2a_base64[(a >> 2 ) & 0x3F] + \
+ table_b2a_base64[(a << 4 ) & 0x3F] + '=='
+ else:
+ a = final[0]
+ b = final[1]
+ snippet = table_b2a_base64[(a >> 2) & 0x3F] + \
+ table_b2a_base64[((a << 4) | (b >> 4) & 0xF) & 0x3F] + \
+ table_b2a_base64[(b << 2) & 0x3F] + '='
+ return bytes(''.join(result) + snippet + '\n', __BRYTHON__.charset)
+
+def a2b_qp(s, header=False):
+ inp = 0
+ odata = []
+ while inp < len(s):
+ if s[inp] == '=':
+ inp += 1
+ if inp >= len(s):
+ break
+ # Soft line breaks
+ if (s[inp] == '\n') or (s[inp] == '\r'):
+ if s[inp] != '\n':
+ while inp < len(s) and s[inp] != '\n':
+ inp += 1
+ if inp < len(s):
+ inp += 1
+ elif s[inp] == '=':
+ # broken case from broken python qp
+ odata.append('=')
+ inp += 1
+ elif s[inp] in hex_numbers and s[inp + 1] in hex_numbers:
+ ch = chr(int(s[inp:inp+2], 16))
+ inp += 2
+ odata.append(ch)
+ else:
+ odata.append('=')
+ elif header and s[inp] == '_':
+ odata.append(' ')
+ inp += 1
+ else:
+ odata.append(s[inp])
+ inp += 1
+ return bytes(''.join(odata), __BRYTHON__.charset)
+
+def b2a_qp(data, quotetabs=False, istext=True, header=False):
+ """quotetabs=True means that tab and space characters are always
+ quoted.
+ istext=False means that \r and \n are treated as regular characters
+ header=True encodes space characters with '_' and requires
+ real '_' characters to be quoted.
+ """
+ MAXLINESIZE = 76
+
+ # See if this string is using CRLF line ends
+ lf = data.find('\n')
+ crlf = lf > 0 and data[lf-1] == '\r'
+
+ inp = 0
+ linelen = 0
+ odata = []
+ while inp < len(data):
+ c = data[inp]
+ if (c > '~' or
+ c == '=' or
+ (header and c == '_') or
+ (c == '.' and linelen == 0 and (inp+1 == len(data) or
+ data[inp+1] == '\n' or
+ data[inp+1] == '\r')) or
+ (not istext and (c == '\r' or c == '\n')) or
+ ((c == '\t' or c == ' ') and (inp + 1 == len(data))) or
+ (c <= ' ' and c != '\r' and c != '\n' and
+ (quotetabs or (not quotetabs and (c != '\t' and c != ' '))))):
+ linelen += 3
+ if linelen >= MAXLINESIZE:
+ odata.append('=')
+ if crlf: odata.append('\r')
+ odata.append('\n')
+ linelen = 3
+ odata.append('=' + two_hex_digits(ord(c)))
+ inp += 1
+ else:
+ if (istext and
+ (c == '\n' or (inp+1 < len(data) and c == '\r' and
+ data[inp+1] == '\n'))):
+ linelen = 0
+ # Protect against whitespace on end of line
+ if (len(odata) > 0 and
+ (odata[-1] == ' ' or odata[-1] == '\t')):
+ ch = ord(odata[-1])
+ odata[-1] = '='
+ odata.append(two_hex_digits(ch))
+
+ if crlf: odata.append('\r')
+ odata.append('\n')
+ if c == '\r':
+ inp += 2
+ else:
+ inp += 1
+ else:
+ if (inp + 1 < len(data) and
+ data[inp+1] != '\n' and
+ (linelen + 1) >= MAXLINESIZE):
+ odata.append('=')
+ if crlf: odata.append('\r')
+ odata.append('\n')
+ linelen = 0
+
+ linelen += 1
+ if header and c == ' ':
+ c = '_'
+ odata.append(c)
+ inp += 1
+ return ''.join(odata)
+
+hex_numbers = '0123456789ABCDEF'
+def hex(n):
+ if n == 0:
+ return '0'
+
+ if n < 0:
+ n = -n
+ sign = '-'
+ else:
+ sign = ''
+ arr = []
+
+ def hex_gen(n):
+ """ Yield a nibble at a time. """
+ while n:
+ yield n % 0x10
+ n = n / 0x10
+
+ for nibble in hex_gen(n):
+ arr = [hex_numbers[nibble]] + arr
+ return sign + ''.join(arr)
+
+def two_hex_digits(n):
+ return hex_numbers[n / 0x10] + hex_numbers[n % 0x10]
+
+
+def strhex_to_int(s):
+ i = 0
+ for c in s:
+ i = i * 0x10 + hex_numbers.index(c)
+ return i
+
+hqx_encoding = '!"#$%&\'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr'
+
+DONE = 0x7f
+SKIP = 0x7e
+FAIL = 0x7d
+
+table_a2b_hqx = [
+ #^@ ^A ^B ^C ^D ^E ^F ^G
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ #\b \t \n ^K ^L \r ^N ^O
+ FAIL, FAIL, SKIP, FAIL, FAIL, SKIP, FAIL, FAIL,
+ #^P ^Q ^R ^S ^T ^U ^V ^W
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ #^X ^Y ^Z ^[ ^\ ^] ^^ ^_
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ # ! " # $ % & '
+ FAIL, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ #( ) * + , - . /
+ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, FAIL, FAIL,
+ #0 1 2 3 4 5 6 7
+ 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, FAIL,
+ #8 9 : ; < = > ?
+ 0x14, 0x15, DONE, FAIL, FAIL, FAIL, FAIL, FAIL,
+ #@ A B C D E F G
+ 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
+ #H I J K L M N O
+ 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, FAIL,
+ #P Q R S T U V W
+ 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, FAIL,
+ #X Y Z [ \ ] ^ _
+ 0x2C, 0x2D, 0x2E, 0x2F, FAIL, FAIL, FAIL, FAIL,
+ #` a b c d e f g
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, FAIL,
+ #h i j k l m n o
+ 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, FAIL, FAIL,
+ #p q r s t u v w
+ 0x3D, 0x3E, 0x3F, FAIL, FAIL, FAIL, FAIL, FAIL,
+ #x y z { | } ~ ^?
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+]
+
+def a2b_hqx(s):
+ result = []
+
+ def quadruples_gen(s):
+ t = []
+ for c in s:
+ res = table_a2b_hqx[ord(c)]
+ if res == SKIP:
+ continue
+ elif res == FAIL:
+ raise Error('Illegal character')
+ elif res == DONE:
+ yield t
+ raise Done
+ else:
+ t.append(res)
+ if len(t) == 4:
+ yield t
+ t = []
+ yield t
+
+ done = 0
+ try:
+ for snippet in quadruples_gen(s):
+ length = len(snippet)
+ if length == 4:
+ result.append(chr(((snippet[0] & 0x3f) << 2) | (snippet[1] >> 4)))
+ result.append(chr(((snippet[1] & 0x0f) << 4) | (snippet[2] >> 2)))
+ result.append(chr(((snippet[2] & 0x03) << 6) | (snippet[3])))
+ elif length == 3:
+ result.append(chr(((snippet[0] & 0x3f) << 2) | (snippet[1] >> 4)))
+ result.append(chr(((snippet[1] & 0x0f) << 4) | (snippet[2] >> 2)))
+ elif length == 2:
+ result.append(chr(((snippet[0] & 0x3f) << 2) | (snippet[1] >> 4)))
+ except Done:
+ done = 1
+ except Error:
+ raise
+ return (''.join(result), done)
+ # should this return a bytes object?
+ #return (bytes(''.join(result), __BRYTHON__.charset), done)
+
+def b2a_hqx(s):
+ result =[]
+
+ def triples_gen(s):
+ while s:
+ try:
+ yield ord(s[0]), ord(s[1]), ord(s[2])
+ except IndexError:
+ yield tuple([ord(c) for c in s])
+ s = s[3:]
+
+ for snippet in triples_gen(s):
+ length = len(snippet)
+ if length == 3:
+ result.append(
+ hqx_encoding[(snippet[0] & 0xfc) >> 2])
+ result.append(hqx_encoding[
+ ((snippet[0] & 0x03) << 4) | ((snippet[1] & 0xf0) >> 4)])
+ result.append(hqx_encoding[
+ (snippet[1] & 0x0f) << 2 | ((snippet[2] & 0xc0) >> 6)])
+ result.append(hqx_encoding[snippet[2] & 0x3f])
+ elif length == 2:
+ result.append(
+ hqx_encoding[(snippet[0] & 0xfc) >> 2])
+ result.append(hqx_encoding[
+ ((snippet[0] & 0x03) << 4) | ((snippet[1] & 0xf0) >> 4)])
+ result.append(hqx_encoding[
+ (snippet[1] & 0x0f) << 2])
+ elif length == 1:
+ result.append(
+ hqx_encoding[(snippet[0] & 0xfc) >> 2])
+ result.append(hqx_encoding[
+ ((snippet[0] & 0x03) << 4)])
+ return ''.join(result)
+
+crctab_hqx = [
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+ 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+ 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+ 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+ 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+ 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+ 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+ 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+ 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+ 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+ 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+ 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+ 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+ 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+ 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+ 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+ 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+ 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+ 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+ 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+ 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0,
+]
+
+def crc_hqx(s, crc):
+ for c in s:
+ crc = ((crc << 8) & 0xff00) ^ crctab_hqx[((crc >> 8) & 0xff) ^ ord(c)]
+
+ return crc
+
+def rlecode_hqx(s):
+ """
+ Run length encoding for binhex4.
+ The CPython implementation does not do run length encoding
+ of \x90 characters. This implementation does.
+ """
+ if not s:
+ return ''
+ result = []
+ prev = s[0]
+ count = 1
+ # Add a dummy character to get the loop to go one extra round.
+ # The dummy must be different from the last character of s.
+ # In the same step we remove the first character, which has
+ # already been stored in prev.
+ if s[-1] == '!':
+ s = s[1:] + '?'
+ else:
+ s = s[1:] + '!'
+
+ for c in s:
+ if c == prev and count < 255:
+ count += 1
+ else:
+ if count == 1:
+ if prev != '\x90':
+ result.append(prev)
+ else:
+ result.extend(['\x90', '\x00'])
+ elif count < 4:
+ if prev != '\x90':
+ result.extend([prev] * count)
+ else:
+ result.extend(['\x90', '\x00'] * count)
+ else:
+ if prev != '\x90':
+ result.extend([prev, '\x90', chr(count)])
+ else:
+ result.extend(['\x90', '\x00', '\x90', chr(count)])
+ count = 1
+ prev = c
+
+ return ''.join(result)
+
+def rledecode_hqx(s):
+ s = s.split('\x90')
+ result = [s[0]]
+ prev = s[0]
+ for snippet in s[1:]:
+ count = ord(snippet[0])
+ if count > 0:
+ result.append(prev[-1] * (count-1))
+ prev = snippet
+ else:
+ result.append('\x90')
+ prev = '\x90'
+ result.append(snippet[1:])
+
+ return ''.join(result)
+
+crc_32_tab = [
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d
+]
+
+def crc32(s, crc=0):
+ result = 0
+ crc = ~int(crc) & 0xffffffff
+ #crc = ~long(crc) & 0xffffffffL
+ for c in s:
+ crc = crc_32_tab[(crc ^ int(ord(c))) & 0xff] ^ (crc >> 8)
+ #crc = crc_32_tab[(crc ^ long(ord(c))) & 0xffL] ^ (crc >> 8)
+ #/* Note: (crc >> 8) MUST zero fill on left
+
+ result = crc ^ 0xffffffff
+
+ if result > 2**31:
+ result = ((result + 2**31) % 2**32) - 2**31
+
+ return result
+
+def b2a_hex(s):
+ result = []
+ for char in s:
+ c = (ord(char) >> 4) & 0xf
+ if c > 9:
+ c = c + ord('a') - 10
+ else:
+ c = c + ord('0')
+ result.append(chr(c))
+ c = ord(char) & 0xf
+ if c > 9:
+ c = c + ord('a') - 10
+ else:
+ c = c + ord('0')
+ result.append(chr(c))
+ return ''.join(result)
+
+hexlify = b2a_hex
+
+table_hex = [
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1,
+ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
+]
+
+
+def a2b_hex(t):
+ result = []
+
+ def pairs_gen(s):
+ while s:
+ try:
+ yield table_hex[ord(s[0])], table_hex[ord(s[1])]
+ except IndexError:
+ if len(s):
+ raise TypeError('Odd-length string')
+ return
+ s = s[2:]
+
+ for a, b in pairs_gen(t):
+ if a < 0 or b < 0:
+ raise TypeError('Non-hexadecimal digit found')
+ result.append(chr((a << 4) + b))
+ return bytes(''.join(result), __BRYTHON__.charset)
+
+
+unhexlify = a2b_hex
diff --git a/lib/assets/Lib/bisect.py b/lib/assets/Lib/bisect.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/bisect.py
@@ -0,0 +1,92 @@
+"""Bisection algorithms."""
+
+def insort_right(a, x, lo=0, hi=None):
+ """Insert item x in list a, and keep it sorted assuming a is sorted.
+
+ If x is already in a, insert it to the right of the rightmost x.
+
+ Optional args lo (default 0) and hi (default len(a)) bound the
+ slice of a to be searched.
+ """
+
+ if lo < 0:
+ raise ValueError('lo must be non-negative')
+ if hi is None:
+ hi = len(a)
+ while lo < hi:
+ mid = (lo+hi)//2
+ if x < a[mid]: hi = mid
+ else: lo = mid+1
+ a.insert(lo, x)
+
+insort = insort_right # backward compatibility
+
+def bisect_right(a, x, lo=0, hi=None):
+ """Return the index where to insert item x in list a, assuming a is sorted.
+
+ The return value i is such that all e in a[:i] have e <= x, and all e in
+ a[i:] have e > x. So if x already appears in the list, a.insert(x) will
+ insert just after the rightmost x already there.
+
+ Optional args lo (default 0) and hi (default len(a)) bound the
+ slice of a to be searched.
+ """
+
+ if lo < 0:
+ raise ValueError('lo must be non-negative')
+ if hi is None:
+ hi = len(a)
+ while lo < hi:
+ mid = (lo+hi)//2
+ if x < a[mid]: hi = mid
+ else: lo = mid+1
+ return lo
+
+bisect = bisect_right # backward compatibility
+
+def insort_left(a, x, lo=0, hi=None):
+ """Insert item x in list a, and keep it sorted assuming a is sorted.
+
+ If x is already in a, insert it to the left of the leftmost x.
+
+ Optional args lo (default 0) and hi (default len(a)) bound the
+ slice of a to be searched.
+ """
+
+ if lo < 0:
+ raise ValueError('lo must be non-negative')
+ if hi is None:
+ hi = len(a)
+ while lo < hi:
+ mid = (lo+hi)//2
+ if a[mid] < x: lo = mid+1
+ else: hi = mid
+ a.insert(lo, x)
+
+
+def bisect_left(a, x, lo=0, hi=None):
+ """Return the index where to insert item x in list a, assuming a is sorted.
+
+ The return value i is such that all e in a[:i] have e < x, and all e in
+ a[i:] have e >= x. So if x already appears in the list, a.insert(x) will
+ insert just before the leftmost x already there.
+
+ Optional args lo (default 0) and hi (default len(a)) bound the
+ slice of a to be searched.
+ """
+
+ if lo < 0:
+ raise ValueError('lo must be non-negative')
+ if hi is None:
+ hi = len(a)
+ while lo < hi:
+ mid = (lo+hi)//2
+ if a[mid] < x: lo = mid+1
+ else: hi = mid
+ return lo
+
+# Overwrite above definitions with a fast C implementation
+try:
+ from _bisect import *
+except ImportError:
+ pass
diff --git a/lib/assets/Lib/browser/__init__.py b/lib/assets/Lib/browser/__init__.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/browser/__init__.py
@@ -0,0 +1,9 @@
+import javascript
+
+from _browser import *
+
+from .local_storage import LocalStorage
+from .session_storage import SessionStorage
+from .object_storage import ObjectStorage
+
+WebSocket = javascript.JSConstructor(window.WebSocket)
\ No newline at end of file
diff --git a/lib/assets/Lib/browser/ajax.py b/lib/assets/Lib/browser/ajax.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/browser/ajax.py
@@ -0,0 +1,1 @@
+from _ajax import *
diff --git a/lib/assets/Lib/browser/html.py b/lib/assets/Lib/browser/html.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/browser/html.py
@@ -0,0 +1,1 @@
+from _html import *
\ No newline at end of file
diff --git a/lib/assets/Lib/browser/indexed_db.py b/lib/assets/Lib/browser/indexed_db.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/browser/indexed_db.py
@@ -0,0 +1,106 @@
+class EventListener:
+ def __init__(self, events=[]):
+ self._events=events
+
+ def append(self, event):
+ self._events.append(event)
+
+ def fire(self, e):
+ for _event in self._events:
+ _event(e)
+
+class IndexedDB:
+ def __init__(self):
+ if not __BRYTHON__.has_indexedDB:
+ raise NotImplementedError("Your browser doesn't support indexedDB")
+ return
+
+ self._indexedDB=__BRYTHON__.indexedDB()
+ self._db=None
+ self._version=None
+
+ def _onsuccess(self, event):
+ self._db=event.target.result
+
+ def open(self, name, onsuccess, version=1.0, onerror=None,
+ onupgradeneeded=None):
+ self._version=version
+ _result=self._indexedDB.open(name, version)
+ _success=EventListener([self._onsuccess, onsuccess])
+ _result.onsuccess=_success.fire
+ _result.onupgradeneeded=onupgradeneeded
+
+ #if onerror is None:
+ def onerror(e):
+ print("onerror: %s:%s" % (e.type, e.target.result))
+
+ def onblocked(e):
+ print("blocked: %s:%s" % (e.type, e.result))
+
+ _result.onerror=onerror
+ _result.onblocked=onblocked
+
+ def transaction(self, entities, mode='read'):
+ return Transaction(self._db.transaction(entities, mode))
+
+class Transaction:
+
+ def __init__(self, transaction):
+ self._transaction=transaction
+
+ def objectStore(self, name):
+ return ObjectStore(self._transaction.objectStore(name))
+
+class ObjectStore:
+
+ def __init__(self, objectStore):
+ self._objectStore=objectStore
+ self._data=[]
+
+ def clear(self, onsuccess=None, onerror=None):
+ _result=self._objectStore.clear()
+
+ if onsuccess is not None:
+ _result.onsuccess=onsuccess
+
+ if onerror is not None:
+ _result.onerror=onerror
+
+ def _helper(self, func, object, onsuccess=None, onerror=None):
+ _result=func(object)
+
+ if onsuccess is not None:
+ _result.onsuccess=onsuccess
+
+ if onerror is not None:
+ _result.onerror=onerror
+
+ def put(self, obj, key=None, onsuccess=None, onerror=None):
+ _r = self._objectStore.put(obj, key)
+ _r.onsuccess = onsuccess
+ _r.onerror = onerror
+
+ def add(self, obj, key, onsuccess=None, onerror=None):
+ _r = self._objectStore.add(obj, key)
+ _r.onsuccess = onsuccess
+ _r.onerror = onerror
+ #self._helper(self._objectStore.add, object, onsuccess, onerror)
+
+ def delete(self, index, onsuccess=None, onerror=None):
+ self._helper(self._objectStore.delete, index, onsuccess, onerror)
+
+ def query(self, *args):
+ self._data=[]
+ def onsuccess(event):
+ cursor=event.target.result
+ if cursor is not None:
+ self._data.append(cursor.value)
+ getattr(cursor,"continue")() # cursor.continue() is illegal
+
+ self._objectStore.openCursor(args).onsuccess=onsuccess
+
+ def fetchall(self):
+ yield self._data
+
+ def get(self, key, onsuccess=None, onerror=None):
+ self._helper(self._objectStore.get, key, onsuccess, onerror)
diff --git a/lib/assets/Lib/browser/local_storage.py b/lib/assets/Lib/browser/local_storage.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/browser/local_storage.py
@@ -0,0 +1,92 @@
+# local storage in browser
+import sys
+from javascript import JSObject
+from browser import window, console
+
+has_local_storage = hasattr(window, 'localStorage')
+
+class __UnProvided():
+ pass
+
+class LocalStorage():
+ storage_type = "local_storage"
+
+ def __init__(self):
+ if not has_local_storage:
+ raise EnvironmentError("LocalStorage not available")
+ self.store = JSObject(window.localStorage)
+
+ def __delitem__(self, key):
+ if (not isinstance(key, str)):
+ raise TypeError("key must be string")
+ if key not in self:
+ raise KeyError(key)
+ self.store.removeItem(key)
+
+ def __getitem__(self, key):
+ if (not isinstance(key, str)):
+ raise TypeError("key must be string")
+ res = __BRYTHON__.JSObject(self.store.getItem(key))
+ if res is not None:
+ return res
+ raise KeyError(key)
+
+ def __setitem__(self, key, value):
+ if (not isinstance(key, str)):
+ raise TypeError("key must be string")
+ if (not isinstance(value, str)):
+ raise TypeError("value must be string")
+ self.store.setItem(key, value)
+
+ # implement "in" functionality
+ def __contains__(self, key):
+ if (not isinstance(key, str)):
+ raise TypeError("key must be string")
+ res = __BRYTHON__.JSObject(self.store.getItem(key))
+ if res is None:
+ return False
+ return True
+
+ def __iter__(self):
+ keys = self.keys()
+ return keys.__iter__()
+
+ def get(self, key, default=None):
+ if (not isinstance(key, str)):
+ raise TypeError("key must be string")
+ return __BRYTHON__.JSObject(self.store.getItem(key)) or default
+
+ def pop(self, key, default=__UnProvided()):
+ if (not isinstance(key, str)):
+ raise TypeError("key must be string")
+ if type(default) is __UnProvided:
+ ret = self.get(key)
+ del self[key] # will throw key error if doesn't exist
+ return ret
+ else:
+ if key in self:
+ ret = self.get(key)
+ del self[key]
+ return ret
+ else:
+ return default
+
+ # while a real dict provides a view, returning a generator would less helpful than simply returning a list
+ # and creating a custom iterator is overkill and would likely result in slower performance
+ def keys(self):
+ return [__BRYTHON__.JSObject(self.store.key(i)) for i in range(self.store.length)]
+
+ def values(self):
+ return [__BRYTHON__.JSObject(self.__getitem__(k)) for k in self.keys()]
+
+ def items(self):
+ return list(zip(self.keys(), self.values()))
+
+ def clear(self):
+ self.store.clear()
+
+ def __len__(self):
+ return self.store.length
+
+if has_local_storage:
+ storage = LocalStorage()
diff --git a/lib/assets/Lib/browser/markdown.py b/lib/assets/Lib/browser/markdown.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/browser/markdown.py
@@ -0,0 +1,423 @@
+# -*- coding: utf-8 -*-
+
+try:
+ import _jsre as re
+except:
+ import re
+
+import random
+import time
+
+letters = 'abcdefghijklmnopqrstuvwxyz'
+letters += letters.upper()+'0123456789'
+
+class URL:
+ def __init__(self,src):
+ elts = src.split(maxsplit=1)
+ self.href = elts[0]
+ self.alt = ''
+ if len(elts)==2:
+ alt = elts[1]
+ if alt[0]=='"' and alt[-1]=='"':self.alt=alt[1:-1]
+ elif alt[0]=="'" and alt[-1]=="'":self.alt=alt[1:-1]
+ elif alt[0]=="(" and alt[-1]==")":self.alt=alt[1:-1]
+
+class CodeBlock:
+ def __init__(self,line):
+ self.lines = [line]
+ if line.startswith("```") and len(line)>3:
+ self.info = line[3:]
+ else:
+ self.info = None
+
+ def to_html(self):
+ if self.lines[0].startswith("`"):
+ self.lines.pop(0)
+ res = escape('\n'.join(self.lines))
+ res = unmark(res)
+ _class = self.info or "marked"
+ res = '%s
\n' %(_class, res)
+ return res,[]
+
+class HtmlBlock:
+
+ def __init__(self, src):
+ self.src = src
+
+ def to_html(self):
+ return self.src
+
+class Marked:
+ def __init__(self, line=''):
+ self.line = line
+ self.children = []
+
+ def to_html(self):
+ return apply_markdown(self.line)
+
+# get references
+refs = {}
+ref_pattern = r"^\[(.*)\]:\s+(.*)"
+
+def mark(src):
+
+ global refs
+ t0 = time.time()
+ refs = {}
+ # split source in sections
+ # sections can be :
+ # - a block-level HTML element (markdown syntax will not be processed)
+ # - a script
+ # - a span-level HTML tag (markdown syntax will be processed)
+ # - a code block
+
+ # normalise line feeds
+ src = src.replace('\r\n','\n')
+
+ # lines followed by dashes
+ src = re.sub(r'(.*?)\n=+\n', '\n# \\1\n', src)
+ src = re.sub(r'(.*?)\n-+\n', '\n## \\1\n', src)
+
+ lines = src.split('\n')+['']
+
+ i = bq = 0
+ ul = ol = 0
+
+ while i in a blockquote
+ if lines[i].startswith('>'):
+ nb = 1
+ while nb':
+ nb += 1
+ lines[i] = lines[i][nb:]
+ if nb>bq:
+ lines.insert(i,''*(nb-bq))
+ i += 1
+ bq = nb
+ elif nb'*(bq-nb))
+ i += 1
+ bq = nb
+ elif bq>0:
+ lines.insert(i,'
'*bq)
+ i += 1
+ bq = 0
+
+ # unordered lists
+ if lines[i].strip() and lines[i].lstrip()[0] in '-+*' \
+ and len(lines[i].lstrip())>1 \
+ and lines[i].lstrip()[1]==' ' \
+ and (i==0 or ul or not lines[i-1].strip()):
+ # line indentation indicates nesting level
+ nb = 1+len(lines[i])-len(lines[i].lstrip())
+ lines[i] = ''+lines[i][nb:]
+ if nb>ul:
+ lines.insert(i,''*(nb-ul))
+ i += 1
+ elif nb'*(ul-nb))
+ i += 1
+ ul = nb
+ elif ul and not lines[i].strip():
+ if i1 and nline[1]==' ':
+ pass
+ else:
+ lines.insert(i,'
'*ul)
+ i += 1
+ ul = 0
+
+ # ordered lists
+ mo = re.search(r'^(\d+\.)',lines[i])
+ if mo:
+ if not ol:
+ lines.insert(i,'')
+ i += 1
+ lines[i] = '- '+lines[i][len(mo.groups()[0]):]
+ ol = 1
+ elif ol and not lines[i].strip() and i
')
+ i += 1
+ ol = 0
+
+ i += 1
+
+ if ul:
+ lines.append(''*ul)
+ if ol:
+ lines.append('
'*ol)
+ if bq:
+ lines.append(''*bq)
+
+ t1 = time.time()
+ #print('part 1', t1-t0)
+ sections = []
+ scripts = []
+ section = Marked()
+
+ i = 0
+ while i'):
+ scripts.append('\n'.join(lines[i+1:j]))
+ for k in range(i,j+1):
+ lines[k] = ''
+ break
+ j += 1
+ i = j
+ continue
+
+ # atext header
+ elif line.startswith('#'):
+ level = 1
+ line = lines[i]
+ while level%s \n' %(level-1,'#',level-1)
+ else:
+ lines[i] = '%s \n' %(level,line[level+1:],level)
+
+ else:
+ mo = re.search(ref_pattern,line)
+ if mo is not None:
+ if isinstance(section,Marked) and section.line:
+ sections.append(section)
+ section = Marked()
+ key = mo.groups()[0]
+ value = URL(mo.groups()[1])
+ refs[key.lower()] = value
+ else:
+ if not line.strip():
+ line = ''
+ if section.line:
+ section.line += '\n'
+ section.line += line
+
+ i += 1
+ t2 = time.time()
+ #print('section 2', t2-t1)
+ if isinstance(section,Marked) and section.line:
+ sections.append(section)
+
+ res = ''
+ for section in sections:
+ mk,_scripts = section.to_html()
+ res += mk
+ scripts += _scripts
+ #print('end mark', time.time()-t2)
+ return res,scripts
+
+def escape(czone):
+ czone = czone.replace('&','&')
+ czone = czone.replace('<','<')
+ czone = czone.replace('>','>')
+ czone = czone.replace('_','_')
+ czone = czone.replace('*','*')
+ return czone
+
+def s_escape(mo):
+ # used in re.sub
+ czone = mo.string[mo.start():mo.end()]
+ return escape(czone)
+
+def unmark(code_zone):
+ # convert _ to _ inside inline code
+ code_zone = code_zone.replace('_','_')
+ return code_zone
+
+def s_unmark(mo):
+ # convert _ to _ inside inline code
+ code_zone = mo.string[mo.start():mo.end()]
+ code_zone = code_zone.replace('_','_')
+ return code_zone
+
+def apply_markdown(src):
+
+ scripts = []
+ key = None
+
+ t0 = time.time()
+ i = 0
+ while i-1 and src[start_a:end_a].find('\n')==-1:
+ link = src[start_a:end_a]
+ rest = src[end_a+1:].lstrip()
+ if rest and rest[0]=='(':
+ j = 0
+ while True:
+ end_href = rest.find(')',j)
+ if end_href == -1:
+ break
+ if rest[end_href-1]=='\\':
+ j = end_href+1
+ else:
+ break
+ if end_href>-1 and rest[:end_href].find('\n')==-1:
+ tag = ''+link+''
+ src = src[:start_a-1]+tag+rest[end_href+1:]
+ i = start_a+len(tag)
+ elif rest and rest[0]=='[':
+ j = 0
+ while True:
+ end_key = rest.find(']',j)
+ if end_key == -1:
+ break
+ if rest[end_key-1]=='\\':
+ j = end_key+1
+ else:
+ break
+ if end_key>-1 and rest[:end_key].find('\n')==-1:
+ if not key:
+ key = link
+ if key.lower() not in refs:
+ raise KeyError('unknown reference %s' %key)
+ url = refs[key.lower()]
+ tag = ''+link+''
+ src = src[:start_a-1]+tag+rest[end_key+1:]
+ i = start_a+len(tag)
+
+ i += 1
+
+ t1 = time.time()
+ #print('apply markdown 1', t1-t0)
+ # before applying the markup with _ and *, isolate HTML tags because
+ # they can contain these characters
+
+ # We replace them temporarily by a random string
+ rstr = ''.join(random.choice(letters) for i in range(16))
+
+ i = 0
+ state = None
+ start = -1
+ data = ''
+ tags = []
+ while i' and state is None:
+ tags.append(src[i:j+1])
+ src = src[:i]+rstr+src[j+1:]
+ i += len(rstr)
+ break
+ elif state=='"' or state=="'":
+ data += src[j]
+ elif src[j]=='\n':
+ # if a sign < is not followed by > in the same ligne, it
+ # is the sign "lesser than"
+ src = src[:i]+'<'+src[i+1:]
+ j=i+4
+ break
+ j += 1
+ elif src[i]=='`' and i>0 and src[i-1]!='\\':
+ # ignore the content of inline code
+ j = i+1
+ while j", "&" and "_" in inline code
+ code_pattern = r'\`(.*?)\`'
+ src = re.sub(code_pattern,s_escape,src)
+
+ # replace escaped ` _ * by HTML characters
+ src = src.replace(r'\\`','`')
+ src = src.replace(r'\_','_')
+ src = src.replace(r'\*','*')
+
+ # emphasis
+ strong_patterns = [('STRONG',r'\*\*(.*?)\*\*'),('B',r'__(.*?)__')]
+ for tag,strong_pattern in strong_patterns:
+ src = re.sub(strong_pattern,r'<%s>\1%s>' %(tag,tag),src)
+
+ em_patterns = [('EM',r'\*(.*?)\*'),('I',r'\_(.*?)\_')]
+ for tag,em_pattern in em_patterns:
+ src = re.sub(em_pattern,r'<%s>\1%s>' %(tag,tag),src)
+
+ # inline code
+ code_pattern = r'\`(.*?)\`'
+ src = re.sub(code_pattern,r'\1
',src)
+
+ # restore tags
+ while True:
+ pos = src.rfind(rstr)
+ if pos==-1:
+ break
+ repl = tags.pop()
+ src = src[:pos]+repl+src[pos+len(rstr):]
+
+ src = ''+src+'
'
+
+ t3 = time.time()
+ #print('apply markdown 3', t3-t2)
+
+ return src,scripts
diff --git a/lib/assets/Lib/browser/object_storage.py b/lib/assets/Lib/browser/object_storage.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/browser/object_storage.py
@@ -0,0 +1,51 @@
+import pickle
+
+class __UnProvided():
+ pass
+
+
+class ObjectStorage():
+
+ def __init__(self, storage):
+ self.storage = storage
+
+ def __delitem__(self, key):
+ del self.storage[pickle.dumps(key)]
+
+ def __getitem__(self, key):
+ return pickle.loads(self.storage[pickle.dumps(key)])
+
+ def __setitem__(self, key, value):
+ self.storage[pickle.dumps(key)] = pickle.dumps(value)
+
+ def __contains__(self, key):
+ return pickle.dumps(key) in self.storage
+
+ def get(self, key, default=None):
+ if pickle.dumps(key) in self.storage:
+ return self.storage[pickle.dumps(key)]
+ return default
+
+ def pop(self, key, default=__UnProvided()):
+ if type(default) is __UnProvided or pickle.dumps(key) in self.storage:
+ return pickle.loads(self.storage.pop(pickle.dumps(key)))
+ return default
+
+ def __iter__(self):
+ keys = self.keys()
+ return keys.__iter__()
+
+ def keys(self):
+ return [pickle.loads(key) for key in self.storage.keys()]
+
+ def values(self):
+ return [pickle.loads(val) for val in self.storage.values()]
+
+ def items(self):
+ return list(zip(self.keys(), self.values()))
+
+ def clear(self):
+ self.storage.clear()
+
+ def __len__(self):
+ return len(self.storage)
diff --git a/lib/assets/Lib/browser/session_storage.py b/lib/assets/Lib/browser/session_storage.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/browser/session_storage.py
@@ -0,0 +1,19 @@
+# session storage in browser
+import sys
+from javascript import JSObject
+from browser import window
+from .local_storage import LocalStorage
+
+has_session_storage = hasattr(window, 'sessionStorage')
+
+class SessionStorage(LocalStorage):
+
+ storage_type = "session_storage"
+
+ def __init__(self):
+ if not has_session_storage:
+ raise EnvironmentError("SessionStorage not available")
+ self.store = window.sessionStorage
+
+if has_session_storage:
+ storage = SessionStorage()
diff --git a/lib/assets/Lib/browser/svg.py b/lib/assets/Lib/browser/svg.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/browser/svg.py
@@ -0,0 +1,1 @@
+from _svg import *
\ No newline at end of file
diff --git a/lib/assets/Lib/browser/timer.py b/lib/assets/Lib/browser/timer.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/browser/timer.py
@@ -0,0 +1,34 @@
+from browser import window
+
+def wrap(func):
+ # Transforms a function f into another function that prints a
+ # traceback in case of exception
+ def f(*args, **kw):
+ try:
+ return func(*args, **kw)
+ except Exception as exc:
+ msg = '{0.info}\n{0.__name__}: {0.args[0]}'.format(exc)
+ import sys
+ sys.stderr.write(msg)
+ return f
+
+clear_interval = window.clearInterval
+
+clear_timeout = window.clearTimeout
+
+def set_interval(func,interval):
+ return window.setInterval(wrap(func),interval)
+
+def set_timeout(func,interval):
+ return int(window.setTimeout(wrap(func),interval))
+
+def request_animation_frame(func):
+ return int(window.requestAnimationFrame(func))
+
+def cancel_animation_frame(int_id):
+ window.cancelAnimationFrame(int_id)
+
+def set_loop_timeout(x):
+ # set a variable used to stop loops that last more than x seconds
+ assert isinstance(x, int)
+ __BRYTHON__.loop_timeout = x
\ No newline at end of file
diff --git a/lib/assets/Lib/browser/websocket.py b/lib/assets/Lib/browser/websocket.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/browser/websocket.py
@@ -0,0 +1,10 @@
+from browser import window
+import javascript
+
+if hasattr(window, 'WebSocket'):
+ supported = True
+ WebSocket = javascript.JSConstructor(window.WebSocket)
+else:
+ supported = False
+ def WebSocket(*args,**kw):
+ raise NotImplementedError
\ No newline at end of file
diff --git a/lib/assets/Lib/calendar.py b/lib/assets/Lib/calendar.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/calendar.py
@@ -0,0 +1,703 @@
+"""Calendar printing functions
+
+Note when comparing these calendars to the ones printed by cal(1): By
+default, these calendars have Monday as the first day of the week, and
+Sunday as the last (the European convention). Use setfirstweekday() to
+set the first day of the week (0=Monday, 6=Sunday)."""
+
+import sys
+import datetime
+import locale as _locale
+
+__all__ = ["IllegalMonthError", "IllegalWeekdayError", "setfirstweekday",
+ "firstweekday", "isleap", "leapdays", "weekday", "monthrange",
+ "monthcalendar", "prmonth", "month", "prcal", "calendar",
+ "timegm", "month_name", "month_abbr", "day_name", "day_abbr"]
+
+# Exception raised for bad input (with string parameter for details)
+error = ValueError
+
+# Exceptions raised for bad input
+class IllegalMonthError(ValueError):
+ def __init__(self, month):
+ self.month = month
+ def __str__(self):
+ return "bad month number %r; must be 1-12" % self.month
+
+
+class IllegalWeekdayError(ValueError):
+ def __init__(self, weekday):
+ self.weekday = weekday
+ def __str__(self):
+ return "bad weekday number %r; must be 0 (Monday) to 6 (Sunday)" % self.weekday
+
+
+# Constants for months referenced later
+January = 1
+February = 2
+
+# Number of days per month (except for February in leap years)
+mdays = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
+
+# This module used to have hard-coded lists of day and month names, as
+# English strings. The classes following emulate a read-only version of
+# that, but supply localized names. Note that the values are computed
+# fresh on each call, in case the user changes locale between calls.
+
+class _localized_month:
+
+ _months = [datetime.date(2001, i+1, 1).strftime for i in range(12)]
+ _months.insert(0, lambda x: "")
+
+ def __init__(self, format):
+ self.format = format
+
+ def __getitem__(self, i):
+ funcs = self._months[i]
+ if isinstance(i, slice):
+ return [f(self.format) for f in funcs]
+ else:
+ return funcs(self.format)
+
+ def __len__(self):
+ return 13
+
+
+class _localized_day:
+
+ # January 1, 2001, was a Monday.
+ _days = [datetime.date(2001, 1, i+1).strftime for i in range(7)]
+
+ def __init__(self, format):
+ self.format = format
+
+ def __getitem__(self, i):
+ funcs = self._days[i]
+ if isinstance(i, slice):
+ return [f(self.format) for f in funcs]
+ else:
+ return funcs(self.format)
+
+ def __len__(self):
+ return 7
+
+
+# Full and abbreviated names of weekdays
+day_name = _localized_day('%A')
+day_abbr = _localized_day('%a')
+
+# Full and abbreviated names of months (1-based arrays!!!)
+month_name = _localized_month('%B')
+month_abbr = _localized_month('%b')
+
+# Constants for weekdays
+(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7)
+
+
+def isleap(year):
+ """Return True for leap years, False for non-leap years."""
+ return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
+
+
+def leapdays(y1, y2):
+ """Return number of leap years in range [y1, y2).
+ Assume y1 <= y2."""
+ y1 -= 1
+ y2 -= 1
+ return (y2//4 - y1//4) - (y2//100 - y1//100) + (y2//400 - y1//400)
+
+
+def weekday(year, month, day):
+ """Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12),
+ day (1-31)."""
+ return datetime.date(year, month, day).weekday()
+
+
+def monthrange(year, month):
+ """Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for
+ year, month."""
+ if not 1 <= month <= 12:
+ raise IllegalMonthError(month)
+ day1 = weekday(year, month, 1)
+ ndays = mdays[month] + (month == February and isleap(year))
+ return day1, ndays
+
+
+class Calendar(object):
+ """
+ Base calendar class. This class doesn't do any formatting. It simply
+ provides data to subclasses.
+ """
+
+ def __init__(self, firstweekday=0):
+ self.firstweekday = firstweekday # 0 = Monday, 6 = Sunday
+
+ def getfirstweekday(self):
+ return self._firstweekday % 7
+
+ def setfirstweekday(self, firstweekday):
+ self._firstweekday = firstweekday
+
+ firstweekday = property(getfirstweekday, setfirstweekday)
+
+ def iterweekdays(self):
+ """
+ Return a iterator for one week of weekday numbers starting with the
+ configured first one.
+ """
+ for i in range(self.firstweekday, self.firstweekday + 7):
+ yield i%7
+
+ def itermonthdates(self, year, month):
+ """
+ Return an iterator for one month. The iterator will yield datetime.date
+ values and will always iterate through complete weeks, so it will yield
+ dates outside the specified month.
+ """
+ date = datetime.date(year, month, 1)
+ # Go back to the beginning of the week
+ days = (date.weekday() - self.firstweekday) % 7
+ date -= datetime.timedelta(days=days)
+ oneday = datetime.timedelta(days=1)
+ while True:
+ yield date
+ try:
+ date += oneday
+ except OverflowError:
+ # Adding one day could fail after datetime.MAXYEAR
+ break
+ if date.month != month and date.weekday() == self.firstweekday:
+ break
+
+ def itermonthdays2(self, year, month):
+ """
+ Like itermonthdates(), but will yield (day number, weekday number)
+ tuples. For days outside the specified month the day number is 0.
+ """
+ for date in self.itermonthdates(year, month):
+ if date.month != month:
+ yield (0, date.weekday())
+ else:
+ yield (date.day, date.weekday())
+
+ def itermonthdays(self, year, month):
+ """
+ Like itermonthdates(), but will yield day numbers. For days outside
+ the specified month the day number is 0.
+ """
+ for date in self.itermonthdates(year, month):
+ if date.month != month:
+ yield 0
+ else:
+ yield date.day
+
+ def monthdatescalendar(self, year, month):
+ """
+ Return a matrix (list of lists) representing a month's calendar.
+ Each row represents a week; week entries are datetime.date values.
+ """
+ dates = list(self.itermonthdates(year, month))
+ return [ dates[i:i+7] for i in range(0, len(dates), 7) ]
+
+ def monthdays2calendar(self, year, month):
+ """
+ Return a matrix representing a month's calendar.
+ Each row represents a week; week entries are
+ (day number, weekday number) tuples. Day numbers outside this month
+ are zero.
+ """
+ days = list(self.itermonthdays2(year, month))
+ return [ days[i:i+7] for i in range(0, len(days), 7) ]
+
+ def monthdayscalendar(self, year, month):
+ """
+ Return a matrix representing a month's calendar.
+ Each row represents a week; days outside this month are zero.
+ """
+ days = list(self.itermonthdays(year, month))
+ return [ days[i:i+7] for i in range(0, len(days), 7) ]
+
+ def yeardatescalendar(self, year, width=3):
+ """
+ Return the data for the specified year ready for formatting. The return
+ value is a list of month rows. Each month row contains up to width months.
+ Each month contains between 4 and 6 weeks and each week contains 1-7
+ days. Days are datetime.date objects.
+ """
+ months = [
+ self.monthdatescalendar(year, i)
+ for i in range(January, January+12)
+ ]
+ return [months[i:i+width] for i in range(0, len(months), width) ]
+
+ def yeardays2calendar(self, year, width=3):
+ """
+ Return the data for the specified year ready for formatting (similar to
+ yeardatescalendar()). Entries in the week lists are
+ (day number, weekday number) tuples. Day numbers outside this month are
+ zero.
+ """
+ months = [
+ self.monthdays2calendar(year, i)
+ for i in range(January, January+12)
+ ]
+ return [months[i:i+width] for i in range(0, len(months), width) ]
+
+ def yeardayscalendar(self, year, width=3):
+ """
+ Return the data for the specified year ready for formatting (similar to
+ yeardatescalendar()). Entries in the week lists are day numbers.
+ Day numbers outside this month are zero.
+ """
+ months = [
+ self.monthdayscalendar(year, i)
+ for i in range(January, January+12)
+ ]
+ return [months[i:i+width] for i in range(0, len(months), width) ]
+
+
+class TextCalendar(Calendar):
+ """
+ Subclass of Calendar that outputs a calendar as a simple plain text
+ similar to the UNIX program cal.
+ """
+
+ def prweek(self, theweek, width):
+ """
+ Print a single week (no newline).
+ """
+ print(self.formatweek(theweek, width), end=' ')
+
+ def formatday(self, day, weekday, width):
+ """
+ Returns a formatted day.
+ """
+ if day == 0:
+ s = ''
+ else:
+ s = '%2i' % day # right-align single-digit days
+ return s.center(width)
+
+ def formatweek(self, theweek, width):
+ """
+ Returns a single week in a string (no newline).
+ """
+ return ' '.join(self.formatday(d, wd, width) for (d, wd) in theweek)
+
+ def formatweekday(self, day, width):
+ """
+ Returns a formatted week day name.
+ """
+ if width >= 9:
+ names = day_name
+ else:
+ names = day_abbr
+ return names[day][:width].center(width)
+
+ def formatweekheader(self, width):
+ """
+ Return a header for a week.
+ """
+ return ' '.join(self.formatweekday(i, width) for i in self.iterweekdays())
+
+ def formatmonthname(self, theyear, themonth, width, withyear=True):
+ """
+ Return a formatted month name.
+ """
+ s = month_name[themonth]
+ if withyear:
+ s = "%s %r" % (s, theyear)
+ return s.center(width)
+
+ def prmonth(self, theyear, themonth, w=0, l=0):
+ """
+ Print a month's calendar.
+ """
+ print(self.formatmonth(theyear, themonth, w, l), end=' ')
+
+ def formatmonth(self, theyear, themonth, w=0, l=0):
+ """
+ Return a month's calendar string (multi-line).
+ """
+ w = max(2, w)
+ l = max(1, l)
+ s = self.formatmonthname(theyear, themonth, 7 * (w + 1) - 1)
+ s = s.rstrip()
+ s += '\n' * l
+ s += self.formatweekheader(w).rstrip()
+ s += '\n' * l
+ for week in self.monthdays2calendar(theyear, themonth):
+ s += self.formatweek(week, w).rstrip()
+ s += '\n' * l
+ return s
+
+ def formatyear(self, theyear, w=2, l=1, c=6, m=3):
+ """
+ Returns a year's calendar as a multi-line string.
+ """
+ w = max(2, w)
+ l = max(1, l)
+ c = max(2, c)
+ colwidth = (w + 1) * 7 - 1
+ v = []
+ a = v.append
+ a(repr(theyear).center(colwidth*m+c*(m-1)).rstrip())
+ a('\n'*l)
+ header = self.formatweekheader(w)
+ for (i, row) in enumerate(self.yeardays2calendar(theyear, m)):
+ # months in this row
+ months = range(m*i+1, min(m*(i+1)+1, 13))
+ a('\n'*l)
+ names = (self.formatmonthname(theyear, k, colwidth, False)
+ for k in months)
+ a(formatstring(names, colwidth, c).rstrip())
+ a('\n'*l)
+ headers = (header for k in months)
+ a(formatstring(headers, colwidth, c).rstrip())
+ a('\n'*l)
+ # max number of weeks for this row
+ height = max(len(cal) for cal in row)
+ for j in range(height):
+ weeks = []
+ for cal in row:
+ if j >= len(cal):
+ weeks.append('')
+ else:
+ weeks.append(self.formatweek(cal[j], w))
+ a(formatstring(weeks, colwidth, c).rstrip())
+ a('\n' * l)
+ return ''.join(v)
+
+ def pryear(self, theyear, w=0, l=0, c=6, m=3):
+ """Print a year's calendar."""
+ print(self.formatyear(theyear, w, l, c, m))
+
+
+class HTMLCalendar(Calendar):
+ """
+ This calendar returns complete HTML pages.
+ """
+
+ # CSS classes for the day s
+ cssclasses = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]
+
+ def formatday(self, day, weekday):
+ """
+ Return a day as a table cell.
+ """
+ if day == 0:
+ return ' ' # day outside month
+ else:
+ return '%d ' % (self.cssclasses[weekday], day)
+
+ def formatweek(self, theweek):
+ """
+ Return a complete week as a table row.
+ """
+ s = ''.join(self.formatday(d, wd) for (d, wd) in theweek)
+ return '%s ' % s
+
+ def formatweekday(self, day):
+ """
+ Return a weekday name as a table header.
+ """
+ return '%s ' % (self.cssclasses[day], day_abbr[day])
+
+ def formatweekheader(self):
+ """
+ Return a header for a week as a table row.
+ """
+ s = ''.join(self.formatweekday(i) for i in self.iterweekdays())
+ return '%s ' % s
+
+ def formatmonthname(self, theyear, themonth, withyear=True):
+ """
+ Return a month name as a table row.
+ """
+ if withyear:
+ s = '%s %s' % (month_name[themonth], theyear)
+ else:
+ s = '%s' % month_name[themonth]
+ return '%s ' % s
+
+ def formatmonth(self, theyear, themonth, withyear=True):
+ """
+ Return a formatted month as a table.
+ """
+ v = []
+ a = v.append
+ a('')
+ a('\n')
+ a(self.formatmonthname(theyear, themonth, withyear=withyear))
+ a('\n')
+ a(self.formatweekheader())
+ a('\n')
+ for week in self.monthdays2calendar(theyear, themonth):
+ a(self.formatweek(week))
+ a('\n')
+ a('
')
+ a('\n')
+ return ''.join(v)
+
+ def formatyear(self, theyear, width=3):
+ """
+ Return a formatted year as a table of tables.
+ """
+ v = []
+ a = v.append
+ width = max(width, 1)
+ a('')
+ a('\n')
+ a('%s ' % (width, theyear))
+ for i in range(January, January+12, width):
+ # months in this row
+ months = range(i, min(i+width, 13))
+ a('')
+ for m in months:
+ a('')
+ a(self.formatmonth(theyear, m, withyear=False))
+ a(' ')
+ a(' ')
+ a('
')
+ return ''.join(v)
+
+ def formatyearpage(self, theyear, width=3, css='calendar.css', encoding=None):
+ """
+ Return a formatted year as a complete HTML page.
+ """
+ if encoding is None:
+ encoding = sys.getdefaultencoding()
+ v = []
+ a = v.append
+ a('\n' % encoding)
+ a('\n')
+ a('\n')
+ a('\n')
+ a('\n' % encoding)
+ if css is not None:
+ a('\n' % css)
+ a('Calendar for %d \n' % theyear)
+ a('\n')
+ a('\n')
+ a(self.formatyear(theyear, width))
+ a('\n')
+ a('\n')
+ return ''.join(v).encode(encoding, "xmlcharrefreplace")
+
+
+class different_locale:
+ def __init__(self, locale):
+ self.locale = locale
+
+ def __enter__(self):
+ self.oldlocale = _locale.getlocale(_locale.LC_TIME)
+ _locale.setlocale(_locale.LC_TIME, self.locale)
+
+ def __exit__(self, *args):
+ _locale.setlocale(_locale.LC_TIME, self.oldlocale)
+
+
+class LocaleTextCalendar(TextCalendar):
+ """
+ This class can be passed a locale name in the constructor and will return
+ month and weekday names in the specified locale. If this locale includes
+ an encoding all strings containing month and weekday names will be returned
+ as unicode.
+ """
+
+ def __init__(self, firstweekday=0, locale=None):
+ TextCalendar.__init__(self, firstweekday)
+ if locale is None:
+ locale = _locale.getdefaultlocale()
+ self.locale = locale
+
+ def formatweekday(self, day, width):
+ with different_locale(self.locale):
+ if width >= 9:
+ names = day_name
+ else:
+ names = day_abbr
+ name = names[day]
+ return name[:width].center(width)
+
+ def formatmonthname(self, theyear, themonth, width, withyear=True):
+ with different_locale(self.locale):
+ s = month_name[themonth]
+ if withyear:
+ s = "%s %r" % (s, theyear)
+ return s.center(width)
+
+
+class LocaleHTMLCalendar(HTMLCalendar):
+ """
+ This class can be passed a locale name in the constructor and will return
+ month and weekday names in the specified locale. If this locale includes
+ an encoding all strings containing month and weekday names will be returned
+ as unicode.
+ """
+ def __init__(self, firstweekday=0, locale=None):
+ HTMLCalendar.__init__(self, firstweekday)
+ if locale is None:
+ locale = _locale.getdefaultlocale()
+ self.locale = locale
+
+ def formatweekday(self, day):
+ with different_locale(self.locale):
+ s = day_abbr[day]
+ return '%s ' % (self.cssclasses[day], s)
+
+ def formatmonthname(self, theyear, themonth, withyear=True):
+ with different_locale(self.locale):
+ s = month_name[themonth]
+ if withyear:
+ s = '%s %s' % (s, theyear)
+ return '%s ' % s
+
+
+# Support for old module level interface
+c = TextCalendar()
+
+firstweekday = c.getfirstweekday
+
+def setfirstweekday(firstweekday):
+ if not MONDAY <= firstweekday <= SUNDAY:
+ raise IllegalWeekdayError(firstweekday)
+ c.firstweekday = firstweekday
+
+monthcalendar = c.monthdayscalendar
+prweek = c.prweek
+week = c.formatweek
+weekheader = c.formatweekheader
+prmonth = c.prmonth
+month = c.formatmonth
+calendar = c.formatyear
+prcal = c.pryear
+
+
+# Spacing of month columns for multi-column year calendar
+_colwidth = 7*3 - 1 # Amount printed by prweek()
+_spacing = 6 # Number of spaces between columns
+
+
+def format(cols, colwidth=_colwidth, spacing=_spacing):
+ """Prints multi-column formatting for year calendars"""
+ print(formatstring(cols, colwidth, spacing))
+
+
+def formatstring(cols, colwidth=_colwidth, spacing=_spacing):
+ """Returns a string formatted from n strings, centered within n columns."""
+ spacing *= ' '
+ return spacing.join(c.center(colwidth) for c in cols)
+
+
+EPOCH = 1970
+_EPOCH_ORD = datetime.date(EPOCH, 1, 1).toordinal()
+
+
+def timegm(tuple):
+ """Unrelated but handy function to calculate Unix timestamp from GMT."""
+ year, month, day, hour, minute, second = tuple[:6]
+ days = datetime.date(year, month, 1).toordinal() - _EPOCH_ORD + day - 1
+ hours = days*24 + hour
+ minutes = hours*60 + minute
+ seconds = minutes*60 + second
+ return seconds
+
+
+def main(args):
+ import optparse
+ parser = optparse.OptionParser(usage="usage: %prog [options] [year [month]]")
+ parser.add_option(
+ "-w", "--width",
+ dest="width", type="int", default=2,
+ help="width of date column (default 2, text only)"
+ )
+ parser.add_option(
+ "-l", "--lines",
+ dest="lines", type="int", default=1,
+ help="number of lines for each week (default 1, text only)"
+ )
+ parser.add_option(
+ "-s", "--spacing",
+ dest="spacing", type="int", default=6,
+ help="spacing between months (default 6, text only)"
+ )
+ parser.add_option(
+ "-m", "--months",
+ dest="months", type="int", default=3,
+ help="months per row (default 3, text only)"
+ )
+ parser.add_option(
+ "-c", "--css",
+ dest="css", default="calendar.css",
+ help="CSS to use for page (html only)"
+ )
+ parser.add_option(
+ "-L", "--locale",
+ dest="locale", default=None,
+ help="locale to be used from month and weekday names"
+ )
+ parser.add_option(
+ "-e", "--encoding",
+ dest="encoding", default=None,
+ help="Encoding to use for output."
+ )
+ parser.add_option(
+ "-t", "--type",
+ dest="type", default="text",
+ choices=("text", "html"),
+ help="output type (text or html)"
+ )
+
+ (options, args) = parser.parse_args(args)
+
+ if options.locale and not options.encoding:
+ parser.error("if --locale is specified --encoding is required")
+ sys.exit(1)
+
+ locale = options.locale, options.encoding
+
+ if options.type == "html":
+ if options.locale:
+ cal = LocaleHTMLCalendar(locale=locale)
+ else:
+ cal = HTMLCalendar()
+ encoding = options.encoding
+ if encoding is None:
+ encoding = sys.getdefaultencoding()
+ optdict = dict(encoding=encoding, css=options.css)
+ write = sys.stdout.buffer.write
+ if len(args) == 1:
+ write(cal.formatyearpage(datetime.date.today().year, **optdict))
+ elif len(args) == 2:
+ write(cal.formatyearpage(int(args[1]), **optdict))
+ else:
+ parser.error("incorrect number of arguments")
+ sys.exit(1)
+ else:
+ if options.locale:
+ cal = LocaleTextCalendar(locale=locale)
+ else:
+ cal = TextCalendar()
+ optdict = dict(w=options.width, l=options.lines)
+ if len(args) != 3:
+ optdict["c"] = options.spacing
+ optdict["m"] = options.months
+ if len(args) == 1:
+ result = cal.formatyear(datetime.date.today().year, **optdict)
+ elif len(args) == 2:
+ result = cal.formatyear(int(args[1]), **optdict)
+ elif len(args) == 3:
+ result = cal.formatmonth(int(args[1]), int(args[2]), **optdict)
+ else:
+ parser.error("incorrect number of arguments")
+ sys.exit(1)
+ write = sys.stdout.write
+ if options.encoding:
+ result = result.encode(options.encoding)
+ write = sys.stdout.buffer.write
+ write(result)
+
+
+if __name__ == "__main__":
+ main(sys.argv)
diff --git a/lib/assets/Lib/cmd.py b/lib/assets/Lib/cmd.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/cmd.py
@@ -0,0 +1,401 @@
+"""A generic class to build line-oriented command interpreters.
+
+Interpreters constructed with this class obey the following conventions:
+
+1. End of file on input is processed as the command 'EOF'.
+2. A command is parsed out of each line by collecting the prefix composed
+ of characters in the identchars member.
+3. A command `foo' is dispatched to a method 'do_foo()'; the do_ method
+ is passed a single argument consisting of the remainder of the line.
+4. Typing an empty line repeats the last command. (Actually, it calls the
+ method `emptyline', which may be overridden in a subclass.)
+5. There is a predefined `help' method. Given an argument `topic', it
+ calls the command `help_topic'. With no arguments, it lists all topics
+ with defined help_ functions, broken into up to three topics; documented
+ commands, miscellaneous help topics, and undocumented commands.
+6. The command '?' is a synonym for `help'. The command '!' is a synonym
+ for `shell', if a do_shell method exists.
+7. If completion is enabled, completing commands will be done automatically,
+ and completing of commands args is done by calling complete_foo() with
+ arguments text, line, begidx, endidx. text is string we are matching
+ against, all returned matches must begin with it. line is the current
+ input line (lstripped), begidx and endidx are the beginning and end
+ indexes of the text being matched, which could be used to provide
+ different completion depending upon which position the argument is in.
+
+The `default' method may be overridden to intercept commands for which there
+is no do_ method.
+
+The `completedefault' method may be overridden to intercept completions for
+commands that have no complete_ method.
+
+The data member `self.ruler' sets the character used to draw separator lines
+in the help messages. If empty, no ruler line is drawn. It defaults to "=".
+
+If the value of `self.intro' is nonempty when the cmdloop method is called,
+it is printed out on interpreter startup. This value may be overridden
+via an optional argument to the cmdloop() method.
+
+The data members `self.doc_header', `self.misc_header', and
+`self.undoc_header' set the headers used for the help function's
+listings of documented functions, miscellaneous topics, and undocumented
+functions respectively.
+"""
+
+import string, sys
+
+__all__ = ["Cmd"]
+
+PROMPT = '(Cmd) '
+IDENTCHARS = string.ascii_letters + string.digits + '_'
+
+class Cmd:
+ """A simple framework for writing line-oriented command interpreters.
+
+ These are often useful for test harnesses, administrative tools, and
+ prototypes that will later be wrapped in a more sophisticated interface.
+
+ A Cmd instance or subclass instance is a line-oriented interpreter
+ framework. There is no good reason to instantiate Cmd itself; rather,
+ it's useful as a superclass of an interpreter class you define yourself
+ in order to inherit Cmd's methods and encapsulate action methods.
+
+ """
+ prompt = PROMPT
+ identchars = IDENTCHARS
+ ruler = '='
+ lastcmd = ''
+ intro = None
+ doc_leader = ""
+ doc_header = "Documented commands (type help ):"
+ misc_header = "Miscellaneous help topics:"
+ undoc_header = "Undocumented commands:"
+ nohelp = "*** No help on %s"
+ use_rawinput = 1
+
+ def __init__(self, completekey='tab', stdin=None, stdout=None):
+ """Instantiate a line-oriented interpreter framework.
+
+ The optional argument 'completekey' is the readline name of a
+ completion key; it defaults to the Tab key. If completekey is
+ not None and the readline module is available, command completion
+ is done automatically. The optional arguments stdin and stdout
+ specify alternate input and output file objects; if not specified,
+ sys.stdin and sys.stdout are used.
+
+ """
+ if stdin is not None:
+ self.stdin = stdin
+ else:
+ self.stdin = sys.stdin
+ if stdout is not None:
+ self.stdout = stdout
+ else:
+ self.stdout = sys.stdout
+ self.cmdqueue = []
+ self.completekey = completekey
+
+ def cmdloop(self, intro=None):
+ """Repeatedly issue a prompt, accept input, parse an initial prefix
+ off the received input, and dispatch to action methods, passing them
+ the remainder of the line as argument.
+
+ """
+
+ self.preloop()
+ if self.use_rawinput and self.completekey:
+ try:
+ import readline
+ self.old_completer = readline.get_completer()
+ readline.set_completer(self.complete)
+ readline.parse_and_bind(self.completekey+": complete")
+ except ImportError:
+ pass
+ try:
+ if intro is not None:
+ self.intro = intro
+ if self.intro:
+ self.stdout.write(str(self.intro)+"\n")
+ stop = None
+ while not stop:
+ if self.cmdqueue:
+ line = self.cmdqueue.pop(0)
+ else:
+ if self.use_rawinput:
+ try:
+ line = input(self.prompt)
+ except EOFError:
+ line = 'EOF'
+ else:
+ self.stdout.write(self.prompt)
+ self.stdout.flush()
+ line = self.stdin.readline()
+ if not len(line):
+ line = 'EOF'
+ else:
+ line = line.rstrip('\r\n')
+ line = self.precmd(line)
+ stop = self.onecmd(line)
+ stop = self.postcmd(stop, line)
+ self.postloop()
+ finally:
+ if self.use_rawinput and self.completekey:
+ try:
+ import readline
+ readline.set_completer(self.old_completer)
+ except ImportError:
+ pass
+
+
+ def precmd(self, line):
+ """Hook method executed just before the command line is
+ interpreted, but after the input prompt is generated and issued.
+
+ """
+ return line
+
+ def postcmd(self, stop, line):
+ """Hook method executed just after a command dispatch is finished."""
+ return stop
+
+ def preloop(self):
+ """Hook method executed once when the cmdloop() method is called."""
+ pass
+
+ def postloop(self):
+ """Hook method executed once when the cmdloop() method is about to
+ return.
+
+ """
+ pass
+
+ def parseline(self, line):
+ """Parse the line into a command name and a string containing
+ the arguments. Returns a tuple containing (command, args, line).
+ 'command' and 'args' may be None if the line couldn't be parsed.
+ """
+ line = line.strip()
+ if not line:
+ return None, None, line
+ elif line[0] == '?':
+ line = 'help ' + line[1:]
+ elif line[0] == '!':
+ if hasattr(self, 'do_shell'):
+ line = 'shell ' + line[1:]
+ else:
+ return None, None, line
+ i, n = 0, len(line)
+ while i < n and line[i] in self.identchars: i = i+1
+ cmd, arg = line[:i], line[i:].strip()
+ return cmd, arg, line
+
+ def onecmd(self, line):
+ """Interpret the argument as though it had been typed in response
+ to the prompt.
+
+ This may be overridden, but should not normally need to be;
+ see the precmd() and postcmd() methods for useful execution hooks.
+ The return value is a flag indicating whether interpretation of
+ commands by the interpreter should stop.
+
+ """
+ cmd, arg, line = self.parseline(line)
+ if not line:
+ return self.emptyline()
+ if cmd is None:
+ return self.default(line)
+ self.lastcmd = line
+ if line == 'EOF' :
+ self.lastcmd = ''
+ if cmd == '':
+ return self.default(line)
+ else:
+ try:
+ func = getattr(self, 'do_' + cmd)
+ except AttributeError:
+ return self.default(line)
+ return func(arg)
+
+ def emptyline(self):
+ """Called when an empty line is entered in response to the prompt.
+
+ If this method is not overridden, it repeats the last nonempty
+ command entered.
+
+ """
+ if self.lastcmd:
+ return self.onecmd(self.lastcmd)
+
+ def default(self, line):
+ """Called on an input line when the command prefix is not recognized.
+
+ If this method is not overridden, it prints an error message and
+ returns.
+
+ """
+ self.stdout.write('*** Unknown syntax: %s\n'%line)
+
+ def completedefault(self, *ignored):
+ """Method called to complete an input line when no command-specific
+ complete_*() method is available.
+
+ By default, it returns an empty list.
+
+ """
+ return []
+
+ def completenames(self, text, *ignored):
+ dotext = 'do_'+text
+ return [a[3:] for a in self.get_names() if a.startswith(dotext)]
+
+ def complete(self, text, state):
+ """Return the next possible completion for 'text'.
+
+ If a command has not been entered, then complete against command list.
+ Otherwise try to call complete_ to get list of completions.
+ """
+ if state == 0:
+ import readline
+ origline = readline.get_line_buffer()
+ line = origline.lstrip()
+ stripped = len(origline) - len(line)
+ begidx = readline.get_begidx() - stripped
+ endidx = readline.get_endidx() - stripped
+ if begidx>0:
+ cmd, args, foo = self.parseline(line)
+ if cmd == '':
+ compfunc = self.completedefault
+ else:
+ try:
+ compfunc = getattr(self, 'complete_' + cmd)
+ except AttributeError:
+ compfunc = self.completedefault
+ else:
+ compfunc = self.completenames
+ self.completion_matches = compfunc(text, line, begidx, endidx)
+ try:
+ return self.completion_matches[state]
+ except IndexError:
+ return None
+
+ def get_names(self):
+ # This method used to pull in base class attributes
+ # at a time dir() didn't do it yet.
+ return dir(self.__class__)
+
+ def complete_help(self, *args):
+ commands = set(self.completenames(*args))
+ topics = set(a[5:] for a in self.get_names()
+ if a.startswith('help_' + args[0]))
+ return list(commands | topics)
+
+ def do_help(self, arg):
+ 'List available commands with "help" or detailed help with "help cmd".'
+ if arg:
+ # XXX check arg syntax
+ try:
+ func = getattr(self, 'help_' + arg)
+ except AttributeError:
+ try:
+ doc=getattr(self, 'do_' + arg).__doc__
+ if doc:
+ self.stdout.write("%s\n"%str(doc))
+ return
+ except AttributeError:
+ pass
+ self.stdout.write("%s\n"%str(self.nohelp % (arg,)))
+ return
+ func()
+ else:
+ names = self.get_names()
+ cmds_doc = []
+ cmds_undoc = []
+ help = {}
+ for name in names:
+ if name[:5] == 'help_':
+ help[name[5:]]=1
+ names.sort()
+ # There can be duplicates if routines overridden
+ prevname = ''
+ for name in names:
+ if name[:3] == 'do_':
+ if name == prevname:
+ continue
+ prevname = name
+ cmd=name[3:]
+ if cmd in help:
+ cmds_doc.append(cmd)
+ del help[cmd]
+ elif getattr(self, name).__doc__:
+ cmds_doc.append(cmd)
+ else:
+ cmds_undoc.append(cmd)
+ self.stdout.write("%s\n"%str(self.doc_leader))
+ self.print_topics(self.doc_header, cmds_doc, 15,80)
+ self.print_topics(self.misc_header, list(help.keys()),15,80)
+ self.print_topics(self.undoc_header, cmds_undoc, 15,80)
+
+ def print_topics(self, header, cmds, cmdlen, maxcol):
+ if cmds:
+ self.stdout.write("%s\n"%str(header))
+ if self.ruler:
+ self.stdout.write("%s\n"%str(self.ruler * len(header)))
+ self.columnize(cmds, maxcol-1)
+ self.stdout.write("\n")
+
+ def columnize(self, list, displaywidth=80):
+ """Display a list of strings as a compact set of columns.
+
+ Each column is only as wide as necessary.
+ Columns are separated by two spaces (one was not legible enough).
+ """
+ if not list:
+ self.stdout.write("\n")
+ return
+
+ nonstrings = [i for i in range(len(list))
+ if not isinstance(list[i], str)]
+ if nonstrings:
+ raise TypeError("list[i] not a string for i in %s"
+ % ", ".join(map(str, nonstrings)))
+ size = len(list)
+ if size == 1:
+ self.stdout.write('%s\n'%str(list[0]))
+ return
+ # Try every row count from 1 upwards
+ for nrows in range(1, len(list)):
+ ncols = (size+nrows-1) // nrows
+ colwidths = []
+ totwidth = -2
+ for col in range(ncols):
+ colwidth = 0
+ for row in range(nrows):
+ i = row + nrows*col
+ if i >= size:
+ break
+ x = list[i]
+ colwidth = max(colwidth, len(x))
+ colwidths.append(colwidth)
+ totwidth += colwidth + 2
+ if totwidth > displaywidth:
+ break
+ if totwidth <= displaywidth:
+ break
+ else:
+ nrows = len(list)
+ ncols = 1
+ colwidths = [0]
+ for row in range(nrows):
+ texts = []
+ for col in range(ncols):
+ i = row + nrows*col
+ if i >= size:
+ x = ""
+ else:
+ x = list[i]
+ texts.append(x)
+ while texts and not texts[-1]:
+ del texts[-1]
+ for col in range(len(texts)):
+ texts[col] = texts[col].ljust(colwidths[col])
+ self.stdout.write("%s\n"%str(" ".join(texts)))
diff --git a/lib/assets/Lib/code.py b/lib/assets/Lib/code.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/code.py
@@ -0,0 +1,302 @@
+"""Utilities needed to emulate Python's interactive interpreter.
+
+"""
+
+# Inspired by similar code by Jeff Epler and Fredrik Lundh.
+
+
+import sys
+import traceback
+from codeop import CommandCompiler, compile_command
+
+__all__ = ["InteractiveInterpreter", "InteractiveConsole", "interact",
+ "compile_command"]
+
+class InteractiveInterpreter:
+ """Base class for InteractiveConsole.
+
+ This class deals with parsing and interpreter state (the user's
+ namespace); it doesn't deal with input buffering or prompting or
+ input file naming (the filename is always passed in explicitly).
+
+ """
+
+ def __init__(self, locals=None):
+ """Constructor.
+
+ The optional 'locals' argument specifies the dictionary in
+ which code will be executed; it defaults to a newly created
+ dictionary with key "__name__" set to "__console__" and key
+ "__doc__" set to None.
+
+ """
+ if locals is None:
+ locals = {"__name__": "__console__", "__doc__": None}
+ self.locals = locals
+ self.compile = CommandCompiler()
+
+ def runsource(self, source, filename="", symbol="single"):
+ """Compile and run some source in the interpreter.
+
+ Arguments are as for compile_command().
+
+ One several things can happen:
+
+ 1) The input is incorrect; compile_command() raised an
+ exception (SyntaxError or OverflowError). A syntax traceback
+ will be printed by calling the showsyntaxerror() method.
+
+ 2) The input is incomplete, and more input is required;
+ compile_command() returned None. Nothing happens.
+
+ 3) The input is complete; compile_command() returned a code
+ object. The code is executed by calling self.runcode() (which
+ also handles run-time exceptions, except for SystemExit).
+
+ The return value is True in case 2, False in the other cases (unless
+ an exception is raised). The return value can be used to
+ decide whether to use sys.ps1 or sys.ps2 to prompt the next
+ line.
+
+ """
+ try:
+ code = self.compile(source, filename, symbol)
+ except (OverflowError, SyntaxError, ValueError):
+ # Case 1
+ self.showsyntaxerror(filename)
+ return False
+
+ if code is None:
+ # Case 2
+ return True
+
+ # Case 3
+ self.runcode(code)
+ return False
+
+ def runcode(self, code):
+ """Execute a code object.
+
+ When an exception occurs, self.showtraceback() is called to
+ display a traceback. All exceptions are caught except
+ SystemExit, which is reraised.
+
+ A note about KeyboardInterrupt: this exception may occur
+ elsewhere in this code, and may not always be caught. The
+ caller should be prepared to deal with it.
+
+ """
+ try:
+ exec(code, self.locals)
+ except SystemExit:
+ raise
+ except:
+ self.showtraceback()
+
+ def showsyntaxerror(self, filename=None):
+ """Display the syntax error that just occurred.
+
+ This doesn't display a stack trace because there isn't one.
+
+ If a filename is given, it is stuffed in the exception instead
+ of what was there before (because Python's parser always uses
+ "" when reading from a string).
+
+ The output is written by self.write(), below.
+
+ """
+ type, value, tb = sys.exc_info()
+ sys.last_type = type
+ sys.last_value = value
+ sys.last_traceback = tb
+ if filename and type is SyntaxError:
+ # Work hard to stuff the correct filename in the exception
+ try:
+ msg, (dummy_filename, lineno, offset, line) = value.args
+ except ValueError:
+ # Not the format we expect; leave it alone
+ pass
+ else:
+ # Stuff in the right filename
+ value = SyntaxError(msg, (filename, lineno, offset, line))
+ sys.last_value = value
+ if sys.excepthook is sys.__excepthook__:
+ lines = traceback.format_exception_only(type, value)
+ self.write(''.join(lines))
+ else:
+ # If someone has set sys.excepthook, we let that take precedence
+ # over self.write
+ sys.excepthook(type, value, tb)
+
+ def showtraceback(self):
+ """Display the exception that just occurred.
+
+ We remove the first stack item because it is our own code.
+
+ The output is written by self.write(), below.
+
+ """
+ try:
+ type, value, tb = sys.exc_info()
+ sys.last_type = type
+ sys.last_value = value
+ sys.last_traceback = tb
+ tblist = traceback.extract_tb(tb)
+ del tblist[:1]
+ lines = traceback.format_list(tblist)
+ if lines:
+ lines.insert(0, "Traceback (most recent call last):\n")
+ lines.extend(traceback.format_exception_only(type, value))
+ finally:
+ tblist = tb = None
+ if sys.excepthook is sys.__excepthook__:
+ self.write(''.join(lines))
+ else:
+ # If someone has set sys.excepthook, we let that take precedence
+ # over self.write
+ sys.excepthook(type, value, tb)
+
+ def write(self, data):
+ """Write a string.
+
+ The base implementation writes to sys.stderr; a subclass may
+ replace this with a different implementation.
+
+ """
+ sys.stderr.write(data)
+
+
+class InteractiveConsole(InteractiveInterpreter):
+ """Closely emulate the behavior of the interactive Python interpreter.
+
+ This class builds on InteractiveInterpreter and adds prompting
+ using the familiar sys.ps1 and sys.ps2, and input buffering.
+
+ """
+
+ def __init__(self, locals=None, filename=""):
+ """Constructor.
+
+ The optional locals argument will be passed to the
+ InteractiveInterpreter base class.
+
+ The optional filename argument should specify the (file)name
+ of the input stream; it will show up in tracebacks.
+
+ """
+ InteractiveInterpreter.__init__(self, locals)
+ self.filename = filename
+ self.resetbuffer()
+
+ def resetbuffer(self):
+ """Reset the input buffer."""
+ self.buffer = []
+
+ def interact(self, banner=None):
+ """Closely emulate the interactive Python console.
+
+ The optional banner argument specifies the banner to print
+ before the first interaction; by default it prints a banner
+ similar to the one printed by the real Python interpreter,
+ followed by the current class name in parentheses (so as not
+ to confuse this with the real interpreter -- since it's so
+ close!).
+
+ """
+ try:
+ sys.ps1
+ except AttributeError:
+ sys.ps1 = ">>> "
+ try:
+ sys.ps2
+ except AttributeError:
+ sys.ps2 = "... "
+ cprt = 'Type "help", "copyright", "credits" or "license" for more information.'
+ if banner is None:
+ self.write("Python %s on %s\n%s\n(%s)\n" %
+ (sys.version, sys.platform, cprt,
+ self.__class__.__name__))
+ elif banner:
+ self.write("%s\n" % str(banner))
+ more = 0
+ while 1:
+ try:
+ if more:
+ prompt = sys.ps2
+ else:
+ prompt = sys.ps1
+ try:
+ line = self.raw_input(prompt)
+ except EOFError:
+ self.write("\n")
+ break
+ else:
+ more = self.push(line)
+ except KeyboardInterrupt:
+ self.write("\nKeyboardInterrupt\n")
+ self.resetbuffer()
+ more = 0
+
+ def push(self, line):
+ """Push a line to the interpreter.
+
+ The line should not have a trailing newline; it may have
+ internal newlines. The line is appended to a buffer and the
+ interpreter's runsource() method is called with the
+ concatenated contents of the buffer as source. If this
+ indicates that the command was executed or invalid, the buffer
+ is reset; otherwise, the command is incomplete, and the buffer
+ is left as it was after the line was appended. The return
+ value is 1 if more input is required, 0 if the line was dealt
+ with in some way (this is the same as runsource()).
+
+ """
+ self.buffer.append(line)
+ source = "\n".join(self.buffer)
+ more = self.runsource(source, self.filename)
+ if not more:
+ self.resetbuffer()
+ return more
+
+ def raw_input(self, prompt=""):
+ """Write a prompt and read a line.
+
+ The returned line does not include the trailing newline.
+ When the user enters the EOF key sequence, EOFError is raised.
+
+ The base implementation uses the built-in function
+ input(); a subclass may replace this with a different
+ implementation.
+
+ """
+ return input(prompt)
+
+
+
+def interact(banner=None, readfunc=None, local=None):
+ """Closely emulate the interactive Python interpreter.
+
+ This is a backwards compatible interface to the InteractiveConsole
+ class. When readfunc is not specified, it attempts to import the
+ readline module to enable GNU readline if it is available.
+
+ Arguments (all optional, all default to None):
+
+ banner -- passed to InteractiveConsole.interact()
+ readfunc -- if not None, replaces InteractiveConsole.raw_input()
+ local -- passed to InteractiveInterpreter.__init__()
+
+ """
+ console = InteractiveConsole(local)
+ if readfunc is not None:
+ console.raw_input = readfunc
+ else:
+ try:
+ import readline
+ except ImportError:
+ pass
+ console.interact(banner)
+
+
+if __name__ == "__main__":
+ interact()
diff --git a/lib/assets/Lib/codecs.py b/lib/assets/Lib/codecs.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/codecs.py
@@ -0,0 +1,1099 @@
+""" codecs -- Python Codec Registry, API and helpers.
+
+
+Written by Marc-Andre Lemburg (mal@lemburg.com).
+
+(c) Copyright CNRI, All Rights Reserved. NO WARRANTY.
+
+"""#"
+
+import builtins, sys
+
+### Registry and builtin stateless codec functions
+
+try:
+ from _codecs import *
+except ImportError as why:
+ raise SystemError('Failed to load the builtin codecs: %s' % why)
+
+__all__ = ["register", "lookup", "open", "EncodedFile", "BOM", "BOM_BE",
+ "BOM_LE", "BOM32_BE", "BOM32_LE", "BOM64_BE", "BOM64_LE",
+ "BOM_UTF8", "BOM_UTF16", "BOM_UTF16_LE", "BOM_UTF16_BE",
+ "BOM_UTF32", "BOM_UTF32_LE", "BOM_UTF32_BE",
+ "strict_errors", "ignore_errors", "replace_errors",
+ "xmlcharrefreplace_errors",
+ "register_error", "lookup_error"]
+
+### Constants
+
+#
+# Byte Order Mark (BOM = ZERO WIDTH NO-BREAK SPACE = U+FEFF)
+# and its possible byte string values
+# for UTF8/UTF16/UTF32 output and little/big endian machines
+#
+
+# UTF-8
+BOM_UTF8 = b'\xef\xbb\xbf'
+
+# UTF-16, little endian
+BOM_LE = BOM_UTF16_LE = b'\xff\xfe'
+
+# UTF-16, big endian
+BOM_BE = BOM_UTF16_BE = b'\xfe\xff'
+
+# UTF-32, little endian
+BOM_UTF32_LE = b'\xff\xfe\x00\x00'
+
+# UTF-32, big endian
+BOM_UTF32_BE = b'\x00\x00\xfe\xff'
+
+if sys.byteorder == 'little':
+
+ # UTF-16, native endianness
+ BOM = BOM_UTF16 = BOM_UTF16_LE
+
+ # UTF-32, native endianness
+ BOM_UTF32 = BOM_UTF32_LE
+
+else:
+
+ # UTF-16, native endianness
+ BOM = BOM_UTF16 = BOM_UTF16_BE
+
+ # UTF-32, native endianness
+ BOM_UTF32 = BOM_UTF32_BE
+
+# Old broken names (don't use in new code)
+BOM32_LE = BOM_UTF16_LE
+BOM32_BE = BOM_UTF16_BE
+BOM64_LE = BOM_UTF32_LE
+BOM64_BE = BOM_UTF32_BE
+
+
+### Codec base classes (defining the API)
+
+class CodecInfo(tuple):
+
+ def __new__(cls, encode, decode, streamreader=None, streamwriter=None,
+ incrementalencoder=None, incrementaldecoder=None, name=None):
+ self = tuple.__new__(cls, (encode, decode, streamreader, streamwriter))
+ self.name = name
+ self.encode = encode
+ self.decode = decode
+ self.incrementalencoder = incrementalencoder
+ self.incrementaldecoder = incrementaldecoder
+ self.streamwriter = streamwriter
+ self.streamreader = streamreader
+ return self
+
+ def __repr__(self):
+ return "<%s.%s object for encoding %s at 0x%x>" % \
+ (self.__class__.__module__, self.__class__.__name__,
+ self.name, id(self))
+
+class Codec:
+
+ """ Defines the interface for stateless encoders/decoders.
+
+ The .encode()/.decode() methods may use different error
+ handling schemes by providing the errors argument. These
+ string values are predefined:
+
+ 'strict' - raise a ValueError error (or a subclass)
+ 'ignore' - ignore the character and continue with the next
+ 'replace' - replace with a suitable replacement character;
+ Python will use the official U+FFFD REPLACEMENT
+ CHARACTER for the builtin Unicode codecs on
+ decoding and '?' on encoding.
+ 'surrogateescape' - replace with private codepoints U+DCnn.
+ 'xmlcharrefreplace' - Replace with the appropriate XML
+ character reference (only for encoding).
+ 'backslashreplace' - Replace with backslashed escape sequences
+ (only for encoding).
+
+ The set of allowed values can be extended via register_error.
+
+ """
+ def encode(self, input, errors='strict'):
+
+ """ Encodes the object input and returns a tuple (output
+ object, length consumed).
+
+ errors defines the error handling to apply. It defaults to
+ 'strict' handling.
+
+ The method may not store state in the Codec instance. Use
+ StreamCodec for codecs which have to keep state in order to
+ make encoding/decoding efficient.
+
+ The encoder must be able to handle zero length input and
+ return an empty object of the output object type in this
+ situation.
+
+ """
+ raise NotImplementedError
+
+ def decode(self, input, errors='strict'):
+
+ """ Decodes the object input and returns a tuple (output
+ object, length consumed).
+
+ input must be an object which provides the bf_getreadbuf
+ buffer slot. Python strings, buffer objects and memory
+ mapped files are examples of objects providing this slot.
+
+ errors defines the error handling to apply. It defaults to
+ 'strict' handling.
+
+ The method may not store state in the Codec instance. Use
+ StreamCodec for codecs which have to keep state in order to
+ make encoding/decoding efficient.
+
+ The decoder must be able to handle zero length input and
+ return an empty object of the output object type in this
+ situation.
+
+ """
+ raise NotImplementedError
+
+class IncrementalEncoder(object):
+ """
+ An IncrementalEncoder encodes an input in multiple steps. The input can
+ be passed piece by piece to the encode() method. The IncrementalEncoder
+ remembers the state of the encoding process between calls to encode().
+ """
+ def __init__(self, errors='strict'):
+ """
+ Creates an IncrementalEncoder instance.
+
+ The IncrementalEncoder may use different error handling schemes by
+ providing the errors keyword argument. See the module docstring
+ for a list of possible values.
+ """
+ self.errors = errors
+ self.buffer = ""
+
+ def encode(self, input, final=False):
+ """
+ Encodes input and returns the resulting object.
+ """
+ raise NotImplementedError
+
+ def reset(self):
+ """
+ Resets the encoder to the initial state.
+ """
+
+ def getstate(self):
+ """
+ Return the current state of the encoder.
+ """
+ return 0
+
+ def setstate(self, state):
+ """
+ Set the current state of the encoder. state must have been
+ returned by getstate().
+ """
+
+class BufferedIncrementalEncoder(IncrementalEncoder):
+ """
+ This subclass of IncrementalEncoder can be used as the baseclass for an
+ incremental encoder if the encoder must keep some of the output in a
+ buffer between calls to encode().
+ """
+ def __init__(self, errors='strict'):
+ IncrementalEncoder.__init__(self, errors)
+ # unencoded input that is kept between calls to encode()
+ self.buffer = ""
+
+ def _buffer_encode(self, input, errors, final):
+ # Overwrite this method in subclasses: It must encode input
+ # and return an (output, length consumed) tuple
+ raise NotImplementedError
+
+ def encode(self, input, final=False):
+ # encode input (taking the buffer into account)
+ data = self.buffer + input
+ (result, consumed) = self._buffer_encode(data, self.errors, final)
+ # keep unencoded input until the next call
+ self.buffer = data[consumed:]
+ return result
+
+ def reset(self):
+ IncrementalEncoder.reset(self)
+ self.buffer = ""
+
+ def getstate(self):
+ return self.buffer or 0
+
+ def setstate(self, state):
+ self.buffer = state or ""
+
+class IncrementalDecoder(object):
+ """
+ An IncrementalDecoder decodes an input in multiple steps. The input can
+ be passed piece by piece to the decode() method. The IncrementalDecoder
+ remembers the state of the decoding process between calls to decode().
+ """
+ def __init__(self, errors='strict'):
+ """
+ Create a IncrementalDecoder instance.
+
+ The IncrementalDecoder may use different error handling schemes by
+ providing the errors keyword argument. See the module docstring
+ for a list of possible values.
+ """
+ self.errors = errors
+
+ def decode(self, input, final=False):
+ """
+ Decode input and returns the resulting object.
+ """
+ raise NotImplementedError
+
+ def reset(self):
+ """
+ Reset the decoder to the initial state.
+ """
+
+ def getstate(self):
+ """
+ Return the current state of the decoder.
+
+ This must be a (buffered_input, additional_state_info) tuple.
+ buffered_input must be a bytes object containing bytes that
+ were passed to decode() that have not yet been converted.
+ additional_state_info must be a non-negative integer
+ representing the state of the decoder WITHOUT yet having
+ processed the contents of buffered_input. In the initial state
+ and after reset(), getstate() must return (b"", 0).
+ """
+ return (b"", 0)
+
+ def setstate(self, state):
+ """
+ Set the current state of the decoder.
+
+ state must have been returned by getstate(). The effect of
+ setstate((b"", 0)) must be equivalent to reset().
+ """
+
+class BufferedIncrementalDecoder(IncrementalDecoder):
+ """
+ This subclass of IncrementalDecoder can be used as the baseclass for an
+ incremental decoder if the decoder must be able to handle incomplete
+ byte sequences.
+ """
+ def __init__(self, errors='strict'):
+ IncrementalDecoder.__init__(self, errors)
+ # undecoded input that is kept between calls to decode()
+ self.buffer = b""
+
+ def _buffer_decode(self, input, errors, final):
+ # Overwrite this method in subclasses: It must decode input
+ # and return an (output, length consumed) tuple
+ raise NotImplementedError
+
+ def decode(self, input, final=False):
+ # decode input (taking the buffer into account)
+ data = self.buffer + input
+ (result, consumed) = self._buffer_decode(data, self.errors, final)
+ # keep undecoded input until the next call
+ self.buffer = data[consumed:]
+ return result
+
+ def reset(self):
+ IncrementalDecoder.reset(self)
+ self.buffer = b""
+
+ def getstate(self):
+ # additional state info is always 0
+ return (self.buffer, 0)
+
+ def setstate(self, state):
+ # ignore additional state info
+ self.buffer = state[0]
+
+#
+# The StreamWriter and StreamReader class provide generic working
+# interfaces which can be used to implement new encoding submodules
+# very easily. See encodings/utf_8.py for an example on how this is
+# done.
+#
+
+class StreamWriter(Codec):
+
+ def __init__(self, stream, errors='strict'):
+
+ """ Creates a StreamWriter instance.
+
+ stream must be a file-like object open for writing
+ (binary) data.
+
+ The StreamWriter may use different error handling
+ schemes by providing the errors keyword argument. These
+ parameters are predefined:
+
+ 'strict' - raise a ValueError (or a subclass)
+ 'ignore' - ignore the character and continue with the next
+ 'replace'- replace with a suitable replacement character
+ 'xmlcharrefreplace' - Replace with the appropriate XML
+ character reference.
+ 'backslashreplace' - Replace with backslashed escape
+ sequences (only for encoding).
+
+ The set of allowed parameter values can be extended via
+ register_error.
+ """
+ self.stream = stream
+ self.errors = errors
+
+ def write(self, object):
+
+ """ Writes the object's contents encoded to self.stream.
+ """
+ data, consumed = self.encode(object, self.errors)
+ self.stream.write(data)
+
+ def writelines(self, list):
+
+ """ Writes the concatenated list of strings to the stream
+ using .write().
+ """
+ self.write(''.join(list))
+
+ def reset(self):
+
+ """ Flushes and resets the codec buffers used for keeping state.
+
+ Calling this method should ensure that the data on the
+ output is put into a clean state, that allows appending
+ of new fresh data without having to rescan the whole
+ stream to recover state.
+
+ """
+ pass
+
+ def seek(self, offset, whence=0):
+ self.stream.seek(offset, whence)
+ if whence == 0 and offset == 0:
+ self.reset()
+
+ def __getattr__(self, name,
+ getattr=getattr):
+
+ """ Inherit all other methods from the underlying stream.
+ """
+ return getattr(self.stream, name)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, tb):
+ self.stream.close()
+
+###
+
+class StreamReader(Codec):
+
+ charbuffertype = str
+
+ def __init__(self, stream, errors='strict'):
+
+ """ Creates a StreamReader instance.
+
+ stream must be a file-like object open for reading
+ (binary) data.
+
+ The StreamReader may use different error handling
+ schemes by providing the errors keyword argument. These
+ parameters are predefined:
+
+ 'strict' - raise a ValueError (or a subclass)
+ 'ignore' - ignore the character and continue with the next
+ 'replace'- replace with a suitable replacement character;
+
+ The set of allowed parameter values can be extended via
+ register_error.
+ """
+ self.stream = stream
+ self.errors = errors
+ self.bytebuffer = b""
+ self._empty_charbuffer = self.charbuffertype()
+ self.charbuffer = self._empty_charbuffer
+ self.linebuffer = None
+
+ def decode(self, input, errors='strict'):
+ raise NotImplementedError
+
+ def read(self, size=-1, chars=-1, firstline=False):
+
+ """ Decodes data from the stream self.stream and returns the
+ resulting object.
+
+ chars indicates the number of characters to read from the
+ stream. read() will never return more than chars
+ characters, but it might return less, if there are not enough
+ characters available.
+
+ size indicates the approximate maximum number of bytes to
+ read from the stream for decoding purposes. The decoder
+ can modify this setting as appropriate. The default value
+ -1 indicates to read and decode as much as possible. size
+ is intended to prevent having to decode huge files in one
+ step.
+
+ If firstline is true, and a UnicodeDecodeError happens
+ after the first line terminator in the input only the first line
+ will be returned, the rest of the input will be kept until the
+ next call to read().
+
+ The method should use a greedy read strategy meaning that
+ it should read as much data as is allowed within the
+ definition of the encoding and the given size, e.g. if
+ optional encoding endings or state markers are available
+ on the stream, these should be read too.
+ """
+ # If we have lines cached, first merge them back into characters
+ if self.linebuffer:
+ self.charbuffer = self._empty_charbuffer.join(self.linebuffer)
+ self.linebuffer = None
+
+ # read until we get the required number of characters (if available)
+ while True:
+ # can the request be satisfied from the character buffer?
+ if chars < 0:
+ if size < 0:
+ if self.charbuffer:
+ break
+ elif len(self.charbuffer) >= size:
+ break
+ else:
+ if len(self.charbuffer) >= chars:
+ break
+ # we need more data
+ if size < 0:
+ newdata = self.stream.read()
+ else:
+ newdata = self.stream.read(size)
+ # decode bytes (those remaining from the last call included)
+ data = self.bytebuffer + newdata
+ try:
+ newchars, decodedbytes = self.decode(data, self.errors)
+ except UnicodeDecodeError as exc:
+ if firstline:
+ newchars, decodedbytes = \
+ self.decode(data[:exc.start], self.errors)
+ lines = newchars.splitlines(keepends=True)
+ if len(lines)<=1:
+ raise
+ else:
+ raise
+ # keep undecoded bytes until the next call
+ self.bytebuffer = data[decodedbytes:]
+ # put new characters in the character buffer
+ self.charbuffer += newchars
+ # there was no data available
+ if not newdata:
+ break
+ if chars < 0:
+ # Return everything we've got
+ result = self.charbuffer
+ self.charbuffer = self._empty_charbuffer
+ else:
+ # Return the first chars characters
+ result = self.charbuffer[:chars]
+ self.charbuffer = self.charbuffer[chars:]
+ return result
+
+ def readline(self, size=None, keepends=True):
+
+ """ Read one line from the input stream and return the
+ decoded data.
+
+ size, if given, is passed as size argument to the
+ read() method.
+
+ """
+ # If we have lines cached from an earlier read, return
+ # them unconditionally
+ if self.linebuffer:
+ line = self.linebuffer[0]
+ del self.linebuffer[0]
+ if len(self.linebuffer) == 1:
+ # revert to charbuffer mode; we might need more data
+ # next time
+ self.charbuffer = self.linebuffer[0]
+ self.linebuffer = None
+ if not keepends:
+ line = line.splitlines(keepends=False)[0]
+ return line
+
+ readsize = size or 72
+ line = self._empty_charbuffer
+ # If size is given, we call read() only once
+ while True:
+ data = self.read(readsize, firstline=True)
+ if data:
+ # If we're at a "\r" read one extra character (which might
+ # be a "\n") to get a proper line ending. If the stream is
+ # temporarily exhausted we return the wrong line ending.
+ if (isinstance(data, str) and data.endswith("\r")) or \
+ (isinstance(data, bytes) and data.endswith(b"\r")):
+ data += self.read(size=1, chars=1)
+
+ line += data
+ lines = line.splitlines(keepends=True)
+ if lines:
+ if len(lines) > 1:
+ # More than one line result; the first line is a full line
+ # to return
+ line = lines[0]
+ del lines[0]
+ if len(lines) > 1:
+ # cache the remaining lines
+ lines[-1] += self.charbuffer
+ self.linebuffer = lines
+ self.charbuffer = None
+ else:
+ # only one remaining line, put it back into charbuffer
+ self.charbuffer = lines[0] + self.charbuffer
+ if not keepends:
+ line = line.splitlines(keepends=False)[0]
+ break
+ line0withend = lines[0]
+ line0withoutend = lines[0].splitlines(keepends=False)[0]
+ if line0withend != line0withoutend: # We really have a line end
+ # Put the rest back together and keep it until the next call
+ self.charbuffer = self._empty_charbuffer.join(lines[1:]) + \
+ self.charbuffer
+ if keepends:
+ line = line0withend
+ else:
+ line = line0withoutend
+ break
+ # we didn't get anything or this was our only try
+ if not data or size is not None:
+ if line and not keepends:
+ line = line.splitlines(keepends=False)[0]
+ break
+ if readsize < 8000:
+ readsize *= 2
+ return line
+
+ def readlines(self, sizehint=None, keepends=True):
+
+ """ Read all lines available on the input stream
+ and return them as list of lines.
+
+ Line breaks are implemented using the codec's decoder
+ method and are included in the list entries.
+
+ sizehint, if given, is ignored since there is no efficient
+ way to finding the true end-of-line.
+
+ """
+ data = self.read()
+ return data.splitlines(keepends)
+
+ def reset(self):
+
+ """ Resets the codec buffers used for keeping state.
+
+ Note that no stream repositioning should take place.
+ This method is primarily intended to be able to recover
+ from decoding errors.
+
+ """
+ self.bytebuffer = b""
+ self.charbuffer = self._empty_charbuffer
+ self.linebuffer = None
+
+ def seek(self, offset, whence=0):
+ """ Set the input stream's current position.
+
+ Resets the codec buffers used for keeping state.
+ """
+ self.stream.seek(offset, whence)
+ self.reset()
+
+ def __next__(self):
+
+ """ Return the next decoded line from the input stream."""
+ line = self.readline()
+ if line:
+ return line
+ raise StopIteration
+
+ def __iter__(self):
+ return self
+
+ def __getattr__(self, name,
+ getattr=getattr):
+
+ """ Inherit all other methods from the underlying stream.
+ """
+ return getattr(self.stream, name)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, tb):
+ self.stream.close()
+
+###
+
+class StreamReaderWriter:
+
+ """ StreamReaderWriter instances allow wrapping streams which
+ work in both read and write modes.
+
+ The design is such that one can use the factory functions
+ returned by the codec.lookup() function to construct the
+ instance.
+
+ """
+ # Optional attributes set by the file wrappers below
+ encoding = 'unknown'
+
+ def __init__(self, stream, Reader, Writer, errors='strict'):
+
+ """ Creates a StreamReaderWriter instance.
+
+ stream must be a Stream-like object.
+
+ Reader, Writer must be factory functions or classes
+ providing the StreamReader, StreamWriter interface resp.
+
+ Error handling is done in the same way as defined for the
+ StreamWriter/Readers.
+
+ """
+ self.stream = stream
+ self.reader = Reader(stream, errors)
+ self.writer = Writer(stream, errors)
+ self.errors = errors
+
+ def read(self, size=-1):
+
+ return self.reader.read(size)
+
+ def readline(self, size=None):
+
+ return self.reader.readline(size)
+
+ def readlines(self, sizehint=None):
+
+ return self.reader.readlines(sizehint)
+
+ def __next__(self):
+
+ """ Return the next decoded line from the input stream."""
+ return next(self.reader)
+
+ def __iter__(self):
+ return self
+
+ def write(self, data):
+
+ return self.writer.write(data)
+
+ def writelines(self, list):
+
+ return self.writer.writelines(list)
+
+ def reset(self):
+
+ self.reader.reset()
+ self.writer.reset()
+
+ def seek(self, offset, whence=0):
+ self.stream.seek(offset, whence)
+ self.reader.reset()
+ if whence == 0 and offset == 0:
+ self.writer.reset()
+
+ def __getattr__(self, name,
+ getattr=getattr):
+
+ """ Inherit all other methods from the underlying stream.
+ """
+ return getattr(self.stream, name)
+
+ # these are needed to make "with codecs.open(...)" work properly
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, tb):
+ self.stream.close()
+
+###
+
+class StreamRecoder:
+
+ """ StreamRecoder instances provide a frontend - backend
+ view of encoding data.
+
+ They use the complete set of APIs returned by the
+ codecs.lookup() function to implement their task.
+
+ Data written to the stream is first decoded into an
+ intermediate format (which is dependent on the given codec
+ combination) and then written to the stream using an instance
+ of the provided Writer class.
+
+ In the other direction, data is read from the stream using a
+ Reader instance and then return encoded data to the caller.
+
+ """
+ # Optional attributes set by the file wrappers below
+ data_encoding = 'unknown'
+ file_encoding = 'unknown'
+
+ def __init__(self, stream, encode, decode, Reader, Writer,
+ errors='strict'):
+
+ """ Creates a StreamRecoder instance which implements a two-way
+ conversion: encode and decode work on the frontend (the
+ input to .read() and output of .write()) while
+ Reader and Writer work on the backend (reading and
+ writing to the stream).
+
+ You can use these objects to do transparent direct
+ recodings from e.g. latin-1 to utf-8 and back.
+
+ stream must be a file-like object.
+
+ encode, decode must adhere to the Codec interface, Reader,
+ Writer must be factory functions or classes providing the
+ StreamReader, StreamWriter interface resp.
+
+ encode and decode are needed for the frontend translation,
+ Reader and Writer for the backend translation. Unicode is
+ used as intermediate encoding.
+
+ Error handling is done in the same way as defined for the
+ StreamWriter/Readers.
+
+ """
+ self.stream = stream
+ self.encode = encode
+ self.decode = decode
+ self.reader = Reader(stream, errors)
+ self.writer = Writer(stream, errors)
+ self.errors = errors
+
+ def read(self, size=-1):
+
+ data = self.reader.read(size)
+ data, bytesencoded = self.encode(data, self.errors)
+ return data
+
+ def readline(self, size=None):
+
+ if size is None:
+ data = self.reader.readline()
+ else:
+ data = self.reader.readline(size)
+ data, bytesencoded = self.encode(data, self.errors)
+ return data
+
+ def readlines(self, sizehint=None):
+
+ data = self.reader.read()
+ data, bytesencoded = self.encode(data, self.errors)
+ return data.splitlines(keepends=True)
+
+ def __next__(self):
+
+ """ Return the next decoded line from the input stream."""
+ data = next(self.reader)
+ data, bytesencoded = self.encode(data, self.errors)
+ return data
+
+ def __iter__(self):
+ return self
+
+ def write(self, data):
+
+ data, bytesdecoded = self.decode(data, self.errors)
+ return self.writer.write(data)
+
+ def writelines(self, list):
+
+ data = ''.join(list)
+ data, bytesdecoded = self.decode(data, self.errors)
+ return self.writer.write(data)
+
+ def reset(self):
+
+ self.reader.reset()
+ self.writer.reset()
+
+ def __getattr__(self, name,
+ getattr=getattr):
+
+ """ Inherit all other methods from the underlying stream.
+ """
+ return getattr(self.stream, name)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, tb):
+ self.stream.close()
+
+### Shortcuts
+
+def open(filename, mode='rb', encoding=None, errors='strict', buffering=1):
+
+ """ Open an encoded file using the given mode and return
+ a wrapped version providing transparent encoding/decoding.
+
+ Note: The wrapped version will only accept the object format
+ defined by the codecs, i.e. Unicode objects for most builtin
+ codecs. Output is also codec dependent and will usually be
+ Unicode as well.
+
+ Files are always opened in binary mode, even if no binary mode
+ was specified. This is done to avoid data loss due to encodings
+ using 8-bit values. The default file mode is 'rb' meaning to
+ open the file in binary read mode.
+
+ encoding specifies the encoding which is to be used for the
+ file.
+
+ errors may be given to define the error handling. It defaults
+ to 'strict' which causes ValueErrors to be raised in case an
+ encoding error occurs.
+
+ buffering has the same meaning as for the builtin open() API.
+ It defaults to line buffered.
+
+ The returned wrapped file object provides an extra attribute
+ .encoding which allows querying the used encoding. This
+ attribute is only available if an encoding was specified as
+ parameter.
+
+ """
+ if encoding is not None and \
+ 'b' not in mode:
+ # Force opening of the file in binary mode
+ mode = mode + 'b'
+ file = builtins.open(filename, mode, buffering)
+ if encoding is None:
+ return file
+ info = lookup(encoding)
+ srw = StreamReaderWriter(file, info.streamreader, info.streamwriter, errors)
+ # Add attributes to simplify introspection
+ srw.encoding = encoding
+ return srw
+
+def EncodedFile(file, data_encoding, file_encoding=None, errors='strict'):
+
+ """ Return a wrapped version of file which provides transparent
+ encoding translation.
+
+ Strings written to the wrapped file are interpreted according
+ to the given data_encoding and then written to the original
+ file as string using file_encoding. The intermediate encoding
+ will usually be Unicode but depends on the specified codecs.
+
+ Strings are read from the file using file_encoding and then
+ passed back to the caller as string using data_encoding.
+
+ If file_encoding is not given, it defaults to data_encoding.
+
+ errors may be given to define the error handling. It defaults
+ to 'strict' which causes ValueErrors to be raised in case an
+ encoding error occurs.
+
+ The returned wrapped file object provides two extra attributes
+ .data_encoding and .file_encoding which reflect the given
+ parameters of the same name. The attributes can be used for
+ introspection by Python programs.
+
+ """
+ if file_encoding is None:
+ file_encoding = data_encoding
+ data_info = lookup(data_encoding)
+ file_info = lookup(file_encoding)
+ sr = StreamRecoder(file, data_info.encode, data_info.decode,
+ file_info.streamreader, file_info.streamwriter, errors)
+ # Add attributes to simplify introspection
+ sr.data_encoding = data_encoding
+ sr.file_encoding = file_encoding
+ return sr
+
+### Helpers for codec lookup
+
+def getencoder(encoding):
+
+ """ Lookup up the codec for the given encoding and return
+ its encoder function.
+
+ Raises a LookupError in case the encoding cannot be found.
+
+ """
+ return lookup(encoding).encode
+
+def getdecoder(encoding):
+
+ """ Lookup up the codec for the given encoding and return
+ its decoder function.
+
+ Raises a LookupError in case the encoding cannot be found.
+
+ """
+ return lookup(encoding).decode
+
+def getincrementalencoder(encoding):
+
+ """ Lookup up the codec for the given encoding and return
+ its IncrementalEncoder class or factory function.
+
+ Raises a LookupError in case the encoding cannot be found
+ or the codecs doesn't provide an incremental encoder.
+
+ """
+ encoder = lookup(encoding).incrementalencoder
+ if encoder is None:
+ raise LookupError(encoding)
+ return encoder
+
+def getincrementaldecoder(encoding):
+
+ """ Lookup up the codec for the given encoding and return
+ its IncrementalDecoder class or factory function.
+
+ Raises a LookupError in case the encoding cannot be found
+ or the codecs doesn't provide an incremental decoder.
+
+ """
+ decoder = lookup(encoding).incrementaldecoder
+ if decoder is None:
+ raise LookupError(encoding)
+ return decoder
+
+def getreader(encoding):
+
+ """ Lookup up the codec for the given encoding and return
+ its StreamReader class or factory function.
+
+ Raises a LookupError in case the encoding cannot be found.
+
+ """
+ return lookup(encoding).streamreader
+
+def getwriter(encoding):
+
+ """ Lookup up the codec for the given encoding and return
+ its StreamWriter class or factory function.
+
+ Raises a LookupError in case the encoding cannot be found.
+
+ """
+ return lookup(encoding).streamwriter
+
+def iterencode(iterator, encoding, errors='strict', **kwargs):
+ """
+ Encoding iterator.
+
+ Encodes the input strings from the iterator using a IncrementalEncoder.
+
+ errors and kwargs are passed through to the IncrementalEncoder
+ constructor.
+ """
+ encoder = getincrementalencoder(encoding)(errors, **kwargs)
+ for input in iterator:
+ output = encoder.encode(input)
+ if output:
+ yield output
+ output = encoder.encode("", True)
+ if output:
+ yield output
+
+def iterdecode(iterator, encoding, errors='strict', **kwargs):
+ """
+ Decoding iterator.
+
+ Decodes the input strings from the iterator using a IncrementalDecoder.
+
+ errors and kwargs are passed through to the IncrementalDecoder
+ constructor.
+ """
+ decoder = getincrementaldecoder(encoding)(errors, **kwargs)
+ for input in iterator:
+ output = decoder.decode(input)
+ if output:
+ yield output
+ output = decoder.decode(b"", True)
+ if output:
+ yield output
+
+### Helpers for charmap-based codecs
+
+def make_identity_dict(rng):
+
+ """ make_identity_dict(rng) -> dict
+
+ Return a dictionary where elements of the rng sequence are
+ mapped to themselves.
+
+ """
+ return {i:i for i in rng}
+
+def make_encoding_map(decoding_map):
+
+ """ Creates an encoding map from a decoding map.
+
+ If a target mapping in the decoding map occurs multiple
+ times, then that target is mapped to None (undefined mapping),
+ causing an exception when encountered by the charmap codec
+ during translation.
+
+ One example where this happens is cp875.py which decodes
+ multiple character to \u001a.
+
+ """
+ m = {}
+ for k,v in decoding_map.items():
+ if not v in m:
+ m[v] = k
+ else:
+ m[v] = None
+ return m
+
+### error handlers
+
+try:
+ strict_errors = lookup_error("strict")
+ ignore_errors = lookup_error("ignore")
+ replace_errors = lookup_error("replace")
+ xmlcharrefreplace_errors = lookup_error("xmlcharrefreplace")
+ backslashreplace_errors = lookup_error("backslashreplace")
+except LookupError:
+ # In --disable-unicode builds, these error handler are missing
+ strict_errors = None
+ ignore_errors = None
+ replace_errors = None
+ xmlcharrefreplace_errors = None
+ backslashreplace_errors = None
+
+# Tell modulefinder that using codecs probably needs the encodings
+# package
+_false = 0
+if _false:
+ import encodings
+
+### Tests
+
+if __name__ == '__main__':
+
+ # Make stdout translate Latin-1 output into UTF-8 output
+ sys.stdout = EncodedFile(sys.stdout, 'latin-1', 'utf-8')
+
+ # Have stdin translate Latin-1 input into UTF-8 input
+ sys.stdin = EncodedFile(sys.stdin, 'utf-8', 'latin-1')
diff --git a/lib/assets/Lib/codeop.py b/lib/assets/Lib/codeop.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/codeop.py
@@ -0,0 +1,168 @@
+r"""Utilities to compile possibly incomplete Python source code.
+
+This module provides two interfaces, broadly similar to the builtin
+function compile(), which take program text, a filename and a 'mode'
+and:
+
+- Return code object if the command is complete and valid
+- Return None if the command is incomplete
+- Raise SyntaxError, ValueError or OverflowError if the command is a
+ syntax error (OverflowError and ValueError can be produced by
+ malformed literals).
+
+Approach:
+
+First, check if the source consists entirely of blank lines and
+comments; if so, replace it with 'pass', because the built-in
+parser doesn't always do the right thing for these.
+
+Compile three times: as is, with \n, and with \n\n appended. If it
+compiles as is, it's complete. If it compiles with one \n appended,
+we expect more. If it doesn't compile either way, we compare the
+error we get when compiling with \n or \n\n appended. If the errors
+are the same, the code is broken. But if the errors are different, we
+expect more. Not intuitive; not even guaranteed to hold in future
+releases; but this matches the compiler's behavior from Python 1.4
+through 2.2, at least.
+
+Caveat:
+
+It is possible (but not likely) that the parser stops parsing with a
+successful outcome before reaching the end of the source; in this
+case, trailing symbols may be ignored instead of causing an error.
+For example, a backslash followed by two newlines may be followed by
+arbitrary garbage. This will be fixed once the API for the parser is
+better.
+
+The two interfaces are:
+
+compile_command(source, filename, symbol):
+
+ Compiles a single command in the manner described above.
+
+CommandCompiler():
+
+ Instances of this class have __call__ methods identical in
+ signature to compile_command; the difference is that if the
+ instance compiles program text containing a __future__ statement,
+ the instance 'remembers' and compiles all subsequent program texts
+ with the statement in force.
+
+The module also provides another class:
+
+Compile():
+
+ Instances of this class act like the built-in function compile,
+ but with 'memory' in the sense described above.
+"""
+
+import __future__
+
+_features = [getattr(__future__, fname)
+ for fname in __future__.all_feature_names]
+
+__all__ = ["compile_command", "Compile", "CommandCompiler"]
+
+PyCF_DONT_IMPLY_DEDENT = 0x200 # Matches pythonrun.h
+
+def _maybe_compile(compiler, source, filename, symbol):
+ # Check for source consisting of only blank lines and comments
+ for line in source.split("\n"):
+ line = line.strip()
+ if line and line[0] != '#':
+ break # Leave it alone
+ else:
+ if symbol != "eval":
+ source = "pass" # Replace it with a 'pass' statement
+
+ err = err1 = err2 = None
+ code = code1 = code2 = None
+
+ try:
+ code = compiler(source, filename, symbol)
+ except SyntaxError as err:
+ pass
+
+ try:
+ code1 = compiler(source + "\n", filename, symbol)
+ except SyntaxError as e:
+ err1 = e
+
+ try:
+ code2 = compiler(source + "\n\n", filename, symbol)
+ except SyntaxError as e:
+ err2 = e
+
+ if code:
+ return code
+ if not code1 and repr(err1) == repr(err2):
+ raise err1
+
+def _compile(source, filename, symbol):
+ return compile(source, filename, symbol, PyCF_DONT_IMPLY_DEDENT)
+
+def compile_command(source, filename="", symbol="single"):
+ r"""Compile a command and determine whether it is incomplete.
+
+ Arguments:
+
+ source -- the source string; may contain \n characters
+ filename -- optional filename from which source was read; default
+ ""
+ symbol -- optional grammar start symbol; "single" (default) or "eval"
+
+ Return value / exceptions raised:
+
+ - Return a code object if the command is complete and valid
+ - Return None if the command is incomplete
+ - Raise SyntaxError, ValueError or OverflowError if the command is a
+ syntax error (OverflowError and ValueError can be produced by
+ malformed literals).
+ """
+ return _maybe_compile(_compile, source, filename, symbol)
+
+class Compile:
+ """Instances of this class behave much like the built-in compile
+ function, but if one is used to compile text containing a future
+ statement, it "remembers" and compiles all subsequent program texts
+ with the statement in force."""
+ def __init__(self):
+ self.flags = PyCF_DONT_IMPLY_DEDENT
+
+ def __call__(self, source, filename, symbol):
+ codeob = compile(source, filename, symbol, self.flags, 1)
+ for feature in _features:
+ if codeob.co_flags & feature.compiler_flag:
+ self.flags |= feature.compiler_flag
+ return codeob
+
+class CommandCompiler:
+ """Instances of this class have __call__ methods identical in
+ signature to compile_command; the difference is that if the
+ instance compiles program text containing a __future__ statement,
+ the instance 'remembers' and compiles all subsequent program texts
+ with the statement in force."""
+
+ def __init__(self,):
+ self.compiler = Compile()
+
+ def __call__(self, source, filename="", symbol="single"):
+ r"""Compile a command and determine whether it is incomplete.
+
+ Arguments:
+
+ source -- the source string; may contain \n characters
+ filename -- optional filename from which source was read;
+ default ""
+ symbol -- optional grammar start symbol; "single" (default) or
+ "eval"
+
+ Return value / exceptions raised:
+
+ - Return a code object if the command is complete and valid
+ - Return None if the command is incomplete
+ - Raise SyntaxError, ValueError or OverflowError if the command is a
+ syntax error (OverflowError and ValueError can be produced by
+ malformed literals).
+ """
+ return _maybe_compile(self.compiler, source, filename, symbol)
diff --git a/lib/assets/Lib/collections/__init__.py b/lib/assets/Lib/collections/__init__.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/collections/__init__.py
@@ -0,0 +1,932 @@
+#__all__ = ['deque', 'defaultdict', 'Counter']
+
+from _collections import deque, defaultdict
+
+#from itertools import repeat as _repeat, chain as _chain, starmap as _starmap
+
+__all__ = ['deque', 'defaultdict', 'namedtuple', 'UserDict', 'UserList',
+ 'UserString', 'Counter', 'OrderedDict']
+# For bootstrapping reasons, the collection ABCs are defined in _abcoll.py.
+# They should however be considered an integral part of collections.py.
+
+# fixme brython.. there is an issue with _abcoll
+#from _abcoll import *
+#from _abcoll import Set
+from _abcoll import MutableMapping
+#import _abcoll
+#__all__ += _abcoll.__all__
+
+from collections.abc import *
+import collections.abc
+__all__ += collections.abc.__all__
+
+from _collections import deque, defaultdict, namedtuple
+from operator import itemgetter as _itemgetter
+from keyword import iskeyword as _iskeyword
+import sys as _sys
+import heapq as _heapq
+#fixme brython
+#from weakref import proxy as _proxy
+from itertools import repeat as _repeat, chain as _chain, starmap as _starmap
+from reprlib import recursive_repr as _recursive_repr
+
+class Set(set):
+ pass
+
+class Sequence(list):
+ pass
+
+def _proxy(obj):
+ return obj
+
+################################################################################
+### OrderedDict
+################################################################################
+
+class _Link(object):
+ __slots__ = 'prev', 'next', 'key', '__weakref__'
+
+class OrderedDict(dict):
+ 'Dictionary that remembers insertion order'
+ # An inherited dict maps keys to values.
+ # The inherited dict provides __getitem__, __len__, __contains__, and get.
+ # The remaining methods are order-aware.
+ # Big-O running times for all methods are the same as regular dictionaries.
+
+ # The internal self.__map dict maps keys to links in a doubly linked list.
+ # The circular doubly linked list starts and ends with a sentinel element.
+ # The sentinel element never gets deleted (this simplifies the algorithm).
+ # The sentinel is in self.__hardroot with a weakref proxy in self.__root.
+ # The prev links are weakref proxies (to prevent circular references).
+ # Individual links are kept alive by the hard reference in self.__map.
+ # Those hard references disappear when a key is deleted from an OrderedDict.
+
+ def __init__(self, *args, **kwds):
+ '''Initialize an ordered dictionary. The signature is the same as
+ regular dictionaries, but keyword arguments are not recommended because
+ their insertion order is arbitrary.
+
+ '''
+ if len(args) > 1:
+ raise TypeError('expected at most 1 arguments, got %d' % len(args))
+ try:
+ self.__root
+ except AttributeError:
+ self.__hardroot = _Link()
+ self.__root = root = _proxy(self.__hardroot)
+ root.prev = root.next = root
+ self.__map = {}
+ self.__update(*args, **kwds)
+
+ def __setitem__(self, key, value,
+ dict_setitem=dict.__setitem__, proxy=_proxy, Link=_Link):
+ 'od.__setitem__(i, y) <==> od[i]=y'
+ # Setting a new item creates a new link at the end of the linked list,
+ # and the inherited dictionary is updated with the new key/value pair.
+ if key not in self:
+ self.__map[key] = link = Link()
+ root = self.__root
+ last = root.prev
+ link.prev, link.next, link.key = last, root, key
+ last.next = link
+ root.prev = proxy(link)
+ dict_setitem(self, key, value)
+
+ def __delitem__(self, key, dict_delitem=dict.__delitem__):
+ 'od.__delitem__(y) <==> del od[y]'
+ # Deleting an existing item uses self.__map to find the link which gets
+ # removed by updating the links in the predecessor and successor nodes.
+ dict_delitem(self, key)
+ link = self.__map.pop(key)
+ link_prev = link.prev
+ link_next = link.next
+ link_prev.next = link_next
+ link_next.prev = link_prev
+
+ def __iter__(self):
+ 'od.__iter__() <==> iter(od)'
+ # Traverse the linked list in order.
+ root = self.__root
+ curr = root.next
+ while curr is not root:
+ yield curr.key
+ curr = curr.next
+
+ def __reversed__(self):
+ 'od.__reversed__() <==> reversed(od)'
+ # Traverse the linked list in reverse order.
+ root = self.__root
+ curr = root.prev
+ while curr is not root:
+ yield curr.key
+ curr = curr.prev
+
+ def clear(self):
+ 'od.clear() -> None. Remove all items from od.'
+ root = self.__root
+ root.prev = root.next = root
+ self.__map.clear()
+ dict.clear(self)
+
+ def popitem(self, last=True):
+ '''od.popitem() -> (k, v), return and remove a (key, value) pair.
+ Pairs are returned in LIFO order if last is true or FIFO order if false.
+
+ '''
+ if not self:
+ raise KeyError('dictionary is empty')
+ root = self.__root
+ if last:
+ link = root.prev
+ link_prev = link.prev
+ link_prev.next = root
+ root.prev = link_prev
+ else:
+ link = root.next
+ link_next = link.next
+ root.next = link_next
+ link_next.prev = root
+ key = link.key
+ del self.__map[key]
+ value = dict.pop(self, key)
+ return key, value
+
+ def move_to_end(self, key, last=True):
+ '''Move an existing element to the end (or beginning if last==False).
+
+ Raises KeyError if the element does not exist.
+ When last=True, acts like a fast version of self[key]=self.pop(key).
+
+ '''
+ link = self.__map[key]
+ link_prev = link.prev
+ link_next = link.next
+ link_prev.next = link_next
+ link_next.prev = link_prev
+ root = self.__root
+ if last:
+ last = root.prev
+ link.prev = last
+ link.next = root
+ last.next = root.prev = link
+ else:
+ first = root.next
+ link.prev = root
+ link.next = first
+ root.next = first.prev = link
+
+ def __sizeof__(self):
+ sizeof = _sys.getsizeof
+ n = len(self) + 1 # number of links including root
+ size = sizeof(self.__dict__) # instance dictionary
+ size += sizeof(self.__map) * 2 # internal dict and inherited dict
+ size += sizeof(self.__hardroot) * n # link objects
+ size += sizeof(self.__root) * n # proxy objects
+ return size
+
+ #fixme brython.. Issue with _abcoll, which contains MutableMapping
+ update = __update = MutableMapping.update
+ keys = MutableMapping.keys
+ values = MutableMapping.values
+ items = MutableMapping.items
+ __ne__ = MutableMapping.__ne__
+
+ __marker = object()
+
+ def pop(self, key, default=__marker):
+ '''od.pop(k[,d]) -> v, remove specified key and return the corresponding
+ value. If key is not found, d is returned if given, otherwise KeyError
+ is raised.
+
+ '''
+ if key in self:
+ result = self[key]
+ del self[key]
+ return result
+ if default is self.__marker:
+ raise KeyError(key)
+ return default
+
+ def setdefault(self, key, default=None):
+ 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
+ if key in self:
+ return self[key]
+ self[key] = default
+ return default
+
+ #fixme, brython issue
+ #@_recursive_repr()
+ def __repr__(self):
+ 'od.__repr__() <==> repr(od)'
+ if not self:
+ return '%s()' % (self.__class__.__name__,)
+ return '%s(%r)' % (self.__class__.__name__, list(self.items()))
+
+ def __reduce__(self):
+ 'Return state information for pickling'
+ items = [[k, self[k]] for k in self]
+ inst_dict = vars(self).copy()
+ for k in vars(OrderedDict()):
+ inst_dict.pop(k, None)
+ if inst_dict:
+ return (self.__class__, (items,), inst_dict)
+ return self.__class__, (items,)
+
+ def copy(self):
+ 'od.copy() -> a shallow copy of od'
+ return self.__class__(self)
+
+ @classmethod
+ def fromkeys(cls, iterable, value=None):
+ '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S.
+ If not specified, the value defaults to None.
+
+ '''
+ self = cls()
+ for key in iterable:
+ self[key] = value
+ return self
+
+ def __eq__(self, other):
+ '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive
+ while comparison to a regular mapping is order-insensitive.
+
+ '''
+ if isinstance(other, OrderedDict):
+ return len(self)==len(other) and \
+ all(p==q for p, q in zip(self.items(), other.items()))
+ return dict.__eq__(self, other)
+
+
+########################################################################
+### Counter
+########################################################################
+
+
+def _count_elements(mapping, iterable):
+ 'Tally elements from the iterable.'
+ mapping_get = mapping.get
+ for elem in iterable:
+ mapping[elem] = mapping_get(elem, 0) + 1
+
+#try: # Load C helper function if available
+# from _collections import _count_elements
+#except ImportError:
+# pass
+
+class Counter(dict):
+ '''Dict subclass for counting hashable items. Sometimes called a bag
+ or multiset. Elements are stored as dictionary keys and their counts
+ are stored as dictionary values.
+
+ >>> c = Counter('abcdeabcdabcaba') # count elements from a string
+
+ >>> c.most_common(3) # three most common elements
+ [('a', 5), ('b', 4), ('c', 3)]
+ >>> sorted(c) # list all unique elements
+ ['a', 'b', 'c', 'd', 'e']
+ >>> ''.join(sorted(c.elements())) # list elements with repetitions
+ 'aaaaabbbbcccdde'
+ >>> sum(c.values()) # total of all counts
+ 15
+
+ >>> c['a'] # count of letter 'a'
+ 5
+ >>> for elem in 'shazam': # update counts from an iterable
+ ... c[elem] += 1 # by adding 1 to each element's count
+ >>> c['a'] # now there are seven 'a'
+ 7
+ >>> del c['b'] # remove all 'b'
+ >>> c['b'] # now there are zero 'b'
+ 0
+
+ >>> d = Counter('simsalabim') # make another counter
+ >>> c.update(d) # add in the second counter
+ >>> c['a'] # now there are nine 'a'
+ 9
+
+ >>> c.clear() # empty the counter
+ >>> c
+ Counter()
+
+ Note: If a count is set to zero or reduced to zero, it will remain
+ in the counter until the entry is deleted or the counter is cleared:
+
+ >>> c = Counter('aaabbc')
+ >>> c['b'] -= 2 # reduce the count of 'b' by two
+ >>> c.most_common() # 'b' is still in, but its count is zero
+ [('a', 3), ('c', 1), ('b', 0)]
+
+ '''
+ # References:
+ # http://en.wikipedia.org/wiki/Multiset
+ # http://www.gnu.org/software/smalltalk/manual-base/html_node/Bag.html
+ # http://www.demo2s.com/Tutorial/Cpp/0380__set-multiset/Catalog0380__set-multiset.htm
+ # http://code.activestate.com/recipes/259174/
+ # Knuth, TAOCP Vol. II section 4.6.3
+
+ def __init__(self, iterable=None, **kwds):
+ '''Create a new, empty Counter object. And if given, count elements
+ from an input iterable. Or, initialize the count from another mapping
+ of elements to their counts.
+
+ >>> c = Counter() # a new, empty counter
+ >>> c = Counter('gallahad') # a new counter from an iterable
+ >>> c = Counter({'a': 4, 'b': 2}) # a new counter from a mapping
+ >>> c = Counter(a=4, b=2) # a new counter from keyword args
+
+ '''
+ #super().__init__() #BE modified since super not supported
+ dict.__init__(self)
+ self.update(iterable, **kwds)
+
+ def __missing__(self, key):
+ 'The count of elements not in the Counter is zero.'
+ # Needed so that self[missing_item] does not raise KeyError
+ return 0
+
+ def most_common(self, n=None):
+ '''List the n most common elements and their counts from the most
+ common to the least. If n is None, then list all element counts.
+
+ >>> Counter('abcdeabcdabcaba').most_common(3)
+ [('a', 5), ('b', 4), ('c', 3)]
+
+ '''
+ # Emulate Bag.sortedByCount from Smalltalk
+ if n is None:
+ return sorted(self.items(), key=_itemgetter(1), reverse=True)
+ return _heapq.nlargest(n, self.items(), key=_itemgetter(1))
+
+ def elements(self):
+ '''Iterator over elements repeating each as many times as its count.
+
+ >>> c = Counter('ABCABC')
+ >>> sorted(c.elements())
+ ['A', 'A', 'B', 'B', 'C', 'C']
+
+ # Knuth's example for prime factors of 1836: 2**2 * 3**3 * 17**1
+ >>> prime_factors = Counter({2: 2, 3: 3, 17: 1})
+ >>> product = 1
+ >>> for factor in prime_factors.elements(): # loop over factors
+ ... product *= factor # and multiply them
+ >>> product
+ 1836
+
+ Note, if an element's count has been set to zero or is a negative
+ number, elements() will ignore it.
+
+ '''
+ # Emulate Bag.do from Smalltalk and Multiset.begin from C++.
+ return _chain.from_iterable(_starmap(_repeat, self.items()))
+
+ # Override dict methods where necessary
+
+ @classmethod
+ def fromkeys(cls, iterable, v=None):
+ # There is no equivalent method for counters because setting v=1
+ # means that no element can have a count greater than one.
+ raise NotImplementedError(
+ 'Counter.fromkeys() is undefined. Use Counter(iterable) instead.')
+
+ def update(self, iterable=None, **kwds):
+ '''Like dict.update() but add counts instead of replacing them.
+
+ Source can be an iterable, a dictionary, or another Counter instance.
+
+ >>> c = Counter('which')
+ >>> c.update('witch') # add elements from another iterable
+ >>> d = Counter('watch')
+ >>> c.update(d) # add elements from another counter
+ >>> c['h'] # four 'h' in which, witch, and watch
+ 4
+
+ '''
+ # The regular dict.update() operation makes no sense here because the
+ # replace behavior results in the some of original untouched counts
+ # being mixed-in with all of the other counts for a mismash that
+ # doesn't have a straight-forward interpretation in most counting
+ # contexts. Instead, we implement straight-addition. Both the inputs
+ # and outputs are allowed to contain zero and negative counts.
+
+ if iterable is not None:
+ if isinstance(iterable, Mapping):
+ if self:
+ self_get = self.get
+ for elem, count in iterable.items():
+ self[elem] = count + self_get(elem, 0)
+ else:
+ super().update(iterable) # fast path when counter is empty
+ else:
+ _count_elements(self, iterable)
+ if kwds:
+ self.update(kwds)
+
+ def subtract(self, iterable=None, **kwds):
+ '''Like dict.update() but subtracts counts instead of replacing them.
+ Counts can be reduced below zero. Both the inputs and outputs are
+ allowed to contain zero and negative counts.
+
+ Source can be an iterable, a dictionary, or another Counter instance.
+
+ >>> c = Counter('which')
+ >>> c.subtract('witch') # subtract elements from another iterable
+ >>> c.subtract(Counter('watch')) # subtract elements from another counter
+ >>> c['h'] # 2 in which, minus 1 in witch, minus 1 in watch
+ 0
+ >>> c['w'] # 1 in which, minus 1 in witch, minus 1 in watch
+ -1
+
+ '''
+ if iterable is not None:
+ self_get = self.get
+ if isinstance(iterable, Mapping):
+ for elem, count in iterable.items():
+ self[elem] = self_get(elem, 0) - count
+ else:
+ for elem in iterable:
+ self[elem] = self_get(elem, 0) - 1
+ if kwds:
+ self.subtract(kwds)
+
+ def copy(self):
+ 'Return a shallow copy.'
+ return self.__class__(self)
+
+ def __reduce__(self):
+ return self.__class__, (dict(self),)
+
+ def __delitem__(self, elem):
+ 'Like dict.__delitem__() but does not raise KeyError for missing values.'
+ if elem in self:
+ super().__delitem__(elem)
+
+ def __repr__(self):
+ if not self:
+ return '%s()' % self.__class__.__name__
+ try:
+ items = ', '.join(map('%r: %r'.__mod__, self.most_common()))
+ return '%s({%s})' % (self.__class__.__name__, items)
+ except TypeError:
+ # handle case where values are not orderable
+ return '{0}({1!r})'.format(self.__class__.__name__, dict(self))
+
+ # Multiset-style mathematical operations discussed in:
+ # Knuth TAOCP Volume II section 4.6.3 exercise 19
+ # and at http://en.wikipedia.org/wiki/Multiset
+ #
+ # Outputs guaranteed to only include positive counts.
+ #
+ # To strip negative and zero counts, add-in an empty counter:
+ # c += Counter()
+
+ def __add__(self, other):
+ '''Add counts from two counters.
+
+ >>> Counter('abbb') + Counter('bcc')
+ Counter({'b': 4, 'c': 2, 'a': 1})
+
+ '''
+ if not isinstance(other, Counter):
+ return NotImplemented
+ result = Counter()
+ for elem, count in self.items():
+ newcount = count + other[elem]
+ if newcount > 0:
+ result[elem] = newcount
+ for elem, count in other.items():
+ if elem not in self and count > 0:
+ result[elem] = count
+ return result
+
+ def __sub__(self, other):
+ ''' Subtract count, but keep only results with positive counts.
+
+ >>> Counter('abbbc') - Counter('bccd')
+ Counter({'b': 2, 'a': 1})
+
+ '''
+ if not isinstance(other, Counter):
+ return NotImplemented
+ result = Counter()
+ for elem, count in self.items():
+ newcount = count - other[elem]
+ if newcount > 0:
+ result[elem] = newcount
+ for elem, count in other.items():
+ if elem not in self and count < 0:
+ result[elem] = 0 - count
+ return result
+
+ def __or__(self, other):
+ '''Union is the maximum of value in either of the input counters.
+
+ >>> Counter('abbb') | Counter('bcc')
+ Counter({'b': 3, 'c': 2, 'a': 1})
+
+ '''
+ if not isinstance(other, Counter):
+ return NotImplemented
+ result = Counter()
+ for elem, count in self.items():
+ other_count = other[elem]
+ newcount = other_count if count < other_count else count
+ if newcount > 0:
+ result[elem] = newcount
+ for elem, count in other.items():
+ if elem not in self and count > 0:
+ result[elem] = count
+ return result
+
+ def __and__(self, other):
+ ''' Intersection is the minimum of corresponding counts.
+
+ >>> Counter('abbb') & Counter('bcc')
+ Counter({'b': 1})
+
+ '''
+ if not isinstance(other, Counter):
+ return NotImplemented
+ result = Counter()
+ for elem, count in self.items():
+ other_count = other[elem]
+ newcount = count if count < other_count else other_count
+ if newcount > 0:
+ result[elem] = newcount
+ return result
+
+
+########################################################################
+### ChainMap (helper for configparser)
+########################################################################
+
+class ChainMap(MutableMapping):
+ ''' A ChainMap groups multiple dicts (or other mappings) together
+ to create a single, updateable view.
+
+ The underlying mappings are stored in a list. That list is public and can
+ accessed or updated using the *maps* attribute. There is no other state.
+
+ Lookups search the underlying mappings successively until a key is found.
+ In contrast, writes, updates, and deletions only operate on the first
+ mapping.
+
+ '''
+
+ def __init__(self, *maps):
+ '''Initialize a ChainMap by setting *maps* to the given mappings.
+ If no mappings are provided, a single empty dictionary is used.
+
+ '''
+ self.maps = list(maps) or [{}] # always at least one map
+
+ def __missing__(self, key):
+ raise KeyError(key)
+
+ def __getitem__(self, key):
+ for mapping in self.maps:
+ try:
+ return mapping[key] # can't use 'key in mapping' with defaultdict
+ except KeyError:
+ pass
+ return self.__missing__(key) # support subclasses that define __missing__
+
+ def get(self, key, default=None):
+ return self[key] if key in self else default
+
+ def __len__(self):
+ return len(set().union(*self.maps)) # reuses stored hash values if possible
+
+ def __iter__(self):
+ return iter(set().union(*self.maps))
+
+ def __contains__(self, key):
+ return any(key in m for m in self.maps)
+
+ def __bool__(self):
+ return any(self.maps)
+
+ #fixme, brython
+ #@_recursive_repr()
+ def __repr__(self):
+ return '{0.__class__.__name__}({1})'.format(
+ self, ', '.join(map(repr, self.maps)))
+
+ def __repr__(self):
+ return ','.join(str(_map) for _map in self.maps)
+
+ @classmethod
+ def fromkeys(cls, iterable, *args):
+ 'Create a ChainMap with a single dict created from the iterable.'
+ return cls(dict.fromkeys(iterable, *args))
+
+ def copy(self):
+ 'New ChainMap or subclass with a new copy of maps[0] and refs to maps[1:]'
+ return self.__class__(self.maps[0].copy(), *self.maps[1:])
+
+ __copy__ = copy
+
+ def new_child(self): # like Django's Context.push()
+ 'New ChainMap with a new dict followed by all previous maps.'
+ return self.__class__({}, *self.maps)
+
+ @property
+ def parents(self): # like Django's Context.pop()
+ 'New ChainMap from maps[1:].'
+ return self.__class__(*self.maps[1:])
+
+ def __setitem__(self, key, value):
+ self.maps[0][key] = value
+
+ def __delitem__(self, key):
+ try:
+ del self.maps[0][key]
+ except KeyError:
+ raise KeyError('Key not found in the first mapping: {!r}'.format(key))
+
+ def popitem(self):
+ 'Remove and return an item pair from maps[0]. Raise KeyError is maps[0] is empty.'
+ try:
+ return self.maps[0].popitem()
+ except KeyError:
+ raise KeyError('No keys found in the first mapping.')
+
+ def pop(self, key, *args):
+ 'Remove *key* from maps[0] and return its value. Raise KeyError if *key* not in maps[0].'
+ try:
+ return self.maps[0].pop(key, *args)
+ except KeyError:
+ #raise KeyError('Key not found in the first mapping: {!r}'.format(key))
+ raise KeyError('Key not found in the first mapping: %s' % key)
+
+ def clear(self):
+ 'Clear maps[0], leaving maps[1:] intact.'
+ self.maps[0].clear()
+
+
+################################################################################
+### UserDict
+################################################################################
+
+class UserDict(MutableMapping):
+
+ # Start by filling-out the abstract methods
+ def __init__(self, dict=None, **kwargs):
+ self.data = {}
+ if dict is not None:
+ self.update(dict)
+ if len(kwargs):
+ self.update(kwargs)
+ def __len__(self): return len(self.data)
+ def __getitem__(self, key):
+ if key in self.data:
+ return self.data[key]
+ if hasattr(self.__class__, "__missing__"):
+ return self.__class__.__missing__(self, key)
+ raise KeyError(key)
+ def __setitem__(self, key, item): self.data[key] = item
+ def __delitem__(self, key): del self.data[key]
+ def __iter__(self):
+ return iter(self.data)
+
+ # Modify __contains__ to work correctly when __missing__ is present
+ def __contains__(self, key):
+ return key in self.data
+
+ # Now, add the methods in dicts but not in MutableMapping
+ def __repr__(self): return repr(self.data)
+ def copy(self):
+ if self.__class__ is UserDict:
+ return UserDict(self.data.copy())
+ import copy
+ data = self.data
+ try:
+ self.data = {}
+ c = copy.copy(self)
+ finally:
+ self.data = data
+ c.update(self)
+ return c
+ @classmethod
+ def fromkeys(cls, iterable, value=None):
+ d = cls()
+ for key in iterable:
+ d[key] = value
+ return d
+
+################################################################################
+### UserList
+################################################################################
+
+class UserList(MutableSequence):
+ """A more or less complete user-defined wrapper around list objects."""
+ def __init__(self, initlist=None):
+ self.data = []
+ if initlist is not None:
+ # XXX should this accept an arbitrary sequence?
+ if type(initlist) == type(self.data):
+ self.data[:] = initlist
+ elif isinstance(initlist, UserList):
+ self.data[:] = initlist.data[:]
+ else:
+ self.data = list(initlist)
+ def __repr__(self): return repr(self.data)
+ def __lt__(self, other): return self.data < self.__cast(other)
+ def __le__(self, other): return self.data <= self.__cast(other)
+ def __eq__(self, other): return self.data == self.__cast(other)
+ def __ne__(self, other): return self.data != self.__cast(other)
+ def __gt__(self, other): return self.data > self.__cast(other)
+ def __ge__(self, other): return self.data >= self.__cast(other)
+ def __cast(self, other):
+ return other.data if isinstance(other, UserList) else other
+ def __contains__(self, item): return item in self.data
+ def __len__(self): return len(self.data)
+ def __getitem__(self, i): return self.data[i]
+ def __setitem__(self, i, item): self.data[i] = item
+ def __delitem__(self, i): del self.data[i]
+ def __add__(self, other):
+ if isinstance(other, UserList):
+ return self.__class__(self.data + other.data)
+ elif isinstance(other, type(self.data)):
+ return self.__class__(self.data + other)
+ return self.__class__(self.data + list(other))
+ def __radd__(self, other):
+ if isinstance(other, UserList):
+ return self.__class__(other.data + self.data)
+ elif isinstance(other, type(self.data)):
+ return self.__class__(other + self.data)
+ return self.__class__(list(other) + self.data)
+ def __iadd__(self, other):
+ if isinstance(other, UserList):
+ self.data += other.data
+ elif isinstance(other, type(self.data)):
+ self.data += other
+ else:
+ self.data += list(other)
+ return self
+ def __mul__(self, n):
+ return self.__class__(self.data*n)
+ __rmul__ = __mul__
+ def __imul__(self, n):
+ self.data *= n
+ return self
+ def append(self, item): self.data.append(item)
+ def insert(self, i, item): self.data.insert(i, item)
+ def pop(self, i=-1): return self.data.pop(i)
+ def remove(self, item): self.data.remove(item)
+ def clear(self): self.data.clear()
+ def copy(self): return self.__class__(self)
+ def count(self, item): return self.data.count(item)
+ def index(self, item, *args): return self.data.index(item, *args)
+ def reverse(self): self.data.reverse()
+ def sort(self, *args, **kwds): self.data.sort(*args, **kwds)
+ def extend(self, other):
+ if isinstance(other, UserList):
+ self.data.extend(other.data)
+ else:
+ self.data.extend(other)
+
+
+
+################################################################################
+### UserString
+################################################################################
+
+class UserString(Sequence):
+ def __init__(self, seq):
+ if isinstance(seq, str):
+ self.data = seq
+ elif isinstance(seq, UserString):
+ self.data = seq.data[:]
+ else:
+ self.data = str(seq)
+ def __str__(self): return str(self.data)
+ def __repr__(self): return repr(self.data)
+ def __int__(self): return int(self.data)
+ def __float__(self): return float(self.data)
+ def __complex__(self): return complex(self.data)
+ def __hash__(self): return hash(self.data)
+
+ def __eq__(self, string):
+ if isinstance(string, UserString):
+ return self.data == string.data
+ return self.data == string
+ def __ne__(self, string):
+ if isinstance(string, UserString):
+ return self.data != string.data
+ return self.data != string
+ def __lt__(self, string):
+ if isinstance(string, UserString):
+ return self.data < string.data
+ return self.data < string
+ def __le__(self, string):
+ if isinstance(string, UserString):
+ return self.data <= string.data
+ return self.data <= string
+ def __gt__(self, string):
+ if isinstance(string, UserString):
+ return self.data > string.data
+ return self.data > string
+ def __ge__(self, string):
+ if isinstance(string, UserString):
+ return self.data >= string.data
+ return self.data >= string
+
+ def __contains__(self, char):
+ if isinstance(char, UserString):
+ char = char.data
+ return char in self.data
+
+ def __len__(self): return len(self.data)
+ def __getitem__(self, index): return self.__class__(self.data[index])
+ def __add__(self, other):
+ if isinstance(other, UserString):
+ return self.__class__(self.data + other.data)
+ elif isinstance(other, str):
+ return self.__class__(self.data + other)
+ return self.__class__(self.data + str(other))
+ def __radd__(self, other):
+ if isinstance(other, str):
+ return self.__class__(other + self.data)
+ return self.__class__(str(other) + self.data)
+ def __mul__(self, n):
+ return self.__class__(self.data*n)
+ __rmul__ = __mul__
+ def __mod__(self, args):
+ return self.__class__(self.data % args)
+
+ # the following methods are defined in alphabetical order:
+ def capitalize(self): return self.__class__(self.data.capitalize())
+ def center(self, width, *args):
+ return self.__class__(self.data.center(width, *args))
+ def count(self, sub, start=0, end=_sys.maxsize):
+ if isinstance(sub, UserString):
+ sub = sub.data
+ return self.data.count(sub, start, end)
+ def encode(self, encoding=None, errors=None): # XXX improve this?
+ if encoding:
+ if errors:
+ return self.__class__(self.data.encode(encoding, errors))
+ return self.__class__(self.data.encode(encoding))
+ return self.__class__(self.data.encode())
+ def endswith(self, suffix, start=0, end=_sys.maxsize):
+ return self.data.endswith(suffix, start, end)
+ def expandtabs(self, tabsize=8):
+ return self.__class__(self.data.expandtabs(tabsize))
+ def find(self, sub, start=0, end=_sys.maxsize):
+ if isinstance(sub, UserString):
+ sub = sub.data
+ return self.data.find(sub, start, end)
+ def format(self, *args, **kwds):
+ return self.data.format(*args, **kwds)
+ def index(self, sub, start=0, end=_sys.maxsize):
+ return self.data.index(sub, start, end)
+ def isalpha(self): return self.data.isalpha()
+ def isalnum(self): return self.data.isalnum()
+ def isdecimal(self): return self.data.isdecimal()
+ def isdigit(self): return self.data.isdigit()
+ def isidentifier(self): return self.data.isidentifier()
+ def islower(self): return self.data.islower()
+ def isnumeric(self): return self.data.isnumeric()
+ def isspace(self): return self.data.isspace()
+ def istitle(self): return self.data.istitle()
+ def isupper(self): return self.data.isupper()
+ def join(self, seq): return self.data.join(seq)
+ def ljust(self, width, *args):
+ return self.__class__(self.data.ljust(width, *args))
+ def lower(self): return self.__class__(self.data.lower())
+ def lstrip(self, chars=None): return self.__class__(self.data.lstrip(chars))
+ def partition(self, sep):
+ return self.data.partition(sep)
+ def replace(self, old, new, maxsplit=-1):
+ if isinstance(old, UserString):
+ old = old.data
+ if isinstance(new, UserString):
+ new = new.data
+ return self.__class__(self.data.replace(old, new, maxsplit))
+ def rfind(self, sub, start=0, end=_sys.maxsize):
+ if isinstance(sub, UserString):
+ sub = sub.data
+ return self.data.rfind(sub, start, end)
+ def rindex(self, sub, start=0, end=_sys.maxsize):
+ return self.data.rindex(sub, start, end)
+ def rjust(self, width, *args):
+ return self.__class__(self.data.rjust(width, *args))
+ def rpartition(self, sep):
+ return self.data.rpartition(sep)
+ def rstrip(self, chars=None):
+ return self.__class__(self.data.rstrip(chars))
+ def split(self, sep=None, maxsplit=-1):
+ return self.data.split(sep, maxsplit)
+ def rsplit(self, sep=None, maxsplit=-1):
+ return self.data.rsplit(sep, maxsplit)
+ def splitlines(self, keepends=False): return self.data.splitlines(keepends)
+ def startswith(self, prefix, start=0, end=_sys.maxsize):
+ return self.data.startswith(prefix, start, end)
+ def strip(self, chars=None): return self.__class__(self.data.strip(chars))
+ def swapcase(self): return self.__class__(self.data.swapcase())
+ def title(self): return self.__class__(self.data.title())
+ def translate(self, *args):
+ return self.__class__(self.data.translate(*args))
+ def upper(self): return self.__class__(self.data.upper())
+ def zfill(self, width): return self.__class__(self.data.zfill(width))
diff --git a/lib/assets/Lib/collections/abc.py b/lib/assets/Lib/collections/abc.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/collections/abc.py
@@ -0,0 +1,660 @@
+# Copyright 2007 Google, Inc. All Rights Reserved.
+# Licensed to PSF under a Contributor Agreement.
+
+"""Abstract Base Classes (ABCs) for collections, according to PEP 3119.
+
+Unit tests are in test_collections.
+"""
+
+from abc import ABCMeta, abstractmethod
+import sys
+
+__all__ = ["Hashable", "Iterable", "Iterator",
+ "Sized", "Container", "Callable",
+ "Set", "MutableSet",
+ "Mapping", "MutableMapping",
+ "MappingView", "KeysView", "ItemsView", "ValuesView",
+ "Sequence", "MutableSequence",
+ "ByteString",
+ ]
+
+# Private list of types that we want to register with the various ABCs
+# so that they will pass tests like:
+# it = iter(somebytearray)
+# assert isinstance(it, Iterable)
+# Note: in other implementations, these types many not be distinct
+# and they make have their own implementation specific types that
+# are not included on this list.
+bytes_iterator = type(iter(b''))
+bytearray_iterator = type(iter(bytearray()))
+#callable_iterator = ???
+dict_keyiterator = type(iter({}.keys()))
+dict_valueiterator = type(iter({}.values()))
+dict_itemiterator = type(iter({}.items()))
+list_iterator = type(iter([]))
+list_reverseiterator = type(iter(reversed([])))
+range_iterator = type(iter(range(0)))
+set_iterator = type(iter(set()))
+str_iterator = type(iter(""))
+tuple_iterator = type(iter(()))
+zip_iterator = type(iter(zip()))
+## views ##
+dict_keys = type({}.keys())
+dict_values = type({}.values())
+dict_items = type({}.items())
+## misc ##
+mappingproxy = type(type.__dict__)
+
+
+### ONE-TRICK PONIES ###
+
+class Hashable(metaclass=ABCMeta):
+
+ __slots__ = ()
+
+ @abstractmethod
+ def __hash__(self):
+ return 0
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is Hashable:
+ for B in C.__mro__:
+ if "__hash__" in B.__dict__:
+ if B.__dict__["__hash__"]:
+ return True
+ break
+ return NotImplemented
+
+
+class Iterable(metaclass=ABCMeta):
+
+ __slots__ = ()
+
+ @abstractmethod
+ def __iter__(self):
+ while False:
+ yield None
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is Iterable:
+ if any("__iter__" in B.__dict__ for B in C.__mro__):
+ return True
+ return NotImplemented
+
+
+class Iterator(Iterable):
+
+ __slots__ = ()
+
+ @abstractmethod
+ def __next__(self):
+ raise StopIteration
+
+ def __iter__(self):
+ return self
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is Iterator:
+ if (any("__next__" in B.__dict__ for B in C.__mro__) and
+ any("__iter__" in B.__dict__ for B in C.__mro__)):
+ return True
+ return NotImplemented
+
+Iterator.register(bytes_iterator)
+Iterator.register(bytearray_iterator)
+#Iterator.register(callable_iterator)
+Iterator.register(dict_keyiterator)
+Iterator.register(dict_valueiterator)
+Iterator.register(dict_itemiterator)
+Iterator.register(list_iterator)
+Iterator.register(list_reverseiterator)
+Iterator.register(range_iterator)
+Iterator.register(set_iterator)
+Iterator.register(str_iterator)
+Iterator.register(tuple_iterator)
+Iterator.register(zip_iterator)
+
+class Sized(metaclass=ABCMeta):
+
+ __slots__ = ()
+
+ @abstractmethod
+ def __len__(self):
+ return 0
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is Sized:
+ if any("__len__" in B.__dict__ for B in C.__mro__):
+ return True
+ return NotImplemented
+
+
+class Container(metaclass=ABCMeta):
+
+ __slots__ = ()
+
+ @abstractmethod
+ def __contains__(self, x):
+ return False
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is Container:
+ if any("__contains__" in B.__dict__ for B in C.__mro__):
+ return True
+ return NotImplemented
+
+
+class Callable(metaclass=ABCMeta):
+
+ __slots__ = ()
+
+ @abstractmethod
+ def __call__(self, *args, **kwds):
+ return False
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is Callable:
+ if any("__call__" in B.__dict__ for B in C.__mro__):
+ return True
+ return NotImplemented
+
+
+### SETS ###
+
+
+class Set(Sized, Iterable, Container):
+
+ """A set is a finite, iterable container.
+
+ This class provides concrete generic implementations of all
+ methods except for __contains__, __iter__ and __len__.
+
+ To override the comparisons (presumably for speed, as the
+ semantics are fixed), all you have to do is redefine __le__ and
+ then the other operations will automatically follow suit.
+ """
+
+ __slots__ = ()
+
+ def __le__(self, other):
+ if not isinstance(other, Set):
+ return NotImplemented
+ if len(self) > len(other):
+ return False
+ for elem in self:
+ if elem not in other:
+ return False
+ return True
+
+ def __lt__(self, other):
+ if not isinstance(other, Set):
+ return NotImplemented
+ return len(self) < len(other) and self.__le__(other)
+
+ def __gt__(self, other):
+ if not isinstance(other, Set):
+ return NotImplemented
+ return other < self
+
+ def __ge__(self, other):
+ if not isinstance(other, Set):
+ return NotImplemented
+ return other <= self
+
+ def __eq__(self, other):
+ if not isinstance(other, Set):
+ return NotImplemented
+ return len(self) == len(other) and self.__le__(other)
+
+ def __ne__(self, other):
+ return not (self == other)
+
+ @classmethod
+ def _from_iterable(cls, it):
+ '''Construct an instance of the class from any iterable input.
+
+ Must override this method if the class constructor signature
+ does not accept an iterable for an input.
+ '''
+ return cls(it)
+
+ def __and__(self, other):
+ if not isinstance(other, Iterable):
+ return NotImplemented
+ return self._from_iterable(value for value in other if value in self)
+
+ def isdisjoint(self, other):
+ for value in other:
+ if value in self:
+ return False
+ return True
+
+ def __or__(self, other):
+ if not isinstance(other, Iterable):
+ return NotImplemented
+ chain = (e for s in (self, other) for e in s)
+ return self._from_iterable(chain)
+
+ def __sub__(self, other):
+ if not isinstance(other, Set):
+ if not isinstance(other, Iterable):
+ return NotImplemented
+ other = self._from_iterable(other)
+ return self._from_iterable(value for value in self
+ if value not in other)
+
+ def __xor__(self, other):
+ if not isinstance(other, Set):
+ if not isinstance(other, Iterable):
+ return NotImplemented
+ other = self._from_iterable(other)
+ return (self - other) | (other - self)
+
+ def _hash(self):
+ """Compute the hash value of a set.
+
+ Note that we don't define __hash__: not all sets are hashable.
+ But if you define a hashable set type, its __hash__ should
+ call this function.
+
+ This must be compatible __eq__.
+
+ All sets ought to compare equal if they contain the same
+ elements, regardless of how they are implemented, and
+ regardless of the order of the elements; so there's not much
+ freedom for __eq__ or __hash__. We match the algorithm used
+ by the built-in frozenset type.
+ """
+ MAX = sys.maxsize
+ MASK = 2 * MAX + 1
+ n = len(self)
+ h = 1927868237 * (n + 1)
+ h &= MASK
+ for x in self:
+ hx = hash(x)
+ h ^= (hx ^ (hx << 16) ^ 89869747) * 3644798167
+ h &= MASK
+ h = h * 69069 + 907133923
+ h &= MASK
+ if h > MAX:
+ h -= MASK + 1
+ if h == -1:
+ h = 590923713
+ return h
+
+Set.register(frozenset)
+
+
+class MutableSet(Set):
+
+ __slots__ = ()
+
+ @abstractmethod
+ def add(self, value):
+ """Add an element."""
+ raise NotImplementedError
+
+ @abstractmethod
+ def discard(self, value):
+ """Remove an element. Do not raise an exception if absent."""
+ raise NotImplementedError
+
+ def remove(self, value):
+ """Remove an element. If not a member, raise a KeyError."""
+ if value not in self:
+ raise KeyError(value)
+ self.discard(value)
+
+ def pop(self):
+ """Return the popped value. Raise KeyError if empty."""
+ it = iter(self)
+ try:
+ value = next(it)
+ except StopIteration:
+ raise KeyError
+ self.discard(value)
+ return value
+
+ def clear(self):
+ """This is slow (creates N new iterators!) but effective."""
+ try:
+ while True:
+ self.pop()
+ except KeyError:
+ pass
+
+ def __ior__(self, it):
+ for value in it:
+ self.add(value)
+ return self
+
+ def __iand__(self, it):
+ for value in (self - it):
+ self.discard(value)
+ return self
+
+ def __ixor__(self, it):
+ if it is self:
+ self.clear()
+ else:
+ if not isinstance(it, Set):
+ it = self._from_iterable(it)
+ for value in it:
+ if value in self:
+ self.discard(value)
+ else:
+ self.add(value)
+ return self
+
+ def __isub__(self, it):
+ if it is self:
+ self.clear()
+ else:
+ for value in it:
+ self.discard(value)
+ return self
+
+MutableSet.register(set)
+
+
+### MAPPINGS ###
+
+
+class Mapping(Sized, Iterable, Container):
+
+ __slots__ = ()
+
+ @abstractmethod
+ def __getitem__(self, key):
+ raise KeyError
+
+ def get(self, key, default=None):
+ try:
+ return self[key]
+ except KeyError:
+ return default
+
+ def __contains__(self, key):
+ try:
+ self[key]
+ except KeyError:
+ return False
+ else:
+ return True
+
+ def keys(self):
+ return KeysView(self)
+
+ def items(self):
+ return ItemsView(self)
+
+ def values(self):
+ return ValuesView(self)
+
+ def __eq__(self, other):
+ if not isinstance(other, Mapping):
+ return NotImplemented
+ return dict(self.items()) == dict(other.items())
+
+ def __ne__(self, other):
+ return not (self == other)
+
+Mapping.register(mappingproxy)
+
+
+class MappingView(Sized):
+
+ def __init__(self, mapping):
+ self._mapping = mapping
+
+ def __len__(self):
+ return len(self._mapping)
+
+ def __repr__(self):
+ return '{0.__class__.__name__}({0._mapping!r})'.format(self)
+
+
+class KeysView(MappingView, Set):
+
+ @classmethod
+ def _from_iterable(self, it):
+ return set(it)
+
+ def __contains__(self, key):
+ return key in self._mapping
+
+ def __iter__(self):
+ for key in self._mapping:
+ yield key
+
+KeysView.register(dict_keys)
+
+
+class ItemsView(MappingView, Set):
+
+ @classmethod
+ def _from_iterable(self, it):
+ return set(it)
+
+ def __contains__(self, item):
+ key, value = item
+ try:
+ v = self._mapping[key]
+ except KeyError:
+ return False
+ else:
+ return v == value
+
+ def __iter__(self):
+ for key in self._mapping:
+ yield (key, self._mapping[key])
+
+ItemsView.register(dict_items)
+
+
+class ValuesView(MappingView):
+
+ def __contains__(self, value):
+ for key in self._mapping:
+ if value == self._mapping[key]:
+ return True
+ return False
+
+ def __iter__(self):
+ for key in self._mapping:
+ yield self._mapping[key]
+
+ValuesView.register(dict_values)
+
+
+class MutableMapping(Mapping):
+
+ __slots__ = ()
+
+ @abstractmethod
+ def __setitem__(self, key, value):
+ raise KeyError
+
+ @abstractmethod
+ def __delitem__(self, key):
+ raise KeyError
+
+ __marker = object()
+
+ def pop(self, key, default=__marker):
+ try:
+ value = self[key]
+ except KeyError:
+ if default is self.__marker:
+ raise
+ return default
+ else:
+ del self[key]
+ return value
+
+ def popitem(self):
+ try:
+ key = next(iter(self))
+ except StopIteration:
+ raise KeyError
+ value = self[key]
+ del self[key]
+ return key, value
+
+ def clear(self):
+ try:
+ while True:
+ self.popitem()
+ except KeyError:
+ pass
+
+ def update(*args, **kwds):
+ if len(args) > 2:
+ raise TypeError("update() takes at most 2 positional "
+ "arguments ({} given)".format(len(args)))
+ elif not args:
+ raise TypeError("update() takes at least 1 argument (0 given)")
+ self = args[0]
+ other = args[1] if len(args) >= 2 else ()
+
+ if isinstance(other, Mapping):
+ for key in other:
+ self[key] = other[key]
+ elif hasattr(other, "keys"):
+ for key in other.keys():
+ self[key] = other[key]
+ else:
+ for key, value in other:
+ self[key] = value
+ for key, value in kwds.items():
+ self[key] = value
+
+ def setdefault(self, key, default=None):
+ try:
+ return self[key]
+ except KeyError:
+ self[key] = default
+ return default
+
+MutableMapping.register(dict)
+
+
+### SEQUENCES ###
+
+
+class Sequence(Sized, Iterable, Container):
+
+ """All the operations on a read-only sequence.
+
+ Concrete subclasses must override __new__ or __init__,
+ __getitem__, and __len__.
+ """
+
+ __slots__ = ()
+
+ @abstractmethod
+ def __getitem__(self, index):
+ raise IndexError
+
+ def __iter__(self):
+ i = 0
+ try:
+ while True:
+ v = self[i]
+ yield v
+ i += 1
+ except IndexError:
+ return
+
+ def __contains__(self, value):
+ for v in self:
+ if v == value:
+ return True
+ return False
+
+ def __reversed__(self):
+ for i in reversed(range(len(self))):
+ yield self[i]
+
+ def index(self, value):
+ for i, v in enumerate(self):
+ if v == value:
+ return i
+ raise ValueError
+
+ def count(self, value):
+ return sum(1 for v in self if v == value)
+
+Sequence.register(tuple)
+Sequence.register(str)
+Sequence.register(range)
+
+
+class ByteString(Sequence):
+
+ """This unifies bytes and bytearray.
+
+ XXX Should add all their methods.
+ """
+
+ __slots__ = ()
+
+ByteString.register(bytes)
+ByteString.register(bytearray)
+
+
+class MutableSequence(Sequence):
+
+ __slots__ = ()
+
+ @abstractmethod
+ def __setitem__(self, index, value):
+ raise IndexError
+
+ @abstractmethod
+ def __delitem__(self, index):
+ raise IndexError
+
+ @abstractmethod
+ def insert(self, index, value):
+ raise IndexError
+
+ def append(self, value):
+ self.insert(len(self), value)
+
+ def clear(self):
+ try:
+ while True:
+ self.pop()
+ except IndexError:
+ pass
+
+ def reverse(self):
+ n = len(self)
+ for i in range(n//2):
+ self[i], self[n-i-1] = self[n-i-1], self[i]
+
+ def extend(self, values):
+ for v in values:
+ self.append(v)
+
+ def pop(self, index=-1):
+ v = self[index]
+ del self[index]
+ return v
+
+ def remove(self, value):
+ del self[self.index(value)]
+
+ def __iadd__(self, values):
+ self.extend(values)
+ return self
+
+MutableSequence.register(list)
+MutableSequence.register(bytearray) # Multiply inheriting, see ByteString
diff --git a/lib/assets/Lib/colorsys.py b/lib/assets/Lib/colorsys.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/colorsys.py
@@ -0,0 +1,156 @@
+"""Conversion functions between RGB and other color systems.
+
+This modules provides two functions for each color system ABC:
+
+ rgb_to_abc(r, g, b) --> a, b, c
+ abc_to_rgb(a, b, c) --> r, g, b
+
+All inputs and outputs are triples of floats in the range [0.0...1.0]
+(with the exception of I and Q, which covers a slightly larger range).
+Inputs outside the valid range may cause exceptions or invalid outputs.
+
+Supported color systems:
+RGB: Red, Green, Blue components
+YIQ: Luminance, Chrominance (used by composite video signals)
+HLS: Hue, Luminance, Saturation
+HSV: Hue, Saturation, Value
+"""
+
+# References:
+# http://en.wikipedia.org/wiki/YIQ
+# http://en.wikipedia.org/wiki/HLS_color_space
+# http://en.wikipedia.org/wiki/HSV_color_space
+
+__all__ = ["rgb_to_yiq","yiq_to_rgb","rgb_to_hls","hls_to_rgb",
+ "rgb_to_hsv","hsv_to_rgb"]
+
+# Some floating point constants
+
+ONE_THIRD = 1.0/3.0
+ONE_SIXTH = 1.0/6.0
+TWO_THIRD = 2.0/3.0
+
+# YIQ: used by composite video signals (linear combinations of RGB)
+# Y: perceived grey level (0.0 == black, 1.0 == white)
+# I, Q: color components
+
+def rgb_to_yiq(r, g, b):
+ y = 0.30*r + 0.59*g + 0.11*b
+ i = 0.60*r - 0.28*g - 0.32*b
+ q = 0.21*r - 0.52*g + 0.31*b
+ return (y, i, q)
+
+def yiq_to_rgb(y, i, q):
+ r = y + 0.948262*i + 0.624013*q
+ g = y - 0.276066*i - 0.639810*q
+ b = y - 1.105450*i + 1.729860*q
+ if r < 0.0:
+ r = 0.0
+ if g < 0.0:
+ g = 0.0
+ if b < 0.0:
+ b = 0.0
+ if r > 1.0:
+ r = 1.0
+ if g > 1.0:
+ g = 1.0
+ if b > 1.0:
+ b = 1.0
+ return (r, g, b)
+
+
+# HLS: Hue, Luminance, Saturation
+# H: position in the spectrum
+# L: color lightness
+# S: color saturation
+
+def rgb_to_hls(r, g, b):
+ maxc = max(r, g, b)
+ minc = min(r, g, b)
+ # XXX Can optimize (maxc+minc) and (maxc-minc)
+ l = (minc+maxc)/2.0
+ if minc == maxc:
+ return 0.0, l, 0.0
+ if l <= 0.5:
+ s = (maxc-minc) / (maxc+minc)
+ else:
+ s = (maxc-minc) / (2.0-maxc-minc)
+ rc = (maxc-r) / (maxc-minc)
+ gc = (maxc-g) / (maxc-minc)
+ bc = (maxc-b) / (maxc-minc)
+ if r == maxc:
+ h = bc-gc
+ elif g == maxc:
+ h = 2.0+rc-bc
+ else:
+ h = 4.0+gc-rc
+ h = (h/6.0) % 1.0
+ return h, l, s
+
+def hls_to_rgb(h, l, s):
+ if s == 0.0:
+ return l, l, l
+ if l <= 0.5:
+ m2 = l * (1.0+s)
+ else:
+ m2 = l+s-(l*s)
+ m1 = 2.0*l - m2
+ return (_v(m1, m2, h+ONE_THIRD), _v(m1, m2, h), _v(m1, m2, h-ONE_THIRD))
+
+def _v(m1, m2, hue):
+ hue = hue % 1.0
+ if hue < ONE_SIXTH:
+ return m1 + (m2-m1)*hue*6.0
+ if hue < 0.5:
+ return m2
+ if hue < TWO_THIRD:
+ return m1 + (m2-m1)*(TWO_THIRD-hue)*6.0
+ return m1
+
+
+# HSV: Hue, Saturation, Value
+# H: position in the spectrum
+# S: color saturation ("purity")
+# V: color brightness
+
+def rgb_to_hsv(r, g, b):
+ maxc = max(r, g, b)
+ minc = min(r, g, b)
+ v = maxc
+ if minc == maxc:
+ return 0.0, 0.0, v
+ s = (maxc-minc) / maxc
+ rc = (maxc-r) / (maxc-minc)
+ gc = (maxc-g) / (maxc-minc)
+ bc = (maxc-b) / (maxc-minc)
+ if r == maxc:
+ h = bc-gc
+ elif g == maxc:
+ h = 2.0+rc-bc
+ else:
+ h = 4.0+gc-rc
+ h = (h/6.0) % 1.0
+ return h, s, v
+
+def hsv_to_rgb(h, s, v):
+ if s == 0.0:
+ return v, v, v
+ i = int(h*6.0) # XXX assume int() truncates!
+ f = (h*6.0) - i
+ p = v*(1.0 - s)
+ q = v*(1.0 - s*f)
+ t = v*(1.0 - s*(1.0-f))
+ i = i%6
+ if i == 0:
+ return v, t, p
+ if i == 1:
+ return q, v, p
+ if i == 2:
+ return p, v, t
+ if i == 3:
+ return p, q, v
+ if i == 4:
+ return t, p, v
+ if i == 5:
+ return v, p, q
+ # Cannot get here
diff --git a/lib/assets/Lib/configparser.py b/lib/assets/Lib/configparser.py
new file mode 100644
--- /dev/null
+++ b/lib/assets/Lib/configparser.py
@@ -0,0 +1,1271 @@
+"""Configuration file parser.
+
+A configuration file consists of sections, lead by a "[section]" header,
+and followed by "name: value" entries, with continuations and such in
+the style of RFC 822.
+
+Intrinsic defaults can be specified by passing them into the
+ConfigParser constructor as a dictionary.
+
+class:
+
+ConfigParser -- responsible for parsing a list of
+ configuration files, and managing the parsed database.
+
+ methods:
+
+ __init__(defaults=None, dict_type=_default_dict, allow_no_value=False,
+ delimiters=('=', ':'), comment_prefixes=('#', ';'),
+ inline_comment_prefixes=None, strict=True,
+ empty_lines_in_values=True):
+ Create the parser. When `defaults' is given, it is initialized into the
+ dictionary or intrinsic defaults. The keys must be strings, the values
+ must be appropriate for %()s string interpolation.
+
+ When `dict_type' is given, it will be used to create the dictionary
+ objects for the list of sections, for the options within a section, and
+ for the default values.
+
+ When `delimiters' is given, it will be used as the set of substrings
+ that divide keys from values.
+
+ When `comment_prefixes' is given, it will be used as the set of
+ substrings that prefix comments in empty lines. Comments can be
+ indented.
+
+ When `inline_comment_prefixes' is given, it will be used as the set of
+ substrings that prefix comments in non-empty lines.
+
+ When `strict` is True, the parser won't allow for any section or option
+ duplicates while reading from a single source (file, string or
+ dictionary). Default is True.
+
+ When `empty_lines_in_values' is False (default: True), each empty line
+ marks the end of an option. Otherwise, internal empty lines of
+ a multiline option are kept as part of the value.
+
+ When `allow_no_value' is True (default: False), options without
+ values are accepted; the value presented for these is None.
+
+ sections()
+ Return all the configuration section names, sans DEFAULT.
+
+ has_section(section)
+ Return whether the given section exists.
+
+ has_option(section, option)
+ Return whether the given option exists in the given section.
+
+ options(section)
+ Return list of configuration options for the named section.
+
+ read(filenames, encoding=None)
+ Read and parse the list of named configuration files, given by
+ name. A single filename is also allowed. Non-existing files
+ are ignored. Return list of successfully read files.
+
+ read_file(f, filename=None)
+ Read and parse one configuration file, given as a file object.
+ The filename defaults to f.name; it is only used in error
+ messages (if f has no `name' attribute, the string `??>' is used).
+
+ read_string(string)
+ Read configuration from a given string.
+
+ read_dict(dictionary)
+ Read configuration from a dictionary. Keys are section names,
+ values are dictionaries with keys and values that should be present
+ in the section. If the used dictionary type preserves order, sections
+ and their keys will be added in order. Values are automatically
+ converted to strings.
+
+ get(section, option, raw=False, vars=None, fallback=_UNSET)
+ Return a string value for the named option. All % interpolations are
+ expanded in the return values, based on the defaults passed into the
+ constructor and the DEFAULT section. Additional substitutions may be
+ provided using the `vars' argument, which must be a dictionary whose
+ contents override any pre-existing defaults. If `option' is a key in
+ `vars', the value from `vars' is used.
+
+ getint(section, options, raw=False, vars=None, fallback=_UNSET)
+ Like get(), but convert value to an integer.
+
+ getfloat(section, options, raw=False, vars=None, fallback=_UNSET)
+ Like get(), but convert value to a float.
+
+ getboolean(section, options, raw=False, vars=None, fallback=_UNSET)
+ Like get(), but convert value to a boolean (currently case
+ insensitively defined as 0, false, no, off for False, and 1, true,
+ yes, on for True). Returns False or True.
+
+ items(section=_UNSET, raw=False, vars=None)
+ If section is given, return a list of tuples with (name, value) for
+ each option in the section. Otherwise, return a list of tuples with
+ (section_name, section_proxy) for each section, including DEFAULTSECT.
+
+ remove_section(section)
+ Remove the given file section and all its options.
+
+ remove_option(section, option)
+ Remove the given option from the given section.
+
+ set(section, option, value)
+ Set the given option.
+
+ write(fp, space_around_delimiters=True)
+ Write the configuration state in .ini format. If
+ `space_around_delimiters' is True (the default), delimiters
+ between keys and values are surrounded by spaces.
+"""
+
+from collections.abc import MutableMapping
+from collections import OrderedDict as _default_dict, ChainMap as _ChainMap
+import functools
+import io
+import itertools
+import re
+import sys
+import warnings
+
+__all__ = ["NoSectionError", "DuplicateOptionError", "DuplicateSectionError",
+ "NoOptionError", "InterpolationError", "InterpolationDepthError",
+ "InterpolationSyntaxError", "ParsingError",
+ "MissingSectionHeaderError",
+ "ConfigParser", "SafeConfigParser", "RawConfigParser",
+ "DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"]
+
+DEFAULTSECT = "DEFAULT"
+
+MAX_INTERPOLATION_DEPTH = 10
+
+
+
+# exception classes
+class Error(Exception):
+ """Base class for ConfigParser exceptions."""
+
+ def _get_message(self):
+ """Getter for 'message'; needed only to override deprecation in
+ BaseException.
+ """
+ return self.__message
+
+ def _set_message(self, value):
+ """Setter for 'message'; needed only to override deprecation in
+ BaseException.
+ """
+ self.__message = value
+
+ # BaseException.message has been deprecated since Python 2.6. To prevent
+ # DeprecationWarning from popping up over this pre-existing attribute, use
+ # a new property that takes lookup precedence.
+ message = property(_get_message, _set_message)
+
+ def __init__(self, msg=''):
+ self.message = msg
+ Exception.__init__(self, msg)
+
+ def __repr__(self):
+ return self.message
+
+ __str__ = __repr__
+
+
+class NoSectionError(Error):
+ """Raised when no section matches a requested option."""
+
+ def __init__(self, section):
+ Error.__init__(self, 'No section: %r' % (section,))
+ self.section = section
+ self.args = (section, )
+
+
+class DuplicateSectionError(Error):
+ """Raised when a section is repeated in an input source.
+
+ Possible repetitions that raise this exception are: multiple creation
+ using the API or in strict parsers when a section is found more than once
+ in a single input file, string or dictionary.
+ """
+
+ def __init__(self, section, source=None, lineno=None):
+ msg = [repr(section), " already exists"]
+ if source is not None:
+ message = ["While reading from ", source]
+ if lineno is not None:
+ message.append(" [line {0:2d}]".format(lineno))
+ message.append(": section ")
+ message.extend(msg)
+ msg = message
+ else:
+ msg.insert(0, "Section ")
+ Error.__init__(self, "".join(msg))
+ self.section = section
+ self.source = source
+ self.lineno = lineno
+ self.args = (section, source, lineno)
+
+
+class DuplicateOptionError(Error):
+ """Raised by strict parsers when an option is repeated in an input source.
+
+ Current implementation raises this exception only when an option is found
+ more than once in a single file, string or dictionary.
+ """
+
+ def __init__(self, section, option, source=None, lineno=None):
+ msg = [repr(option), " in section ", repr(section),
+ " already exists"]
+ if source is not None:
+ message = ["While reading from ", source]
+ if lineno is not None:
+ message.append(" [line {0:2d}]".format(lineno))
+ message.append(": option ")
+ message.extend(msg)
+ msg = message
+ else:
+ msg.insert(0, "Option ")
+ Error.__init__(self, "".join(msg))
+ self.section = section
+ self.option = option
+ self.source = source
+ self.lineno = lineno
+ self.args = (section, option, source, lineno)
+
+
+class NoOptionError(Error):
+ """A requested option was not found."""
+
+ def __init__(self, option, section):
+ Error.__init__(self, "No option %r in section: %r" %
+ (option, section))
+ self.option = option
+ self.section = section
+ self.args = (option, section)
+
+
+class InterpolationError(Error):
+ """Base class for interpolation-related exceptions."""
+
+ def __init__(self, option, section, msg):
+ Error.__init__(self, msg)
+ self.option = option
+ self.section = section
+ self.args = (option, section, msg)
+
+
+class InterpolationMissingOptionError(InterpolationError):
+ """A string substitution required a setting which was not available."""
+
+ def __init__(self, option, section, rawval, reference):
+ msg = ("Bad value substitution:\n"
+ "\tsection: [%s]\n"
+ "\toption : %s\n"
+ "\tkey : %s\n"
+ "\trawval : %s\n"
+ % (section, option, reference, rawval))
+ InterpolationError.__init__(self, option, section, msg)
+ self.reference = reference
+ self.args = (option, section, rawval, reference)
+
+
+class InterpolationSyntaxError(InterpolationError):
+ """Raised when the source text contains invalid syntax.
+
+ Current implementation raises this exception when the source text into
+ which substitutions are made does not conform to the required syntax.
+ """
+
+
+class InterpolationDepthError(InterpolationError):
+ """Raised when substitutions are nested too deeply."""
+
+ def __init__(self, option, section, rawval):
+ msg = ("Value interpolation too deeply recursive:\n"
+ "\tsection: [%s]\n"
+ "\toption : %s\n"
+ "\trawval : %s\n"
+ % (section, option, rawval))
+ InterpolationError.__init__(self, option, section, msg)
+ self.args = (option, section, rawval)
+
+
+class ParsingError(Error):
+ """Raised when a configuration file does not follow legal syntax."""
+
+ def __init__(self, source=None, filename=None):
+ # Exactly one of `source'/`filename' arguments has to be given.
+ # `filename' kept for compatibility.
+ if filename and source:
+ raise ValueError("Cannot specify both `filename' and `source'. "
+ "Use `source'.")
+ elif not filename and not source:
+ raise ValueError("Required argument `source' not given.")
+ elif filename:
+ source = filename
+ Error.__init__(self, 'Source contains parsing errors: %s' % source)
+ self.source = source
+ self.errors = []
+ self.args = (source, )
+
+ @property
+ def filename(self):
+ """Deprecated, use `source'."""
+ warnings.warn(
+ "The 'filename' attribute will be removed in future versions. "
+ "Use 'source' instead.",
+ DeprecationWarning, stacklevel=2
+ )
+ return self.source
+
+ @filename.setter
+ def filename(self, value):
+ """Deprecated, user `source'."""
+ warnings.warn(
+ "The 'filename' attribute will be removed in future versions. "
+ "Use 'source' instead.",
+ DeprecationWarning, stacklevel=2
+ )
+ self.source = value
+
+ def append(self, lineno, line):
+ self.errors.append((lineno, line))
+ self.message += '\n\t[line %2d]: %s' % (lineno, line)
+
+
+class MissingSectionHeaderError(ParsingError):
+ """Raised when a key-value pair is found before any section header."""
+
+ def __init__(self, filename, lineno, line):
+ Error.__init__(
+ self,
+ 'File contains no section headers.\nfile: %s, line: %d\n%r' %
+ (filename, lineno, line))
+ self.source = filename
+ self.lineno = lineno
+ self.line = line
+ self.args = (filename, lineno, line)
+
+
+# Used in parser getters to indicate the default behaviour when a specific
+# option is not found it to raise an exception. Created to enable `None' as
+# a valid fallback value.
+_UNSET = object()
+
+
+class Interpolation:
+ """Dummy interpolation that passes the value through with no changes."""
+
+ def before_get(self, parser, section, option, value, defaults):
+ return value
+
+ def before_set(self, parser, section, option, value):
+ return value
+
+ def before_read(self, parser, section, option, value):
+ return value
+
+ def before_write(self, parser, section, option, value):
+ return value
+
+
+class BasicInterpolation(Interpolation):
+ """Interpolation as implemented in the classic ConfigParser.
+
+ The option values can contain format strings which refer to other values in
+ the same section, or values in the special default section.
+
+ For example:
+
+ something: %(dir)s/whatever
+
+ would resolve the "%(dir)s" to the value of dir. All reference
+ expansions are done late, on demand. If a user needs to use a bare % in
+ a configuration file, she can escape it by writing %%. Other % usage
+ is considered a user error and raises `InterpolationSyntaxError'."""
+
+ _KEYCRE = re.compile(r"%\(([^)]+)\)s")
+
+ def before_get(self, parser, section, option, value, defaults):
+ L = []
+ self._interpolate_some(parser, option, L, value, section, defaults, 1)
+ return ''.join(L)
+
+ def before_set(self, parser, section, option, value):
+ tmp_value = value.replace('%%', '') # escaped percent signs
+ tmp_value = self._KEYCRE.sub('', tmp_value) # valid syntax
+ if '%' in tmp_value:
+ raise ValueError("invalid interpolation syntax in %r at "
+ "position %d" % (value, tmp_value.find('%')))
+ return value
+
+ def _interpolate_some(self, parser, option, accum, rest, section, map,
+ depth):
+ if depth > MAX_INTERPOLATION_DEPTH:
+ raise InterpolationDepthError(option, section, rest)
+ while rest:
+ p = rest.find("%")
+ if p < 0:
+ accum.append(rest)
+ return
+ if p > 0:
+ accum.append(rest[:p])
+ rest = rest[p:]
+ # p is no longer used
+ c = rest[1:2]
+ if c == "%":
+ accum.append("%")
+ rest = rest[2:]
+ elif c == "(":
+ m = self._KEYCRE.match(rest)
+ if m is None:
+ raise InterpolationSyntaxError(option, section,
+ "bad interpolation variable reference %r" % rest)
+ var = parser.optionxform(m.group(1))
+ rest = rest[m.end():]
+ try:
+ v = map[var]
+ except KeyError:
+ raise InterpolationMissingOptionError(
+ option, section, rest, var)
+ if "%" in v:
+ self._interpolate_some(parser, option, accum, v,
+ section, map, depth + 1)
+ else:
+ accum.append(v)
+ else:
+ raise InterpolationSyntaxError(
+ option, section,
+ "'%%' must be followed by '%%' or '(', "
+ "found: %r" % (rest,))
+
+
+class ExtendedInterpolation(Interpolation):
+ """Advanced variant of interpolation, supports the syntax used by
+ `zc.buildout'. Enables interpolation between sections."""
+
+ _KEYCRE = re.compile(r"\$\{([^}]+)\}")
+
+ def before_get(self, parser, section, option, value, defaults):
+ L = []
+ self._interpolate_some(parser, option, L, value, section, defaults, 1)
+ return ''.join(L)
+
+ def before_set(self, parser, section, option, value):
+ tmp_value = value.replace('$$', '') # escaped dollar signs
+ tmp_value = self._KEYCRE.sub('', tmp_value) # valid syntax
+ if '$' in tmp_value:
+ raise ValueError("invalid interpolation syntax in %r at "
+ "position %d" % (value, tmp_value.find('%')))
+ return value
+
+ def _interpolate_some(self, parser, option, accum, rest, section, map,
+ depth):
+ if depth > MAX_INTERPOLATION_DEPTH:
+ raise InterpolationDepthError(option, section, rest)
+ while rest:
+ p = rest.find("$")
+ if p < 0:
+ accum.append(rest)
+ return
+ if p > 0:
+ accum.append(rest[:p])
+ rest = rest[p:]
+ # p is no longer used
+ c = rest[1:2]
+ if c == "$":
+ accum.append("$")
+ rest = rest[2:]
+ elif c == "{":
+ m = self._KEYCRE.match(rest)
+ if m is None:
+ raise InterpolationSyntaxError(option, section,
+ "bad interpolation variable reference %r" % rest)
+ path = m.group(1).split(':')
+ rest = rest[m.end():]
+ sect = section
+ opt = option
+ try:
+ if len(path) == 1:
+ opt = parser.optionxform(path[0])
+ v = map[opt]
+ elif len(path) == 2:
+ sect = path[0]
+ opt = parser.optionxform(path[1])
+ v = parser.get(sect, opt, raw=True)
+ else:
+ raise InterpolationSyntaxError(
+ option, section,
+ "More than one ':' found: %r" % (rest,))
+ except (KeyError, NoSectionError, NoOptionError):
+ raise InterpolationMissingOptionError(
+ option, section, rest, ":".join(path))
+ if "$" in v:
+ self._interpolate_some(parser, opt, accum, v, sect,
+ dict(parser.items(sect, raw=True)),
+ depth + 1)
+ else:
+ accum.append(v)
+ else:
+ raise InterpolationSyntaxError(
+ option, section,
+ "'$' must be followed by '$' or '{', "
+ "found: %r" % (rest,))
+
+
+class LegacyInterpolation(Interpolation):
+ """Deprecated interpolation used in old versions of ConfigParser.
+ Use BasicInterpolation or ExtendedInterpolation instead."""
+
+ _KEYCRE = re.compile(r"%\(([^)]*)\)s|.")
+
+ def before_get(self, parser, section, option, value, vars):
+ rawval = value
+ depth = MAX_INTERPOLATION_DEPTH
+ while depth: # Loop through this until it's done
+ depth -= 1
+ if value and "%(" in value:
+ replace = functools.partial(self._interpolation_replace,
+ parser=parser)
+ value = self._KEYCRE.sub(replace, value)
+ try:
+ value = value % vars
+ except KeyError as e:
+ raise InterpolationMissingOptionError(
+ option, section, rawval, e.args[0])
+ else:
+ break
+ if value and "%(" in value:
+ raise InterpolationDepthError(option, section, rawval)
+ return value
+
+ def before_set(self, parser, section, option, value):
+ return value
+
+ @staticmethod
+ def _interpolation_replace(match, parser):
+ s = match.group(1)
+ if s is None:
+ return match.group()
+ else:
+ return "%%(%s)s" % parser.optionxform(s)
+
+
+class RawConfigParser(MutableMapping):
+ """ConfigParser that does not do interpolation."""
+
+ # Regular expressions for parsing section headers and options
+ _SECT_TMPL = r"""
+ \[ # [
+ (?P[^]]+) # very permissive!
+ \] # ]
+ """
+ _OPT_TMPL = r"""
+ (?P