Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/vendor
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-06-30 03:08:16 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-06-30 03:08:16 +0300
commit7b5ff5df506fb54eea0e5d58aadecd0e184ca089 (patch)
tree8e1748068f8a2c17cb99948f1e2721718f41f0e4 /vendor
parentab593c8ded443f7ade3540ff8dac69ee51bc74fd (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'vendor')
-rw-r--r--vendor/gems/ipynbdiff/.gitignore2
-rw-r--r--vendor/gems/ipynbdiff/.gitlab-ci.yml32
-rw-r--r--vendor/gems/ipynbdiff/Gemfile5
-rw-r--r--vendor/gems/ipynbdiff/Gemfile.lock64
-rw-r--r--vendor/gems/ipynbdiff/LICENSE21
-rw-r--r--vendor/gems/ipynbdiff/README.md56
-rw-r--r--vendor/gems/ipynbdiff/ipynbdiff.gemspec33
-rw-r--r--vendor/gems/ipynbdiff/lib/diff.rb20
-rw-r--r--vendor/gems/ipynbdiff/lib/ipynb_symbol_map.rb218
-rw-r--r--vendor/gems/ipynbdiff/lib/ipynbdiff.rb23
-rw-r--r--vendor/gems/ipynbdiff/lib/output_transformer.rb83
-rw-r--r--vendor/gems/ipynbdiff/lib/symbolized_markdown_helper.rb26
-rw-r--r--vendor/gems/ipynbdiff/lib/transformed_notebook.rb20
-rw-r--r--vendor/gems/ipynbdiff/lib/transformer.rb101
-rw-r--r--vendor/gems/ipynbdiff/lib/version.rb5
-rw-r--r--vendor/gems/ipynbdiff/spec/ipynb_symbol_map_spec.rb165
-rw-r--r--vendor/gems/ipynbdiff/spec/ipynbdiff_spec.rb126
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/backslash_as_last_char/expected.md7
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/backslash_as_last_char/expected_symbols.txt7
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/backslash_as_last_char/input.ipynb16
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/error_output/expected.md16
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/error_output/expected_symbols.txt16
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/error_output/input.ipynb32
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/from.ipynb198
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/hide_images/expected.md12
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/hide_images/expected_symbols.txt12
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/hide_images/input.ipynb45
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/ignore_html_output/expected.md11
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/ignore_html_output/expected_symbols.txt11
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/ignore_html_output/input.ipynb74
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/latex_output/expected.md10
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/latex_output/expected_symbols.txt10
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/latex_output/input.ipynb34
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/multiline_png_output/expected.md9
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/multiline_png_output/expected_symbols.txt9
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/multiline_png_output/input.ipynb25
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/no_cells/expected.md19
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/no_cells/expected_symbols.txt19
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/no_cells/input.ipynb25
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/no_cells_no_metadata/expected.md0
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/no_cells_no_metadata/expected_symbols.txt0
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/no_cells_no_metadata/input.ipynb25
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/no_metadata_on_cell/expected.md13
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/no_metadata_on_cell/expected_symbols.txt13
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/no_metadata_on_cell/input.ipynb29
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/only_code/expected.md7
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/only_code/expected_symbols.txt7
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/only_code/input.ipynb21
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/only_code_no_kernelspec/expected.md5
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/only_code_no_kernelspec/expected_symbols.txt5
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/only_code_no_kernelspec/input.ipynb12
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/only_code_no_language/expected.md5
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/only_code_no_language/expected_symbols.txt5
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/only_code_no_language/input.ipynb14
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/only_code_no_metadata/expected.md5
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/only_code_no_metadata/expected_symbols.txt5
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/only_code_no_metadata/input.ipynb11
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/only_md/expected.md5
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/only_md/expected_symbols.txt5
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/only_md/input.ipynb21
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/only_raw/expected.md4
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/only_raw/expected_symbols.txt4
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/only_raw/input.ipynb15
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/percent_decorator/expected.md70
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/percent_decorator/expected_symbols.txt70
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/single_line_md/expected.md3
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/single_line_md/expected_symbols.txt3
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/single_line_md/input.ipynb17
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/stream_text/expected.md9
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/stream_text/expected_symbols.txt9
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/stream_text/input.ipynb27
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/svg/expected.md19
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/svg/expected_symbols.txt19
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/svg/input.ipynb66
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/text_output/expected.md9
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/text_output/expected_symbols.txt9
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/text_output/input.ipynb31
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/text_png_output/expected.md16
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/text_png_output/expected_symbols.txt16
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/text_png_output/input.ipynb49
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/to.ipynb200
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/unknown_output_type/expected.md5
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/unknown_output_type/expected_symbols.txt5
-rw-r--r--vendor/gems/ipynbdiff/spec/testdata/unknown_output_type/input.ipynb27
-rw-r--r--vendor/gems/ipynbdiff/spec/transformer_spec.rb90
85 files changed, 2622 insertions, 0 deletions
diff --git a/vendor/gems/ipynbdiff/.gitignore b/vendor/gems/ipynbdiff/.gitignore
new file mode 100644
index 00000000000..4f284c35a42
--- /dev/null
+++ b/vendor/gems/ipynbdiff/.gitignore
@@ -0,0 +1,2 @@
+*.gem
+.bundle
diff --git a/vendor/gems/ipynbdiff/.gitlab-ci.yml b/vendor/gems/ipynbdiff/.gitlab-ci.yml
new file mode 100644
index 00000000000..7b0c9df6cd9
--- /dev/null
+++ b/vendor/gems/ipynbdiff/.gitlab-ci.yml
@@ -0,0 +1,32 @@
+# You can override the included template(s) by including variable overrides
+# SAST customization: https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings
+# Secret Detection customization: https://docs.gitlab.com/ee/user/application_security/secret_detection/#customizing-settings
+# Dependency Scanning customization: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#customizing-the-dependency-scanning-settings
+# Note that environment variables can be set in several places
+# See https://docs.gitlab.com/ee/ci/variables/#cicd-variable-precedence
+workflow:
+ rules:
+ - if: $CI_MERGE_REQUEST_ID
+
+.rspec:
+ cache:
+ key: ipynbdiff
+ paths:
+ - vendor/gems/ipynbdiff/vendor/ruby
+ before_script:
+ - cd vendor/gems/ipynbdiff
+ - ruby -v # Print out ruby version for debugging
+ - gem install bundler --no-document # Bundler is not installed with the image
+ - bundle config set --local path 'vendor' # Install dependencies into ./vendor/ruby
+ - bundle config set with 'development'
+ - bundle install -j $(nproc)
+ script:
+ - bundle exec rspec
+
+rspec-2.7:
+ image: "ruby:2.7"
+ extends: .rspec
+
+rspec-3.0:
+ image: "ruby:3.0"
+ extends: .rspec
diff --git a/vendor/gems/ipynbdiff/Gemfile b/vendor/gems/ipynbdiff/Gemfile
new file mode 100644
index 00000000000..7f4f5e950d1
--- /dev/null
+++ b/vendor/gems/ipynbdiff/Gemfile
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+source 'https://rubygems.org'
+
+gemspec
diff --git a/vendor/gems/ipynbdiff/Gemfile.lock b/vendor/gems/ipynbdiff/Gemfile.lock
new file mode 100644
index 00000000000..a5e8e3e4e86
--- /dev/null
+++ b/vendor/gems/ipynbdiff/Gemfile.lock
@@ -0,0 +1,64 @@
+PATH
+ remote: .
+ specs:
+ ipynbdiff (0.4.7)
+ diffy (~> 3.3)
+ json (~> 2.5, >= 2.5.1)
+
+GEM
+ remote: https://rubygems.org/
+ specs:
+ ast (2.4.2)
+ binding_ninja (0.2.3)
+ coderay (1.1.3)
+ diff-lcs (1.5.0)
+ diffy (3.4.2)
+ json (2.6.2)
+ method_source (1.0.0)
+ parser (3.1.2.0)
+ ast (~> 2.4.1)
+ proc_to_ast (0.1.0)
+ coderay
+ parser
+ unparser
+ pry (0.14.1)
+ coderay (~> 1.1)
+ method_source (~> 1.0)
+ rake (13.0.6)
+ rspec (3.11.0)
+ rspec-core (~> 3.11.0)
+ rspec-expectations (~> 3.11.0)
+ rspec-mocks (~> 3.11.0)
+ rspec-core (3.11.0)
+ rspec-support (~> 3.11.0)
+ rspec-expectations (3.11.0)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.11.0)
+ rspec-mocks (3.11.1)
+ diff-lcs (>= 1.2.0, < 2.0)
+ rspec-support (~> 3.11.0)
+ rspec-parameterized (0.5.1)
+ binding_ninja (>= 0.2.3)
+ parser
+ proc_to_ast
+ rspec (>= 2.13, < 4)
+ unparser
+ rspec-support (3.11.0)
+ unparser (0.6.5)
+ diff-lcs (~> 1.3)
+ parser (>= 3.1.0)
+
+PLATFORMS
+ x86_64-darwin-20
+ x86_64-linux
+
+DEPENDENCIES
+ bundler (~> 2.2)
+ ipynbdiff!
+ pry (~> 0.14)
+ rake (~> 13.0)
+ rspec (~> 3.10)
+ rspec-parameterized (~> 0.5.1)
+
+BUNDLED WITH
+ 2.3.16
diff --git a/vendor/gems/ipynbdiff/LICENSE b/vendor/gems/ipynbdiff/LICENSE
new file mode 100644
index 00000000000..e6de2f90864
--- /dev/null
+++ b/vendor/gems/ipynbdiff/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016-2021 GitLab B.V.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/gems/ipynbdiff/README.md b/vendor/gems/ipynbdiff/README.md
new file mode 100644
index 00000000000..f046f678a4d
--- /dev/null
+++ b/vendor/gems/ipynbdiff/README.md
@@ -0,0 +1,56 @@
+# IpynbDiff: Better diff for Jupyter Notebooks
+
+This is a simple diff tool that cleans up Jupyter notebooks, transforming each [notebook](example/1/from.ipynb)
+into a [readable markdown file](example/1/from_html.md), keeping the output of cells, and running the
+diff after. Markdowns are generated using an opinionated Jupyter to Markdown conversion. This means
+that the entire file is readable on the diff.
+
+The result are diffs that are much easier to read:
+
+| Diff | IpynbDiff |
+| ----------------------------------- | ----------------------------------------------------- |
+| [Diff text](example/diff.txt) | [IpynbDiff text](example/ipynbdiff_percent.txt) |
+| ![Diff image](example/img/diff.png) | ![IpynbDiff image](example/img/ipynbdiff_percent.png) |
+
+This started as a port of [ipynbdiff](https://gitlab.com/gitlab-org/incubation-engineering/mlops/poc/ipynbdiff),
+but now has extended functionality although not working as git driver.
+
+## Usage
+
+### Generating diffs
+
+```ruby
+IpynbDiff.diff(from_path, to_path, options)
+```
+
+Options:
+
+```ruby
+@default_transform_options = {
+ preprocess_input: true, # Whether the input should be transformed
+ write_output_to: nil, # Pass a path to save the output to a file
+ format: :text, # These are the formats Diffy accepts https://github.com/samg/diffy
+ sources_are_files: false, # Weather to use the from/to as string or path to a file
+ raise_if_invalid_notebook: false, # Raises an error if the notebooks are invalid, otherwise returns nil
+ transform_options: @default_transform_options, # See below for transform options
+ diff_opts: {
+ include_diff_info: false # These are passed to Diffy https://github.com/samg/diffy
+ }
+}
+```
+
+### Transforming the notebooks
+
+It might be necessary to have the transformed files in addition to the diff.
+
+```ruby
+IpynbDiff.transform(notebook, options)
+```
+
+Options:
+
+```ruby
+@default_transform_options = {
+ include_frontmatter: false, # Whether to include or not the notebook metadata (kernel, language, etc)
+}
+```
diff --git a/vendor/gems/ipynbdiff/ipynbdiff.gemspec b/vendor/gems/ipynbdiff/ipynbdiff.gemspec
new file mode 100644
index 00000000000..8f4dfef8177
--- /dev/null
+++ b/vendor/gems/ipynbdiff/ipynbdiff.gemspec
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+lib = File.expand_path('lib/..', __dir__)
+$LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
+
+require 'lib/version'
+
+Gem::Specification.new do |s|
+ s.name = 'ipynbdiff'
+ s.version = IpynbDiff::VERSION
+ s.summary = 'Human Readable diffs for Jupyter Notebooks'
+ s.description = 'Better diff for Jupyter Notebooks by first preprocessing them and removing clutter'
+ s.authors = ['Eduardo Bonet']
+ s.email = 'ebonet@gitlab.com'
+ # Specify which files should be added to the gem when it is released.
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
+ s.files = Dir.glob("lib/**/*.*")
+ s.test_files = Dir.glob("spec/**/*.*")
+ s.homepage =
+ 'https://gitlab.com/gitlab-org/incubation-engineering/mlops/rb-ipynbdiff'
+ s.license = 'MIT'
+
+ s.require_paths = ['lib']
+
+ s.add_runtime_dependency 'diffy', '~> 3.3'
+ s.add_runtime_dependency 'json', '~> 2.5', '>= 2.5.1'
+
+ s.add_development_dependency 'bundler', '~> 2.2'
+ s.add_development_dependency 'pry', '~> 0.14'
+ s.add_development_dependency 'rake', '~> 13.0'
+ s.add_development_dependency 'rspec', '~> 3.10'
+ s.add_development_dependency 'rspec-parameterized', '~> 0.5.1'
+end
diff --git a/vendor/gems/ipynbdiff/lib/diff.rb b/vendor/gems/ipynbdiff/lib/diff.rb
new file mode 100644
index 00000000000..3554ac55d99
--- /dev/null
+++ b/vendor/gems/ipynbdiff/lib/diff.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+# Custom differ for Jupyter Notebooks
+module IpynbDiff
+ require 'delegate'
+
+ # The result of a diff object
+ class Diff < SimpleDelegator
+ require 'diffy'
+
+ attr_reader :from, :to
+
+ def initialize(from, to, diffy_opts)
+ super(Diffy::Diff.new(from.as_text, to.as_text, **diffy_opts))
+
+ @from = from
+ @to = to
+ end
+ end
+end
diff --git a/vendor/gems/ipynbdiff/lib/ipynb_symbol_map.rb b/vendor/gems/ipynbdiff/lib/ipynb_symbol_map.rb
new file mode 100644
index 00000000000..33e06aa8d18
--- /dev/null
+++ b/vendor/gems/ipynbdiff/lib/ipynb_symbol_map.rb
@@ -0,0 +1,218 @@
+# frozen_string_literal: true
+
+module IpynbDiff
+ class InvalidTokenError < StandardError
+ end
+
+ # Creates a symbol map for a ipynb file (JSON format)
+ class IpynbSymbolMap
+ class << self
+ def parse(notebook, objects_to_ignore = [])
+ IpynbSymbolMap.new(notebook, objects_to_ignore).parse('')
+ end
+ end
+
+ attr_reader :current_line, :char_idx, :results
+
+ WHITESPACE_CHARS = ["\t", "\r", ' ', "\n"].freeze
+
+ VALUE_STOPPERS = [',', '[', ']', '{', '}', *WHITESPACE_CHARS].freeze
+
+ def initialize(notebook, objects_to_ignore = [])
+ @chars = notebook.chars
+ @current_line = 0
+ @char_idx = 0
+ @results = {}
+ @objects_to_ignore = objects_to_ignore
+ end
+
+ def parse(prefix = '.')
+ raise_if_file_ended
+
+ skip_whitespaces
+
+ if (c = current_char) == '"'
+ parse_string
+ elsif c == '['
+ parse_array(prefix)
+ elsif c == '{'
+ parse_object(prefix)
+ else
+ parse_value
+ end
+
+ results
+ end
+
+ def parse_array(prefix)
+ # [1, 2, {"some": "object"}, [1]]
+
+ i = 0
+
+ current_should_be '['
+
+ loop do
+ raise_if_file_ended
+
+ break if skip_beginning(']')
+
+ new_prefix = "#{prefix}.#{i}"
+
+ add_result(new_prefix, current_line)
+
+ parse(new_prefix)
+
+ i += 1
+ end
+ end
+
+ def parse_object(prefix)
+ # {"name":"value", "another_name": [1, 2, 3]}
+
+ current_should_be '{'
+
+ loop do
+ raise_if_file_ended
+
+ break if skip_beginning('}')
+
+ prop_name = parse_string(return_value: true)
+
+ next_and_skip_whitespaces
+
+ current_should_be ':'
+
+ next_and_skip_whitespaces
+
+ if @objects_to_ignore.include? prop_name
+ skip
+ else
+ new_prefix = "#{prefix}.#{prop_name}"
+
+ add_result(new_prefix, current_line)
+
+ parse(new_prefix)
+ end
+ end
+ end
+
+ def parse_string(return_value: false)
+ current_should_be '"'
+ init_idx = @char_idx
+
+ loop do
+ increment_char_index
+
+ raise_if_file_ended
+
+ if current_char == '"' && !prev_backslash?
+ init_idx += 1
+ break
+ end
+ end
+
+ @chars[init_idx...@char_idx].join if return_value
+ end
+
+ def add_result(key, line_number)
+ @results[key] = line_number
+ end
+
+ def parse_value
+ increment_char_index until raise_if_file_ended || VALUE_STOPPERS.include?(current_char)
+ end
+
+ def skip_whitespaces
+ while WHITESPACE_CHARS.include?(current_char)
+ raise_if_file_ended
+ check_for_new_line
+ increment_char_index
+ end
+ end
+
+ def increment_char_index
+ @char_idx += 1
+ end
+
+ def next_and_skip_whitespaces
+ increment_char_index
+ skip_whitespaces
+ end
+
+ def current_char
+ raise_if_file_ended
+
+ @chars[@char_idx]
+ end
+
+ def prev_backslash?
+ @chars[@char_idx - 1] == '\\' && @chars[@char_idx - 2] != '\\'
+ end
+
+ def current_should_be(another_char)
+ raise InvalidTokenError unless current_char == another_char
+ end
+
+ def check_for_new_line
+ @current_line += 1 if current_char == "\n"
+ end
+
+ def raise_if_file_ended
+ @char_idx >= @chars.size && raise(InvalidTokenError)
+ end
+
+ def skip
+ raise_if_file_ended
+
+ skip_whitespaces
+
+ if (c = current_char) == '"'
+ parse_string
+ elsif c == '['
+ skip_array
+ elsif c == '{'
+ skip_object
+ else
+ parse_value
+ end
+ end
+
+ def skip_array
+ loop do
+ raise_if_file_ended
+
+ break if skip_beginning(']')
+
+ skip
+ end
+ end
+
+ def skip_object
+ loop do
+ raise_if_file_ended
+
+ break if skip_beginning('}')
+
+ parse_string
+
+ next_and_skip_whitespaces
+
+ current_should_be ':'
+
+ next_and_skip_whitespaces
+
+ skip
+ end
+ end
+
+ def skip_beginning(closing_char)
+ check_for_new_line
+
+ next_and_skip_whitespaces
+
+ return true if current_char == closing_char
+
+ next_and_skip_whitespaces if current_char == ','
+ end
+ end
+end
diff --git a/vendor/gems/ipynbdiff/lib/ipynbdiff.rb b/vendor/gems/ipynbdiff/lib/ipynbdiff.rb
new file mode 100644
index 00000000000..1765e434bf9
--- /dev/null
+++ b/vendor/gems/ipynbdiff/lib/ipynbdiff.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+# Human Readable Jupyter Diffs
+module IpynbDiff
+ require 'transformer'
+ require 'diff'
+
+ def self.diff(from, to, raise_if_invalid_nb: false, include_frontmatter: false, hide_images: false, diffy_opts: {})
+ transformer = Transformer.new(include_frontmatter: include_frontmatter, hide_images: hide_images)
+
+ Diff.new(transformer.transform(from), transformer.transform(to), diffy_opts)
+ rescue InvalidNotebookError
+ raise if raise_if_invalid_nb
+ end
+
+ def self.transform(notebook, raise_errors: false, include_frontmatter: true, hide_images: false)
+ return unless notebook
+
+ Transformer.new(include_frontmatter: include_frontmatter, hide_images: hide_images).transform(notebook).as_text
+ rescue InvalidNotebookError
+ raise if raise_errors
+ end
+end
diff --git a/vendor/gems/ipynbdiff/lib/output_transformer.rb b/vendor/gems/ipynbdiff/lib/output_transformer.rb
new file mode 100644
index 00000000000..88728df2f17
--- /dev/null
+++ b/vendor/gems/ipynbdiff/lib/output_transformer.rb
@@ -0,0 +1,83 @@
+# frozen_string_literal: true
+
+module IpynbDiff
+ # Transforms Jupyter output data into markdown
+ class OutputTransformer
+ require 'symbolized_markdown_helper'
+ include SymbolizedMarkdownHelper
+
+ HIDDEN_IMAGE_OUTPUT = ' [Hidden Image Output]'
+
+ ORDERED_KEYS = {
+ 'execute_result' => %w[image/png image/svg+xml image/jpeg text/markdown text/latex text/plain],
+ 'display_data' => %w[image/png image/svg+xml image/jpeg text/markdown text/latex],
+ 'stream' => %w[text]
+ }.freeze
+
+ def initialize(hide_images: false)
+ @hide_images = hide_images
+ end
+
+ def transform(output, symbol)
+ transformed = case (output_type = output['output_type'])
+ when 'error'
+ transform_error(output['traceback'], symbol / 'traceback')
+ when 'execute_result', 'display_data'
+ transform_non_error(ORDERED_KEYS[output_type], output['data'], symbol / 'data')
+ when 'stream'
+ transform_element('text', output['text'], symbol)
+ end
+
+ transformed ? decorate_output(transformed, output, symbol) : []
+ end
+
+ def decorate_output(output_rows, output, symbol)
+ [
+ _,
+ _(symbol, %(%%%% Output: #{output['output_type']})),
+ _,
+ *output_rows
+ ]
+ end
+
+ def transform_error(traceback, symbol)
+ traceback.map.with_index do |t, idx|
+ t.split("\n").map do |l|
+ _(symbol / idx, l.gsub(/\[[0-9][0-9;]*m/, '').sub("\u001B", ' ').gsub(/\u001B/, '').rstrip)
+ end
+ end
+ end
+
+ def transform_non_error(accepted_keys, elements, symbol)
+ accepted_keys.filter { |key| elements.key?(key) }.map do |key|
+ transform_element(key, elements[key], symbol)
+ end
+ end
+
+ def transform_element(output_type, output_element, symbol_prefix)
+ new_symbol = symbol_prefix / output_type
+ case output_type
+ when 'image/png', 'image/jpeg'
+ transform_image(output_type + ';base64', output_element, new_symbol)
+ when 'image/svg+xml'
+ transform_image(output_type + ';utf8', output_element, new_symbol)
+ when 'text/markdown', 'text/latex', 'text/plain', 'text'
+ transform_text(output_element, new_symbol)
+ end
+ end
+
+ def transform_image(image_type, image_content, symbol)
+ return _(nil, HIDDEN_IMAGE_OUTPUT) if @hide_images
+
+ lines = image_content.is_a?(Array) ? image_content : [image_content]
+
+ single_line = lines.map(&:strip).join.gsub(/\s+/, ' ')
+
+ _(symbol, " ![](data:#{image_type},#{single_line})")
+ end
+
+ def transform_text(text_content, symbol)
+ symbolize_array(symbol, text_content) { |l| " #{l.rstrip}" }
+ end
+ end
+end
diff --git a/vendor/gems/ipynbdiff/lib/symbolized_markdown_helper.rb b/vendor/gems/ipynbdiff/lib/symbolized_markdown_helper.rb
new file mode 100644
index 00000000000..918666ed899
--- /dev/null
+++ b/vendor/gems/ipynbdiff/lib/symbolized_markdown_helper.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module IpynbDiff
+ # Helper functions
+ module SymbolizedMarkdownHelper
+
+ def _(symbol = nil, content = '')
+ { symbol: symbol, content: content }
+ end
+
+ def symbolize_array(symbol, content, &block)
+ if content.is_a?(Array)
+ content.map.with_index { |l, idx| _(symbol / idx, block.call(l)) }
+ else
+ _(symbol, content)
+ end
+ end
+ end
+
+ # Simple wrapper for a string
+ class JsonSymbol < String
+ def /(other)
+ JsonSymbol.new((other.is_a?(Array) ? [self, *other] : [self, other]).join('.'))
+ end
+ end
+end
diff --git a/vendor/gems/ipynbdiff/lib/transformed_notebook.rb b/vendor/gems/ipynbdiff/lib/transformed_notebook.rb
new file mode 100644
index 00000000000..7a8edf7c22f
--- /dev/null
+++ b/vendor/gems/ipynbdiff/lib/transformed_notebook.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module IpynbDiff
+ # Notebook that was transformed into md, including location of source cells
+ class TransformedNotebook
+ attr_reader :blocks
+
+ def as_text
+ @blocks.map { |b| b[:content] }.join("\n")
+ end
+
+ private
+
+ def initialize(lines = [], symbol_map = {})
+ @blocks = lines.map do |line|
+ { content: line[:content], source_symbol: (symbol = line[:symbol]), source_line: symbol && symbol_map[symbol] }
+ end
+ end
+ end
+end
diff --git a/vendor/gems/ipynbdiff/lib/transformer.rb b/vendor/gems/ipynbdiff/lib/transformer.rb
new file mode 100644
index 00000000000..153d821db27
--- /dev/null
+++ b/vendor/gems/ipynbdiff/lib/transformer.rb
@@ -0,0 +1,101 @@
+# frozen_string_literal: true
+
+module IpynbDiff
+ class InvalidNotebookError < StandardError
+ end
+
+ # Returns a markdown version of the Jupyter Notebook
+ class Transformer
+ require 'json'
+ require 'yaml'
+ require 'output_transformer'
+ require 'symbolized_markdown_helper'
+ require 'ipynb_symbol_map'
+ require 'transformed_notebook'
+ include SymbolizedMarkdownHelper
+
+ @include_frontmatter = true
+ @objects_to_ignore = ['application/javascript', 'application/vnd.holoviews_load.v0+json']
+
+ def initialize(include_frontmatter: true, hide_images: false)
+ @include_frontmatter = include_frontmatter
+ @hide_images = hide_images
+ @output_transformer = OutputTransformer.new(hide_images: hide_images)
+ end
+
+ def validate_notebook(notebook)
+ notebook_json = JSON.parse(notebook)
+
+ return notebook_json if notebook_json.key?('cells')
+
+ raise InvalidNotebookError
+ rescue JSON::ParserError
+ raise InvalidNotebookError
+ end
+
+ def transform(notebook)
+ return TransformedNotebook.new unless notebook
+
+ notebook_json = validate_notebook(notebook)
+ transformed = transform_document(notebook_json)
+ symbol_map = IpynbSymbolMap.parse(notebook)
+
+ TransformedNotebook.new(transformed, symbol_map)
+ end
+
+ def transform_document(notebook)
+ symbol = JsonSymbol.new('.cells')
+
+ transformed_blocks = notebook['cells'].map.with_index do |cell, idx|
+ decorate_cell(transform_cell(cell, notebook, symbol / idx), cell, symbol / idx)
+ end
+
+ transformed_blocks.prepend(transform_metadata(notebook)) if @include_frontmatter
+ transformed_blocks.flatten
+ end
+
+ def decorate_cell(rows, cell, symbol)
+ tags = cell['metadata']&.fetch('tags', [])
+ type = cell['cell_type'] || 'raw'
+
+ [
+ _(symbol, %(%% Cell type:#{type} id:#{cell['id']} tags:#{tags&.join(',')})),
+ _,
+ rows,
+ _
+ ]
+ end
+
+ def transform_cell(cell, notebook, symbol)
+ cell['cell_type'] == 'code' ? transform_code_cell(cell, notebook, symbol) : transform_text_cell(cell, symbol)
+ end
+
+ def transform_code_cell(cell, notebook, symbol)
+ [
+ _(symbol / 'source', %(``` #{notebook.dig('metadata', 'kernelspec', 'language') || ''})),
+ symbolize_array(symbol / 'source', cell['source'], &:rstrip),
+ _(nil, '```'),
+ cell['outputs'].map.with_index do |output, idx|
+ @output_transformer.transform(output, symbol / ['outputs', idx])
+ end
+ ]
+ end
+
+ def transform_text_cell(cell, symbol)
+ symbolize_array(symbol / 'source', cell['source'], &:rstrip)
+ end
+
+ def transform_metadata(notebook_json)
+ as_yaml = {
+ 'jupyter' => {
+ 'kernelspec' => notebook_json['metadata']['kernelspec'],
+ 'language_info' => notebook_json['metadata']['language_info'],
+ 'nbformat' => notebook_json['nbformat'],
+ 'nbformat_minor' => notebook_json['nbformat_minor']
+ }
+ }.to_yaml
+
+ as_yaml.split("\n").map { |l| _(nil, l) }.append(_(nil, '---'), _)
+ end
+ end
+end
diff --git a/vendor/gems/ipynbdiff/lib/version.rb b/vendor/gems/ipynbdiff/lib/version.rb
new file mode 100644
index 00000000000..1451bb4ef32
--- /dev/null
+++ b/vendor/gems/ipynbdiff/lib/version.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+module IpynbDiff
+ VERSION = '0.4.7'
+end
diff --git a/vendor/gems/ipynbdiff/spec/ipynb_symbol_map_spec.rb b/vendor/gems/ipynbdiff/spec/ipynb_symbol_map_spec.rb
new file mode 100644
index 00000000000..a002fc370f5
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/ipynb_symbol_map_spec.rb
@@ -0,0 +1,165 @@
+# frozen_string_literal: true
+
+require 'rspec'
+require 'json'
+require 'rspec-parameterized'
+require 'ipynb_symbol_map'
+
+describe IpynbDiff::IpynbSymbolMap do
+ def res(*cases)
+ cases&.to_h || []
+ end
+
+ describe '#parse_string' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:mapper) { IpynbDiff::IpynbSymbolMap.new(input) }
+
+ where(:input, :result) do
+ # Empty string
+ '""' | ''
+ # Some string with quotes
+ '"he\nll\"o"' | 'he\nll\"o'
+ end
+
+ with_them do
+ it { expect(mapper.parse_string(return_value: true)).to eq(result) }
+ it { expect(mapper.parse_string).to be_nil }
+ it { expect(mapper.results).to be_empty }
+ end
+
+ it 'raises if invalid string' do
+ mapper = IpynbDiff::IpynbSymbolMap.new('"')
+
+ expect { mapper.parse_string }.to raise_error(IpynbDiff::InvalidTokenError)
+ end
+
+ end
+
+ describe '#parse_object' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:mapper) { IpynbDiff::IpynbSymbolMap.new(notebook, objects_to_ignore) }
+
+ before do
+ mapper.parse_object('')
+ end
+
+ where(:notebook, :objects_to_ignore, :result) do
+ # Empty object
+ '{ }' | [] | res
+ # Object with string
+ '{ "hello" : "world" }' | [] | res(['.hello', 0])
+ # Object with boolean
+ '{ "hello" : true }' | [] | res(['.hello', 0])
+ # Object with integer
+ '{ "hello" : 1 }' | [] | res(['.hello', 0])
+ # Object with 2 properties in the same line
+ '{ "hello" : "world" , "my" : "bad" }' | [] | res(['.hello', 0], ['.my', 0])
+ # Object with 2 properties in the different lines line
+ "{ \"hello\" : \"world\" , \n \n \"my\" : \"bad\" }" | [] | res(['.hello', 0], ['.my', 2])
+ # Object with 2 properties, but one is ignored
+ "{ \"hello\" : \"world\" , \n \n \"my\" : \"bad\" }" | ['hello'] | res(['.my', 2])
+ end
+
+ with_them do
+ it { expect(mapper.results).to include(result) }
+ end
+ end
+
+ describe '#parse_array' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:notebook, :result) do
+ # Empty Array
+ '[]' | res
+ # Array with string value
+ '["a"]' | res(['.0', 0])
+ # Array with boolean
+ '[ true ]' | res(['.0', 0])
+ # Array with integer
+ '[ 1 ]' | res(['.0', 0])
+ # Two values on the same line
+ '["a", "b"]' | res(['.0', 0], ['.1', 0])
+ # With line breaks'
+ "[\n \"a\" \n , \n \"b\" ]" | res(['.0', 1], ['.1', 3])
+ end
+
+ let(:mapper) { IpynbDiff::IpynbSymbolMap.new(notebook) }
+
+ before do
+ mapper.parse_array('')
+ end
+
+ with_them do
+ it { expect(mapper.results).to match_array(result) }
+ end
+ end
+
+ describe '#skip_object' do
+ subject { IpynbDiff::IpynbSymbolMap.parse(JSON.pretty_generate(source)) }
+ end
+
+ describe '#parse' do
+
+ let(:objects_to_ignore) { [] }
+
+ subject { IpynbDiff::IpynbSymbolMap.parse(JSON.pretty_generate(source), objects_to_ignore) }
+
+ context 'Empty object' do
+ let(:source) { {} }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'Object with inner object and number' do
+ let(:source) { { obj1: { obj2: 1 } } }
+
+ it { is_expected.to match_array(res(['.obj1', 1], ['.obj1.obj2', 2])) }
+ end
+
+ context 'Object with inner object and number, string and array with object' do
+ let(:source) { { obj1: { obj2: [123, 2, true], obj3: "hel\nlo", obj4: true, obj5: 123, obj6: 'a' } } }
+
+ it do
+ is_expected.to match_array(
+ res(['.obj1', 1],
+ ['.obj1.obj2', 2],
+ ['.obj1.obj2.0', 3],
+ ['.obj1.obj2.1', 4],
+ ['.obj1.obj2.2', 5],
+ ['.obj1.obj3', 7],
+ ['.obj1.obj4', 8],
+ ['.obj1.obj5', 9],
+ ['.obj1.obj6', 10])
+ )
+ end
+ end
+
+ context 'When index is exceeded because of failure' do
+ it 'raises an exception' do
+ source = '{"\\a": "a\""}'
+
+ mapper = IpynbDiff::IpynbSymbolMap.new(source)
+
+ expect(mapper).to receive(:prev_backslash?).at_least(1).time.and_return(false)
+
+ expect { mapper.parse('') }.to raise_error(IpynbDiff::InvalidTokenError)
+ end
+ end
+
+ context 'Object with inner object and number, string and array with object' do
+ let(:source) { { obj1: { obj2: [123, 2, true], obj3: "hel\nlo", obj4: true, obj5: 123, obj6: { obj7: 'a' } } } }
+ let(:objects_to_ignore) { %w(obj2 obj6) }
+ it do
+ is_expected.to match_array(
+ res(['.obj1', 1],
+ ['.obj1.obj3', 7],
+ ['.obj1.obj4', 8],
+ ['.obj1.obj5', 9],
+ )
+ )
+ end
+ end
+ end
+end
diff --git a/vendor/gems/ipynbdiff/spec/ipynbdiff_spec.rb b/vendor/gems/ipynbdiff/spec/ipynbdiff_spec.rb
new file mode 100644
index 00000000000..1c2a2188edf
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/ipynbdiff_spec.rb
@@ -0,0 +1,126 @@
+# frozen_string_literal: true
+
+require 'ipynbdiff'
+require 'rspec'
+require 'rspec-parameterized'
+
+BASE_PATH = File.join(File.expand_path(File.dirname(__FILE__)), 'testdata')
+
+describe IpynbDiff do
+ def diff_signs(diff)
+ diff.to_s(:text).scan(/.*\n/).map { |l| l[0] }.join('')
+ end
+
+ describe 'diff' do
+ let(:from_path) { File.join(BASE_PATH, 'from.ipynb') }
+ let(:to_path) { File.join(BASE_PATH,'to.ipynb') }
+ let(:from) { File.read(from_path) }
+ let(:to) { File.read(to_path) }
+ let(:include_frontmatter) { false }
+ let(:hide_images) { false }
+
+ subject { IpynbDiff.diff(from, to, include_frontmatter: include_frontmatter, hide_images: hide_images) }
+
+ context 'if preprocessing is active' do
+ it 'html tables are stripped' do
+ is_expected.to_not include('<td>')
+ end
+ end
+
+ context 'when to is nil' do
+ let(:to) { nil }
+ let(:from_path) { File.join(BASE_PATH, 'only_md', 'input.ipynb') }
+
+ it 'all lines are removals' do
+ expect(diff_signs(subject)).to eq('-----')
+ end
+ end
+
+ context 'when to is nil' do
+ let(:from) { nil }
+ let(:to_path) { File.join(BASE_PATH, 'only_md', 'input.ipynb') }
+
+ it 'all lines are additions' do
+ expect(diff_signs(subject)).to eq('+++++')
+ end
+ end
+
+ context 'When include_frontmatter is true' do
+ let(:include_frontmatter) { true }
+
+ it 'should show changes metadata in the metadata' do
+ expect(subject.to_s(:text)).to include('+ display_name: New Python 3 (ipykernel)')
+ end
+ end
+
+ context 'When hide_images is true' do
+ let(:hide_images) { true }
+
+ it 'hides images' do
+ expect(subject.to_s(:text)).to include(' [Hidden Image Output]')
+ end
+ end
+
+ context 'When include_frontmatter is false' do
+ it 'should drop metadata from the diff' do
+ expect(subject.to_s(:text)).to_not include('+ display_name: New Python 3 (ipykernel)')
+ end
+ end
+
+ context 'when either notebook can not be processed' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:ctx, :from, :to) do
+ 'because from is invalid' | 'a' | nil
+ 'because from does not have the cell tag' | '{"metadata":[]}' | nil
+ 'because to is invalid' | nil | 'a'
+ 'because to does not have the cell tag' | nil | '{"metadata":[]}'
+ end
+
+ with_them do
+ it { is_expected.to be_nil }
+ end
+ end
+ end
+
+ describe 'transform' do
+ [nil, 'a', '{"metadata":[]}'].each do |invalid_nb|
+ context "when json is invalid (#{invalid_nb || 'nil'})" do
+ it 'is nil' do
+ expect(IpynbDiff.transform(invalid_nb)).to be_nil
+ end
+ end
+ end
+
+ context 'options' do
+ let(:include_frontmatter) { false }
+ let(:hide_images) { false }
+
+ subject do
+ IpynbDiff.transform(File.read(File.join(BASE_PATH, 'from.ipynb')),
+ include_frontmatter: include_frontmatter,
+ hide_images: hide_images)
+ end
+
+ context 'include_frontmatter is false' do
+ it { is_expected.to_not include('display_name: Python 3 (ipykernel)') }
+ end
+
+ context 'include_frontmatter is true' do
+ let(:include_frontmatter) { true }
+
+ it { is_expected.to include('display_name: Python 3 (ipykernel)') }
+ end
+
+ context 'hide_images is false' do
+ it { is_expected.not_to include('[Hidden Image Output]') }
+ end
+
+ context 'hide_images is true' do
+ let(:hide_images) { true }
+
+ it { is_expected.to include(' [Hidden Image Output]') }
+ end
+ end
+ end
+end
diff --git a/vendor/gems/ipynbdiff/spec/testdata/backslash_as_last_char/expected.md b/vendor/gems/ipynbdiff/spec/testdata/backslash_as_last_char/expected.md
new file mode 100644
index 00000000000..299e286c679
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/backslash_as_last_char/expected.md
@@ -0,0 +1,7 @@
+%% Cell type:markdown id: tags:
+
+\
+
+%% Cell type:markdown id: tags:
+
+a
diff --git a/vendor/gems/ipynbdiff/spec/testdata/backslash_as_last_char/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/backslash_as_last_char/expected_symbols.txt
new file mode 100644
index 00000000000..6fa29ae28de
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/backslash_as_last_char/expected_symbols.txt
@@ -0,0 +1,7 @@
+.cells.0
+
+.cells.0.source.0
+
+.cells.1
+
+.cells.1.source.0
diff --git a/vendor/gems/ipynbdiff/spec/testdata/backslash_as_last_char/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/backslash_as_last_char/input.ipynb
new file mode 100644
index 00000000000..0714044e3ae
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/backslash_as_last_char/input.ipynb
@@ -0,0 +1,16 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "source": [
+ "\\"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "a"
+ ]
+ }
+ ]
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/error_output/expected.md b/vendor/gems/ipynbdiff/spec/testdata/error_output/expected.md
new file mode 100644
index 00000000000..5be645de9c9
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/error_output/expected.md
@@ -0,0 +1,16 @@
+%% Cell type:code id:5 tags:
+
+``` python
+# A cell that has an error
+y = sin(x)
+```
+
+%%%% Output: error
+
+ ---------------------------------------------------------------------------
+ NameError Traceback (most recent call last)
+ /var/folders/cq/l637k4x13gx6y9p_gfs4c_gc0000gn/T/ipykernel_72857/3962062127.py in <module>
+ 1 # A cell that has an error
+ ----> 2 y = sin(x)
+
+ NameError: name 'sin' is not defined
diff --git a/vendor/gems/ipynbdiff/spec/testdata/error_output/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/error_output/expected_symbols.txt
new file mode 100644
index 00000000000..75e35d123d0
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/error_output/expected_symbols.txt
@@ -0,0 +1,16 @@
+.cells.0
+
+.cells.0.source
+.cells.0.source.0
+.cells.0.source.1
+
+
+.cells.0.outputs.0
+
+.cells.0.outputs.0.traceback.0
+.cells.0.outputs.0.traceback.1
+.cells.0.outputs.0.traceback.2
+.cells.0.outputs.0.traceback.2
+.cells.0.outputs.0.traceback.2
+.cells.0.outputs.0.traceback.2
+.cells.0.outputs.0.traceback.3
diff --git a/vendor/gems/ipynbdiff/spec/testdata/error_output/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/error_output/input.ipynb
new file mode 100644
index 00000000000..45ee81a0e2d
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/error_output/input.ipynb
@@ -0,0 +1,32 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "5",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "NameError",
+ "evalue": "name 'sin' is not defined",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
+ "\u001b[0;32m/var/folders/cq/l637k4x13gx6y9p_gfs4c_gc0000gn/T/ipykernel_72857/3962062127.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# A cell that has an error\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;31mNameError\u001b[0m: name 'sin' is not defined"
+ ]
+ }
+ ],
+ "source": [
+ "# A cell that has an error\n",
+ "y = sin(x)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "language": "python"
+ }
+ }
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/from.ipynb b/vendor/gems/ipynbdiff/spec/testdata/from.ipynb
new file mode 100644
index 00000000000..a731c9bfffd
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/from.ipynb
@@ -0,0 +1,198 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "0aac5da7-745c-4eda-847a-3d0d07a1bb9b",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# This is a markdown cell\n",
+ "\n",
+ "This paragraph has\n",
+ "With\n",
+ "Many\n",
+ "Lines. How we will he handle MR notes?\n",
+ "\n",
+ "But I can add another paragraph"
+ ]
+ },
+ {
+ "cell_type": "raw",
+ "id": "faecea5b-de0a-49fa-9a3a-61c2add652da",
+ "metadata": {},
+ "source": [
+ "This is a raw cell\n",
+ "With\n",
+ "Multiple lines"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "893ca2c0-ab75-4276-9dad-be1c40e16e8a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "0d707fb5-226f-46d6-80bd-489ebfb8905c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "np.random.seed(42)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "35467fcf-28b1-4c7b-bb09-4cb192c35293",
+ "metadata": {
+ "tags": [
+ "senoid"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[<matplotlib.lines.Line2D at 0x123e39370>]"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "some_invalid_base64_image_here\n",
+ "text/plain": [
+ "<Figure size 432x288 with 1 Axes>"
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "x = np.linspace(0, 4*np.pi,50)\n",
+ "y = np.sin(x)\n",
+ "\n",
+ "plt.plot(x, y)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "dc1178cd-c46d-4da3-9ab5-08f000699884",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "df = pd.DataFrame({\"x\": x, \"y\": y})"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "6e749b4f-b409-4700-870f-f68c39462490",
+ "metadata": {
+ "tags": [
+ "some-table"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "<div>\n",
+ "<style scoped>\n",
+ " .dataframe tbody tr th:only-of-type {\n",
+ " vertical-align: middle;\n",
+ " }\n",
+ "\n",
+ " .dataframe tbody tr th {\n",
+ " vertical-align: top;\n",
+ " }\n",
+ "\n",
+ " .dataframe thead th {\n",
+ " text-align: right;\n",
+ " }\n",
+ "</style>\n",
+ "<table border=\"1\" class=\"dataframe\">\n",
+ " <thead>\n",
+ " <tr style=\"text-align: right;\">\n",
+ " <th></th>\n",
+ " <th>x</th>\n",
+ " <th>y</th>\n",
+ " </tr>\n",
+ " </thead>\n",
+ " <tbody>\n",
+ " <tr>\n",
+ " <th>0</th>\n",
+ " <td>0.000000</td>\n",
+ " <td>0.000000</td>\n",
+ " </tr>\n",
+ " <tr>\n",
+ " <th>1</th>\n",
+ " <td>0.256457</td>\n",
+ " <td>0.253655</td>\n",
+ " </tr>\n",
+ " </tbody>\n",
+ "</table>\n",
+ "</div>"
+ ],
+ "text/plain": [
+ " x y\n",
+ "0 0.000000 0.000000\n",
+ "1 0.256457 0.253655"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df[:2]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0ddef5ef-94a3-4afd-9c70-ddee9694f512",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ },
+ "toc-showtags": true
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/hide_images/expected.md b/vendor/gems/ipynbdiff/spec/testdata/hide_images/expected.md
new file mode 100644
index 00000000000..89a812740a6
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/hide_images/expected.md
@@ -0,0 +1,12 @@
+%% Cell type:code id:5 tags:senoid
+
+``` python
+```
+
+%%%% Output: display_data
+
+ [Hidden Image Output]
+
+%%%% Output: display_data
+
+ [Hidden Image Output]
diff --git a/vendor/gems/ipynbdiff/spec/testdata/hide_images/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/hide_images/expected_symbols.txt
new file mode 100644
index 00000000000..b94e9538f58
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/hide_images/expected_symbols.txt
@@ -0,0 +1,12 @@
+.cells.0
+
+.cells.0.source
+
+
+.cells.0.outputs.0
+
+
+
+.cells.0.outputs.1
+
+
diff --git a/vendor/gems/ipynbdiff/spec/testdata/hide_images/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/hide_images/input.ipynb
new file mode 100644
index 00000000000..dab0e5bb9cf
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/hide_images/input.ipynb
@@ -0,0 +1,45 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "5",
+ "metadata": {
+ "tags": [
+ "senoid"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/png": "this_is_an_invalid_hash_for_testing_purposes\n",
+ "text/plain": [
+ "<Figure size 432x288 with 1 Axes>"
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\"><circle cx=\"50\" cy=\"50\" r=\"50\"/></svg>",
+ "text/plain": [
+ "<IPython.core.display.SVG object>"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "language": "python"
+ }
+ }
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/ignore_html_output/expected.md b/vendor/gems/ipynbdiff/spec/testdata/ignore_html_output/expected.md
new file mode 100644
index 00000000000..456224f3aff
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/ignore_html_output/expected.md
@@ -0,0 +1,11 @@
+%% Cell type:code id:5 tags:some-table
+
+``` python
+df[:2]
+```
+
+%%%% Output: execute_result
+
+ x y
+ 0 0.000000 0.000000
+ 1 0.256457 0.507309
diff --git a/vendor/gems/ipynbdiff/spec/testdata/ignore_html_output/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/ignore_html_output/expected_symbols.txt
new file mode 100644
index 00000000000..fa9d412c6dc
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/ignore_html_output/expected_symbols.txt
@@ -0,0 +1,11 @@
+.cells.0
+
+.cells.0.source
+.cells.0.source.0
+
+
+.cells.0.outputs.0
+
+.cells.0.outputs.0.data.text/plain.0
+.cells.0.outputs.0.data.text/plain.1
+.cells.0.outputs.0.data.text/plain.2
diff --git a/vendor/gems/ipynbdiff/spec/testdata/ignore_html_output/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/ignore_html_output/input.ipynb
new file mode 100644
index 00000000000..26117a78934
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/ignore_html_output/input.ipynb
@@ -0,0 +1,74 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "5",
+ "metadata": {
+ "tags": [
+ "some-table"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "<div>\n",
+ "<style scoped>\n",
+ " .dataframe tbody tr th:only-of-type {\n",
+ " vertical-align: middle;\n",
+ " }\n",
+ "\n",
+ " .dataframe tbody tr th {\n",
+ " vertical-align: top;\n",
+ " }\n",
+ "\n",
+ " .dataframe thead th {\n",
+ " text-align: right;\n",
+ " }\n",
+ "</style>\n",
+ "<table border=\"1\" class=\"dataframe\">\n",
+ " <thead>\n",
+ " <tr style=\"text-align: right;\">\n",
+ " <th></th>\n",
+ " <th>x</th>\n",
+ " <th>y</th>\n",
+ " </tr>\n",
+ " </thead>\n",
+ " <tbody>\n",
+ " <tr>\n",
+ " <th>0</th>\n",
+ " <td>0.000000</td>\n",
+ " <td>0.000000</td>\n",
+ " </tr>\n",
+ " <tr>\n",
+ " <th>1</th>\n",
+ " <td>0.256457</td>\n",
+ " <td>0.507309</td>\n",
+ " </tr>\n",
+ " </tbody>\n",
+ "</table>\n",
+ "</div>"
+ ],
+ "text/plain": [
+ " x y\n",
+ "0 0.000000 0.000000\n",
+ "1 0.256457 0.507309"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df[:2]"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "language": "python"
+ }
+ }
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/latex_output/expected.md b/vendor/gems/ipynbdiff/spec/testdata/latex_output/expected.md
new file mode 100644
index 00000000000..add84ed26a0
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/latex_output/expected.md
@@ -0,0 +1,10 @@
+%% Cell type:code id:5 tags:
+
+``` python
+from IPython.display import display, Math
+display(Math(r'Dims: {}x{}m \\ Area: {}m^2 \\ Volume: {}m^3'.format(1, round(2,2), 3, 4)))
+```
+
+%%%% Output: display_data
+
+ $\displaystyle Dims: 1x2m \\ Area: 3m^2 \\ Volume: 4m^3$
diff --git a/vendor/gems/ipynbdiff/spec/testdata/latex_output/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/latex_output/expected_symbols.txt
new file mode 100644
index 00000000000..9407e6db702
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/latex_output/expected_symbols.txt
@@ -0,0 +1,10 @@
+.cells.0
+
+.cells.0.source
+.cells.0.source.0
+.cells.0.source.1
+
+
+.cells.0.outputs.0
+
+.cells.0.outputs.0.data.text/latex.0
diff --git a/vendor/gems/ipynbdiff/spec/testdata/latex_output/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/latex_output/input.ipynb
new file mode 100644
index 00000000000..f8ff3e72beb
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/latex_output/input.ipynb
@@ -0,0 +1,34 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "5",
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle Dims: 1x2m \\\\ Area: 3m^2 \\\\ Volume: 4m^3$"
+ ],
+ "text/plain": [
+ "<IPython.core.display.Math object>"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "from IPython.display import display, Math\n",
+ "display(Math(r'Dims: {}x{}m \\\\ Area: {}m^2 \\\\ Volume: {}m^3'.format(1, round(2,2), 3, 4)))"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ }
+ }
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/multiline_png_output/expected.md b/vendor/gems/ipynbdiff/spec/testdata/multiline_png_output/expected.md
new file mode 100644
index 00000000000..4a880d8ce18
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/multiline_png_output/expected.md
@@ -0,0 +1,9 @@
+%% Cell type:code id:5 tags:
+
+```
+Some Image
+```
+
+%%%% Output: display_data
+
+ ![](data:image/png;base64,this_is_an_invalid_hash_for_testing_purposes)
diff --git a/vendor/gems/ipynbdiff/spec/testdata/multiline_png_output/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/multiline_png_output/expected_symbols.txt
new file mode 100644
index 00000000000..26e11781ec1
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/multiline_png_output/expected_symbols.txt
@@ -0,0 +1,9 @@
+.cells.0
+
+.cells.0.source
+.cells.0.source.0
+
+
+.cells.0.outputs.0
+
+.cells.0.outputs.0.data.image/png
diff --git a/vendor/gems/ipynbdiff/spec/testdata/multiline_png_output/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/multiline_png_output/input.ipynb
new file mode 100644
index 00000000000..4d19a504553
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/multiline_png_output/input.ipynb
@@ -0,0 +1,25 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "id": "5",
+ "metadata": {
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/png": [
+ "this_is_an_invalid_hash_for_testing_purposes"
+ ]
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "Some Image"
+ ]
+ }
+ ],
+ "metadata": {
+ }
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/no_cells/expected.md b/vendor/gems/ipynbdiff/spec/testdata/no_cells/expected.md
new file mode 100644
index 00000000000..b7c09c51fb8
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/no_cells/expected.md
@@ -0,0 +1,19 @@
+---
+jupyter:
+ kernelspec:
+ display_name: Python 3 (ipykernel)
+ language: python
+ name: python3
+ language_info:
+ codemirror_mode:
+ name: ipython
+ version: 3
+ file_extension: ".py"
+ mimetype: text/x-python
+ name: python
+ nbconvert_exporter: python
+ pygments_lexer: ipython3
+ version: 3.9.7
+ nbformat: 4
+ nbformat_minor: 5
+---
diff --git a/vendor/gems/ipynbdiff/spec/testdata/no_cells/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/no_cells/expected_symbols.txt
new file mode 100644
index 00000000000..a60f3032882
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/no_cells/expected_symbols.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vendor/gems/ipynbdiff/spec/testdata/no_cells/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/no_cells/input.ipynb
new file mode 100644
index 00000000000..c2ba0ebf50a
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/no_cells/input.ipynb
@@ -0,0 +1,25 @@
+{
+ "cells": [],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ },
+ "toc-showtags": true
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/no_cells_no_metadata/expected.md b/vendor/gems/ipynbdiff/spec/testdata/no_cells_no_metadata/expected.md
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/no_cells_no_metadata/expected.md
diff --git a/vendor/gems/ipynbdiff/spec/testdata/no_cells_no_metadata/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/no_cells_no_metadata/expected_symbols.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/no_cells_no_metadata/expected_symbols.txt
diff --git a/vendor/gems/ipynbdiff/spec/testdata/no_cells_no_metadata/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/no_cells_no_metadata/input.ipynb
new file mode 100644
index 00000000000..c2ba0ebf50a
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/no_cells_no_metadata/input.ipynb
@@ -0,0 +1,25 @@
+{
+ "cells": [],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ },
+ "toc-showtags": true
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/no_metadata_on_cell/expected.md b/vendor/gems/ipynbdiff/spec/testdata/no_metadata_on_cell/expected.md
new file mode 100644
index 00000000000..d9d72bf8f76
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/no_metadata_on_cell/expected.md
@@ -0,0 +1,13 @@
+%% Cell type:markdown id:1 tags:
+
+# A
+
+B
+
+%% Cell type:code id:3 tags:
+
+``` python
+import pandas as pd
+import numpy as np
+import matplotlib.pyplot as plt
+```
diff --git a/vendor/gems/ipynbdiff/spec/testdata/no_metadata_on_cell/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/no_metadata_on_cell/expected_symbols.txt
new file mode 100644
index 00000000000..a7000494a1b
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/no_metadata_on_cell/expected_symbols.txt
@@ -0,0 +1,13 @@
+.cells.0
+
+.cells.0.source.0
+.cells.0.source.1
+.cells.0.source.2
+
+.cells.1
+
+.cells.1.source
+.cells.1.source.0
+.cells.1.source.1
+.cells.1.source.2
+
diff --git a/vendor/gems/ipynbdiff/spec/testdata/no_metadata_on_cell/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/no_metadata_on_cell/input.ipynb
new file mode 100644
index 00000000000..62060124a2a
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/no_metadata_on_cell/input.ipynb
@@ -0,0 +1,29 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "1",
+ "source": [
+ "# A\n",
+ "\n",
+ "B"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "3",
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "language": "python"
+ }
+ }
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/only_code/expected.md b/vendor/gems/ipynbdiff/spec/testdata/only_code/expected.md
new file mode 100644
index 00000000000..124b8217a6a
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/only_code/expected.md
@@ -0,0 +1,7 @@
+%% Cell type:code id:3 tags:
+
+``` python
+import pandas as pd
+import numpy as np
+import matplotlib.pyplot as plt
+```
diff --git a/vendor/gems/ipynbdiff/spec/testdata/only_code/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/only_code/expected_symbols.txt
new file mode 100644
index 00000000000..59b11103195
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/only_code/expected_symbols.txt
@@ -0,0 +1,7 @@
+.cells.0
+
+.cells.0.source
+.cells.0.source.0
+.cells.0.source.1
+.cells.0.source.2
+
diff --git a/vendor/gems/ipynbdiff/spec/testdata/only_code/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/only_code/input.ipynb
new file mode 100644
index 00000000000..a93108dccb8
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/only_code/input.ipynb
@@ -0,0 +1,21 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "language": "python"
+ }
+ }
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/only_code_no_kernelspec/expected.md b/vendor/gems/ipynbdiff/spec/testdata/only_code_no_kernelspec/expected.md
new file mode 100644
index 00000000000..9100045e0f5
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/only_code_no_kernelspec/expected.md
@@ -0,0 +1,5 @@
+%% Cell type:code id:3 tags:
+
+```
+
+```
diff --git a/vendor/gems/ipynbdiff/spec/testdata/only_code_no_kernelspec/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/only_code_no_kernelspec/expected_symbols.txt
new file mode 100644
index 00000000000..5f9ad320b8c
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/only_code_no_kernelspec/expected_symbols.txt
@@ -0,0 +1,5 @@
+.cells.0
+
+.cells.0.source
+.cells.0.source
+
diff --git a/vendor/gems/ipynbdiff/spec/testdata/only_code_no_kernelspec/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/only_code_no_kernelspec/input.ipynb
new file mode 100644
index 00000000000..c3ff71057a6
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/only_code_no_kernelspec/input.ipynb
@@ -0,0 +1,12 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "3",
+ "source": "",
+ "outputs": []
+ }
+ ],
+ "metadata": {}
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/only_code_no_language/expected.md b/vendor/gems/ipynbdiff/spec/testdata/only_code_no_language/expected.md
new file mode 100644
index 00000000000..9100045e0f5
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/only_code_no_language/expected.md
@@ -0,0 +1,5 @@
+%% Cell type:code id:3 tags:
+
+```
+
+```
diff --git a/vendor/gems/ipynbdiff/spec/testdata/only_code_no_language/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/only_code_no_language/expected_symbols.txt
new file mode 100644
index 00000000000..5f9ad320b8c
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/only_code_no_language/expected_symbols.txt
@@ -0,0 +1,5 @@
+.cells.0
+
+.cells.0.source
+.cells.0.source
+
diff --git a/vendor/gems/ipynbdiff/spec/testdata/only_code_no_language/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/only_code_no_language/input.ipynb
new file mode 100644
index 00000000000..fb16b106cbe
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/only_code_no_language/input.ipynb
@@ -0,0 +1,14 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "3",
+ "source": "",
+ "outputs": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {}
+ }
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/only_code_no_metadata/expected.md b/vendor/gems/ipynbdiff/spec/testdata/only_code_no_metadata/expected.md
new file mode 100644
index 00000000000..9100045e0f5
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/only_code_no_metadata/expected.md
@@ -0,0 +1,5 @@
+%% Cell type:code id:3 tags:
+
+```
+
+```
diff --git a/vendor/gems/ipynbdiff/spec/testdata/only_code_no_metadata/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/only_code_no_metadata/expected_symbols.txt
new file mode 100644
index 00000000000..5f9ad320b8c
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/only_code_no_metadata/expected_symbols.txt
@@ -0,0 +1,5 @@
+.cells.0
+
+.cells.0.source
+.cells.0.source
+
diff --git a/vendor/gems/ipynbdiff/spec/testdata/only_code_no_metadata/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/only_code_no_metadata/input.ipynb
new file mode 100644
index 00000000000..364c080168b
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/only_code_no_metadata/input.ipynb
@@ -0,0 +1,11 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "3",
+ "source": "",
+ "outputs": []
+ }
+ ]
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/only_md/expected.md b/vendor/gems/ipynbdiff/spec/testdata/only_md/expected.md
new file mode 100644
index 00000000000..bdf4db5aea5
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/only_md/expected.md
@@ -0,0 +1,5 @@
+%% Cell type:markdown id:1 tags:hello,world
+
+# A
+
+B
diff --git a/vendor/gems/ipynbdiff/spec/testdata/only_md/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/only_md/expected_symbols.txt
new file mode 100644
index 00000000000..d3d6d526fc3
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/only_md/expected_symbols.txt
@@ -0,0 +1,5 @@
+.cells.0
+
+.cells.0.source.0
+.cells.0.source.1
+.cells.0.source.2
diff --git a/vendor/gems/ipynbdiff/spec/testdata/only_md/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/only_md/input.ipynb
new file mode 100644
index 00000000000..9d6b550af31
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/only_md/input.ipynb
@@ -0,0 +1,21 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "1",
+ "metadata": {
+ "tags": [
+ "hello",
+ "world"
+ ]
+ },
+ "source": [
+ "# A\n",
+ "\n",
+ "B"
+ ]
+ }
+ ],
+ "metadata": {
+ }
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/only_raw/expected.md b/vendor/gems/ipynbdiff/spec/testdata/only_raw/expected.md
new file mode 100644
index 00000000000..91c476e843b
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/only_raw/expected.md
@@ -0,0 +1,4 @@
+%% Cell type:raw id:2 tags:
+
+A
+B
diff --git a/vendor/gems/ipynbdiff/spec/testdata/only_raw/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/only_raw/expected_symbols.txt
new file mode 100644
index 00000000000..bceaf355c2f
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/only_raw/expected_symbols.txt
@@ -0,0 +1,4 @@
+.cells.0
+
+.cells.0.source.0
+.cells.0.source.1
diff --git a/vendor/gems/ipynbdiff/spec/testdata/only_raw/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/only_raw/input.ipynb
new file mode 100644
index 00000000000..750e1bba615
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/only_raw/input.ipynb
@@ -0,0 +1,15 @@
+{
+ "cells": [
+ {
+ "cell_type": "raw",
+ "id": "2",
+ "metadata": {},
+ "source": [
+ "A\n",
+ "B"
+ ]
+ }
+ ],
+ "metadata": {
+ }
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/percent_decorator/expected.md b/vendor/gems/ipynbdiff/spec/testdata/percent_decorator/expected.md
new file mode 100644
index 00000000000..ecb0029f256
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/percent_decorator/expected.md
@@ -0,0 +1,70 @@
+%% Cell type:markdown id:0aac5da7-745c-4eda-847a-3d0d07a1bb9b tags:
+
+# This is a markdown cell
+
+This paragraph has
+With
+Many
+Lines. How we will he handle MR notes?
+
+But I can add another paragraph
+
+%% Cell type:raw id:faecea5b-de0a-49fa-9a3a-61c2add652da tags:
+
+This is a raw cell
+With
+Multiple lines
+
+%% Cell type:code id:893ca2c0-ab75-4276-9dad-be1c40e16e8a tags:
+
+``` python
+import pandas as pd
+import numpy as np
+import matplotlib.pyplot as plt
+```
+
+%% Cell type:code id:0d707fb5-226f-46d6-80bd-489ebfb8905c tags:
+
+``` python
+np.random.seed(42)
+```
+
+%% Cell type:code id:35467fcf-28b1-4c7b-bb09-4cb192c35293 tags:senoid
+
+``` python
+x = np.linspace(0, 4*np.pi,50)
+y = np.sin(x)
+
+plt.plot(x, y)
+```
+
+%%%% Output: execute_result
+
+ [<matplotlib.lines.Line2D at 0x123e39370>]
+
+%%%% Output: display_data
+
+ ![](data:image/png;base64,some_invalid_base64_image_here)
+
+%% Cell type:code id:dc1178cd-c46d-4da3-9ab5-08f000699884 tags:
+
+``` python
+df = pd.DataFrame({"x": x, "y": y})
+```
+
+%% Cell type:code id:6e749b4f-b409-4700-870f-f68c39462490 tags:some-table
+
+``` python
+df[:2]
+```
+
+%%%% Output: execute_result
+
+ x y
+ 0 0.000000 0.000000
+ 1 0.256457 0.253655
+
+%% Cell type:code id:0ddef5ef-94a3-4afd-9c70-ddee9694f512 tags:
+
+``` python
+```
diff --git a/vendor/gems/ipynbdiff/spec/testdata/percent_decorator/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/percent_decorator/expected_symbols.txt
new file mode 100644
index 00000000000..ab70e7bc908
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/percent_decorator/expected_symbols.txt
@@ -0,0 +1,70 @@
+.cells.0
+
+.cells.0.source.0
+.cells.0.source.1
+.cells.0.source.2
+.cells.0.source.3
+.cells.0.source.4
+.cells.0.source.5
+.cells.0.source.6
+.cells.0.source.7
+
+.cells.1
+
+.cells.1.source.0
+.cells.1.source.1
+.cells.1.source.2
+
+.cells.2
+
+.cells.2.source
+.cells.2.source.0
+.cells.2.source.1
+.cells.2.source.2
+
+
+.cells.3
+
+.cells.3.source
+.cells.3.source.0
+
+
+.cells.4
+
+.cells.4.source
+.cells.4.source.0
+.cells.4.source.1
+.cells.4.source.2
+.cells.4.source.3
+
+
+.cells.4.outputs.0
+
+.cells.4.outputs.0.data.text/plain.0
+
+.cells.4.outputs.1
+
+.cells.4.outputs.1.data.image/png
+
+.cells.5
+
+.cells.5.source
+.cells.5.source.0
+
+
+.cells.6
+
+.cells.6.source
+.cells.6.source.0
+
+
+.cells.6.outputs.0
+
+.cells.6.outputs.0.data.text/plain.0
+.cells.6.outputs.0.data.text/plain.1
+.cells.6.outputs.0.data.text/plain.2
+
+.cells.7
+
+.cells.7.source
+
diff --git a/vendor/gems/ipynbdiff/spec/testdata/single_line_md/expected.md b/vendor/gems/ipynbdiff/spec/testdata/single_line_md/expected.md
new file mode 100644
index 00000000000..392a5048f59
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/single_line_md/expected.md
@@ -0,0 +1,3 @@
+%% Cell type:markdown id:1 tags:hello,world
+
+A
diff --git a/vendor/gems/ipynbdiff/spec/testdata/single_line_md/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/single_line_md/expected_symbols.txt
new file mode 100644
index 00000000000..86a7f6b3960
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/single_line_md/expected_symbols.txt
@@ -0,0 +1,3 @@
+.cells.0
+
+.cells.0.source
diff --git a/vendor/gems/ipynbdiff/spec/testdata/single_line_md/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/single_line_md/input.ipynb
new file mode 100644
index 00000000000..5ebd41adbfa
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/single_line_md/input.ipynb
@@ -0,0 +1,17 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "1",
+ "metadata": {
+ "tags": [
+ "hello",
+ "world"
+ ]
+ },
+ "source": "A"
+ }
+ ],
+ "metadata": {
+ }
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/stream_text/expected.md b/vendor/gems/ipynbdiff/spec/testdata/stream_text/expected.md
new file mode 100644
index 00000000000..fb862cbb636
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/stream_text/expected.md
@@ -0,0 +1,9 @@
+%% Cell type:code id:123 tags:
+
+``` python
+print("G'bye")
+```
+
+%%%% Output: stream
+
+ G'bye
diff --git a/vendor/gems/ipynbdiff/spec/testdata/stream_text/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/stream_text/expected_symbols.txt
new file mode 100644
index 00000000000..ed4a8a075d3
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/stream_text/expected_symbols.txt
@@ -0,0 +1,9 @@
+.cells.0
+
+.cells.0.source
+.cells.0.source.0
+
+
+.cells.0.outputs.0
+
+.cells.0.outputs.0.text.0
diff --git a/vendor/gems/ipynbdiff/spec/testdata/stream_text/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/stream_text/input.ipynb
new file mode 100644
index 00000000000..14601fe35e5
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/stream_text/input.ipynb
@@ -0,0 +1,27 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "123",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "G'bye\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(\"G'bye\")"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "language": "python"
+ }
+ }
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/svg/expected.md b/vendor/gems/ipynbdiff/spec/testdata/svg/expected.md
new file mode 100644
index 00000000000..37269446f5a
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/svg/expected.md
@@ -0,0 +1,19 @@
+%% Cell type:code id:5 tags:
+
+``` python
+from IPython.display import SVG, display
+
+svg = """<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
+ <circle cx="50" cy="50" r="50"/>
+</svg>"""
+
+display(SVG(svg))
+```
+
+%%%% Output: display_data
+
+ ![](data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle cx="50" cy="50" r="50"/></svg>)
+
+%%%% Output: display_data
+
+ ![](data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle cx="50" cy="50" r="50"/></svg>)
diff --git a/vendor/gems/ipynbdiff/spec/testdata/svg/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/svg/expected_symbols.txt
new file mode 100644
index 00000000000..dd2e412302d
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/svg/expected_symbols.txt
@@ -0,0 +1,19 @@
+.cells.0
+
+.cells.0.source
+.cells.0.source.0
+.cells.0.source.1
+.cells.0.source.2
+.cells.0.source.3
+.cells.0.source.4
+.cells.0.source.5
+.cells.0.source.6
+
+
+.cells.0.outputs.0
+
+.cells.0.outputs.0.data.image/svg+xml
+
+.cells.0.outputs.1
+
+.cells.0.outputs.1.data.image/svg+xml
diff --git a/vendor/gems/ipynbdiff/spec/testdata/svg/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/svg/input.ipynb
new file mode 100644
index 00000000000..a02d01f7bf2
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/svg/input.ipynb
@@ -0,0 +1,66 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "5",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\">\n",
+ " <circle cx=\"50\" cy=\"50\" r=\"50\"/>\n",
+ "</svg>"
+ ],
+ "text/plain": [
+ "<IPython.core.display.SVG object>"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/svg+xml": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\"><circle cx=\"50\" cy=\"50\" r=\"50\"/></svg>",
+ "text/plain": [
+ "<IPython.core.display.SVG object>"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "from IPython.display import SVG, display\n",
+ "\n",
+ "svg = \"\"\"<svg viewBox=\"0 0 100 100\" xmlns=\"http://www.w3.org/2000/svg\">\n",
+ " <circle cx=\"50\" cy=\"50\" r=\"50\"/>\n",
+ "</svg>\"\"\"\n",
+ "\n",
+ "display(SVG(svg))"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/text_output/expected.md b/vendor/gems/ipynbdiff/spec/testdata/text_output/expected.md
new file mode 100644
index 00000000000..924f4939f54
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/text_output/expected.md
@@ -0,0 +1,9 @@
+%% Cell type:code id:5 tags:senoid
+
+``` python
+plt.plot(x, y)
+```
+
+%%%% Output: execute_result
+
+ [<matplotlib.lines.Line2D at 0x12a4e43d0>]
diff --git a/vendor/gems/ipynbdiff/spec/testdata/text_output/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/text_output/expected_symbols.txt
new file mode 100644
index 00000000000..179b30098a1
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/text_output/expected_symbols.txt
@@ -0,0 +1,9 @@
+.cells.0
+
+.cells.0.source
+.cells.0.source.0
+
+
+.cells.0.outputs.0
+
+.cells.0.outputs.0.data.text/plain.0
diff --git a/vendor/gems/ipynbdiff/spec/testdata/text_output/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/text_output/input.ipynb
new file mode 100644
index 00000000000..b1b387bb99d
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/text_output/input.ipynb
@@ -0,0 +1,31 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "id": "5",
+ "metadata": {
+ "tags": [
+ "senoid"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[<matplotlib.lines.Line2D at 0x12a4e43d0>]"
+ ]
+ },
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "plt.plot(x, y)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "language": "python"
+ }
+ }
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/text_png_output/expected.md b/vendor/gems/ipynbdiff/spec/testdata/text_png_output/expected.md
new file mode 100644
index 00000000000..b1dda235951
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/text_png_output/expected.md
@@ -0,0 +1,16 @@
+%% Cell type:code id:5 tags:senoid
+
+``` python
+x = np.linspace(0, 4*np.pi,50)
+y = 2 * np.sin(x)
+
+plt.plot(x, y)
+```
+
+%%%% Output: execute_result
+
+ [<matplotlib.lines.Line2D at 0x12a4e43d0>]
+
+%%%% Output: display_data
+
+ ![](data:image/png;base64,this_is_an_invalid_hash_for_testing_purposes)
diff --git a/vendor/gems/ipynbdiff/spec/testdata/text_png_output/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/text_png_output/expected_symbols.txt
new file mode 100644
index 00000000000..5a86e4daa67
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/text_png_output/expected_symbols.txt
@@ -0,0 +1,16 @@
+.cells.0
+
+.cells.0.source
+.cells.0.source.0
+.cells.0.source.1
+.cells.0.source.2
+.cells.0.source.3
+
+
+.cells.0.outputs.0
+
+.cells.0.outputs.0.data.text/plain.0
+
+.cells.0.outputs.1
+
+.cells.0.outputs.1.data.image/png
diff --git a/vendor/gems/ipynbdiff/spec/testdata/text_png_output/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/text_png_output/input.ipynb
new file mode 100644
index 00000000000..3728b129d26
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/text_png_output/input.ipynb
@@ -0,0 +1,49 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "5",
+ "metadata": {
+ "tags": [
+ "senoid"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[<matplotlib.lines.Line2D at 0x12a4e43d0>]"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "this_is_an_invalid_hash_for_testing_purposes\n",
+ "text/plain": [
+ "<Figure size 432x288 with 1 Axes>"
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "x = np.linspace(0, 4*np.pi,50)\n",
+ "y = 2 * np.sin(x)\n",
+ "\n",
+ "plt.plot(x, y)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "language": "python"
+ }
+ }
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/to.ipynb b/vendor/gems/ipynbdiff/spec/testdata/to.ipynb
new file mode 100644
index 00000000000..99b51f3b857
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/to.ipynb
@@ -0,0 +1,200 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "0aac5da7-745c-4eda-847a-3d0d07a1bb9b",
+ "metadata": {
+ "tags": []
+ },
+ "source": [
+ "# This is a markdown cell\n",
+ "\n",
+ "This paragraph has\n",
+ "With\n",
+ "Many\n",
+ "Lines. How we will he handle MR notes?\n",
+ "\n",
+ "But I can add another paragraph\n",
+ "\n",
+ "Another paragraph added"
+ ]
+ },
+ {
+ "cell_type": "raw",
+ "id": "faecea5b-de0a-49fa-9a3a-61c2add652da",
+ "metadata": {},
+ "source": [
+ "This is a raw cell\n",
+ "With\n",
+ "Multiple lines"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "893ca2c0-ab75-4276-9dad-be1c40e16e8a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "0d707fb5-226f-46d6-80bd-489ebfb8905c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "np.random.seed(42)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "35467fcf-28b1-4c7b-bb09-4cb192c35293",
+ "metadata": {
+ "tags": [
+ "senoid"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[<matplotlib.lines.Line2D at 0x12a4e43d0>]"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "another_invalid_base64_image_here\n",
+ "text/plain": [
+ "<Figure size 432x288 with 1 Axes>"
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "x = np.linspace(0, 4*np.pi,50)\n",
+ "y = 2 * np.sin(x)\n",
+ "\n",
+ "plt.plot(x, y)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "dc1178cd-c46d-4da3-9ab5-08f000699884",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "df = pd.DataFrame({\"x\": x, \"y\": y})"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "6e749b4f-b409-4700-870f-f68c39462490",
+ "metadata": {
+ "tags": [
+ "some-table"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "<div>\n",
+ "<style scoped>\n",
+ " .dataframe tbody tr th:only-of-type {\n",
+ " vertical-align: middle;\n",
+ " }\n",
+ "\n",
+ " .dataframe tbody tr th {\n",
+ " vertical-align: top;\n",
+ " }\n",
+ "\n",
+ " .dataframe thead th {\n",
+ " text-align: right;\n",
+ " }\n",
+ "</style>\n",
+ "<table border=\"1\" class=\"dataframe\">\n",
+ " <thead>\n",
+ " <tr style=\"text-align: right;\">\n",
+ " <th></th>\n",
+ " <th>x</th>\n",
+ " <th>y</th>\n",
+ " </tr>\n",
+ " </thead>\n",
+ " <tbody>\n",
+ " <tr>\n",
+ " <th>0</th>\n",
+ " <td>0.000000</td>\n",
+ " <td>0.000000</td>\n",
+ " </tr>\n",
+ " <tr>\n",
+ " <th>1</th>\n",
+ " <td>0.256457</td>\n",
+ " <td>0.507309</td>\n",
+ " </tr>\n",
+ " </tbody>\n",
+ "</table>\n",
+ "</div>"
+ ],
+ "text/plain": [
+ " x y\n",
+ "0 0.000000 0.000000\n",
+ "1 0.256457 0.507309"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df[:2]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0ddef5ef-94a3-4afd-9c70-ddee9694f512",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "New Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.7"
+ },
+ "toc-showtags": true
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/vendor/gems/ipynbdiff/spec/testdata/unknown_output_type/expected.md b/vendor/gems/ipynbdiff/spec/testdata/unknown_output_type/expected.md
new file mode 100644
index 00000000000..af34d6eb8c3
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/unknown_output_type/expected.md
@@ -0,0 +1,5 @@
+%% Cell type:code id:123 tags:
+
+``` python
+print("G'bye")
+```
diff --git a/vendor/gems/ipynbdiff/spec/testdata/unknown_output_type/expected_symbols.txt b/vendor/gems/ipynbdiff/spec/testdata/unknown_output_type/expected_symbols.txt
new file mode 100644
index 00000000000..cb35f88c897
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/unknown_output_type/expected_symbols.txt
@@ -0,0 +1,5 @@
+.cells.0
+
+.cells.0.source
+.cells.0.source.0
+
diff --git a/vendor/gems/ipynbdiff/spec/testdata/unknown_output_type/input.ipynb b/vendor/gems/ipynbdiff/spec/testdata/unknown_output_type/input.ipynb
new file mode 100644
index 00000000000..42f4b39b365
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/testdata/unknown_output_type/input.ipynb
@@ -0,0 +1,27 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "123",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "unknown_output",
+ "text": [
+ "G'bye\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(\"G'bye\")"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "language": "python"
+ }
+ }
+}
diff --git a/vendor/gems/ipynbdiff/spec/transformer_spec.rb b/vendor/gems/ipynbdiff/spec/transformer_spec.rb
new file mode 100644
index 00000000000..8f9527847fa
--- /dev/null
+++ b/vendor/gems/ipynbdiff/spec/transformer_spec.rb
@@ -0,0 +1,90 @@
+# frozen_string_literal: true
+
+require 'rspec'
+require 'ipynbdiff'
+require 'json'
+require 'rspec-parameterized'
+
+BASE_PATH = File.join(File.expand_path(File.dirname(__FILE__)), 'testdata')
+
+def read_file(*paths)
+ File.read(File.join(BASE_PATH, *paths))
+end
+
+def default_config
+ @default_config ||= {
+ include_frontmatter: false,
+ hide_images: false
+ }
+end
+
+def from_ipynb
+ @from_ipynb ||= read_file('from.ipynb')
+end
+
+def read_notebook(input_path)
+ read_file(input_path, 'input.ipynb')
+rescue Errno::ENOENT
+ from_ipynb
+end
+
+describe IpynbDiff::Transformer do
+ describe 'When notebook is valid' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:ctx, :test_case, :config) do
+ 'renders metadata' | 'no_cells' | { include_frontmatter: true }
+ 'is empty for no cells, but metadata is false' | 'no_cells_no_metadata' | {}
+ 'adds markdown cell' | 'only_md' | {}
+ 'adds block with only one line of markdown' | 'single_line_md' | {}
+ 'adds raw block' | 'only_raw' | {}
+ 'code cell, but no output' | 'only_code' | {}
+ 'code cell, but no language' | 'only_code_no_language' | {}
+ 'code cell, but no kernelspec' | 'only_code_no_kernelspec' | {}
+ 'code cell, but no nb metadata' | 'only_code_no_metadata' | {}
+ 'text output' | 'text_output' | {}
+ 'ignores html output' | 'ignore_html_output' | {}
+ 'extracts png output along with text' | 'text_png_output' | {}
+ 'embeds svg as image' | 'svg' | {}
+ 'extracts latex output' | 'latex_output' | {}
+ 'extracts error output' | 'error_output' | {}
+ 'does not fetch tags if there is no cell metadata' | 'no_metadata_on_cell' | {}
+ 'generates :percent decorator' | 'percent_decorator' | {}
+ 'parses stream output' | 'stream_text' | {}
+ 'ignores unknown output type' | 'unknown_output_type' | {}
+ 'handles backslash correctly' | 'backslash_as_last_char' | {}
+ 'multiline png output' | 'multiline_png_output' | {}
+ 'hides images when option passed' | 'hide_images' | { hide_images: true }
+ end
+
+ with_them do
+ let(:expected_md) { read_file(test_case, 'expected.md') }
+ let(:expected_symbols) { read_file(test_case, 'expected_symbols.txt') }
+ let(:input) { read_notebook(test_case) }
+ let(:transformed) { IpynbDiff::Transformer.new(**default_config.merge(config)).transform(input) }
+
+ it 'generates the expected markdown' do
+ expect(transformed.as_text).to eq expected_md
+ end
+
+ it 'generates the expected symbol map' do
+ expect(transformed.blocks.map { |b| b[:source_symbol] }.join("\n")).to eq expected_symbols
+ end
+ end
+ end
+
+ context 'When the notebook is invalid' do
+ [
+ ['because the json is invalid', 'a'],
+ ['because it doesnt have the cell tag', '{"metadata":[]}']
+ ].each do |ctx, notebook|
+ context ctx do
+ it 'raises error' do
+ expect do
+ IpynbDiff::Transformer.new.transform(notebook)
+ end.to raise_error(IpynbDiff::InvalidNotebookError)
+ end
+ end
+ end
+ end
+end